Software /
code /
prosody
Comparison
net/http/parser.lua @ 11021:9673c95895fb
net.http.parser: Allow specifying sink for large request bodies
This enables uses such as saving uploaded files directly to a file on
disk or streaming parsing of payloads.
See #726
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sat, 01 Aug 2020 18:41:23 +0200 |
parent | 11020:7076ed654ac9 |
child | 11029:5550fc5e83f3 |
comparison
equal
deleted
inserted
replaced
11020:7076ed654ac9 | 11021:9673c95895fb |
---|---|
86 end | 86 end |
87 end | 87 end |
88 if not first_line then error = true; return error_cb("invalid-status-line"); end | 88 if not first_line then error = true; return error_cb("invalid-status-line"); end |
89 chunked = have_body and headers["transfer-encoding"] == "chunked"; | 89 chunked = have_body and headers["transfer-encoding"] == "chunked"; |
90 len = tonumber(headers["content-length"]); -- TODO check for invalid len | 90 len = tonumber(headers["content-length"]); -- TODO check for invalid len |
91 if len and len > bodylimit then error = true; return error_cb("content-length-limit-exceeded"); end | |
92 -- TODO ask a callback whether to proceed in case of large requests or Expect: 100-continue | |
93 if client then | 91 if client then |
94 -- FIXME handle '100 Continue' response (by skipping it) | 92 -- FIXME handle '100 Continue' response (by skipping it) |
95 if not have_body then len = 0; end | 93 if not have_body then len = 0; end |
96 packet = { | 94 packet = { |
97 code = status_code; | 95 code = status_code; |
124 headers = headers; | 122 headers = headers; |
125 body = false; | 123 body = false; |
126 body_sink = nil; | 124 body_sink = nil; |
127 }; | 125 }; |
128 end | 126 end |
129 if chunked then | 127 if len and len > bodylimit then |
128 -- Early notification, for redirection | |
129 success_cb(packet); | |
130 if not packet.body_sink then error = true; return error_cb("content-length-limit-exceeded"); end | |
131 end | |
132 if chunked and not packet.body_sink then | |
133 success_cb(packet); | |
134 if not packet.body_sink then | |
130 packet.body_buffer = dbuffer.new(buflimit); | 135 packet.body_buffer = dbuffer.new(buflimit); |
136 end | |
131 end | 137 end |
132 state = true; | 138 state = true; |
133 end | 139 end |
134 if state then -- read body | 140 if state then -- read body |
135 if chunked then | 141 if chunked then |
152 buffer:write(buf); | 158 buffer:write(buf); |
153 state, chunked = nil, nil; | 159 state, chunked = nil, nil; |
154 success_cb(packet); | 160 success_cb(packet); |
155 elseif buffer:length() - chunk_start - 2 >= chunk_size then -- we have a chunk | 161 elseif buffer:length() - chunk_start - 2 >= chunk_size then -- we have a chunk |
156 buffer:discard(chunk_start - 1); -- TODO verify that it's not off-by-one | 162 buffer:discard(chunk_start - 1); -- TODO verify that it's not off-by-one |
157 packet.body_buffer:write(buffer:read(chunk_size)); | 163 (packet.body_sink or packet.body_buffer):write(buffer:read(chunk_size)); |
158 buffer:discard(2); -- CRLF | 164 buffer:discard(2); -- CRLF |
159 else -- Partial chunk remaining | 165 else -- Partial chunk remaining |
160 break; | 166 break; |
161 end | 167 end |
168 elseif packet.body_sink then | |
169 local chunk = buffer:read_chunk(len); | |
170 while chunk and len > 0 do | |
171 if packet.body_sink:write(chunk) then | |
172 len = len - #chunk; | |
173 chunk = buffer:read_chunk(len); | |
174 else | |
175 error = true; | |
176 return error_cb("body-sink-write-failure"); | |
177 end | |
178 end | |
179 if len == 0 then state = nil; success_cb(packet); end | |
162 elseif buffer:length() >= len then | 180 elseif buffer:length() >= len then |
163 assert(not chunked) | 181 assert(not chunked) |
164 packet.body = buffer:read(len) or ""; | 182 packet.body = buffer:read(len) or ""; |
165 state = nil; success_cb(packet); | 183 state = nil; success_cb(packet); |
166 else | 184 else |