http_tools 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,18 +8,31 @@ class ResponseTest < Test::Unit::TestCase
8
8
  parser = HTTPTools::Parser.new
9
9
  version = nil
10
10
 
11
- parser.add_listener(:version) {|v| version = v}
11
+ parser.add_listener(:header) {version = parser.version}
12
12
 
13
- parser << "HTTP/1.1 "
13
+ parser << "HTTP/1.1 200 OK\r\n\r\n"
14
14
 
15
15
  assert_equal("1.1", version)
16
16
  end
17
17
 
18
+ def test_one_dot_x_version
19
+ parser = HTTPTools::Parser.new
20
+ version = nil
21
+
22
+ parser.add_listener(:header) {version = parser.version}
23
+
24
+ parser << "HTTP/1.x 200 OK\r\n\r\n"
25
+
26
+ assert_equal("1.x", version)
27
+ end
28
+
18
29
  def test_ok
19
30
  parser = HTTPTools::Parser.new
20
31
  code, message = nil
21
32
 
22
- parser.add_listener(:status) {|c, m| code, message = c, m}
33
+ parser.add_listener(:header) do
34
+ code, message = parser.status_code, parser.message
35
+ end
23
36
 
24
37
  parser << "HTTP/1.1 200 OK\r\n\r\n"
25
38
 
@@ -32,7 +45,9 @@ class ResponseTest < Test::Unit::TestCase
32
45
  parser = HTTPTools::Parser.new
33
46
  code, message = nil
34
47
 
35
- parser.add_listener(:status) {|c, m| code, message = c, m}
48
+ parser.add_listener(:header) do
49
+ code, message = parser.status_code, parser.message
50
+ end
36
51
 
37
52
  parser << "HTTP/1.1 404 Not Found\r\n\r\n"
38
53
 
@@ -41,11 +56,61 @@ class ResponseTest < Test::Unit::TestCase
41
56
  assert(!parser.finished?, "parser should not be finished")
42
57
  end
43
58
 
59
+ def test_missing_message
60
+ parser = HTTPTools::Parser.new
61
+ code, message = nil
62
+
63
+ parser.add_listener(:header) do
64
+ code, message = parser.status_code, parser.message
65
+ end
66
+
67
+ parser << "HTTP/1.1 302\r\n\r\n"
68
+
69
+ assert_equal(302, code)
70
+ assert_equal("", message)
71
+ assert(!parser.finished?, "parser should not be finished")
72
+ end
73
+
74
+ def test_non_standard_message
75
+ parser = HTTPTools::Parser.new
76
+ version, code, message = nil
77
+
78
+ parser.add_listener(:header) do
79
+ version = parser.version
80
+ code = parser.status_code
81
+ message = parser.message
82
+ end
83
+
84
+ parser << "HTTP/1.0 200 (OK)\r\n\r\n"
85
+
86
+ assert_equal("1.0", version)
87
+ assert_equal(200, code)
88
+ assert_equal("(OK)", message)
89
+ assert(!parser.finished?, "parser should not be finished")
90
+ end
91
+
92
+ def test_status_message_with_accent
93
+ parser = HTTPTools::Parser.new
94
+ code, message = nil
95
+
96
+ parser.add_listener(:header) do
97
+ code, message = parser.status_code, parser.message
98
+ end
99
+
100
+ parser << "HTTP/1.1 403 Accès interdit\r\n\r\n"
101
+
102
+ assert_equal(403, code)
103
+ assert_equal("Accès interdit", message)
104
+ assert(!parser.finished?, "parser should not be finished")
105
+ end
106
+
44
107
  def test_no_content
45
108
  parser = HTTPTools::Parser.new
46
109
  code, message = nil
47
110
 
48
- parser.add_listener(:status) {|c, m| code, message = c, m}
111
+ parser.add_listener(:header) do
112
+ code, message = parser.status_code, parser.message
113
+ end
49
114
 
50
115
  parser << "HTTP/1.1 204 No Content\r\n\r\n"
51
116
 
