# HG changeset patch # User jbe # Date 1428160752 -7200 # Node ID ad06fc76906aa3e5179ff445809808039eb6000f # Parent c488f2ea29aa8434e2a58200f92219af1ef55f96 Extended io.poll(...) to check FILE buffers; Replaced method "readuntil" with "xread" diff -r c488f2ea29aa -r ad06fc76906a moonbridge.c --- a/moonbridge.c Sat Apr 04 11:42:34 2015 +0200 +++ b/moonbridge.c Sat Apr 04 17:19:12 2015 +0200 @@ -937,9 +937,9 @@ } /* Lua method for socket object to read from input stream until terminator */ -static int moonbr_child_lua_readuntil_stream(lua_State *L) { +static int moonbr_child_lua_xread_stream(lua_State *L) { lua_getfield(L, 1, "input"); - lua_getfield(L, -1, "readuntil"); + lua_getfield(L, -1, "xread"); lua_insert(L, 1); lua_replace(L, 2); lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); @@ -1043,7 +1043,7 @@ /* Methods of (bidirectional) socket object passed to handler */ static luaL_Reg moonbr_child_lua_socket_functions[] = { {"read", moonbr_child_lua_read_stream}, - {"readuntil", moonbr_child_lua_readuntil_stream}, + {"xread", moonbr_child_lua_xread_stream}, {"lines", moonbr_child_lua_lines_stream}, {"write", moonbr_child_lua_write_stream}, {"flush", moonbr_child_lua_flush_stream}, @@ -2283,11 +2283,43 @@ #endif stream = luaL_testudata(L, -1, LUA_FILEHANDLE); if (stream) { - fd = fileno(stream->f); - } else { - fd = lua_tointegerx(L, -1, &isnum); - if (!isnum) luaL_error(L, "File descriptor is not an integer"); + FILE *file = stream->f; + int flags, chr; + flockfile(file); + fd = fileno_unlocked(file); + if (ferror(file) || feof(file)) goto moonbr_io_poll_pending_shortcut; + flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) goto moonbr_io_poll_pending_error; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_poll_pending_error; + chr = getc_unlocked(file); + if (chr == EOF) { + if (ferror(file) && errno == EAGAIN) clearerr_unlocked(file); + else goto moonbr_io_poll_pending_shortcut; + } else { + if (ungetc(chr, file) == EOF) { + fcntl(fd, F_SETFL, flags); + goto moonbr_io_poll_pending_error; + } + goto moonbr_io_poll_pending_shortcut; + } + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_poll_pending_error; + funlockfile(file); + goto moonbr_io_poll_pending_cont; + moonbr_io_poll_pending_shortcut: + funlockfile(file); + lua_pushboolean(L, 1); + return 1; + moonbr_io_poll_pending_error: + funlockfile(file); + { + char errmsg[MOONBR_MAXSTRERRORLEN]; + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ + return luaL_error(L, "Unexpected error while checking buffer of FILE handle: %s", errmsg); + } } + fd = lua_tointegerx(L, -1, &isnum); + if (!isnum) luaL_error(L, "File descriptor is not an integer"); + moonbr_io_poll_pending_cont: FD_SET(fd, &readfds); if (fd+1 > nfds) nfds = fd+1; lua_pop(L, 1); @@ -2340,49 +2372,8 @@ } } -/* New method for Lua file objects: check if non-blocking reading is possible */ -static int moonbr_io_pending(lua_State *L) { - luaL_Stream *stream; - FILE *file; - int fd, flags, chr; - stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); - if (!stream->closef) luaL_error(L, "attempt to use a closed file"); - file = stream->f; - flockfile(file); - fd = fileno_unlocked(file); - if (ferror(file) || feof(file)) { - funlockfile(file); - lua_pushboolean(L, 1); - return 1; - } - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) goto moonbr_io_pending_error; - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_pending_error; - chr = getc_unlocked(file); - lua_pushboolean(L, 1); - if (chr == EOF) { - if (ferror(file) && errno == EAGAIN) { - clearerr_unlocked(file); - lua_pushboolean(L, 0); - } - } else { - if (ungetc(chr, file) == EOF) goto moonbr_io_pending_error; - } - if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_pending_error; - funlockfile(file); - return 1; - moonbr_io_pending_error: - funlockfile(file); - { - char errmsg[MOONBR_MAXSTRERRORLEN]; - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ - luaL_error(L, "Unexpected error in method \"pending\" of FILE handle: %s", errmsg); - } - return 0; -} - /* New method for Lua file objects: read until terminator or length exceeded */ -static int moonbr_io_readuntil(lua_State *L) { +static int moonbr_io_xread(lua_State *L) { luaL_Stream *stream; FILE *file; const char *terminatorstr; @@ -2900,10 +2891,8 @@ moonbr_terminate_error(); } lua_getfield(L, -1, "__index"); - lua_pushcfunction(L, moonbr_io_pending); - lua_setfield(L, -2, "pending"); - lua_pushcfunction(L, moonbr_io_readuntil); - lua_setfield(L, -2, "readuntil"); + lua_pushcfunction(L, moonbr_io_xread); + lua_setfield(L, -2, "xread"); lua_pop(L, 2); lua_pushcfunction(L, moonbr_timeout); lua_setglobal(L, "timeout"); diff -r c488f2ea29aa -r ad06fc76906a moonbridge_http.lua --- a/moonbridge_http.lua Sat Apr 04 11:42:34 2015 +0200 +++ b/moonbridge_http.lua Sat Apr 04 17:19:12 2015 +0200 @@ -833,7 +833,7 @@ end if request.headers_flags["Transfer-Encoding"]["chunked"] then while true do - local line = socket:readuntil("\n", 32 + remaining_body_size_limit) + local line = socket:xread(32 + remaining_body_size_limit, "\n") if not line then request_error(true, "400 Bad Request", "Unexpected EOF while reading next chunk of request body") end @@ -854,13 +854,13 @@ end if len == 0 then break end read_body_bytes(len, callback) - local term = socket:readuntil("\n", 2) + local term = socket:xread(2, "\n") if term ~= "\r\n" and term ~= "\n" then request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body") end end while true do - local line = socket:readuntil("\n", 2 + remaining_body_size_limit) + local line = socket:xread(2 + remaining_body_size_limit, "\n") if line == "\r\n" or line == "\n" then break end remaining_body_size_limit = remaining_body_size_limit - #line if remaining_body_size_limit < 0 then @@ -895,15 +895,13 @@ end }) -- wait for input: - if not socket.input:pending() then - if not io.poll({socket.input}, nil, request_idle_timeout) then - return request_error(false, "408 Request Timeout") - end + if not io.poll({socket.input}, nil, request_idle_timeout) then + return request_error(false, "408 Request Timeout") end -- set timeout for request header processing: timeout(request_header_timeout) -- read and parse request line: - local line = socket:readuntil("\n", remaining_header_size_limit) + local line = socket:xread(remaining_header_size_limit, "\n") if not line then return survive end remaining_header_size_limit = remaining_header_size_limit - #line if remaining_header_size_limit == 0 then @@ -919,7 +917,7 @@ end -- read and parse headers: while true do - local line = socket:readuntil("\n", remaining_header_size_limit); + local line = socket:xread(remaining_header_size_limit, "\n"); remaining_header_size_limit = remaining_header_size_limit - #line if not line then return request_error(false, "400 Bad Request")