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")

Impressum / About Us