X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=net%2Fhttpserver.lua;h=7d574788253ea25a6f67bf20f0e426e0449c34ce;hb=b33842507539ae3b2cc4e4da2bc61eae4a5fc3d1;hp=0ecf84ea4e84bf5a24c010bced0c73e2400682b1;hpb=e0d0b0fa0b49e963d91ec1711864cef4ce239c13;p=prosody.git diff --git a/net/httpserver.lua b/net/httpserver.lua index 0ecf84ea..7d574788 100644 --- a/net/httpserver.lua +++ b/net/httpserver.lua @@ -1,250 +1,15 @@ - -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, s_char = string.match, string.gmatch; -local tonumber, tostring, pairs = tonumber, tostring, pairs; - -local urlcodes = setmetatable({}, { __index = function (t, k) t[k] = s_char(tonumber("0x"..k)); return t[k]; end }); -local urlencode = function (s) return s and (s:gsub("%W", function (c) return string.format("%%%x", 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 - 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 response.body and not (h and h["Content-Length"]) then - t_insert(resp, "Content-Length: "); - t_insert(resp, #response.body); - t_insert(resp, "\r\n"); - end - t_insert(resp, "\r\n"); - - if response.body and request.method ~= "HEAD" then - t_insert(resp, response.body); - end - else - -- Response we have is just a string (the body) - log("debug", "Sending response to %s: %s", request.id, response); - - 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("warn", "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 = "