Comparison

net/http/parser.lua @ 7581:01d0d466d7be

Merge 0.9->0.10
author Kim Alvefur <zash@zash.se>
date Thu, 18 Aug 2016 15:16:02 +0200
parent 7569:a15ce0014ac9
parent 7578:65bf55fdf971
child 7634:b1132d74f54c
comparison
equal deleted inserted replaced
7572:f549587b8c06 7581:01d0d466d7be
1 local tonumber = tonumber; 1 local tonumber = tonumber;
2 local assert = assert; 2 local assert = assert;
3 local t_insert, t_concat = table.insert, table.concat;
3 local url_parse = require "socket.url".parse; 4 local url_parse = require "socket.url".parse;
4 local urldecode = require "util.http".urldecode; 5 local urldecode = require "util.http".urldecode;
5 6
6 local function preprocess_path(path) 7 local function preprocess_path(path)
7 path = urldecode((path:gsub("//+", "/"))); 8 path = urldecode((path:gsub("//+", "/")));
25 local httpstream = {}; 26 local httpstream = {};
26 27
27 function httpstream.new(success_cb, error_cb, parser_type, options_cb) 28 function httpstream.new(success_cb, error_cb, parser_type, options_cb)
28 local client = true; 29 local client = true;
29 if not parser_type or parser_type == "server" then client = false; else assert(parser_type == "client", "Invalid parser type"); end 30 if not parser_type or parser_type == "server" then client = false; else assert(parser_type == "client", "Invalid parser type"); end
30 local buf = ""; 31 local buf, buflen, buftable = {}, 0, true;
32 local bodylimit = tonumber(options_cb and options_cb().body_size_limit) or 10*1024*1024;
33 local buflimit = tonumber(options_cb and options_cb().buffer_size_limit) or bodylimit * 2;
31 local chunked, chunk_size, chunk_start; 34 local chunked, chunk_size, chunk_start;
32 local state = nil; 35 local state = nil;
33 local packet; 36 local packet;
34 local len; 37 local len;
35 local have_body; 38 local have_body;
36 local error; 39 local error;
37 return { 40 return {
38 feed = function(_, data) 41 feed = function(_, data)
39 if error then return nil, "parse has failed"; end 42 if error then return nil, "parse has failed"; end
40 if not data then -- EOF 43 if not data then -- EOF
44 if buftable then buf, buftable = t_concat(buf), false; end
41 if state and client and not len then -- reading client body until EOF 45 if state and client and not len then -- reading client body until EOF
42 packet.body = buf; 46 packet.body = buf;
43 success_cb(packet); 47 success_cb(packet);
44 elseif buf ~= "" then -- unexpected EOF 48 elseif buf ~= "" then -- unexpected EOF
45 error = true; return error_cb(); 49 error = true; return error_cb();
46 end 50 end
47 return; 51 return;
48 end 52 end
49 buf = buf..data; 53 if buftable then
50 while #buf > 0 do 54 t_insert(buf, data);
55 else
56 buf = { buf, data };
57 buftable = true;
58 end
59 buflen = buflen + #data;
60 if buflen > buflimit then error = true; return error_cb("max-buffer-size-exceeded"); end
61 while buflen > 0 do
51 if state == nil then -- read request 62 if state == nil then -- read request
63 if buftable then buf, buftable = t_concat(buf), false; end
52 local index = buf:find("\r\n\r\n", nil, true); 64 local index = buf:find("\r\n\r\n", nil, true);
53 if not index then return; end -- not enough data 65 if not index then return; end -- not enough data
54 local method, path, httpversion, status_code, reason_phrase; 66 local method, path, httpversion, status_code, reason_phrase;
55 local first_line; 67 local first_line;
56 local headers = {}; 68 local headers = {};
77 end 89 end
78 end 90 end
79 if not first_line then error = true; return error_cb("invalid-status-line"); end 91 if not first_line then error = true; return error_cb("invalid-status-line"); end
80 chunked = have_body and headers["transfer-encoding"] == "chunked"; 92 chunked = have_body and headers["transfer-encoding"] == "chunked";
81 len = tonumber(headers["content-length"]); -- TODO check for invalid len 93 len = tonumber(headers["content-length"]); -- TODO check for invalid len
94 if len and len > bodylimit then error = true; return error_cb("content-length-limit-exceeded"); end
82 if client then 95 if client then
83 -- FIXME handle '100 Continue' response (by skipping it) 96 -- FIXME handle '100 Continue' response (by skipping it)
84 if not have_body then len = 0; end 97 if not have_body then len = 0; end
85 packet = { 98 packet = {
86 code = status_code; 99 code = status_code;
113 headers = headers; 126 headers = headers;
114 body = nil; 127 body = nil;
115 }; 128 };
116 end 129 end
117 buf = buf:sub(index + 4); 130 buf = buf:sub(index + 4);
131 buflen = #buf;
118 state = true; 132 state = true;
119 end 133 end
120 if state then -- read body 134 if state then -- read body
121 if client then 135 if client then
122 if chunked then 136 if chunked then
137 if buftable then buf, buftable = t_concat(buf), false; end
123 if not buf:find("\r\n", nil, true) then 138 if not buf:find("\r\n", nil, true) then
124 return; 139 return;
125 end -- not enough data 140 end -- not enough data
126 if not chunk_size then 141 if not chunk_size then
127 chunk_size, chunk_start = buf:match("^(%x+)[^\r\n]*\r\n()"); 142 chunk_size, chunk_start = buf:match("^(%x+)[^\r\n]*\r\n()");
130 end 145 end
131 if chunk_size == 0 and buf:find("\r\n\r\n", chunk_start-2, true) then 146 if chunk_size == 0 and buf:find("\r\n\r\n", chunk_start-2, true) then
132 state, chunk_size = nil, nil; 147 state, chunk_size = nil, nil;
133 buf = buf:gsub("^.-\r\n\r\n", ""); -- This ensure extensions and trailers are stripped 148 buf = buf:gsub("^.-\r\n\r\n", ""); -- This ensure extensions and trailers are stripped
134 success_cb(packet); 149 success_cb(packet);
135 elseif #buf - chunk_start - 2 >= chunk_size then -- we have a chunk 150 elseif buflen - chunk_start - 2 >= chunk_size then -- we have a chunk
136 packet.body = packet.body..buf:sub(chunk_start, chunk_start + (chunk_size-1)); 151 packet.body = packet.body..buf:sub(chunk_start, chunk_start + (chunk_size-1));
137 buf = buf:sub(chunk_start + chunk_size + 2); 152 buf = buf:sub(chunk_start + chunk_size + 2);
138 chunk_size, chunk_start = nil, nil; 153 chunk_size, chunk_start = nil, nil;
139 else -- Partial chunk remaining 154 else -- Partial chunk remaining
140 break; 155 break;
141 end 156 end
142 elseif len and #buf >= len then 157 elseif len and buflen >= len then
158 if buftable then buf, buftable = t_concat(buf), false; end
143 if packet.code == 101 then 159 if packet.code == 101 then
144 packet.body, buf = buf, ""; 160 packet.body, buf, buflen, buftable = buf, {}, 0, true;
145 else 161 else
146 packet.body, buf = buf:sub(1, len), buf:sub(len + 1); 162 packet.body, buf = buf:sub(1, len), buf:sub(len + 1);
163 buflen = #buf;
147 end 164 end
148 state = nil; success_cb(packet); 165 state = nil; success_cb(packet);
149 else 166 else
150 break; 167 break;
151 end 168 end
152 elseif #buf >= len then 169 elseif buflen >= len then
170 if buftable then buf, buftable = t_concat(buf), false; end
153 packet.body, buf = buf:sub(1, len), buf:sub(len + 1); 171 packet.body, buf = buf:sub(1, len), buf:sub(len + 1);
172 buflen = #buf;
154 state = nil; success_cb(packet); 173 state = nil; success_cb(packet);
155 else 174 else
156 break; 175 break;
157 end 176 end
158 end 177 end