Software / code / prosody
Comparison
net/http/server.lua @ 11371:73f7acf8a61f
net.http.server: Enable async during HTTP request handling (fixes #1487)
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sun, 12 Jul 2020 20:31:31 +0200 |
| parent | 11160:e9eeaefa09a7 |
| child | 11372:b877bd74d65e |
comparison
equal
deleted
inserted
replaced
| 11370:7c2ef5a1ec9c | 11371:73f7acf8a61f |
|---|---|
| 1 | 1 |
| 2 local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat; | 2 local t_insert, t_concat = table.insert, table.concat; |
| 3 local parser_new = require "net.http.parser".new; | 3 local parser_new = require "net.http.parser".new; |
| 4 local events = require "util.events".new(); | 4 local events = require "util.events".new(); |
| 5 local addserver = require "net.server".addserver; | 5 local addserver = require "net.server".addserver; |
| 6 local log = require "util.logger".init("http.server"); | 6 local log = require "util.logger".init("http.server"); |
| 7 local os_date = os.date; | 7 local os_date = os.date; |
| 8 local pairs = pairs; | 8 local pairs = pairs; |
| 9 local s_upper = string.upper; | 9 local s_upper = string.upper; |
| 10 local setmetatable = setmetatable; | 10 local setmetatable = setmetatable; |
| 11 local xpcall = require "util.xpcall".xpcall; | |
| 12 local traceback = debug.traceback; | |
| 13 local tostring = tostring; | |
| 14 local cache = require "util.cache"; | 11 local cache = require "util.cache"; |
| 15 local codes = require "net.http.codes"; | 12 local codes = require "net.http.codes"; |
| 16 local promise = require "util.promise"; | 13 local promise = require "util.promise"; |
| 17 local errors = require "util.error"; | 14 local errors = require "util.error"; |
| 18 local blocksize = 2^16; | 15 local blocksize = 2^16; |
| 16 local async = require "util.async"; | |
| 19 | 17 |
| 20 local _M = {}; | 18 local _M = {}; |
| 21 | 19 |
| 22 local sessions = {}; | 20 local sessions = {}; |
| 23 local incomplete = {}; | 21 local incomplete = {}; |
| 89 end; | 87 end; |
| 90 }); | 88 }); |
| 91 | 89 |
| 92 local handle_request; | 90 local handle_request; |
| 93 | 91 |
| 94 local last_err; | |
| 95 local function _traceback_handler(err) last_err = err; log("error", "Traceback[httpserver]: %s", traceback(tostring(err), 2)); end | |
| 96 events.add_handler("http-error", function (error) | 92 events.add_handler("http-error", function (error) |
| 97 return "Error processing request: "..codes[error.code]..". Check your error log for more information."; | 93 return "Error processing request: "..codes[error.code]..". Check your error log for more information."; |
| 98 end, -1); | 94 end, -1); |
| 99 | 95 |
| 96 local runner_callbacks = {}; | |
| 97 | |
| 98 function runner_callbacks:ready() | |
| 99 self.data:resume(); | |
| 100 end | |
| 101 | |
| 102 function runner_callbacks:waiting() | |
| 103 self.data:pause(); | |
| 104 end | |
| 105 | |
| 106 function runner_callbacks:error(err) | |
| 107 log("error", "Traceback[httpserver]: %s", err); | |
| 108 self.data:write("HTTP/1.0 500 Internal Server Error\r\n\r\n"..events.fire_event("http-error", { code = 500, private_message = err })); | |
| 109 self.data:close(); | |
| 110 end | |
| 111 | |
| 100 function listener.onconnect(conn) | 112 function listener.onconnect(conn) |
| 101 local secure = conn:ssl() and true or nil; | 113 local secure = conn:ssl() and true or nil; |
| 102 local pending = {}; | 114 conn._thread = async.runner(function (request) |
| 103 local waiting = false; | 115 local wait, done = async.waiter(); |
| 104 local function process_next() | 116 handle_request(conn, request, done); wait(); |
| 105 if waiting then return; end -- log("debug", "can't process_next, waiting"); | 117 end, runner_callbacks, conn); |
| 106 waiting = true; | |
| 107 while sessions[conn] and #pending > 0 do | |
| 108 local request = t_remove(pending); | |
| 109 --log("debug", "process_next: %s", request.path); | |
| 110 if not xpcall(handle_request, _traceback_handler, conn, request, process_next) then | |
| 111 conn:write("HTTP/1.0 500 Internal Server Error\r\n\r\n"..events.fire_event("http-error", { code = 500, private_message = last_err })); | |
| 112 conn:close(); | |
| 113 end | |
| 114 end | |
| 115 --log("debug", "ready for more"); | |
| 116 waiting = false; | |
| 117 end | |
| 118 local function success_cb(request) | 118 local function success_cb(request) |
| 119 --log("debug", "success_cb: %s", request.path); | 119 --log("debug", "success_cb: %s", request.path); |
| 120 if waiting then | |
| 121 log("error", "http connection handler is not reentrant: %s", request.path); | |
| 122 assert(false, "http connection handler is not reentrant"); | |
| 123 end | |
| 124 request.secure = secure; | 120 request.secure = secure; |
| 125 t_insert(pending, request); | 121 conn._thread:run(request); |
| 126 process_next(); | |
| 127 end | 122 end |
| 128 local function error_cb(err) | 123 local function error_cb(err) |
| 129 log("debug", "error_cb: %s", err or "<nil>"); | 124 log("debug", "error_cb: %s", err or "<nil>"); |
| 130 -- FIXME don't close immediately, wait until we process current stuff | 125 -- FIXME don't close immediately, wait until we process current stuff |
| 131 -- FIXME if err, send off a bad-request response | 126 -- FIXME if err, send off a bad-request response |