Skip to content

Commit b59ffe4

Browse files
committed
bugfix: resty.upload could not parse Content-Type header values like boundary="simple boundary", that is, with double quotes around the boundary value.
1 parent 7fa2550 commit b59ffe4

File tree

2 files changed

+214
-2
lines changed

2 files changed

+214
-2
lines changed

lib/resty/upload.lua

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ local state_handlers
3333

3434
function new(self, chunk_size)
3535
local boundary = get_boundary()
36+
37+
-- print("boundary: ", boundary)
38+
3639
if not boundary then
3740
return nil, "no boundary defined in Content-Type"
3841
end
@@ -44,7 +47,6 @@ function new(self, chunk_size)
4447
return nil, err
4548
end
4649

47-
4850
local read2boundary, err = sock:receiveuntil("--" .. boundary)
4951
if not read2boundary then
5052
return nil, err
@@ -244,7 +246,12 @@ function get_boundary()
244246
return nil
245247
end
246248

247-
return match(header, ";%s+boundary=(%S+)")
249+
local m = match(header, ";%s+boundary=\"([^\"]+)\"")
250+
if m then
251+
return m
252+
end
253+
254+
return match(header, ";%s+boundary=([^\",;]+)")
248255
end
249256

250257

t/sanity.t

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,208 @@ failed to read: line too long: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
192192
--- no_error_log
193193
[error]
194194

