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 |