Comparison

net/http/server.lua @ 11200:bf8f2da84007

Merge 0.11->trunk
author Kim Alvefur <zash@zash.se>
date Thu, 05 Nov 2020 22:31:25 +0100
parent 11160:e9eeaefa09a7
child 11371:73f7acf8a61f
comparison
equal deleted inserted replaced
11199:6c7c50a4de32 11200:bf8f2da84007
11 local xpcall = require "util.xpcall".xpcall; 11 local xpcall = require "util.xpcall".xpcall;
12 local traceback = debug.traceback; 12 local traceback = debug.traceback;
13 local tostring = tostring; 13 local tostring = tostring;
14 local cache = require "util.cache"; 14 local cache = require "util.cache";
15 local codes = require "net.http.codes"; 15 local codes = require "net.http.codes";
16 local promise = require "util.promise";
17 local errors = require "util.error";
16 local blocksize = 2^16; 18 local blocksize = 2^16;
17 19
18 local _M = {}; 20 local _M = {};
19 21
20 local sessions = {}; 22 local sessions = {};
168 t[k] = v; 170 t[k] = v;
169 return v; 171 return v;
170 end 172 end
171 }); 173 });
172 174
175 local function handle_result(request, response, result)
176 if result == nil then
177 result = 404;
178 end
179
180 if result == true then
181 return;
182 end
183
184 local body;
185 local result_type = type(result);
186 if result_type == "number" then
187 response.status_code = result;
188 if result >= 400 then
189 body = events.fire_event("http-error", { request = request, response = response, code = result });
190 end
191 elseif result_type == "string" then
192 body = result;
193 elseif errors.is_err(result) then
194 response.status_code = result.code or 500;
195 body = events.fire_event("http-error", { request = request, response = response, code = result.code or 500, error = result });
196 elseif promise.is_promise(result) then
197 result:next(function (ret)
198 handle_result(request, response, ret);
199 end, function (err)
200 response.status_code = 500;
201 handle_result(request, response, err or 500);
202 end);
203 return true;
204 elseif result_type == "table" then
205 for k, v in pairs(result) do
206 if k ~= "headers" then
207 response[k] = v;
208 else
209 for header_name, header_value in pairs(v) do
210 response.headers[header_name] = header_value;
211 end
212 end
213 end
214 end
215 return response:send(body);
216 end
217
173 function _M.hijack_response(response, listener) -- luacheck: ignore 218 function _M.hijack_response(response, listener) -- luacheck: ignore
174 error("TODO"); 219 error("TODO");
175 end 220 end
176 function handle_request(conn, request, finish_cb) 221 function handle_request(conn, request, finish_cb)
177 --log("debug", "handler: %s", request.path); 222 --log("debug", "handler: %s", request.path);
192 response_conn_header = "Keep-Alive"; 237 response_conn_header = "Keep-Alive";
193 else 238 else
194 response_conn_header = httpversion == "1.1" and "close" or nil 239 response_conn_header = httpversion == "1.1" and "close" or nil
195 end 240 end
196 241
242 local is_head_request = request.method == "HEAD";
243
197 local response = { 244 local response = {
198 request = request; 245 request = request;
246 is_head_request = is_head_request;
199 status_code = 200; 247 status_code = 200;
200 headers = { date = date_header, connection = response_conn_header }; 248 headers = { date = date_header, connection = response_conn_header };
201 persistent = persistent; 249 persistent = persistent;
202 conn = conn; 250 conn = conn;
203 send = _M.send_response; 251 send = _M.send_response;
225 local global_event = request.method.." "..request.path:match("[^?]*"); 273 local global_event = request.method.." "..request.path:match("[^?]*");
226 274
227 local payload = { request = request, response = response }; 275 local payload = { request = request, response = response };
228 log("debug", "Firing event: %s", global_event); 276 log("debug", "Firing event: %s", global_event);
229 local result = events.fire_event(global_event, payload); 277 local result = events.fire_event(global_event, payload);
278 if result == nil and is_head_request then
279 local global_head_event = "GET "..request.path:match("[^?]*");
280 log("debug", "Firing event: %s", global_head_event);
281 result = events.fire_event(global_head_event, payload);
282 end
230 if result == nil then 283 if result == nil then
231 if not hosts[host] then 284 if not hosts[host] then
232 if hosts[default_host] then 285 if hosts[default_host] then
233 host = default_host; 286 host = default_host;
234 elseif host then 287 elseif host then
245 end 298 end
246 299
247 local host_event = request.method.." "..host..request.path:match("[^?]*"); 300 local host_event = request.method.." "..host..request.path:match("[^?]*");
248 log("debug", "Firing event: %s", host_event); 301 log("debug", "Firing event: %s", host_event);
249 result = events.fire_event(host_event, payload); 302 result = events.fire_event(host_event, payload);
250 end 303
251 if result ~= nil then 304 if result == nil and is_head_request then
252 if result ~= true then 305 local host_head_event = "GET "..host..request.path:match("[^?]*");
253 local body; 306 log("debug", "Firing event: %s", host_head_event);
254 local result_type = type(result); 307 result = events.fire_event(host_head_event, payload);
255 if result_type == "number" then 308 end
256 response.status_code = result; 309 end
257 if result >= 400 then 310
258 payload.code = result; 311 return handle_result(request, response, result);
259 body = events.fire_event("http-error", payload); 312 end
260 end 313
261 elseif result_type == "string" then
262 body = result;
263 elseif result_type == "table" then
264 for k, v in pairs(result) do
265 if k ~= "headers" then
266 response[k] = v;
267 else
268 for header_name, header_value in pairs(v) do
269 response.headers[header_name] = header_value;
270 end
271 end
272 end
273 end
274 response:send(body);
275 end
276 return;
277 end
278
279 -- if handler not called, return 404
280 response.status_code = 404;
281 payload.code = 404;
282 response:send(events.fire_event("http-error", payload));
283 end
284 local function prepare_header(response) 314 local function prepare_header(response)
285 local status_line = "HTTP/"..response.request.httpversion.." "..(response.status or codes[response.status_code]); 315 local status_line = "HTTP/"..response.request.httpversion.." "..(response.status or codes[response.status_code]);
286 local headers = response.headers; 316 local headers = response.headers;
287 local output = { status_line }; 317 local output = { status_line };
288 for k,v in pairs(headers) do 318 for k,v in pairs(headers) do
290 end 320 end
291 t_insert(output, "\r\n\r\n"); 321 t_insert(output, "\r\n\r\n");
292 return output; 322 return output;
293 end 323 end
294 _M.prepare_header = prepare_header; 324 _M.prepare_header = prepare_header;
325 function _M.send_head_response(response)
326 if response.finished then return; end
327 local output = prepare_header(response);
328 response.conn:write(t_concat(output));
329 response:done();
330 end
295 function _M.send_response(response, body) 331 function _M.send_response(response, body)
296 if response.finished then return; end 332 if response.finished then return; end
297 body = body or response.body or ""; 333 body = body or response.body or "";
298 -- Per RFC 7230, informational (1xx) and 204 (no content) should have no c-l header 334 -- Per RFC 7230, informational (1xx) and 204 (no content) should have no c-l header
299 if response.status_code > 199 and response.status_code ~= 204 then 335 if response.status_code > 199 and response.status_code ~= 204 then
300 response.headers.content_length = #body; 336 response.headers.content_length = ("%d"):format(#body);
337 end
338 if response.is_head_request then
339 return _M.send_head_response(response)
301 end 340 end
302 local output = prepare_header(response); 341 local output = prepare_header(response);
303 t_insert(output, body); 342 t_insert(output, body);
304 response.conn:write(t_concat(output)); 343 response.conn:write(t_concat(output));
305 response:done(); 344 response:done();
306 end 345 end
307 function _M.send_file(response, f) 346 function _M.send_file(response, f)
347 if response.is_head_request then
348 if f.close then f:close(); end
349 return _M.send_head_response(response);
350 end
308 if response.finished then return; end 351 if response.finished then return; end
309 local chunked = not response.headers.content_length; 352 local chunked = not response.headers.content_length;
310 if chunked then response.headers.transfer_encoding = "chunked"; end 353 if chunked then response.headers.transfer_encoding = "chunked"; end
311 incomplete[response.conn] = response; 354 incomplete[response.conn] = response;
312 response._send_more = function () 355 response._send_more = function ()