moonbridge
changeset 68:ad06fc76906a
Extended io.poll(...) to check FILE buffers; Replaced method "readuntil" with "xread"
author | jbe |
---|---|
date | Sat Apr 04 17:19:12 2015 +0200 (2015-04-04) |
parents | c488f2ea29aa |
children | daef4a38cc98 |
files | moonbridge.c moonbridge_http.lua |
line diff
1.1 --- a/moonbridge.c Sat Apr 04 11:42:34 2015 +0200 1.2 +++ b/moonbridge.c Sat Apr 04 17:19:12 2015 +0200 1.3 @@ -937,9 +937,9 @@ 1.4 } 1.5 1.6 /* Lua method for socket object to read from input stream until terminator */ 1.7 -static int moonbr_child_lua_readuntil_stream(lua_State *L) { 1.8 +static int moonbr_child_lua_xread_stream(lua_State *L) { 1.9 lua_getfield(L, 1, "input"); 1.10 - lua_getfield(L, -1, "readuntil"); 1.11 + lua_getfield(L, -1, "xread"); 1.12 lua_insert(L, 1); 1.13 lua_replace(L, 2); 1.14 lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.15 @@ -1043,7 +1043,7 @@ 1.16 /* Methods of (bidirectional) socket object passed to handler */ 1.17 static luaL_Reg moonbr_child_lua_socket_functions[] = { 1.18 {"read", moonbr_child_lua_read_stream}, 1.19 - {"readuntil", moonbr_child_lua_readuntil_stream}, 1.20 + {"xread", moonbr_child_lua_xread_stream}, 1.21 {"lines", moonbr_child_lua_lines_stream}, 1.22 {"write", moonbr_child_lua_write_stream}, 1.23 {"flush", moonbr_child_lua_flush_stream}, 1.24 @@ -2283,11 +2283,43 @@ 1.25 #endif 1.26 stream = luaL_testudata(L, -1, LUA_FILEHANDLE); 1.27 if (stream) { 1.28 - fd = fileno(stream->f); 1.29 - } else { 1.30 - fd = lua_tointegerx(L, -1, &isnum); 1.31 - if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.32 + FILE *file = stream->f; 1.33 + int flags, chr; 1.34 + flockfile(file); 1.35 + fd = fileno_unlocked(file); 1.36 + if (ferror(file) || feof(file)) goto moonbr_io_poll_pending_shortcut; 1.37 + flags = fcntl(fd, F_GETFL, 0); 1.38 + if (flags == -1) goto moonbr_io_poll_pending_error; 1.39 + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_poll_pending_error; 1.40 + chr = getc_unlocked(file); 1.41 + if (chr == EOF) { 1.42 + if (ferror(file) && errno == EAGAIN) clearerr_unlocked(file); 1.43 + else goto moonbr_io_poll_pending_shortcut; 1.44 + } else { 1.45 + if (ungetc(chr, file) == EOF) { 1.46 + fcntl(fd, F_SETFL, flags); 1.47 + goto moonbr_io_poll_pending_error; 1.48 + } 1.49 + goto moonbr_io_poll_pending_shortcut; 1.50 + } 1.51 + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_poll_pending_error; 1.52 + funlockfile(file); 1.53 + goto moonbr_io_poll_pending_cont; 1.54 + moonbr_io_poll_pending_shortcut: 1.55 + funlockfile(file); 1.56 + lua_pushboolean(L, 1); 1.57 + return 1; 1.58 + moonbr_io_poll_pending_error: 1.59 + funlockfile(file); 1.60 + { 1.61 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.62 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.63 + return luaL_error(L, "Unexpected error while checking buffer of FILE handle: %s", errmsg); 1.64 + } 1.65 } 1.66 + fd = lua_tointegerx(L, -1, &isnum); 1.67 + if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.68 + moonbr_io_poll_pending_cont: 1.69 FD_SET(fd, &readfds); 1.70 if (fd+1 > nfds) nfds = fd+1; 1.71 lua_pop(L, 1); 1.72 @@ -2340,49 +2372,8 @@ 1.73 } 1.74 } 1.75 1.76 -/* New method for Lua file objects: check if non-blocking reading is possible */ 1.77 -static int moonbr_io_pending(lua_State *L) { 1.78 - luaL_Stream *stream; 1.79 - FILE *file; 1.80 - int fd, flags, chr; 1.81 - stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.82 - if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.83 - file = stream->f; 1.84 - flockfile(file); 1.85 - fd = fileno_unlocked(file); 1.86 - if (ferror(file) || feof(file)) { 1.87 - funlockfile(file); 1.88 - lua_pushboolean(L, 1); 1.89 - return 1; 1.90 - } 1.91 - flags = fcntl(fd, F_GETFL, 0); 1.92 - if (flags == -1) goto moonbr_io_pending_error; 1.93 - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_pending_error; 1.94 - chr = getc_unlocked(file); 1.95 - lua_pushboolean(L, 1); 1.96 - if (chr == EOF) { 1.97 - if (ferror(file) && errno == EAGAIN) { 1.98 - clearerr_unlocked(file); 1.99 - lua_pushboolean(L, 0); 1.100 - } 1.101 - } else { 1.102 - if (ungetc(chr, file) == EOF) goto moonbr_io_pending_error; 1.103 - } 1.104 - if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_pending_error; 1.105 - funlockfile(file); 1.106 - return 1; 1.107 - moonbr_io_pending_error: 1.108 - funlockfile(file); 1.109 - { 1.110 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.111 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.112 - luaL_error(L, "Unexpected error in method \"pending\" of FILE handle: %s", errmsg); 1.113 - } 1.114 - return 0; 1.115 -} 1.116 - 1.117 /* New method for Lua file objects: read until terminator or length exceeded */ 1.118 -static int moonbr_io_readuntil(lua_State *L) { 1.119 +static int moonbr_io_xread(lua_State *L) { 1.120 luaL_Stream *stream; 1.121 FILE *file; 1.122 const char *terminatorstr; 1.123 @@ -2900,10 +2891,8 @@ 1.124 moonbr_terminate_error(); 1.125 } 1.126 lua_getfield(L, -1, "__index"); 1.127 - lua_pushcfunction(L, moonbr_io_pending); 1.128 - lua_setfield(L, -2, "pending"); 1.129 - lua_pushcfunction(L, moonbr_io_readuntil); 1.130 - lua_setfield(L, -2, "readuntil"); 1.131 + lua_pushcfunction(L, moonbr_io_xread); 1.132 + lua_setfield(L, -2, "xread"); 1.133 lua_pop(L, 2); 1.134 lua_pushcfunction(L, moonbr_timeout); 1.135 lua_setglobal(L, "timeout");
2.1 --- a/moonbridge_http.lua Sat Apr 04 11:42:34 2015 +0200 2.2 +++ b/moonbridge_http.lua Sat Apr 04 17:19:12 2015 +0200 2.3 @@ -833,7 +833,7 @@ 2.4 end 2.5 if request.headers_flags["Transfer-Encoding"]["chunked"] then 2.6 while true do 2.7 - local line = socket:readuntil("\n", 32 + remaining_body_size_limit) 2.8 + local line = socket:xread(32 + remaining_body_size_limit, "\n") 2.9 if not line then 2.10 request_error(true, "400 Bad Request", "Unexpected EOF while reading next chunk of request body") 2.11 end 2.12 @@ -854,13 +854,13 @@ 2.13 end 2.14 if len == 0 then break end 2.15 read_body_bytes(len, callback) 2.16 - local term = socket:readuntil("\n", 2) 2.17 + local term = socket:xread(2, "\n") 2.18 if term ~= "\r\n" and term ~= "\n" then 2.19 request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body") 2.20 end 2.21 end 2.22 while true do 2.23 - local line = socket:readuntil("\n", 2 + remaining_body_size_limit) 2.24 + local line = socket:xread(2 + remaining_body_size_limit, "\n") 2.25 if line == "\r\n" or line == "\n" then break end 2.26 remaining_body_size_limit = remaining_body_size_limit - #line 2.27 if remaining_body_size_limit < 0 then 2.28 @@ -895,15 +895,13 @@ 2.29 end 2.30 }) 2.31 -- wait for input: 2.32 - if not socket.input:pending() then 2.33 - if not io.poll({socket.input}, nil, request_idle_timeout) then 2.34 - return request_error(false, "408 Request Timeout") 2.35 - end 2.36 + if not io.poll({socket.input}, nil, request_idle_timeout) then 2.37 + return request_error(false, "408 Request Timeout") 2.38 end 2.39 -- set timeout for request header processing: 2.40 timeout(request_header_timeout) 2.41 -- read and parse request line: 2.42 - local line = socket:readuntil("\n", remaining_header_size_limit) 2.43 + local line = socket:xread(remaining_header_size_limit, "\n") 2.44 if not line then return survive end 2.45 remaining_header_size_limit = remaining_header_size_limit - #line 2.46 if remaining_header_size_limit == 0 then 2.47 @@ -919,7 +917,7 @@ 2.48 end 2.49 -- read and parse headers: 2.50 while true do 2.51 - local line = socket:readuntil("\n", remaining_header_size_limit); 2.52 + local line = socket:xread(remaining_header_size_limit, "\n"); 2.53 remaining_header_size_limit = remaining_header_size_limit - #line 2.54 if not line then 2.55 return request_error(false, "400 Bad Request")