moonbridge
changeset 115:7014436d88ea
Added helper function moonbridge_io.timeref(...); HTTP module sends 408 Request Timeout
author | jbe |
---|---|
date | Fri Apr 10 00:33:07 2015 +0200 (2015-04-10) |
parents | 0eba766e9be2 |
children | 2ab19e15aa6b |
files | example_application.lua moonbridge.c moonbridge_http.lua moonbridge_io.c |
line diff
1.1 --- a/example_application.lua Thu Apr 09 20:02:43 2015 +0200 1.2 +++ b/example_application.lua Fri Apr 10 00:33:07 2015 +0200 1.3 @@ -60,7 +60,8 @@ 1.4 { 1.5 static_headers = {"Server: Moonbridge Example Server"}, 1.6 request_body_size_limit = 16*1024*1024*1024, -- allow big file uploads 1.7 - request_header_timeout = 360, -- request headers must be sent within 6 minutes (if nil, defaults to timeout below) 1.8 + request_idle_timeout = 330, -- 5 minutes and 30 seconds after which an idle connection will be closed 1.9 + request_header_timeout = 30, -- request headers must be sent within 30 seconds after first byte was received 1.10 timeout = 1800 -- request body and response must be sent within 30 minutes 1.11 }, 1.12 function(request)
2.1 --- a/moonbridge.c Thu Apr 09 20:02:43 2015 +0200 2.2 +++ b/moonbridge.c Fri Apr 10 00:33:07 2015 +0200 2.3 @@ -2016,7 +2016,7 @@ 2.4 return lua_gettop(L) - 1; 2.5 } 2.6 } 2.7 - lua_pushnumber(L, oldval.it_value.tv_sec + 1e-6 * oldval.it_value.tv_usec); 2.8 + lua_pushnumber(L, oldval.it_value.tv_sec + 1e-6 * oldval.it_value.tv_usec); 2.9 return 1; 2.10 } 2.11
3.1 --- a/moonbridge_http.lua Thu Apr 09 20:02:43 2015 +0200 3.2 +++ b/moonbridge_http.lua Fri Apr 10 00:33:07 2015 +0200 3.3 @@ -180,13 +180,16 @@ 3.4 end 3.5 local input_chunk_size = options.maximum_input_chunk_size or options.chunk_size or 16384 3.6 local output_chunk_size = options.minimum_output_chunk_size or options.chunk_size or 1024 3.7 - local request_header_timeout, response_timeout 3.8 + local request_idle_timeout, request_header_timeout, response_timeout 3.9 + if options.request_idle_timeout ~= nil then 3.10 + request_idle_timeout = options.request_idle_timeout or 0 3.11 + else 3.12 + request_idle_timeout = 330 3.13 + end 3.14 if options.request_header_timeout ~= nil then 3.15 - request_header_timeout = options.request_header_timeout 3.16 - elseif options.timeout ~= nil then 3.17 - request_header_timeout = options.timeout or 0 3.18 + request_header_timeout = options.request_header_timeout or 0 3.19 else 3.20 - request_header_timeout = 360 3.21 + request_header_timeout = 30 3.22 end 3.23 if options.timeout ~= nil then 3.24 response_timeout = options.timeout or 0 3.25 @@ -195,10 +198,9 @@ 3.26 end 3.27 -- return connect handler: 3.28 return function(socket) 3.29 + local socket_set = {[socket] = true} -- used for moonbridge_io.poll(...) 3.30 local survive = true -- set to false if process shall be terminated later 3.31 repeat 3.32 - -- (re)set timeout: 3.33 - timeout(request_header_timeout or 0) 3.34 -- process named arguments "request_header_size_limit" and "request_body_size_limit": 3.35 local remaining_header_size_limit = options.request_header_size_limit or 1024*1024 3.36 local remaining_body_size_limit = options.request_body_size_limit or 64*1024*1024 3.37 @@ -311,9 +313,13 @@ 3.38 -- close output stream: 3.39 assert_output(socket:finish()) 3.40 -- wait for EOF of peer to avoid immediate TCP RST condition: 3.41 - timeout(2, function() 3.42 - socket:drain() 3.43 - end) 3.44 + do 3.45 + local start_time = moonbridge_io.timeref() 3.46 + repeat 3.47 + socket:drain_nb() 3.48 + local time_left = 2 - moonbridge_io.timeref(start_time) 3.49 + until time_left <= 0 or not moonbridge_io.poll(socket_set, nil, time_left) 3.50 + end 3.51 -- fully close socket: 3.52 socket_closed = true -- avoid double close on error 3.53 assert_output(socket:close()) 3.54 @@ -893,6 +899,12 @@ 3.55 end 3.56 end 3.57 }) 3.58 + -- wait for input: 3.59 + if not moonbridge_io.poll({[socket] = true}, nil, request_idle_timeout) then 3.60 + return request_error(false, "408 Request Timeout") 3.61 + end 3.62 + -- set timeout for request header processing: 3.63 + timeout(request_header_timeout) 3.64 -- read and parse request line: 3.65 local line = socket:read(remaining_header_size_limit, "\n") 3.66 if not line then return survive end 3.67 @@ -991,12 +1003,14 @@ 3.68 request.cookies[decode_uri(rawkey)] = decode_uri(rawvalue) 3.69 end 3.70 end 3.71 - -- (re)set timeout: 3.72 + -- (re)set timeout for handler: 3.73 timeout(response_timeout or 0) 3.74 -- call underlying handler and remember boolean result: 3.75 if handler(request) ~= true then survive = false end 3.76 -- finish request (unless already done by underlying handler): 3.77 request:finish() 3.78 + -- stop timeout timer: 3.79 + timeout(0) 3.80 until connection_close_responded 3.81 return survive 3.82 end
4.1 --- a/moonbridge_io.c Thu Apr 09 20:02:43 2015 +0200 4.2 +++ b/moonbridge_io.c Fri Apr 10 00:33:07 2015 +0200 4.3 @@ -14,6 +14,7 @@ 4.4 #include <sys/types.h> 4.5 #include <netdb.h> 4.6 #include <signal.h> 4.7 +#include <time.h> 4.8 4.9 #include <lua.h> 4.10 #include <lauxlib.h> 4.11 @@ -1026,6 +1027,17 @@ 4.12 } 4.13 } 4.14 4.15 +static int moonbr_io_timeref(lua_State *L) { 4.16 + lua_Number sub; 4.17 + struct timespec tp; 4.18 + sub = luaL_optnumber(L, 1, 0); 4.19 + if (clock_gettime(CLOCK_MONOTONIC, &tp)) { 4.20 + return luaL_error(L, "Could not access CLOCK_MONOTONIC"); 4.21 + } 4.22 + lua_pushnumber(L, tp.tv_sec + tp.tv_nsec / 1.0e9 - sub); 4.23 + return 1; 4.24 +} 4.25 + 4.26 static const struct luaL_Reg moonbr_io_handle_methods[] = { 4.27 {"read", moonbr_io_read}, 4.28 {"read_nb", moonbr_io_read_nb}, 4.29 @@ -1068,6 +1080,7 @@ 4.30 {"locallisten", moonbr_io_locallisten}, 4.31 {"tcplisten", moonbr_io_tcplisten}, 4.32 {"poll", moonbr_io_poll}, 4.33 + {"timeref", moonbr_io_timeref}, 4.34 {NULL, NULL} 4.35 }; 4.36