@@ -58,7 +123,9 @@ class ResponseTest < Test::Unit::TestCase
58
123
  parser = HTTPTools::Parser.new
59
124
  code, message = nil
60
125
 
61
- parser.add_listener(:status) {|c, m| code, message = c, m}
126
+ parser.add_listener(:header) do
127
+ code, message = parser.status_code, parser.message
128
+ end
62
129
 
63
130
  parser << "HTTP/1.1 304 Not Modified\r\n\r\n"
64
131
 
@@ -72,7 +139,7 @@ class ResponseTest < Test::Unit::TestCase
72
139
  parser.force_no_body = true
73
140
  headers = nil
74
141
 
75
- parser.add_listener(:headers) {|h| headers = h}
142
+ parser.add_listener(:header) {headers = parser.header}
76
143
 
77
144
  parser << "HTTP/1.1 200 OK\r\n"
78
145
  parser << "Content-Length: 20\r\n"
@@ -82,12 +149,178 @@ class ResponseTest < Test::Unit::TestCase
82
149
  assert(parser.finished?, "parser should be finished")
83
150
  end
84
151
 
152
+ def test_messed_up_iis_headers
153
+ parser = HTTPTools::Parser.new
154
+ headers = nil
155
+
156
+ parser.add_listener(:header) {headers = parser.header}
157
+
158
+ parser << "HTTP/1.1 200 OK\r\n"
159
+ parser << "Server:: Harris Associates L.P.\r\n"
160
+ parser << "X-DIP:202\r\n"
161
+ parser << "\r\n"
162
+
163
+ assert_equal({
164
+ "Server" => ": Harris Associates L.P.",
165
+ "X-DIP" => "202"}, headers)
166
+ end
167
+
168
+ def test_space_in_header_key
169
+ parser = HTTPTools::Parser.new
170
+ headers = nil
171
+
172
+ parser.add_listener(:header) {headers = parser.header}
173
+
174
+ parser << "HTTP/1.1 200 OK\r\n"
175
+ parser << "X-Powered-By: PHP/5.3.5\r\n"
176
+ parser << "HTTP Status Code: HTTP/1.1 404 Not Found\r\n"
177
+ parser << "\r\n"
178
+
179
+ assert_equal({
180
+ "X-Powered-By" => "PHP/5.3.5",
181
+ "HTTP Status Code" => "HTTP/1.1 404 Not Found"}, headers)
182
+ end
183
+
184
+ def test_header_empty_value
185
+ parser = HTTPTools::Parser.new
186
+ headers = nil
187
+
188
+ parser.add_listener(:header) {headers = parser.header}
189
+
190
+ parser << "HTTP/1.1 200 OK\r\n"
191
+ parser << "X-Empty: \r\n"
192
+ parser << "Content-Type: text/html\r\n\r\n"
193
+
194
+ assert_equal({
195
+ "X-Empty" => "",
196
+ "Content-Type" => "text/html"}, headers)
197
+ end
198
+
199
+ def test_weird_iis_content_header
200
+ parser = HTTPTools::Parser.new
201
+ code, message, headers = nil
202
+ body = ""
203
+
204
+ parser.add_listener(:header) do
205
+ code = parser.status_code
206
+ message = parser.message
207
+ headers = parser.header
208
+ end
209
+ parser.add_listener(:stream) {|chunk| body << chunk}
210
+
211
+ parser << "HTTP/1.1 200 OK\r\n"
212
+ parser << "Content-Length: 20\r\n"
213
+ parser << "Content:\r\n"
214
+ parser << "\r\n"
215
+ parser << "<h1>Hello world</h1>"
216
+
217
+ assert_equal(200, code)
218
+ assert_equal("OK", message)
219
+ assert_equal({"Content-Length" => "20", "Content" => ""}, headers)
220
+ assert_equal("<h1>Hello world</h1>", body)
221
+ assert(parser.finished?, "parser should be finished")
222
+ end
223
+
224
+ def test_multiple_set_cookie_headers
225
+ parser = HTTPTools::Parser.new
226
+ headers = nil
227
+
228
+ parser.add_listener(:header) {headers = parser.header}
229
+
230
+ parser << "HTTP/1.1 200 OK\r\n"
231
+ parser << "Set-Cookie: foo=bar\r\n"
232
+ parser << "Set-Cookie: baz=qux\r\n\r\n"
233
+
234
+ assert_equal({"Set-Cookie" => ["foo=bar", "baz=qux"]}, headers)
235
+ end
236
+
237
+ def test_skip_junk_headers_at_end
238
+ parser = HTTPTools::Parser.new
239
+ code, message, headers = nil
240
+ body = ""
241
+
242
+ parser.add_listener(:header) do
243
+ code = parser.status_code
244
+ message = parser.message
245
+ headers = parser.header
246
+ end
247
+ parser.add_listener(:stream) {|chunk| body << chunk}
248
+
249
+ parser << "HTTP/1.1 301 Redirect\r\n"
250
+ parser << "Location: /index.html\r\n"
251
+ parser << "Content-Length: 74\r\n"
252
+ parser << "301 Moved Permanently\r\n\r\n"
253
+ parser << "You should have been redirected to\n"
254
+ parser << "<a href=\"/index.html\">/index.html</a>.\n"
255
+
256
+ assert_equal(301, code)
257
+ assert_equal("Redirect", message)
258
+ assert_equal({"Location" => "/index.html", "Content-Length" => "74"}, headers)
259
+ assert_equal("You should have been redirected to\n<a href=\"/index.html\">/index.html</a>.\n", body)
260
+ assert(parser.finished?, "parser should be finished")
261
+ end
262
+
263
+ def test_skip_junk_headers_at_start
264
+ parser = HTTPTools::Parser.new
265
+ code, message, headers = nil
266
+ body = ""
267
+
268
+ parser.add_listener(:header) do
269
+ code = parser.status_code
270
+ message = parser.message
271
+ headers = parser.header
272
+ end
273
+ parser.add_listener(:stream) {|chunk| body << chunk}
274
+
275
+ parser << "HTTP/1.0 200 OK\r\n"
276
+ parser << "QWEBS/1.0 (HP 3000)\r\n"
277
+ parser << "Content-Type: text/html\r\n\r\n"
278
+ parser << "<h1>Hello world</h1>"
279
+ parser.finish
280
+
281
+ assert_equal(200, code)
282
+ assert_equal("OK", message)
283
+ assert_equal({"Content-Type" => "text/html"}, headers)
284
+ assert_equal("<h1>Hello world</h1>", body)
285
+ assert(parser.finished?, "parser should be finished")
286
+ end
287
+
288
+ def test_skip_junk_headers_in_the_middle
289
+ parser = HTTPTools::Parser.new
290
+ code, message, headers = nil
291
+ body = ""
292
+
293
+ parser.add_listener(:header) do
294
+ code = parser.status_code
295
+ message = parser.message
296
+ headers = parser.header
297
+ end
298
+ parser.add_listener(:stream) {|chunk| body << chunk}
299
+
300
+ parser << "HTTP/1.1 200 OK\r\n"
301
+ parser << "Content-Length: 20\r\n"
302
+ parser << "random\t"
303
+ parser << "garbage\n"
304
+ parser << "Content-Type: text/html\r\n"
305
+ parser << "\r\n"
306
+ parser << "<h1>Hello world</h1>"
307
+
308
+ assert_equal(200, code)
309
+ assert_equal("OK", message)
310
+ assert_equal({"Content-Length" => "20", "Content-Type" => "text/html"}, headers)
311
+ assert_equal("<h1>Hello world</h1>", body)
312
+ assert(parser.finished?, "parser should be finished")
313
+ end
314
+
85
315
  def test_apple_dot_com
