aboutsummaryrefslogtreecommitdiffstats
path: root/net/httpserver.lua
diff options
context:
space:
mode:
Diffstat (limited to 'net/httpserver.lua')
-rw-r--r--net/httpserver.lua279
1 files changed, 8 insertions, 271 deletions
diff --git a/net/httpserver.lua b/net/httpserver.lua
index 57c8eede..7d574788 100644
--- a/net/httpserver.lua
+++ b/net/httpserver.lua
@@ -1,278 +1,15 @@
--- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-
-local socket = require "socket"
-local server = require "net.server"
-local url_parse = require "socket.url".parse;
-
-local connlisteners_start = require "net.connlisteners".start;
-local connlisteners_get = require "net.connlisteners".get;
-local listener;
-
-local t_insert, t_concat = table.insert, table.concat;
-local s_match, s_gmatch = string.match, string.gmatch;
-local tonumber, tostring, pairs, ipairs, type = tonumber, tostring, pairs, ipairs, type;
-
-local urlencode = function (s) return s and (s:gsub("%W", function (c) return string.format("%%%02x", c:byte()); end)); end
-
-local log = require "util.logger".init("httpserver");
-
-local http_servers = {};
+-- COMPAT w/pre-0.9
+local log = require "util.logger".init("net.httpserver");
+local traceback = debug.traceback;
module "httpserver"
-local default_handler;
-
-local function expectbody(reqt)
- return reqt.method == "POST";
-end
-
-local function send_response(request, response)
- -- Write status line
- local resp;
- if response.body then
- local body = tostring(response.body);
- log("debug", "Sending response to %s", request.id);
- resp = { "HTTP/1.0 ", response.status or "200 OK", "\r\n"};
- local h = response.headers;
- if h then
- for k, v in pairs(h) do
- t_insert(resp, k);
- t_insert(resp, ": ");
- t_insert(resp, v);
- t_insert(resp, "\r\n");
- end
- end
- if not (h and h["Content-Length"]) then
- t_insert(resp, "Content-Length: ");
- t_insert(resp, #body);
- t_insert(resp, "\r\n");
- end
- t_insert(resp, "\r\n");
-
- if request.method ~= "HEAD" then
- t_insert(resp, body);
- end
- else
- -- Response we have is just a string (the body)
- log("debug", "Sending response to %s: %s", request.id or "<none>", response or "<none>");
-
- resp = { "HTTP/1.0 200 OK\r\n" };
- t_insert(resp, "Connection: close\r\n");
- t_insert(resp, "Content-Length: ");
- t_insert(resp, #response);
- t_insert(resp, "\r\n\r\n");
-
- t_insert(resp, response);
- end
- request.write(t_concat(resp));
- if not request.stayopen then
- request:destroy();
- end
-end
-
-local function call_callback(request, err)
- if request.handled then return; end
- request.handled = true;
- local callback = request.callback;
- if not callback and request.path then
- local path = request.url.path;
- local base = path:match("^/([^/?]+)");
- if not base then
- base = path:match("^http://[^/?]+/([^/?]+)");
- end
-
- callback = (request.server and request.server.handlers[base]) or default_handler;
- if callback == default_handler then
- log("debug", "Default callback for this request (base: "..tostring(base)..")")
- end
- end
- if callback then
- if err then
- log("debug", "Request error: "..err);
- if not callback(nil, err, request) then
- destroy_request(request);
- end
- return;
- end
-
- local response = callback(request.method, request.body and t_concat(request.body), request);
- if response then
- if response == true and not request.destroyed then
- -- Keep connection open, we will reply later
- log("debug", "Request %s left open, on_destroy is %s", request.id, tostring(request.on_destroy));
- elseif response ~= true then
- -- Assume response
- send_response(request, response);
- destroy_request(request);
- end
- else
- log("debug", "Request handler provided no response, destroying request...");
- -- No response, close connection
- destroy_request(request);
- end
- end
-end
-
-local function request_reader(request, data, startpos)
- if not data then
- if request.body then
- call_callback(request);
- else
- -- Error.. connection was closed prematurely
- call_callback(request, "connection-closed");
- end
- -- Here we force a destroy... the connection is gone, so we can't reply later
- destroy_request(request);
- return;
- end
- if request.state == "body" then
- log("debug", "Reading body...")
- if not request.body then request.body = {}; request.havebodylength, request.bodylength = 0, tonumber(request.headers["content-length"]); end
- if startpos then
- data = data:sub(startpos, -1)
- end
- t_insert(request.body, data);
- if request.bodylength then
- request.havebodylength = request.havebodylength + #data;
- if request.havebodylength >= request.bodylength then
- -- We have the body
- call_callback(request);
- end
- end
- elseif request.state == "headers" then
- log("debug", "Reading headers...")
- local pos = startpos;
- local headers = request.headers or {};
- for line in data:gmatch("(.-)\r\n") do
- startpos = (startpos or 1) + #line + 2;
- local k, v = line:match("(%S+): (.+)");
- if k and v then
- headers[k:lower()] = v;
--- log("debug", "Header: "..k:lower().." = "..v);
- elseif #line == 0 then
- request.headers = headers;
- break;
- else
- log("debug", "Unhandled header line: "..line);
- end
- end
-
- if not expectbody(request) then
- call_callback(request);
- return;
- end
-
- -- Reached the end of the headers
- request.state = "body";
- if #data > startpos then
- return request_reader(request, data:sub(startpos, -1));
- end
- elseif request.state == "request" then
- log("debug", "Reading request line...")
- local method, path, http, linelen = data:match("^(%S+) (%S+) HTTP/(%S+)\r\n()", startpos);
- if not method then
- return call_callback(request, "invalid-status-line");
- end
-
- request.method, request.path, request.httpversion = method, path, http;
-
- request.url = url_parse(request.path);
-
- log("debug", method.." request for "..tostring(request.path) .. " on port "..request.handler.serverport());
-
- if request.onlystatus then
- if not call_callback(request) then
- return;
- end
- end
-
- request.state = "headers";
-
- if #data > linelen then
- return request_reader(request, data:sub(linelen, -1));
- end
- end
-end
-
--- The default handler for requests
-default_handler = function (method, body, request)
- log("debug", method.." request for "..tostring(request.path) .. " on port "..request.handler.serverport());
- return { status = "404 Not Found",
- headers = { ["Content-Type"] = "text/html" },
- body = "<html><head><title>Page Not Found</title></head><body>Not here :(</body></html>" };
-end
-
-
-function new_request(handler)
- return { handler = handler, conn = handler.socket,
- write = handler.write, state = "request",
- server = http_servers[handler.serverport()],
- send = send_response,
- destroy = destroy_request,
- id = tostring{}:match("%x+$")
- };
-end
-
-function destroy_request(request)
- log("debug", "Destroying request %s", request.id);
- listener = listener or connlisteners_get("httpserver");
- if not request.destroyed then
- request.destroyed = true;
- if request.on_destroy then
- log("debug", "Request has destroy callback");
- request.on_destroy(request);
- else
- log("debug", "Request has no destroy callback");
- end
- request.handler.close()
- if request.conn then
- listener.disconnect(request.conn, "closed");
- end
- end
-end
-
-function new(params)
- local http_server = http_servers[params.port];
- if not http_server then
- http_server = { handlers = {} };
- http_servers[params.port] = http_server;
- -- We weren't already listening on this port, so start now
- connlisteners_start("httpserver", params);
- end
- if params.base then
- http_server.handlers[params.base] = params.handler;
- end
-end
-
-function new_from_config(ports, default_base, handle_request)
- for _, options in ipairs(ports) do
- local port, base, ssl, interface = 5280, default_base, false, nil;
- if type(options) == "number" then
- port = options;
- elseif type(options) == "table" then
- port, base, ssl, interface = options.port or 5280, options.path or default_base, options.ssl or false, options.interface;
- elseif type(options) == "string" then
- base = options;
- end
-
- if ssl then
- ssl.mode = "server";
- ssl.protocol = "sslv23";
- end
-
- new{ port = port, base = base, handler = handle_request, ssl = ssl, type = (ssl and "ssl") or "tcp" }
- end
+function fail()
+ log("error", "Attempt to use legacy HTTP API. For more info see http://prosody.im/doc/developers/legacy_http");
+ log("error", "Legacy HTTP API usage, %s", traceback("", 2));
end
-_M.request_reader = request_reader;
-_M.send_response = send_response;
-_M.urlencode = urlencode;
+new, new_from_config = fail, fail;
+set_default_handler = fail;
return _M;