moonbridge
diff moonbridge_http.lua @ 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 |
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")