86
316
  parser = HTTPTools::Parser.new
87
317
  code, message, headers = nil
88
318
 
89
- parser.add_listener(:status) {|c, m| code, message = c, m}
90
- parser.add_listener(:headers) {|h| headers = h}
319
+ parser.add_listener(:header) do
320
+ code = parser.status_code
321
+ message = parser.message
322
+ headers = parser.header
323
+ end
91
324
 
92
325
  parser << "HTTP/1.1 200 OK\r\n"
93
326
  parser << "Server: Apache/2.2.11 (Unix)\r\n"
@@ -114,9 +347,12 @@ class ResponseTest < Test::Unit::TestCase
114
347
  code, message, headers = nil
115
348
  body = []
116
349
 
117
- parser.add_listener(:status) {|c, m| code, message = c, m}
118
- parser.add_listener(:headers) {|h| headers = h}
119
- parser.add_listener(:stream) {|b| body << b}
350
+ parser.add_listener(:header) do
351
+ code = parser.status_code
352
+ message = parser.message
353
+ headers = parser.header
354
+ end
355
+ parser.add_listener(:stream) {|chunk| body << chunk}
120
356
 
121
357
  parser << "HTTP/1.1 200 OK\r\n"
122
358
  parser << "Content-Length: 20\r\n"
@@ -133,11 +369,15 @@ class ResponseTest < Test::Unit::TestCase
133
369
 
