http: remove the keepalive requests limit
[unicorn.git] / test / unit / test_http_parser_ng.rb
blob91678458acd8cbeeffe6e62d634d31a295eaf228
1 # -*- encoding: binary -*-
3 require 'test/test_helper'
4 require 'digest/md5'
6 include Unicorn
8 class HttpParserNgTest < Test::Unit::TestCase
10   def setup
11     @parser = HttpParser.new
12   end
14   def test_next_clear
15     r = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
16     @parser.buf << r
17     @parser.parse
18     @parser.response_start_sent = true
19     assert @parser.keepalive?
20     assert @parser.next?
21     assert @parser.response_start_sent
23     # persistent client makes another request:
24     @parser.buf << r
25     @parser.parse
26     assert @parser.keepalive?
27     assert @parser.next?
28     assert_equal false, @parser.response_start_sent
29   end
31   def test_connection_TE
32     @parser.buf << "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: TE\r\n"
33     @parser.buf << "TE: trailers\r\n\r\n"
34     @parser.parse
35     assert @parser.keepalive?
36     assert @parser.next?
37   end
39   def test_keepalive_requests_with_next?
40     req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
41     expect = {
42       "SERVER_NAME" => "example.com",
43       "HTTP_HOST" => "example.com",
44       "rack.url_scheme" => "http",
45       "REQUEST_PATH" => "/",
46       "SERVER_PROTOCOL" => "HTTP/1.1",
47       "PATH_INFO" => "/",
48       "HTTP_VERSION" => "HTTP/1.1",
49       "REQUEST_URI" => "/",
50       "SERVER_PORT" => "80",
51       "REQUEST_METHOD" => "GET",
52       "QUERY_STRING" => ""
53     }.freeze
54     100.times do |nr|
55       @parser.buf << req
56       assert_equal expect, @parser.parse
57       assert @parser.next?
58     end
59   end
61   def test_default_keepalive_is_off
62     assert ! @parser.keepalive?
63     assert ! @parser.next?
64     @parser.buf << "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
65     @parser.parse
66     assert @parser.keepalive?
67     @parser.clear
68     assert ! @parser.keepalive?
69     assert ! @parser.next?
70   end
72   def test_identity_byte_headers
73     req = @parser.env
74     str = "PUT / HTTP/1.1\r\n"
75     str << "Content-Length: 123\r\n"
76     str << "\r"
77     hdr = @parser.buf
78     str.each_byte { |byte|
79       hdr << byte.chr
80       assert_nil @parser.parse
81     }
82     hdr << "\n"
83     assert_equal req.object_id, @parser.parse.object_id
84     assert_equal '123', req['CONTENT_LENGTH']
85     assert_equal 0, hdr.size
86     assert ! @parser.keepalive?
87     assert @parser.headers?
88     assert_equal 123, @parser.content_length
89     dst = ""
90     buf = '.' * 123
91     @parser.filter_body(dst, buf)
92     assert_equal '.' * 123, dst
93     assert_equal "", buf
94     assert @parser.keepalive?
95   end
97   def test_identity_step_headers
98     req = @parser.env
99     str = @parser.buf
100     str << "PUT / HTTP/1.1\r\n"
101     assert ! @parser.parse
102     str << "Content-Length: 123\r\n"
103     assert ! @parser.parse
104     str << "\r\n"
105     assert_equal req.object_id, @parser.parse.object_id
106     assert_equal '123', req['CONTENT_LENGTH']
107     assert_equal 0, str.size
108     assert ! @parser.keepalive?
109     assert @parser.headers?
110     dst = ""
111     buf = '.' * 123
112     @parser.filter_body(dst, buf)
113     assert_equal '.' * 123, dst
114     assert_equal "", buf
115     assert @parser.keepalive?
116   end
118   def test_identity_oneshot_header
119     req = @parser.env
120     str = @parser.buf
121     str << "PUT / HTTP/1.1\r\nContent-Length: 123\r\n\r\n"
122     assert_equal req.object_id, @parser.parse.object_id
123     assert_equal '123', req['CONTENT_LENGTH']
124     assert_equal 0, str.size
125     assert ! @parser.keepalive?
126     assert @parser.headers?
127     dst = ""
128     buf = '.' * 123
129     @parser.filter_body(dst, buf)
130     assert_equal '.' * 123, dst
131     assert_equal "", buf
132   end
134   def test_identity_oneshot_header_with_body
135     body = ('a' * 123).freeze
136     req = @parser.env
137     str = @parser.buf
138     str << "PUT / HTTP/1.1\r\n" \
139            "Content-Length: #{body.length}\r\n" \
140            "\r\n#{body}"
141     assert_equal req.object_id, @parser.parse.object_id
142     assert_equal '123', req['CONTENT_LENGTH']
143     assert_equal 123, str.size
144     assert_equal body, str
145     tmp = ''
146     assert_nil @parser.filter_body(tmp, str)
147     assert_equal 0, str.size
148     assert_equal tmp, body
149     assert_equal "", @parser.filter_body(tmp, str)
150     assert @parser.keepalive?
151   end
153   def test_identity_oneshot_header_with_body_partial
154     str = @parser.buf
155     str << "PUT / HTTP/1.1\r\nContent-Length: 123\r\n\r\na"
156     assert_equal Hash, @parser.parse.class
157     assert_equal 1, str.size
158     assert_equal 'a', str
159     tmp = ''
160     assert_nil @parser.filter_body(tmp, str)
161     assert_equal "", str
162     assert_equal "a", tmp
163     str << ' ' * 122
164     rv = @parser.filter_body(tmp, str)
165     assert_equal 122, tmp.size
166     assert_nil rv
167     assert_equal "", str
168     assert_equal str.object_id, @parser.filter_body(tmp, str).object_id
169     assert @parser.keepalive?
170   end
172   def test_identity_oneshot_header_with_body_slop
173     str = @parser.buf
174     str << "PUT / HTTP/1.1\r\nContent-Length: 1\r\n\r\naG"
175     assert_equal Hash, @parser.parse.class
176     assert_equal 2, str.size
177     assert_equal 'aG', str
178     tmp = ''
179     assert_nil @parser.filter_body(tmp, str)
180     assert_equal "G", str
181     assert_equal "G", @parser.filter_body(tmp, str)
182     assert_equal 1, tmp.size
183     assert_equal "a", tmp
184     assert @parser.keepalive?
185   end
187   def test_chunked
188     str = @parser.buf
189     req = @parser.env
190     str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
191     assert_equal req, @parser.parse, "msg=#{str}"
192     assert_equal 0, str.size
193     tmp = ""
194     assert_nil @parser.filter_body(tmp, str << "6")
195     assert_equal 0, tmp.size
196     assert_nil @parser.filter_body(tmp, str << "\r\n")
197     assert_equal 0, str.size
198     assert_equal 0, tmp.size
199     tmp = ""
200     assert_nil @parser.filter_body(tmp, str << "..")
201     assert_equal "..", tmp
202     assert_nil @parser.filter_body(tmp, str << "abcd\r\n0\r\n")
203     assert_equal "abcd", tmp
204     assert_equal str.object_id, @parser.filter_body(tmp, str << "PUT").object_id
205     assert_equal "PUT", str
206     assert ! @parser.keepalive?
207     str << "TY: FOO\r\n\r\n"
208     assert_equal req, @parser.parse
209     assert_equal "FOO", req["HTTP_PUTTY"]
210     assert @parser.keepalive?
211   end
213   def test_chunked_empty
214     str = @parser.buf
215     req = @parser.env
216     str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
217     assert_equal req, @parser.parse, "msg=#{str}"
218     assert_equal 0, str.size
219     tmp = ""
220     assert_equal str, @parser.filter_body(tmp, str << "0\r\n\r\n")
221     assert_equal "", tmp
222   end
224   def test_two_chunks
225     str = @parser.buf
226     str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
227     req = @parser.env
228     assert_equal req, @parser.parse
229     assert_equal 0, str.size
230     tmp = ""
231     assert_nil @parser.filter_body(tmp, str << "6")
232     assert_equal 0, tmp.size
233     assert_nil @parser.filter_body(tmp, str << "\r\n")
234     assert_equal "", str
235     assert_equal 0, tmp.size
236     tmp = ""
237     assert_nil @parser.filter_body(tmp, str << "..")
238     assert_equal 2, tmp.size
239     assert_equal "..", tmp
240     assert_nil @parser.filter_body(tmp, str << "abcd\r\n1")
241     assert_equal "abcd", tmp
242     assert_nil @parser.filter_body(tmp, str << "\r")
243     assert_equal "", tmp
244     assert_nil @parser.filter_body(tmp, str << "\n")
245     assert_equal "", tmp
246     assert_nil @parser.filter_body(tmp, str << "z")
247     assert_equal "z", tmp
248     assert_nil @parser.filter_body(tmp, str << "\r\n")
249     assert_nil @parser.filter_body(tmp, str << "0")
250     assert_nil @parser.filter_body(tmp, str << "\r")
251     rv = @parser.filter_body(tmp, str << "\nGET")
252     assert_equal "GET", rv
253     assert_equal str.object_id, rv.object_id
254     assert ! @parser.keepalive?
255   end
257   def test_big_chunk
258     str = @parser.buf
259     str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" \
260            "4000\r\nabcd"
261     req = @parser.env
262     assert_equal req, @parser.parse
263     tmp = ''
264     assert_nil @parser.filter_body(tmp, str)
265     assert_equal '', str
266     str << ' ' * 16300
267     assert_nil @parser.filter_body(tmp, str)
268     assert_equal '', str
269     str << ' ' * 80
270     assert_nil @parser.filter_body(tmp, str)
271     assert_equal '', str
272     assert ! @parser.body_eof?
273     assert_equal "", @parser.filter_body(tmp, str << "\r\n0\r\n")
274     assert_equal "", tmp
275     assert @parser.body_eof?
276     str << "\r\n"
277     assert_equal req, @parser.parse
278     assert_equal "", str
279     assert @parser.body_eof?
280     assert @parser.keepalive?
281   end
283   def test_two_chunks_oneshot
284     str = @parser.buf
285     req = @parser.env
286     str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" \
287            "1\r\na\r\n2\r\n..\r\n0\r\n"
288     assert_equal req, @parser.parse
289     tmp = ''
290     assert_nil @parser.filter_body(tmp, str)
291     assert_equal 'a..', tmp
292     rv = @parser.filter_body(tmp, str)
293     assert_equal rv.object_id, str.object_id
294     assert ! @parser.keepalive?
295   end
297   def test_chunks_bytewise
298     chunked = "10\r\nabcdefghijklmnop\r\n11\r\n0123456789abcdefg\r\n0\r\n"
299     str = "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
300     buf = @parser.buf
301     buf << str
302     req = @parser.env
303     assert_equal req, @parser.parse
304     assert_equal "", buf
305     tmp = ''
306     body = ''
307     str = chunked[0..-2]
308     str.each_byte { |byte|
309       assert_nil @parser.filter_body(tmp, buf << byte.chr)
310       body << tmp
311     }
312     assert_equal 'abcdefghijklmnop0123456789abcdefg', body
313     rv = @parser.filter_body(tmp, buf<< "\n")
314     assert_equal rv.object_id, buf.object_id
315     assert ! @parser.keepalive?
316   end
318   def test_trailers
319     req = @parser.env
320     str = @parser.buf
321     str << "PUT / HTTP/1.1\r\n" \
322            "Trailer: Content-MD5\r\n" \
323            "transfer-Encoding: chunked\r\n\r\n" \
324            "1\r\na\r\n2\r\n..\r\n0\r\n"
325     assert_equal req, @parser.parse
326     assert_equal 'Content-MD5', req['HTTP_TRAILER']
327     assert_nil req['HTTP_CONTENT_MD5']
328     tmp = ''
329     assert_nil @parser.filter_body(tmp, str)
330     assert_equal 'a..', tmp
331     md5_b64 = [ Digest::MD5.digest(tmp) ].pack('m').strip.freeze
332     rv = @parser.filter_body(tmp, str)
333     assert_equal rv.object_id, str.object_id
334     assert_equal '', str
335     md5_hdr = "Content-MD5: #{md5_b64}\r\n".freeze
336     str << md5_hdr
337     assert_nil @parser.trailers(req, str)
338     assert_equal md5_b64, req['HTTP_CONTENT_MD5']
339     assert_equal "CONTENT_MD5: #{md5_b64}\r\n", str
340     str << "\r"
341     assert_nil @parser.parse
342     str << "\nGET / "
343     assert_equal req, @parser.parse
344     assert_equal "GET / ", str
345     assert @parser.keepalive?
346   end
348   def test_trailers_slowly
349     str = @parser.buf
350     str << "PUT / HTTP/1.1\r\n" \
351            "Trailer: Content-MD5\r\n" \
352            "transfer-Encoding: chunked\r\n\r\n" \
353            "1\r\na\r\n2\r\n..\r\n0\r\n"
354     req = @parser.env
355     assert_equal req, @parser.parse
356     assert_equal 'Content-MD5', req['HTTP_TRAILER']
357     assert_nil req['HTTP_CONTENT_MD5']
358     tmp = ''
359     assert_nil @parser.filter_body(tmp, str)
360     assert_equal 'a..', tmp
361     md5_b64 = [ Digest::MD5.digest(tmp) ].pack('m').strip.freeze
362     rv = @parser.filter_body(tmp, str)
363     assert_equal rv.object_id, str.object_id
364     assert_equal '', str
365     assert_nil @parser.trailers(req, str)
366     md5_hdr = "Content-MD5: #{md5_b64}\r\n".freeze
367     md5_hdr.each_byte { |byte|
368       str << byte.chr
369       assert_nil @parser.trailers(req, str)
370     }
371     assert_equal md5_b64, req['HTTP_CONTENT_MD5']
372     assert_equal "CONTENT_MD5: #{md5_b64}\r\n", str
373     str << "\r"
374     assert_nil @parser.parse
375     str << "\n"
376     assert_equal req, @parser.parse
377   end
379   def test_max_chunk
380     str = @parser.buf
381     str << "PUT / HTTP/1.1\r\n" \
382            "transfer-Encoding: chunked\r\n\r\n" \
383            "#{HttpParser::CHUNK_MAX.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n"
384     req = @parser.env
385     assert_equal req, @parser.parse
386     assert_nil @parser.content_length
387     @parser.filter_body('', str)
388     assert ! @parser.keepalive?
389   end
391   def test_max_body
392     n = HttpParser::LENGTH_MAX
393     @parser.buf << "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n"
394     req = @parser.env
395     @parser.headers(req, @parser.buf)
396     assert_equal n, req['CONTENT_LENGTH'].to_i
397     assert ! @parser.keepalive?
398   end
400   def test_overflow_chunk
401     n = HttpParser::CHUNK_MAX + 1
402     str = @parser.buf
403     req = @parser.env
404     str << "PUT / HTTP/1.1\r\n" \
405            "transfer-Encoding: chunked\r\n\r\n" \
406            "#{n.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n"
407     assert_equal req, @parser.parse
408     assert_nil @parser.content_length
409     assert_raise(HttpParserError) { @parser.filter_body('', str) }
410   end
412   def test_overflow_content_length
413     n = HttpParser::LENGTH_MAX + 1
414     @parser.buf << "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n"
415     assert_raise(HttpParserError) { @parser.parse }
416   end
418   def test_bad_chunk
419     @parser.buf << "PUT / HTTP/1.1\r\n" \
420                    "transfer-Encoding: chunked\r\n\r\n" \
421                    "#zzz\r\na\r\n2\r\n..\r\n0\r\n"
422     req = @parser.env
423     assert_equal req, @parser.parse
424     assert_nil @parser.content_length
425     assert_raise(HttpParserError) { @parser.filter_body("", @parser.buf) }
426   end
428   def test_bad_content_length
429     @parser.buf << "PUT / HTTP/1.1\r\nContent-Length: 7ff\r\n\r\n"
430     assert_raise(HttpParserError) { @parser.parse }
431   end
433   def test_bad_trailers
434     str = @parser.buf
435     req = @parser.env
436     str << "PUT / HTTP/1.1\r\n" \
437            "Trailer: Transfer-Encoding\r\n" \
438            "transfer-Encoding: chunked\r\n\r\n" \
439            "1\r\na\r\n2\r\n..\r\n0\r\n"
440     assert_equal req, @parser.parse
441     assert_equal 'Transfer-Encoding', req['HTTP_TRAILER']
442     tmp = ''
443     assert_nil @parser.filter_body(tmp, str)
444     assert_equal 'a..', tmp
445     assert_equal '', str
446     str << "Transfer-Encoding: identity\r\n\r\n"
447     assert_raise(HttpParserError) { @parser.parse }
448   end
450   def test_repeat_headers
451     str = "PUT / HTTP/1.1\r\n" \
452           "Trailer: Content-MD5\r\n" \
453           "Trailer: Content-SHA1\r\n" \
454           "transfer-Encoding: chunked\r\n\r\n" \
455           "1\r\na\r\n2\r\n..\r\n0\r\n"
456     req = @parser.env
457     @parser.buf << str
458     assert_equal req, @parser.parse
459     assert_equal 'Content-MD5,Content-SHA1', req['HTTP_TRAILER']
460     assert ! @parser.keepalive?
461   end
463   def test_parse_simple_request
464     parser = HttpParser.new
465     req = parser.env
466     parser.buf << "GET /read-rfc1945-if-you-dont-believe-me\r\n"
467     assert_equal req, parser.parse
468     assert_equal '', parser.buf
469     expect = {
470       "SERVER_NAME"=>"localhost",
471       "rack.url_scheme"=>"http",
472       "REQUEST_PATH"=>"/read-rfc1945-if-you-dont-believe-me",
473       "PATH_INFO"=>"/read-rfc1945-if-you-dont-believe-me",
474       "REQUEST_URI"=>"/read-rfc1945-if-you-dont-believe-me",
475       "SERVER_PORT"=>"80",
476       "SERVER_PROTOCOL"=>"HTTP/0.9",
477       "REQUEST_METHOD"=>"GET",
478       "QUERY_STRING"=>""
479     }
480     assert_equal expect, req
481     assert ! parser.headers?
482   end
484   def test_path_info_semicolon
485     qs = "QUERY_STRING"
486     pi = "PATH_INFO"
487     req = {}
488     str = "GET %s HTTP/1.1\r\nHost: example.com\r\n\r\n"
489     {
490       "/1;a=b?c=d&e=f" => { qs => "c=d&e=f", pi => "/1;a=b" },
491       "/1?c=d&e=f" => { qs => "c=d&e=f", pi => "/1" },
492       "/1;a=b" => { qs => "", pi => "/1;a=b" },
493       "/1;a=b?" => { qs => "", pi => "/1;a=b" },
494       "/1?a=b;c=d&e=f" => { qs => "a=b;c=d&e=f", pi => "/1" },
495       "*" => { qs => "", pi => "" },
496     }.each do |uri,expect|
497       assert_equal req, @parser.headers(req.clear, str % [ uri ])
498       req = req.dup
499       @parser.clear
500       assert_equal uri, req["REQUEST_URI"], "REQUEST_URI mismatch"
501       assert_equal expect[qs], req[qs], "#{qs} mismatch"
502       assert_equal expect[pi], req[pi], "#{pi} mismatch"
503       next if uri == "*"
504       uri = URI.parse("http://example.com#{uri}")
505       assert_equal uri.query.to_s, req[qs], "#{qs} mismatch URI.parse disagrees"
506       assert_equal uri.path, req[pi], "#{pi} mismatch URI.parse disagrees"
507     end
508   end
510   def test_path_info_semicolon_absolute
511     qs = "QUERY_STRING"
512     pi = "PATH_INFO"
513     req = {}
514     str = "GET http://example.com%s HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
515     {
516       "/1;a=b?c=d&e=f" => { qs => "c=d&e=f", pi => "/1;a=b" },
517       "/1?c=d&e=f" => { qs => "c=d&e=f", pi => "/1" },
518       "/1;a=b" => { qs => "", pi => "/1;a=b" },
519       "/1;a=b?" => { qs => "", pi => "/1;a=b" },
520       "/1?a=b;c=d&e=f" => { qs => "a=b;c=d&e=f", pi => "/1" },
521     }.each do |uri,expect|
522       assert_equal req, @parser.headers(req.clear, str % [ uri ])
523       req = req.dup
524       @parser.clear
525       assert_equal uri, req["REQUEST_URI"], "REQUEST_URI mismatch"
526       assert_equal "example.com", req["HTTP_HOST"], "Host: mismatch"
527       assert_equal expect[qs], req[qs], "#{qs} mismatch"
528       assert_equal expect[pi], req[pi], "#{pi} mismatch"
529     end
530   end
532   def test_negative_content_length
533     req = {}
534     str = "PUT / HTTP/1.1\r\n" \
535           "Content-Length: -1\r\n" \
536           "\r\n"
537     assert_raises(HttpParserError) do
538       @parser.headers(req, str)
539     end
540   end
542   def test_invalid_content_length
543     req = {}
544     str = "PUT / HTTP/1.1\r\n" \
545           "Content-Length: zzzzz\r\n" \
546           "\r\n"
547     assert_raises(HttpParserError) do
548       @parser.headers(req, str)
549     end
550   end
552   def test_backtrace_is_empty
553     begin
554       @parser.headers({}, "AAADFSFDSFD\r\n\r\n")
555       assert false, "should never get here line:#{__LINE__}"
556     rescue HttpParserError => e
557       assert_equal [], e.backtrace
558       return
559     end
560     assert false, "should never get here line:#{__LINE__}"
561   end
563   def test_ignore_version_header
564     @parser.buf << "GET / HTTP/1.1\r\nVersion: hello\r\n\r\n"
565     req = @parser.env
566     assert_equal req, @parser.parse
567     assert_equal '', @parser.buf
568     expect = {
569       "SERVER_NAME" => "localhost",
570       "rack.url_scheme" => "http",
571       "REQUEST_PATH" => "/",
572       "SERVER_PROTOCOL" => "HTTP/1.1",
573       "PATH_INFO" => "/",
574       "HTTP_VERSION" => "HTTP/1.1",
575       "REQUEST_URI" => "/",
576       "SERVER_PORT" => "80",
577       "REQUEST_METHOD" => "GET",
578       "QUERY_STRING" => ""
579     }
580     assert_equal expect, req
581   end
583   def test_pipelined_requests
584     host = "example.com"
585     expect = {
586       "HTTP_HOST" => host,
587       "SERVER_NAME" => host,
588       "REQUEST_PATH" => "/",
589       "rack.url_scheme" => "http",
590       "SERVER_PROTOCOL" => "HTTP/1.1",
591       "PATH_INFO" => "/",
592       "HTTP_VERSION" => "HTTP/1.1",
593       "REQUEST_URI" => "/",
594       "SERVER_PORT" => "80",
595       "REQUEST_METHOD" => "GET",
596       "QUERY_STRING" => ""
597     }
598     req1 = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
599     req2 = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
600     @parser.buf << (req1 + req2)
601     env1 = @parser.parse.dup
602     assert_equal expect, env1
603     assert_equal req2, @parser.buf
604     assert ! @parser.env.empty?
605     assert @parser.next?
606     assert @parser.keepalive?
607     assert @parser.headers?
608     assert_equal expect, @parser.env
609     env2 = @parser.parse.dup
610     host.replace "www.example.com"
611     assert_equal "www.example.com", expect["HTTP_HOST"]
612     assert_equal "www.example.com", expect["SERVER_NAME"]
613     assert_equal expect, env2
614     assert_equal "", @parser.buf
615   end
617   def test_chunk_only
618     tmp = ""
619     assert_equal @parser, @parser.dechunk!
620     assert_nil @parser.filter_body(tmp, "6\r\n")
621     assert_equal "", tmp
622     assert_nil @parser.filter_body(tmp, "abcdef")
623     assert_equal "abcdef", tmp
624     assert_nil @parser.filter_body(tmp, "\r\n")
625     assert_equal "", tmp
626     src = "0\r\n\r\n"
627     assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
628     assert_equal "", tmp
629   end
631   def test_chunk_only_bad_align
632     tmp = ""
633     assert_equal @parser, @parser.dechunk!
634     assert_nil @parser.filter_body(tmp, "6\r\na")
635     assert_equal "a", tmp
636     assert_nil @parser.filter_body(tmp, "bcde")
637     assert_equal "bcde", tmp
638     assert_nil @parser.filter_body(tmp, "f\r")
639     assert_equal "f", tmp
640     src = "\n0\r\n\r\n"
641     assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
642     assert_equal "", tmp
643   end
645   def test_chunk_only_reset_ok
646     tmp = ""
647     assert_equal @parser, @parser.dechunk!
648     src = "1\r\na\r\n0\r\n\r\n"
649     assert_nil @parser.filter_body(tmp, src)
650     assert_equal "a", tmp
651     assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
653     assert_equal @parser, @parser.dechunk!
654     src = "0\r\n\r\n"
655     assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
656     assert_equal "", tmp
657     assert_equal src, @parser.filter_body(tmp, src)
658   end