moonbridge

diff moonbridge_http.lua @ 44:e835cda61478

Added io_error_handler; Code cleanup
author jbe
date Tue Mar 17 23:06:48 2015 +0100 (2015-03-17)
parents 0bb356c04f6b
children ab51824e139b
line diff
     1.1 --- a/moonbridge_http.lua	Mon Mar 09 16:42:55 2015 +0100
     1.2 +++ b/moonbridge_http.lua	Tue Mar 17 23:06:48 2015 +0100
     1.3 @@ -178,13 +178,23 @@
     1.4      t[#t+1] = ""
     1.5      preamble = table.concat(t, "\r\n")
     1.6    end
     1.7 +  local function assert_io(retval, errmsg)
     1.8 +    if retval then
     1.9 +      return retval
    1.10 +    end
    1.11 +    if options.io_error_handler then
    1.12 +      options.io_error_handler(errmsg)
    1.13 +      error(errmsg)
    1.14 +    end
    1.15 +    error(errmsg, 2)
    1.16 +  end
    1.17 +  -- desired chunk sizes:
    1.18 +  local input_chunk_size = options.maximum_input_chunk_size or options.chunk_size or 16384
    1.19 +  local output_chunk_size = options.minimum_output_chunk_size or options.chunk_size or 1024
    1.20    -- return connect handler:
    1.21    return function(socket)
    1.22      local survive = true  -- set to false if process shall be terminated later
    1.23      repeat
    1.24 -      -- desired chunk sizes:
    1.25 -      local input_chunk_size = options.maximum_input_chunk_size or options.chunk_size or 16384
    1.26 -      local output_chunk_size = options.minimum_output_chunk_size or options.chunk_size or 1024
    1.27        -- process named arguments "request_header_size_limit" and "request_body_size_limit":
    1.28        local remaining_header_size_limit = options.request_header_size_limit or 1024*1024
    1.29        local remaining_body_size_limit = options.request_body_size_limit or 64*1024*1024
    1.30 @@ -226,7 +236,7 @@
    1.31            end
    1.32            local chunk = socket:read(limit)
    1.33            if not chunk or #chunk ~= limit then
    1.34 -            error("Unexpected EOF while reading chunk of request body")
    1.35 +            assert_io(false, "Unexpected EOF or read error while reading chunk of request body")
    1.36            end
    1.37            remaining = remaining - limit
    1.38            if callback then
    1.39 @@ -245,22 +255,22 @@
    1.40              while socket.input:read(input_chunk_size) do end
    1.41            end)
    1.42            -- fully close socket:
    1.43 -          assert(socket:close())
    1.44 +          assert_io(socket:close())
    1.45          else
    1.46 -          assert(socket:flush())
    1.47 +          assert_io(socket:flush())
    1.48            request:stream_request_body()
    1.49          end
    1.50        end
    1.51        -- writes out buffered chunks (without flushing the socket):
    1.52        local function send_chunk()
    1.53          if chunk_bytes > 0 then
    1.54 -          assert(socket:write(string.format("%x\r\n", chunk_bytes)))
    1.55 +          assert_io(socket:write(string.format("%x\r\n", chunk_bytes)))
    1.56            for i = 1, #chunk_parts do
    1.57 -            assert(socket:write(chunk_parts[i]))
    1.58 +            assert_io(socket:write(chunk_parts[i]))
    1.59            end
    1.60            chunk_parts = {}
    1.61            chunk_bytes = 0
    1.62 -          assert(socket:write("\r\n"))
    1.63 +          assert_io(socket:write("\r\n"))
    1.64          end
    1.65        end
    1.66        -- terminate header section in response, optionally flushing:
    1.67 @@ -271,28 +281,28 @@
    1.68          elseif output_state == "finished" then
    1.69            error("Response has already been finished")
    1.70          elseif output_state == "info_status_sent" then
    1.71 -          assert(socket:write("\r\n"))
    1.72 -          assert(socket:flush())
    1.73 +          assert_io(socket:write("\r\n"))
    1.74 +          assert_io(socket:flush())
    1.75            output_state = "no_status_sent"
    1.76          elseif output_state == "bodyless_status_sent" then
    1.77            if connection_close_requested and not connection_close_responded then
    1.78              request:send_header("Connection", "close")
    1.79            end
    1.80 -          assert(socket:write("\r\n"))
    1.81 +          assert_io(socket:write("\r\n"))
    1.82            finish_response()
    1.83            output_state = "finished"
    1.84          elseif output_state == "status_sent" then
    1.85            if not content_length then
    1.86 -            assert(socket:write("Transfer-Encoding: chunked\r\n"))
    1.87 +            assert_io(socket:write("Transfer-Encoding: chunked\r\n"))
    1.88            end
    1.89            if connection_close_requested and not connection_close_responded then
    1.90              request:send_header("Connection", "close")
    1.91            end
    1.92 -          assert(socket:write("\r\n"))
    1.93 +          assert_io(socket:write("\r\n"))
    1.94            if request.method == "HEAD" then
    1.95              finish_response()
    1.96            elseif flush then
    1.97 -            assert(socket:flush())
    1.98 +            assert_io(socket:flush())
    1.99            end
   1.100            output_state = "headers_sent"
   1.101          elseif output_state ~= "headers_sent" then
   1.102 @@ -311,14 +321,14 @@
   1.103              request:process_request_body()
   1.104            end
   1.105            if output_state == "info_status_sent" then
   1.106 -            assert(socket:write("\r\n"))
   1.107 -            assert(socket:flush())
   1.108 +            assert_io(socket:write("\r\n"))
   1.109 +            assert_io(socket:flush())
   1.110            elseif output_state ~= "no_status_sent" then
   1.111              error("HTTP status has already been sent")
   1.112            end
   1.113            local status1 = string.sub(value, 1, 1)
   1.114            local status3 = string.sub(value, 1, 3)
   1.115 -          assert(socket:write("HTTP/1.1 ", value, "\r\n", preamble))
   1.116 +          assert_io(socket:write("HTTP/1.1 ", value, "\r\n", preamble))
   1.117            local without_response_body = status_without_response_body[status3]
   1.118            if without_response_body then
   1.119              output_state = "bodyless_status_sent"
   1.120 @@ -371,7 +381,7 @@
   1.121                end
   1.122              end
   1.123            end
   1.124 -          assert(socket:write(key, ": ", value, "\r\n"))
   1.125 +          assert_io(socket:write(key, ": ", value, "\r\n"))
   1.126          end,
   1.127          -- method to finish and flush headers:
   1.128          finish_headers = function()
   1.129 @@ -397,11 +407,11 @@
   1.130                if content_length then
   1.131                  local bytes_to_send = #str
   1.132                  if bytes_sent + bytes_to_send > content_length then
   1.133 -                  assert(socket:write(string.sub(str, 1, content_length - bytes_sent)))
   1.134 +                  assert_io(socket:write(string.sub(str, 1, content_length - bytes_sent)))
   1.135                    bytes_sent = content_length
   1.136                    error("Content length exceeded")
   1.137                  else
   1.138 -                  assert(socket:write(str))
   1.139 +                  assert_io(socket:write(str))
   1.140                    bytes_sent = bytes_sent + bytes_to_send
   1.141                  end
   1.142                else
   1.143 @@ -417,7 +427,7 @@
   1.144          -- flush output buffer:
   1.145          flush = function(self)
   1.146            send_chunk()
   1.147 -          assert(socket:flush())
   1.148 +          assert_io(socket:flush())
   1.149          end,
   1.150          -- finish response:
   1.151          finish = function(self)
   1.152 @@ -435,7 +445,7 @@
   1.153                  end
   1.154                else
   1.155                  send_chunk()
   1.156 -                assert(socket:write("0\r\n\r\n"))
   1.157 +                assert_io(socket:write("0\r\n\r\n"))
   1.158                end
   1.159                finish_response()
   1.160              end
   1.161 @@ -742,8 +752,13 @@
   1.162            if request.headers_flags["Transfer-Encoding"]["chunked"] then
   1.163              while true do
   1.164                local line = socket:readuntil("\n", 32 + remaining_body_size_limit)
   1.165 -              if not line then
   1.166 -                error("Unexpected EOF while reading next chunk of request body")
   1.167 +              if not (
   1.168 +                line and (
   1.169 +                  string.match(line, "^[0-9A-Fa-f]+\r?$") or
   1.170 +                  string.match(line, "^[0-9A-Fa-f]+[ \t;]")
   1.171 +                )
   1.172 +              ) then
   1.173 +                assert_io(false, "Unexpected EOF or read error while reading next chunk of request body")
   1.174                end
   1.175                local zeros, lenstr = string.match(line, "^(0*)([1-9A-Fa-f]+[0-9A-Fa-f]*)\r?\n$")
   1.176                local chunkext
   1.177 @@ -753,7 +768,7 @@
   1.178                  zeros, lenstr, chunkext = string.match(line, "^(0*)([1-9A-Fa-f]+[0-9A-Fa-f]*)([ \t;].-)\r?\n$")
   1.179                end
   1.180                if not lenstr or #lenstr > 13 then
   1.181 -                error("Encoding error or unexpected EOF while reading chunk of request body")
   1.182 +                error("Encoding error while reading chunk of request body")
   1.183                end
   1.184                local len = tonumber("0x" .. lenstr)
   1.185                remaining_body_size_limit = remaining_body_size_limit - (#zeros + #chunkext + len)

Impressum / About Us