aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/http/parser.lua7
-rw-r--r--net/http/server.lua23
-rw-r--r--plugins/mod_http_errors.lua75
3 files changed, 100 insertions, 5 deletions
diff --git a/net/http/parser.lua b/net/http/parser.lua
index c98c75af..fdcb8ebb 100644
--- a/net/http/parser.lua
+++ b/net/http/parser.lua
@@ -53,7 +53,6 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
else
method, path, httpversion = line:match("^(%w+) (%S+) HTTP/(1%.[01])$");
if not method then error = true; return error_cb("invalid-status-line"); end
- path = path:gsub("^//+", "/"); -- TODO parse url more
end
end
end
@@ -71,6 +70,12 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
responseheaders = headers;
};
else
+ -- path normalization
+ if path:match("^https?://") then
+ headers.host, path = path:match("^https?://([^/]*)(.*)");
+ end
+ path = path:gsub("^//+", "/"); -- TODO parse url more
+
len = len or 0;
packet = {
method = method;
diff --git a/net/http/server.lua b/net/http/server.lua
index d6c3a03a..d693fb52 100644
--- a/net/http/server.lua
+++ b/net/http/server.lua
@@ -75,7 +75,12 @@ setmetatable(events._handlers, {
local handle_request;
local _1, _2, _3;
local function _handle_request() return handle_request(_1, _2, _3); end
-local function _traceback_handler(err) log("error", "Traceback[http]: %s: %s", tostring(err), debug.traceback()); end
+
+local last_err;
+local function _traceback_handler(err) last_err = err; log("error", "Traceback[http]: %s: %s", tostring(err), debug.traceback()); end
+events.add_handler("http-error", function (error)
+ return "Error processing request: "..codes[error.code]..". Check your error log for more information.";
+end, -1);
function listener.onconnect(conn)
local secure = conn:ssl() and true or nil;
@@ -90,7 +95,7 @@ function listener.onconnect(conn)
--handle_request(conn, request, process_next);
_1, _2, _3 = conn, request, process_next;
if not xpcall(_handle_request, _traceback_handler) then
- conn:write("HTTP/1.0 503 Internal Server Error\r\n\r\nAn error occured during the processing of this request.");
+ conn:write("HTTP/1.0 500 Internal Server Error\r\n\r\n"..events.fire_event("http-error", { code = 500, private_message = last_err }));
conn:close();
end
else
@@ -161,10 +166,17 @@ function handle_request(conn, request, finish_cb)
};
conn._http_open_response = response;
+ local err;
if not request.headers.host then
+ err = "No 'Host' header";
+ elseif not request.path then
+ err = "Invalid path";
+ end
+
+ if err then
response.status_code = 400;
response.headers.content_type = "text/html";
- response:send("<html><head>400 Bad Request</head><body>400 Bad Request: No Host header.</body></html>");
+ response:send(events.fire_event("http-error", { code = 400, message = err }));
else
local host = request.headers.host;
if host then
@@ -179,6 +191,9 @@ function handle_request(conn, request, finish_cb)
local result_type = type(result);
if result_type == "number" then
response.status_code = result;
+ if result >= 400 then
+ body = events.fire_event("http-error", { code = result });
+ end
elseif result_type == "string" then
body = result;
elseif result_type == "table" then
@@ -197,7 +212,7 @@ function handle_request(conn, request, finish_cb)
-- if handler not called, return 404
response.status_code = 404;
response.headers.content_type = "text/html";
- response:send("<html><head><title>404 Not Found</title></head><body>404 Not Found: No such page.</body></html>");
+ response:send(events.fire_event("http-error", { code = 404 }));
end
end
function _M.send_response(response, body)
diff --git a/plugins/mod_http_errors.lua b/plugins/mod_http_errors.lua
new file mode 100644
index 00000000..820bcc2f
--- /dev/null
+++ b/plugins/mod_http_errors.lua
@@ -0,0 +1,75 @@
+module:set_global();
+module:depends("http");
+
+local server = require "net.http.server";
+local codes = require "net.http.codes";
+local termcolours = require "util.termcolours";
+
+local show_private = module:get_option_boolean("http_errors_detailed", false);
+
+local default_messages = {
+ [400] = { "What kind of request do you call that??" };
+ [403] = { "You're not allowed to do that." };
+ [404] = { "Whatever you were looking for is not here. %";
+ "Where did you put it?", "It's behind you.", "Keep looking." };
+ [500] = { "% Check your error log for more info.";
+ "Gremlins.", "It broke.", "Don't look at me." };
+};
+
+local messages = setmetatable(module:get_option("http_errors_messages", {}), { __index = default_messages });
+
+local html = [[
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <style>
+ body{
+ margin-top:14%;
+ text-align:center;
+ background-color:#F8F8F8;
+ font-family:sans-serif;
+ }
+ h1{
+ font-size:xx-large;
+ }
+ p{
+ font-size:x-large;
+ }
+ p+p { font-size: large; font-family: courier }
+ </style>
+</head>
+<body>
+ <h1>$title</h1>
+ <p>$message</p>
+ <p>$extra</p>
+</body>
+</html>]];
+html = html:gsub("%s%s+", "");
+
+local entities = {
+ ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;",
+ ["'"] = "&apos;", ["\""] = "&quot;", ["\n"] = "<br/>",
+};
+
+local function tohtml(plain)
+ return (plain:gsub("[<>&'\"\n]", entities));
+
+end
+
+local function get_page(code, extra)
+ local message = messages[code];
+ if message then
+ return (html:gsub("$(%a+)", {
+ title = rawget(codes, code) or ("Code "..tostring(code));
+ message = message[1]:gsub("%%", function ()
+ return message[math.random(2, math.max(#message,2))];
+ end);
+ extra = tohtml(extra or "");
+ }));
+ end
+end
+
+module:hook_object_event(server, "http-error", function (event)
+ return get_page(event.code, (show_private and event.private_message) or event.message);
+end);