134
370
  def test_body
135
371
  parser = HTTPTools::Parser.new
136
- code, message, headers, body = nil
372
+ code, message, headers = nil
373
+ body = ""
137
374
 
138
- parser.add_listener(:status) {|c, m| code, message = c, m}
139
- parser.add_listener(:headers) {|h| headers = h}
140
- parser.add_listener(:body) {|b| body = b}
375
+ parser.add_listener(:header) do
376
+ code = parser.status_code
377
+ message = parser.message
378
+ headers = parser.header
379
+ end
380
+ parser.add_listener(:stream) {|chunk| body << chunk}
141
381
 
142
382
  parser << "HTTP/1.1 200 OK\r\n"
143
383
  parser << "Content-Length: 20\r\n"
@@ -152,13 +392,67 @@ class ResponseTest < Test::Unit::TestCase
152
392
  assert(parser.finished?, "parser should be finished")
153
393
  end
154
394
 
155
- def test_sub_line_chunks
395
+ def test_zero_length_body
396
+ parser = HTTPTools::Parser.new
397
+ code, message, headers, body = nil
398
+ stream = []
399
+ body = ""
400
+
401
+ parser.add_listener(:header) do
402
+ code = parser.status_code
403
+ message = parser.message
404
+ headers = parser.header
405
+ end
406
+ parser.add_listener(:stream) {|chunk| body << chunk; stream.push(chunk)}
407
+
408
+ parser << "HTTP/1.1 302 Moved Temporarily\r\n"
409
+ parser << "Location: http://www.example.com/\r\n"
410
+ parser << "Content-Length: 0\r\n\r\n"
411
+
412
+ assert_equal(302, code)
413
+ assert_equal("Moved Temporarily", message)
414
+ assert_equal({"Location" => "http://www.example.com/", "Content-Length" => "0"}, headers)
415
+ assert_equal([""], stream)
416
+ assert_equal("", body)
417
+ assert(parser.finished?, "parser should be finished")
418
+ end
419
+
420
+ def test_zero_length_body_terminated_by_close
156
421
  parser = HTTPTools::Parser.new
157
422
  code, message, headers, body = nil
423
+ stream = []
424
+ body = ""
425
+
426
+ parser.add_listener(:header) do
427
+ code = parser.status_code
428
+ message = parser.message
429
+ headers = parser.header
430
+ end
431
+ parser.add_listener(:stream) {|chunk| body << chunk; stream.push(chunk)}
432
+
433
+ parser << "HTTP/1.1 302 Moved Temporarily\r\n"
434
+ parser << "Location: http://www.example.com/\r\n\r\n"
435
+ parser.finish # notify parser the connection has closed
436
+
437
+ assert_equal(302, code)
438
+ assert_equal("Moved Temporarily", message)
439
+ assert_equal({"Location" => "http://www.example.com/"}, headers)
440
+ assert_equal([""], stream)
441
+ assert_equal("", body)
442
+ assert(parser.finished?, "parser should be finished")
443
+ end
444
+
445
+ def test_sub_line_chunks
446
+ parser = HTTPTools::Parser.new
447
+ code, message, headers = nil
448
+ body = ""
158
449
 
