moonbridge

changeset 168:d4f5d6a7d401

Work on new HTTP module implementation
author jbe
date Mon Jun 15 02:14:55 2015 +0200 (2015-06-15)
parents 625ab06babe9
children a9433e394eb7
files moonbridge_http.lua
line diff
     1.1 --- a/moonbridge_http.lua	Mon Jun 15 00:07:08 2015 +0200
     1.2 +++ b/moonbridge_http.lua	Mon Jun 15 02:14:55 2015 +0200
     1.3 @@ -235,6 +235,9 @@
     1.4      end
     1.5      -- handle requests in a loop:
     1.6      repeat
     1.7 +      -- copy limits:
     1.8 +      local remaining_header_size_limit = header_size_limit
     1.9 +      local remaining_body_size_limit = body_size_limit
    1.10        -- table for caching nil values:
    1.11        local headers_value_nil = {}
    1.12        -- create a new request object:
    1.13 @@ -402,6 +405,111 @@
    1.14            send("\r\n")
    1.15          end
    1.16        end
    1.17 +      -- function to report an error:
    1.18 +      local function request_error(throw_error, status, text)
    1.19 +        local errmsg = "Error while reading request from client. Error response: " .. status
    1.20 +        if text then
    1.21 +          errmsg = errmsg .. " (" .. text .. ")"
    1.22 +        end
    1.23 +        if
    1.24 +          state == "init" or
    1.25 +          state == "prepare" or
    1.26 +          state == "no_status_sent" or
    1.27 +          state == "info_status_sent"
    1.28 +        then
    1.29 +          local error_response_status, errmsg2 = pcall(function()
    1.30 +            request:monologue()
    1.31 +            request:send_status(status)
    1.32 +            request:send_header("Content-Type", "text/plain")
    1.33 +            request:send_data(status, "\n")
    1.34 +            if text then
    1.35 +              request:send_data("\n", text, "\n")
    1.36 +            end
    1.37 +            request:finish()
    1.38 +          end)
    1.39 +          if not error_response_status then
    1.40 +            error("Unexpected error while sending error response: " .. errmsg2)
    1.41 +          end
    1.42 +        elseif state ~= "faulty" then
    1.43 +          assert_close(socket:reset())
    1.44 +        end
    1.45 +        if throw_error then
    1.46 +          error(errmsg)
    1.47 +        else
    1.48 +          return survive
    1.49 +        end
    1.50 +      end
    1.51 +      -- callback for request body streaming:
    1.52 +      local process_body_chunk
    1.53 +      -- reads a number of bytes from the socket,
    1.54 +      -- optionally feeding these bytes chunk-wise
    1.55 +      -- into a callback function:
    1.56 +      local function read_body_bytes(remaining)
    1.57 +        while remaining > 0 do
    1.58 +          local limit
    1.59 +          if remaining > input_chunk_size then
    1.60 +            limit = input_chunk_size
    1.61 +          else
    1.62 +            limit = remaining
    1.63 +          end
    1.64 +          local chunk = socket:read_yield(limit)
    1.65 +          if not chunk then
    1.66 +            request_error(true, "400 Bad Request", "Read error while reading chunk of request body")
    1.67 +          end
    1.68 +          if #chunk ~= limit then
    1.69 +            request_error(true, "400 Bad Request", "Unexpected EOF while reading chunk of request body")
    1.70 +          end
    1.71 +          remaining = remaining - limit
    1.72 +          if process_body_chunk then
    1.73 +            process_body_chunk(chunk)
    1.74 +          end
    1.75 +        end
    1.76 +      end
    1.77 +      -- coroutine for request body processing:
    1.78 +      local function read_body()
    1.79 +        if request.headers_flags["Transfer-Encoding"]["chunked"] then
    1.80 +          while true do
    1.81 +            local line, status = socket:read_yield(32 + remaining_body_size_limit, "\n")
    1.82 +            if not line then
    1.83 +              request_error(true, "400 Bad Request", "Read error while reading next chunk of request body")
    1.84 +            end
    1.85 +            if status == "eof" then
    1.86 +              request_error(true, "400 Bad Request", "Unexpected EOF while reading next chunk of request body")
    1.87 +            end
    1.88 +            local zeros, lenstr = string.match(line, "^(0*)([1-9A-Fa-f]+[0-9A-Fa-f]*)\r?\n$")
    1.89 +            local chunkext
    1.90 +            if lenstr then
    1.91 +              chunkext = ""
    1.92 +            else
    1.93 +              zeros, lenstr, chunkext = string.match(line, "^(0*)([1-9A-Fa-f]+[0-9A-Fa-f]*)([ \t;].-)\r?\n$")
    1.94 +            end
    1.95 +            if not lenstr or #lenstr > 13 then
    1.96 +              request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body")
    1.97 +            end
    1.98 +            local len = tonumber("0x" .. lenstr)
    1.99 +            remaining_body_size_limit = remaining_body_size_limit - (#zeros + #chunkext + len)
   1.100 +            if remaining_body_size_limit < 0 then
   1.101 +              request_error(true, "413 Request Entity Too Large", "Request body size limit exceeded")
   1.102 +            end
   1.103 +            if len == 0 then break end
   1.104 +            read_body_bytes(len)
   1.105 +            local term = socket:read(2, "\n")
   1.106 +            if term ~= "\r\n" and term ~= "\n" then
   1.107 +              request_error(true, "400 Bad Request", "Encoding error while reading chunk of request body")
   1.108 +            end
   1.109 +          end
   1.110 +          while true do
   1.111 +            local line = socket:read(2 + remaining_body_size_limit, "\n")
   1.112 +            if line == "\r\n" or line == "\n" then break end
   1.113 +            remaining_body_size_limit = remaining_body_size_limit - #line
   1.114 +            if remaining_body_size_limit < 0 then
   1.115 +              request_error(true, "413 Request Entity Too Large", "Request body size limit exceeded while reading trailer section of chunked request body")
   1.116 +            end
   1.117 +          end
   1.118 +        elseif request_body_content_length then
   1.119 +          read_body_bytes(request_body_content_length)
   1.120 +        end
   1.121 +      end
   1.122        -- function to prepare (or skip) body processing:
   1.123        local function prepare()
   1.124          assert_not_faulty()
   1.125 @@ -608,40 +716,6 @@
   1.126            error("Unexpected internal status in HTTP engine")
   1.127          end
   1.128        end
   1.129 -      -- function to report an error:
   1.130 -      local function request_error(throw_error, status, text)
   1.131 -        local errmsg = "Error while reading request from client. Error response: " .. status
   1.132 -        if text then
   1.133 -          errmsg = errmsg .. " (" .. text .. ")"
   1.134 -        end
   1.135 -        if
   1.136 -          state == "init" or
   1.137 -          state == "prepare" or
   1.138 -          state == "no_status_sent" or
   1.139 -          state == "info_status_sent"
   1.140 -        then
   1.141 -          local error_response_status, errmsg2 = pcall(function()
   1.142 -            request:monologue()
   1.143 -            request:send_status(status)
   1.144 -            request:send_header("Content-Type", "text/plain")
   1.145 -            request:send_data(status, "\n")
   1.146 -            if text then
   1.147 -              request:send_data("\n", text, "\n")
   1.148 -            end
   1.149 -            request:finish()
   1.150 -          end)
   1.151 -          if not error_response_status then
   1.152 -            error("Unexpected error while sending error response: " .. errmsg2)
   1.153 -          end
   1.154 -        elseif state ~= "faulty" then
   1.155 -          assert_close(socket:reset())
   1.156 -        end
   1.157 -        if throw_error then
   1.158 -          error(errmsg)
   1.159 -        else
   1.160 -          return survive
   1.161 -        end
   1.162 -      end
   1.163        -- wait for input:
   1.164        if not poll(socket_set, nil, request_idle_timeout) then
   1.165          return request_error(false, "408 Request Timeout", "Idle connection timed out")

Impressum / About Us