195+
196+
197+
=== TEST 4: example from RFC 1521
198+
--- http_config eval: $::HttpConfig
199+
--- config
200+
location /t {
201+
content_by_lua '
202+
local upload = require "resty.upload"
203+
local cjson = require "cjson"
204+
205+
local form = upload:new(20)
206+
207+
form:set_timeout(1000) -- 1 sec
208+
209+
while true do
210+
local typ, res, err = form:read()
211+
if not typ then
212+
ngx.say("failed to read: ", err)
213+
return
214+
end
215+
216+
ngx.say("read: ", cjson.encode({typ, res}))
217+
218+
if typ == "eof" then
219+
break
220+
end
221+
end
222+
223+
local typ, res, err = form:read()
224+
ngx.say("read: ", cjson.encode({typ, res}))
225+
';
226+
}
227+
--- more_headers
228+
Content-Type: multipart/form-data; boundary="simple boundary"
229+
--- request eval
230+
qq{POST /t
231+
This is the preamble. It is to be ignored, though it
232+
is a handy place for mail composers to include an
233+
explanatory note to non-MIME conformant readers.
234+
--simple boundary\r
235+
\r
236+
This is implicitly typed plain ASCII text.
237+
It does NOT end with a linebreak.\r
238+
--simple boundary\r
239+
Content-type: text/plain; charset=us-ascii\r
240+
\r
241+
This is explicitly typed plain ASCII text.
242+
It DOES end with a linebreak.
243+
\r
244+
--simple boundary--\r
245+
This is the epilogue. It is also to be ignored.
246+
247+
}
248+
--- response_body
249+
read: ["body","This is implicitly t"]
250+
read: ["body","yped plain ASCII tex"]
251+
read: ["body","t.\nIt does NOT end w"]
252+
read: ["body","ith a linebreak."]
253+
read: ["part_end"]
254+
read: ["header",["Content-type","text\/plain; charset=us-ascii","Content-type: text\/plain; charset=us-ascii"]]
255+
read: ["body","This is explicitly t"]
256+
read: ["body","yped plain ASCII tex"]
257+
read: ["body","t.\nIt DOES end with "]
258+
read: ["body","a linebreak.\n"]
259+
read: ["part_end"]
260+
read: ["eof"]
261+
read: ["eof"]
262+
--- no_error_log
263+
[error]
264+
265+
266+
267+
=== TEST 5: example from RFC 1521, no double quotes for the boundary value in the Content-Type response header
268+
--- http_config eval: $::HttpConfig
269+
--- config
270+
location /t {
271+
content_by_lua '
272+
local upload = require "resty.upload"
273+
local cjson = require "cjson"
274+
275+
local form = upload:new(20)
276+
277+
form:set_timeout(1000) -- 1 sec
278+
279+
while true do
280+
local typ, res, err = form:read()
281+
if not typ then
282+
ngx.say("failed to read: ", err)
283+
return
284+
end
285+
286+
ngx.say("read: ", cjson.encode({typ, res}))
287+
288+
if typ == "eof" then
289+
break
290+
end
291+
end
292+
293+
local typ, res, err = form:read()
294+
ngx.say("read: ", cjson.encode({typ, res}))
295+
';
296+
}
297+
--- more_headers
298+
Content-Type: multipart/form-data; boundary=simple boundary
299+
--- request eval
300+
qq{POST /t
301+
This is the preamble. It is to be ignored, though it
302+
is a handy place for mail composers to include an
303+
explanatory note to non-MIME conformant readers.
304+
--simple boundary\r
305+
\r
306+
This is implicitly typed plain ASCII text.
307+
It does NOT end with a linebreak.\r
308+
--simple boundary\r
309+
Content-type: text/plain; charset=us-ascii\r
310+
\r
311+
This is explicitly typed plain ASCII text.
312+
It DOES end with a linebreak.
313+
\r
314+
--simple boundary--\r
315+
This is the epilogue. It is also to be ignored.
316+
317+
}
318+
--- response_body
319+
read: ["body","This is implicitly t"]
320+
read: ["body","yped plain ASCII tex"]
321+
read: ["body","t.\nIt does NOT end w"]
322+
read: ["body","ith a linebreak."]
323+
read: ["part_end"]
324+
read: ["header",["Content-type","text\/plain; charset=us-ascii","Content-type: text\/plain; charset=us-ascii"]]
325+
read: ["body","This is explicitly t"]
326+
read: ["body","yped plain ASCII tex"]
327+
read: ["body","t.\nIt DOES end with "]
328+
read: ["body","a linebreak.\n"]
329+
read: ["part_end"]
330+
read: ["eof"]
331+
read: ["eof"]
332+
--- no_error_log
333+
[error]
334+
335+
336+
337+
=== TEST 6: example from RFC 1521, using the default chunk size
338+
--- http_config eval: $::HttpConfig
339+
--- config
340+
location /t {
341+
content_by_lua '
342+
local upload = require "resty.upload"
343+
local cjson = require "cjson"
344+
345+
local form = upload:new()
346+
347+
form:set_timeout(1000) -- 1 sec
348+
349+
while true do
350+
local typ, res, err = form:read()
351+
if not typ then
352+
ngx.say("failed to read: ", err)
353+
return
354+
end
355+
356+
ngx.say("read: ", cjson.encode({typ, res}))
357+
358+
if typ == "eof" then
359+
break
360+
end
361+
end
362+
363+
local typ, res, err = form:read()
364+
ngx.say("read: ", cjson.encode({typ, res}))
365+
';
366+
}
367+
--- more_headers
368+
Content-Type: multipart/form-data; boundary=simple boundary
369+
--- request eval
370+
qq{POST /t
371+
This is the preamble. It is to be ignored, though it
372+
is a handy place for mail composers to include an
373+
explanatory note to non-MIME conformant readers.
374+
--simple boundary\r
375+
\r
376+
This is implicitly typed plain ASCII text.
377+
It does NOT end with a linebreak.\r
378+
--simple boundary\r
379+
Content-type: text/plain; charset=us-ascii\r
380+
\r
381+
This is explicitly typed plain ASCII text.
382+
It DOES end with a linebreak.
383+
\r
384+
--simple boundary--\r
385+
This is the epilogue. It is also to be ignored.
386+
387+
}
388+
389+
--- response_body
390+
read: ["body","This is implicitly typed plain ASCII text.\nIt does NOT end with a linebreak."]
391+
read: ["part_end"]
392+
read: ["header",["Content-type","text\/plain; charset=us-ascii","Content-type: text\/plain; charset=us-ascii"]]
393+
read: ["body","This is explicitly typed plain ASCII text.\nIt DOES end with a linebreak.\n"]
394+
read: ["part_end"]
395+
read: ["eof"]
396+
read: ["eof"]
397+
--- no_error_log
398+
[error]
399+

0 commit comments

Comments
 (0)