159
- parser.add_listener(:status) {|c, m| code, message = c, m}
160
- parser.add_listener(:headers) {|h| headers = h}
161
- parser.add_listener(:body) {|b| body = b}
450
+ parser.add_listener(:header) do
451
+ code = parser.status_code
452
+ message = parser.message
453
+ headers = parser.header
454
+ end
455
+ parser.add_listener(:stream) {|chunk| body << chunk}
162
456
 
163
457
  parser << "HTTP/"
164
458
  parser << "1."
@@ -177,13 +471,60 @@ class ResponseTest < Test::Unit::TestCase
177
471
  assert(parser.finished?, "parser should be finished")
178
472
  end
179
473
 
474
+ def test_break_between_crlf
475
+ parser = HTTPTools::Parser.new
476
+ code, message, headers = nil
477
+ body = ""
478
+
479
+ parser.add_listener(:header) do
480
+ code = parser.status_code
481
+ message = parser.message
482
+ headers = parser.header
483
+ end
484
+ parser.add_listener(:stream) {|chunk| body << chunk}
485
+
486
+ parser << "HTTP/1.1 200 OK\r"
487
+ parser << "\nContent-Length: 20\r"
488
+ parser << "\n\r"
489
+ parser << "\n<h1>Hello world</h1>"
490
+
491
+ assert_equal(200, code)
492
+ assert_equal("OK", message)
493
+ assert_equal({"Content-Length" => "20"}, headers)
494
+ assert_equal("<h1>Hello world</h1>", body)
495
+ assert(parser.finished?, "parser should be finished")
496
+ end
497
+
498
+ def test_double_cr
499
+ parser = HTTPTools::Parser.new
500
+ headers = nil
501
+ body = ""
502
+
503
+ parser.add_listener(:header) {headers = parser.header}
504
+ parser.add_listener(:stream) {|chunk| body << chunk}
505
+
506
+ parser << "HTTP/1.1 200 OK\r\n"
507
+ parser << "Page-Completion-Status: Normal\r\r\n"
508
+ parser << "Content-Length: 20\r\n"
509
+ parser << "\r\n"
510
+ parser << "<h1>Hello world</h1>"
511
+
512
+ assert_equal({"Page-Completion-Status" => "Normal\r", "Content-Length" => "20"}, headers)
513
+ assert_equal("<h1>Hello world</h1>", body)
514
+ assert(parser.finished?, "parser should be finished")
515
+ end
516
+
180
517
  def test_body_with_key_terminator_like_value
181
518
  parser = HTTPTools::Parser.new
182
- code, message, headers, body = nil
519
+ code, message, headers = nil
520
+ body = ""
183
521
 
184
- parser.add_listener(:status) {|c, m| code, message = c, m}
185
- parser.add_listener(:headers) {|h| headers = h}
186
- parser.add_listener(:body) {|b| body = b}
522
+ parser.add_listener(:header) do
523
+ code = parser.status_code
524
+ message = parser.message
525
+ headers = parser.header
526
+ end
527
+ parser.add_listener(:stream) {|chunk| body << chunk}
187
528
 
188
529
  parser << "HTTP/1.1 200 OK\r\n"
189
530
  parser << "Content-Length: 21\r\n"
@@ -198,11 +539,15 @@ class ResponseTest < Test::Unit::TestCase
198
539
 
199
540
  def test_lazy_server
200
541
  parser = HTTPTools::Parser.new
201
- code, message, headers, body = nil
542
+ code, message, headers = nil
543
+ body = ""
202
544
 
