Software / code / prosody
Comparison
net/http/parser.lua @ 5467:9b7c919bf238
Merge 0.9->trunk
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 12 Apr 2013 00:32:10 +0100 |
| parent | 5463:111953bfe767 |
| child | 5475:c2c9f07c5d6a |
comparison
equal
deleted
inserted
replaced
| 5457:953888c31071 | 5467:9b7c919bf238 |
|---|---|
| 1 | |
| 2 local tonumber = tonumber; | 1 local tonumber = tonumber; |
| 3 local assert = assert; | 2 local assert = assert; |
| 4 local url_parse = require "socket.url".parse; | 3 local url_parse = require "socket.url".parse; |
| 5 local urldecode = require "net.http".urldecode; | 4 local urldecode = require "util.http".urldecode; |
| 6 | 5 |
| 7 local function preprocess_path(path) | 6 local function preprocess_path(path) |
| 8 path = urldecode((path:gsub("//+", "/"))); | 7 path = urldecode((path:gsub("//+", "/"))); |
| 9 if path:sub(1,1) ~= "/" then | 8 if path:sub(1,1) ~= "/" then |
| 10 path = "/"..path; | 9 path = "/"..path; |
| 27 | 26 |
| 28 function httpstream.new(success_cb, error_cb, parser_type, options_cb) | 27 function httpstream.new(success_cb, error_cb, parser_type, options_cb) |
| 29 local client = true; | 28 local client = true; |
| 30 if not parser_type or parser_type == "server" then client = false; else assert(parser_type == "client", "Invalid parser type"); end | 29 if not parser_type or parser_type == "server" then client = false; else assert(parser_type == "client", "Invalid parser type"); end |
| 31 local buf = ""; | 30 local buf = ""; |
| 32 local chunked; | 31 local chunked, chunk_size, chunk_start; |
| 33 local state = nil; | 32 local state = nil; |
| 34 local packet; | 33 local packet; |
| 35 local len; | 34 local len; |
| 36 local have_body; | 35 local have_body; |
| 37 local error; | 36 local error; |
| 63 headers[key] = headers[key] and headers[key]..","..val or val; | 62 headers[key] = headers[key] and headers[key]..","..val or val; |
| 64 else | 63 else |
| 65 first_line = line; | 64 first_line = line; |
| 66 if client then | 65 if client then |
| 67 httpversion, status_code, reason_phrase = line:match("^HTTP/(1%.[01]) (%d%d%d) (.*)$"); | 66 httpversion, status_code, reason_phrase = line:match("^HTTP/(1%.[01]) (%d%d%d) (.*)$"); |
| 67 status_code = tonumber(status_code); | |
| 68 if not status_code then error = true; return error_cb("invalid-status-line"); end | 68 if not status_code then error = true; return error_cb("invalid-status-line"); end |
| 69 have_body = not | 69 have_body = not |
| 70 ( (options_cb and options_cb().method == "HEAD") | 70 ( (options_cb and options_cb().method == "HEAD") |
| 71 or (status_code == 204 or status_code == 304 or status_code == 301) | 71 or (status_code == 204 or status_code == 304 or status_code == 301) |
| 72 or (status_code >= 100 and status_code < 200) ); | 72 or (status_code >= 100 and status_code < 200) ); |
| 73 chunked = have_body and headers["transfer-encoding"] == "chunked"; | |
| 74 else | 73 else |
| 75 method, path, httpversion = line:match("^(%w+) (%S+) HTTP/(1%.[01])$"); | 74 method, path, httpversion = line:match("^(%w+) (%S+) HTTP/(1%.[01])$"); |
| 76 if not method then error = true; return error_cb("invalid-status-line"); end | 75 if not method then error = true; return error_cb("invalid-status-line"); end |
| 77 end | 76 end |
| 78 end | 77 end |
| 79 end | 78 end |
| 80 if not first_line then error = true; return error_cb("invalid-status-line"); end | 79 if not first_line then error = true; return error_cb("invalid-status-line"); end |
| 80 chunked = have_body and headers["transfer-encoding"] == "chunked"; | |
| 81 len = tonumber(headers["content-length"]); -- TODO check for invalid len | 81 len = tonumber(headers["content-length"]); -- TODO check for invalid len |
| 82 if client then | 82 if client then |
| 83 -- FIXME handle '100 Continue' response (by skipping it) | 83 -- FIXME handle '100 Continue' response (by skipping it) |
| 84 if not have_body then len = 0; end | 84 if not have_body then len = 0; end |
| 85 packet = { | 85 packet = { |
| 118 state = true; | 118 state = true; |
| 119 end | 119 end |
| 120 if state then -- read body | 120 if state then -- read body |
| 121 if client then | 121 if client then |
| 122 if chunked then | 122 if chunked then |
| 123 local index = buf:find("\r\n", nil, true); | 123 if not buf:find("\r\n", nil, true) then |
| 124 if not index then return; end -- not enough data | 124 return; |
| 125 local chunk_size = buf:match("^%x+"); | 125 end -- not enough data |
| 126 if not chunk_size then error = true; return error_cb("invalid-chunk-size"); end | 126 if not chunk_size then |
| 127 chunk_size = tonumber(chunk_size, 16); | 127 chunk_size, chunk_start = buf:match("^(%x+)[^\r\n]*\r\n()"); |
| 128 index = index + 2; | 128 chunk_size = chunk_size and tonumber(chunk_size, 16); |
| 129 if chunk_size == 0 then | 129 if not chunk_size then error = true; return error_cb("invalid-chunk-size"); end |
| 130 state = nil; success_cb(packet); | |
| 131 elseif #buf - index + 1 >= chunk_size then -- we have a chunk | |
| 132 packet.body = packet.body..buf:sub(index, index + chunk_size - 1); | |
| 133 buf = buf:sub(index + chunk_size); | |
| 134 end | 130 end |
| 135 error("trailers"); -- FIXME MUST read trailers | 131 if chunk_size == 0 and buf:find("\r\n\r\n", chunk_start-2, true) then |
| 132 state, chunk_size = nil, nil; | |
| 133 buf = buf:gsub("^.-\r\n\r\n", ""); -- This ensure extensions and trailers are stripped | |
| 134 success_cb(packet); | |
| 135 elseif #buf - chunk_start + 2 >= chunk_size then -- we have a chunk | |
| 136 packet.body = packet.body..buf:sub(chunk_start, chunk_start + chunk_size); | |
| 137 buf = buf:sub(chunk_start + chunk_size + 2); | |
| 138 chunk_size, chunk_start = nil, nil; | |
| 139 else -- Partial chunk remaining | |
| 140 break; | |
| 141 end | |
| 136 elseif len and #buf >= len then | 142 elseif len and #buf >= len then |
| 137 packet.body, buf = buf:sub(1, len), buf:sub(len + 1); | 143 packet.body, buf = buf:sub(1, len), buf:sub(len + 1); |
| 138 state = nil; success_cb(packet); | 144 state = nil; success_cb(packet); |
| 145 else | |
| 146 break; | |
| 139 end | 147 end |
| 140 elseif #buf >= len then | 148 elseif #buf >= len then |
| 141 packet.body, buf = buf:sub(1, len), buf:sub(len + 1); | 149 packet.body, buf = buf:sub(1, len), buf:sub(len + 1); |
| 142 state = nil; success_cb(packet); | 150 state = nil; success_cb(packet); |
| 143 else | 151 else |