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