203
- parser.add_listener(:status) {|c, m| code, message = c, m}
204
- parser.add_listener(:headers) {|h| headers = h}
205
- parser.add_listener(:body) {|b| body = b}
545
+ parser.add_listener(:header) do
546
+ code = parser.status_code
547
+ message = parser.message
548
+ headers = parser.header
549
+ end
550
+ parser.add_listener(:stream) {|chunk| body << chunk}
206
551
 
207
552
  parser << "HTTP/1.1 200 OK\n"
208
553
  parser << "Content-Type: text/html; charset=utf-8\n"
@@ -219,11 +564,15 @@ class ResponseTest < Test::Unit::TestCase
219
564
 
220
565
  def test_chunked
221
566
  parser = HTTPTools::Parser.new
222
- code, message, headers, body = nil
567
+ code, message, headers = nil
568
+ body = ""
223
569
 
224
- parser.add_listener(:status) {|c, m| code, message = c, m}
225
- parser.add_listener(:headers) {|h| headers = h}
226
- parser.add_listener(:body) {|b| body = b}
570
+ parser.add_listener(:header) do
571
+ code = parser.status_code
572
+ message = parser.message
573
+ headers = parser.header
574
+ end
575
+ parser.add_listener(:stream) {|chunk| body << chunk}
227
576
 
228
577
  parser << "HTTP/1.1 200 OK\r\n"
229
578
  parser << "Transfer-Encoding: chunked\r\n"
@@ -244,9 +593,12 @@ class ResponseTest < Test::Unit::TestCase
244
593
  code, message, headers = nil
245
594
  body = []
246
595
 
247
- parser.add_listener(:status) {|c, m| code, message = c, m}
248
- parser.add_listener(:headers) {|h| headers = h}
249
- parser.add_listener(:stream) {|b| body << b}
596
+ parser.add_listener(:header) do
597
+ code = parser.status_code
598
+ message = parser.message
599
+ headers = parser.header
600
+ end
601
+ parser.add_listener(:stream) {|chunk| body << chunk}
250
602
 
251
603
  parser << "HTTP/1.1 200 OK\r\n"
252
604
  parser << "Transfer-Encoding: chunked\r\n"
@@ -267,9 +619,12 @@ class ResponseTest < Test::Unit::TestCase
267
619
  code, message, headers = nil
268
620
  body = []
269
621
 
270
- parser.add_listener(:status) {|c, m| code, message = c, m}
271
- parser.add_listener(:headers) {|h| headers = h}
272
- parser.add_listener(:stream) {|b| body << b}
622
+ parser.add_listener(:header) do
623
+ code = parser.status_code
624
+ message = parser.message
625
+ headers = parser.header
626
+ end
627
+ parser.add_listener(:stream) {|chunk| body << chunk}
273
628
 
274
629
  parser << "HTTP/1.1 200 OK\r\n"
275
630
  parser << "Transfer-Encoding: chunked\r\n"
@@ -285,13 +640,82 @@ class ResponseTest < Test::Unit::TestCase
285
640
  assert(parser.finished?, "parser should be finished")
286
641
  end
287
642
 
643
+ # shouldn't really be allowed, but IIS can't do chunked encoding properly
644
+ def test_chunked_terminated_by_close
645
+ parser = HTTPTools::Parser.new
646
+ code, message, headers = nil
647
+ body = []
648
+
649
+ parser.add_listener(:header) do
650
+ code = parser.status_code
651
+ message = parser.message
652
+ headers = parser.header
653
+ end
654
+ parser.add_listener(:stream) {|chunk| body << chunk}
655
+
656
+ parser << "HTTP/1.1 200 OK\r\n"
657
+ parser << "Connection: close\r\n"
658
+ parser << "Transfer-Encoding: chunked\r\n"
659
+ parser << "\r\n"
660
+ parser << "9\r\n<h1>Hello\r\n"
661
+ parser << "b\r\n world</h1>\r\n"
662
+ parser.finish # notify parser the connection has closed
663
+
664
+ assert_equal(200, code)
665
+ assert_equal("OK", message)
666
+ assert_equal({
667
+ "Transfer-Encoding" => "chunked",
668
+ "Connection" => "close"}, headers)
669
+ assert_equal(["<h1>Hello", " world</h1>"], body)
670
+ assert(parser.finished?, "parser should be finished")
671
+ end
672
+
673
+ def test_html_body_only_not_allowed
674
+ parser = HTTPTools::Parser.new
675
+
676
+ assert_raise(HTTPTools::ParseError) do
677
+ parser << "<html><p>HTTP is hard</p></html>"
678
+ end
679
+ end
680
+
681
+ def test_html_body_only_allowed
682
+ parser = HTTPTools::Parser.new
683
+ version, code, message, headers = nil
684
+ body = ""
685
+
686
+ parser.allow_html_without_header = true
687
+
688
+ parser.add_listener(:header) do
689
+ version = parser.version
690
+ code = parser.status_code
691
+ message = parser.message
692
+ headers = parser.header
693
+ end
694
+ parser.add_listener(:stream) {|chunk| body << chunk}
695
+
696
+ parser << "<html><p>HTTP is hard</p></html>"
697
+ parser.finish
698
+
699
+ assert_equal("0.0", version)
700
+ assert_equal(200, code)
701
+ assert_equal("", message)
702
+ assert_equal({}, headers)
703
+ assert_equal("<html><p>HTTP is hard</p></html>", body)
704
+ assert(parser.finished?, "parser should be finished")
705
+ end
706
+
288
707
  def test_finished
289
708
  parser = HTTPTools::Parser.new
290
- code, message, body, remainder = nil
709
+ code, message, remainder = nil
710
+ body = ""
291
711
 
292
- parser.add_listener(:status) {|c, m| code, message = c, m}
293
- parser.add_listener(:body) {|b| body = b}
294
- parser.add_listener(:finished) {|r| remainder = r}
712
+ parser.add_listener(:header) do
713
+ code = parser.status_code
714
+ message = parser.message
715
+ headers = parser.header
716
+ end
717
+ parser.add_listener(:stream) {|chunk| body << chunk}
718
+ parser.add_listener(:finish) {|r| remainder = r}
295
719
 
296
720
  parser << "HTTP/1.1 200 OK\r\nContent-Length: 20\r\n\r\n"
297
721
  parser << "<h1>Hello world</h1>HTTP/1.1 404 Not Found\r\n"
@@ -305,11 +729,16 @@ class ResponseTest < Test::Unit::TestCase
305
729
 
306
730
  def test_finished_chunked
307
731
  parser = HTTPTools::Parser.new
308
- code, message, body, remainder = nil
732
+ code, message, remainder = nil
733
+ body = ""
309
734
 
310
- parser.add_listener(:status) {|c, m| code, message = c, m}
311
- parser.add_listener(:body) {|b| body = b}
312
- parser.add_listener(:finished) {|r| remainder = r}
735
+ parser.add_listener(:header) do
736
+ code = parser.status_code
737
+ message = parser.message
738
+ headers = parser.header
739
+ end
740
+ parser.add_listener(:stream) {|chunk| body << chunk}
741
+ parser.add_listener(:finish) {|r| remainder = r}
313
742
 
314
743
  parser << "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
315
744
  parser << "14\r\n<h1>Hello world</h1>\r\n0\r\nHTTP/1.1 404 Not Found\r\n"
@@ -325,7 +754,7 @@ class ResponseTest < Test::Unit::TestCase
325
754
  parser = HTTPTools::Parser.new
326
755
  trailer = nil
327
756
 
328
- parser.add_listener(:trailer) {|t| trailer = t}
757
+ parser.add_listener(:trailer) {trailer = parser.trailer}
329
758
 
330
759
  parser << "HTTP/1.1 200 OK\r\n"
331
760
  parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
@@ -340,7 +769,7 @@ class ResponseTest < Test::Unit::TestCase
340
769
  parser = HTTPTools::Parser.new
341
770
  trailer = nil
342
771
 
343
- parser.add_listener(:trailer) {|t| trailer = t}
772
+ parser.add_listener(:trailer) {trailer = parser.trailer}
344
773
 
345
774
  parser << "HTTP/1.1 200 OK\r\n"
346
775
  parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
@@ -356,7 +785,7 @@ class ResponseTest < Test::Unit::TestCase
356
785
  parser = HTTPTools::Parser.new
357
786
  trailer = nil
358
787
 
359
- parser.add_listener(:trailer) {|t| trailer = t}
788
+ parser.add_listener(:trailer) {trailer = parser.trailer}
360
789
 
361
790
  parser.force_trailer = true
362
791
 
@@ -369,6 +798,39 @@ class ResponseTest < Test::Unit::TestCase
369
798
  assert(parser.finished?, "parser should be finished")
370
799
  end
371
800
 
801
+ def test_messed_up_iis_header_style_trailer_1
802
+ parser = HTTPTools::Parser.new
803
+ trailer = nil
804
+
805
+ parser.add_listener(:trailer) {trailer = parser.trailer}
806
+
807
+ parser << "HTTP/1.1 200 OK\r\n"
808
+ parser << "Server: Microsoft-IIS/6.0\r\n"
809
+ parser << "Transfer-Encoding: chunked\r\nTrailer: Server::\r\n\r\n"
810
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
811
+ parser << "Server:: Harris Associates L.P.\r\n"
812
+ parser << "\r\n"
813
+
814
+ assert_equal({"Server" => ": Harris Associates L.P."}, trailer)
815
+ assert(parser.finished?, "parser should be finished")
816
+ end
817
+
818
+ def test_messed_up_iis_header_style_trailer_2
819
+ parser = HTTPTools::Parser.new
820
+ trailer = nil
821
+
822
+ parser.add_listener(:trailer) {trailer = parser.trailer}
823
+
824
+ parser << "HTTP/1.1 200 OK\r\n"
825
+ parser << "Transfer-Encoding: chunked\r\nTrailer: Server::\r\n\r\n"
826
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
827
+ parser << "X-DIP:202\r\n"
828
+ parser << "\r\n"
829
+
830
+ assert_equal({"X-DIP" => "202"}, trailer)
831
+ assert(parser.finished?, "parser should be finished")
832
+ end
833
+
372
834
  def test_error_on_unallowed_trailer
373
835
  parser = HTTPTools::Parser.new
374
836
 
@@ -397,14 +859,14 @@ class ResponseTest < Test::Unit::TestCase
397
859
  parser = HTTPTools::Parser.new
398
860
  trailer = nil
399
861
 
400
- parser.add_listener(:trailer) {|t| trailer = t}
862
+ parser.add_listener(:trailer) {trailer = parser.trailer}
401
863
 
402
864
  parser << "HTTP/1.1 200 OK\r\n"
403
865
  parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
404
866
  parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
405
867
 
406
868
  assert_raise(HTTPTools::ParseError) do
407
- parser << "x-invalid key: value\r\n\r\n"
869
+ parser << "x-invalid\0key: value\r\n\r\n"
408
870
  end
409
871
  end
410
872
 
@@ -412,7 +874,7 @@ class ResponseTest < Test::Unit::TestCase
412
874
  parser = HTTPTools::Parser.new
413
875
  trailer = nil
414
876
 
415
- parser.add_listener(:trailer) {|t| trailer = t}
877
+ parser.add_listener(:trailer) {trailer = parser.trailer}
416
878
 
417
879
  parser << "HTTP/1.1 200 OK\r\n"
418
880
  parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
@@ -443,4 +905,10 @@ class ResponseTest < Test::Unit::TestCase
443
905
  assert_raise(HTTPTools::MessageIncompleteError) {parser.finish}
444
906
  end
445
907
 
908
+ def test_empty
909
+ parser = HTTPTools::Parser.new
910
+
911
+ assert_raise(HTTPTools::EmptyMessageError) {parser.finish}
912
+ end
913
+
446
914
  end