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.
@@ -119,6 +119,28 @@ class TransferEncodingChunkedTest < Test::Unit::TestCase
119
119
  assert_equal("14\r\n<h1>Hello world</h1>\r\n0\r\n", encoded)
120
120
  end
121
121
 
122
+ def test_decode_with_space_after_chunk_length
123
+ # some servers mistakenly put a space after the chunk length
124
+ encoded = "14 \r\n<h1>Hello world</h1>\r\n0\r\n"
125
+ decoded = HTTPTools::Encoding.transfer_encoding_chunked_decode(encoded)
126
+
127
+ assert_equal(["<h1>Hello world</h1>", nil], decoded)
128
+ end
129
+
130
+ def test_decode_lots_of_tiny_chunks
131
+ encoded = "1\r\na\r\n" * 10000 + "0\r\n"
132
+ decoded = HTTPTools::Encoding.transfer_encoding_chunked_decode(encoded)
133
+
134
+ assert_equal(["a" * 10000, nil], decoded)
135
+ end
136
+
137
+ def test_decode_break_between_cr_lf
138
+ encoded = "14\r\n<h1>Hello world</h1>\r"
139
+ decoded = HTTPTools::Encoding.transfer_encoding_chunked_decode(encoded)
140
+
141
+ assert_equal([nil, "14\r\n<h1>Hello world</h1>\r"], decoded)
142
+ end
143
+
122
144
  def test_encode
123
145
  encoded = HTTPTools::Encoding.transfer_encoding_chunked_encode("foo")
124
146
 
@@ -8,11 +8,11 @@ class RequestTest < Test::Unit::TestCase
8
8
  parser = HTTPTools::Parser.new
9
9
  result = nil
10
10
 
11
- parser.add_listener(:method) do |method|
12
- result = method
11
+ parser.add_listener(:header) do
12
+ result = parser.request_method
13
13
  end
14
14
 
15
- parser << "GET / HTTP/1.1\r\n"
15
+ parser << "GET / HTTP/1.1\r\n\r\n"
16
16
 
17
17
  assert_equal("GET", result)
18
18
  end
@@ -21,52 +21,52 @@ class RequestTest < Test::Unit::TestCase
21
21
  parser = HTTPTools::Parser.new
22
22
  result = nil
23
23
 
24
- parser.add_listener(:method) do |method|
25
- result = method
24
+ parser.add_listener(:header) do
25
+ result = parser.request_method
26
26
  end
27
27
 
28
- parser << "POST / HTTP/1.1\r\n"
28
+ parser << "POST / HTTP/1.1\r\n\r\n"
29
29
 
30
30
  assert_equal("POST", result)
31
31
  end
32
32
 
33
33
  def test_empty_path
34
34
  parser = HTTPTools::Parser.new
35
- result = nil
35
+ path, query = nil
36
36
 
37
- parser.add_listener(:path) do |path, query|
38
- result = path
37
+ parser.add_listener(:header) do
38
+ path, query = parser.path_info, parser.query_string
39
39
  end
40
40
 
41
- parser << "GET / HTTP/1.1\r\n"
41
+ parser << "GET / HTTP/1.1\r\n\r\n"
42
42
 
43
- assert_equal("/", result)
43
+ assert_equal("/", path)
44
+ assert_equal("", query)
44
45
  end
45
46
 
46
47
  def test_basic_path
47
48
  parser = HTTPTools::Parser.new
48
- result = nil
49
+ path, query = nil
49
50
 
50
- parser.add_listener(:path) do |path, query|
51
- result = path
51
+ parser.add_listener(:header) do
52
+ path, query = parser.path_info, parser.query_string
52
53
  end
53
54
 
54
- parser << "GET /foo HTTP/1.1\r\n"
55
+ parser << "GET /foo HTTP/1.1\r\n\r\n"
55
56
 
56
- assert_equal("/foo", result)
57
+ assert_equal("/foo", path)
58
+ assert_equal("", query)
57
59
  end
58
60
 
59
61
  def test_complicated_path
60
62
  parser = HTTPTools::Parser.new
61
- path = nil
62
- query = nil
63
+ path, query = nil
63
64
 
64
- parser.add_listener(:path) do |p, q|
65
- path = p
66
- query = q
65
+ parser.add_listener(:header) do
66
+ path, query = parser.path_info, parser.query_string
67
67
  end
68
68
 
69
- parser << "GET /foo%20bar/baz.html?key=value#qux HTTP/1.1\r\n"
69
+ parser << "GET /foo%20bar/baz.html?key=value#qux HTTP/1.1\r\n\r\n"
70
70
 
71
71
  assert_equal("/foo%20bar/baz.html", path)
72
72
  assert_equal("key=value", query)
@@ -76,7 +76,7 @@ class RequestTest < Test::Unit::TestCase
76
76
  parser = HTTPTools::Parser.new
77
77
 
78
78
  assert_raise(HTTPTools::ParseError) do
79
- parser << "GET \\ HTTP/1.1\r\n"
79
+ parser << "GET \\ HTTP/1.1\r\n\r\n"
80
80
  end
81
81
  end
82
82
 
@@ -84,11 +84,11 @@ class RequestTest < Test::Unit::TestCase
84
84
  parser = HTTPTools::Parser.new
85
85
  result = nil
86
86
 
87
- parser.add_listener(:uri) do |uri|
88
- result = uri
87
+ parser.add_listener(:header) do
88
+ result = parser.request_uri
89
89
  end
90
90
 
91
- parser << "GET http://example.com/foo HTTP/1.1\r\n"
91
+ parser << "GET http://example.com/foo HTTP/1.1\r\n\r\n"
92
92
 
93
93
  assert_equal("http://example.com/foo", result)
94
94
  end
@@ -97,11 +97,11 @@ class RequestTest < Test::Unit::TestCase
97
97
  parser = HTTPTools::Parser.new
98
98
  result = nil
99
99
 
100
- parser.add_listener(:path) do |path, query|
101
- result = path
100
+ parser.add_listener(:header) do
101
+ result = parser.path_info
102
102
  end
103
103
 
104
- parser << "GET http://example.com/foo HTTP/1.1\r\n"
104
+ parser << "GET http://example.com/foo HTTP/1.1\r\n\r\n"
105
105
 
106
106
  assert_nil(result)
107
107
  end
@@ -112,13 +112,13 @@ class RequestTest < Test::Unit::TestCase
112
112
  path = nil
113
113
  query = nil
114
114
 
115
- parser.add_listener(:uri) {|u| uri = u}
116
- parser.add_listener(:path) do |p, q|
117
- path = p
118
- query = q
115
+ parser.add_listener(:header) do
116
+ uri = parser.request_uri
117
+ path = parser.path_info
118
+ query = parser.query_string
119
119
  end
120
120
 
121
- parser << "GET /foo/bar.html?key=value HTTP/1.1\r\n"
121
+ parser << "GET /foo/bar.html?key=value HTTP/1.1\r\n\r\n"
122
122
 
123
123
  assert_equal("/foo/bar.html?key=value", uri)
124
124
  assert_equal("/foo/bar.html", path)
@@ -130,10 +130,12 @@ class RequestTest < Test::Unit::TestCase
130
130
  path = nil
131
131
  fragment = nil
132
132
 
133
- parser.add_listener(:path) {|p, q| path = p}
134
- parser.add_listener(:fragment) {|f| fragment = f}
133
+ parser.add_listener(:header) do
134
+ path = parser.path_info
135
+ fragment = parser.fragment
136
+ end
135
137
 
136
- parser << "GET /foo#bar HTTP/1.1\r\n"
138
+ parser << "GET /foo#bar HTTP/1.1\r\n\r\n"
137
139
 
138
140
  assert_equal("/foo", path)
139
141
  assert_equal("bar", fragment)
@@ -144,10 +146,12 @@ class RequestTest < Test::Unit::TestCase
144
146
  uri = nil
145
147
  fragment = nil
146
148
 
147
- parser.add_listener(:uri) {|u| uri = u}
148
- parser.add_listener(:fragment) {|f| fragment = f}
149
+ parser.add_listener(:header) do
150
+ uri = parser.request_uri
151
+ fragment = parser.fragment
152
+ end
149
153
 
150
- parser << "GET http://example.com/foo#bar HTTP/1.1\r\n"
154
+ parser << "GET http://example.com/foo#bar HTTP/1.1\r\n\r\n"
151
155
 
152
156
  assert_equal("http://example.com/foo", uri)
153
157
  assert_equal("bar", fragment)
@@ -159,9 +163,11 @@ class RequestTest < Test::Unit::TestCase
159
163
  path = nil
160
164
  headers = nil
161
165
 
162
- parser.add_listener(:method) {|m| method = m}
163
- parser.add_listener(:path) {|p, q| path = p}
164
- parser.add_listener(:headers) {|h| headers = h}
166
+ parser.add_listener(:header) do
167
+ method = parser.request_method
168
+ path = parser.path_info
169
+ headers = parser.header
170
+ end
165
171
 
166
172
  parser << "GET / HTTP/1.1\r\n"
167
173
  parser << "Host: www.example.com\r\n"
@@ -178,9 +184,11 @@ class RequestTest < Test::Unit::TestCase
178
184
  path = nil
179
185
  headers = nil
180
186
 
181
- parser.add_listener(:method) {|m| method = m}
182
- parser.add_listener(:path) {|p, q| path = p}
183
- parser.add_listener(:headers) {|h| headers = h}
187
+ parser.add_listener(:header) do
188
+ method = parser.request_method
189
+ path = parser.path_info
190
+ headers = parser.header
191
+ end
184
192
 
185
193
  parser << "GET / HTTP/1.1\r\n"
186
194
  parser << "Host: www.example.com\r\n"
@@ -198,9 +206,11 @@ class RequestTest < Test::Unit::TestCase
198
206
  path = nil
199
207
  headers = nil
200
208
 
201
- parser.add_listener(:method) {|m| method = m}
202
- parser.add_listener(:path) {|p, q| path = p}
203
- parser.add_listener(:headers) {|h| headers = h}
209
+ parser.add_listener(:header) do
210
+ method = parser.request_method
211
+ path = parser.path_info
212
+ headers = parser.header
213
+ end
204
214
 
205
215
  parser << "GE"
206
216
  parser << "T /foo/"
@@ -222,9 +232,11 @@ class RequestTest < Test::Unit::TestCase
222
232
  path = nil
223
233
  headers = nil
224
234
 
225
- parser.add_listener(:method) {|m| method = m}
226
- parser.add_listener(:path) {|p, q| path = p}
227
- parser.add_listener(:headers) {|h| headers = h}
235
+ parser.add_listener(:header) do
236
+ method = parser.request_method
237
+ path = parser.path_info
238
+ headers = parser.header
239
+ end
228
240
 
229
241
  parser << "POST"
230
242
  parser << " /bar/foo"
@@ -250,9 +262,11 @@ class RequestTest < Test::Unit::TestCase
250
262
  path = nil
251
263
  headers = nil
252
264
 
253
- parser.add_listener(:method) {|m| method = m}
254
- parser.add_listener(:path) {|p, q| path = p}
255
- parser.add_listener(:headers) {|h| headers = h}
265
+ parser.add_listener(:header) do
266
+ method = parser.request_method
267
+ path = parser.path_info
268
+ headers = parser.header
269
+ end
256
270
 
257
271
  request = "GET /foo/bar HTTP/1.1\r\n"
258
272
  request << "Host: www.example.com\r\nAccept: text/plain\r\n\r\n"
@@ -268,9 +282,9 @@ class RequestTest < Test::Unit::TestCase
268
282
  parser = HTTPTools::Parser.new
269
283
  method = nil
270
284
 
271
- parser.add_listener(:method) {|m| method = m}
285
+ parser.add_listener(:header) {method = parser.request_method}
272
286
 
273
- parser << "UNICORNS / HTTP/1.1\r\n"
287
+ parser << "UNICORNS / HTTP/1.1\r\n\r\n"
274
288
 
275
289
  assert_equal("UNICORNS", method)
276
290
  end
@@ -281,9 +295,11 @@ class RequestTest < Test::Unit::TestCase
281
295
  path = nil
282
296
  headers = nil
283
297
 
284
- parser.add_listener(:method) {|m| method = m}
285
- parser.add_listener(:path) {|p, q| path = p}
286
- parser.add_listener(:headers) {|h| headers = h}
298
+ parser.add_listener(:header) do
299
+ method = parser.request_method
300
+ path = parser.path_info
301
+ headers = parser.header
302
+ end
287
303
 
288
304
  parser << "GET /\r\nHost: www.example.com\r\n\r\n"
289
305
 
@@ -302,9 +318,9 @@ class RequestTest < Test::Unit::TestCase
302
318
  parser = HTTPTools::Parser.new
303
319
  version = nil
304
320
 
305
- parser.add_listener(:version) {|v| version = v}
321
+ parser.add_listener(:header) {version = parser.version}
306
322
 
307
- parser << "GET / HTTP/1.1\r\n"
323
+ parser << "GET / HTTP/1.1\r\n\r\n"
308
324
 
309
325
  assert_equal("1.1", version)
310
326
  end
@@ -312,21 +328,33 @@ class RequestTest < Test::Unit::TestCase
312
328
  def test_protocol_without_version
313
329
  parser = HTTPTools::Parser.new
314
330
 
315
- assert_raise(HTTPTools::ParseError) {parser << "GET / HTTP\r\n"}
331
+ assert_raise(HTTPTools::ParseError) {parser << "GET / HTTP\r\n\r\n"}
332
+ end
333
+
334
+ def test_one_dot_x_protocol_version
335
+ parser = HTTPTools::Parser.new
336
+ version = nil
337
+
338
+ parser.add_listener(:header) {version = parser.version}
339
+
340
+ parser << "GET / HTTP/1.x\r\n\r\n"
341
+
342
+ assert_equal("1.x", version)
316
343
  end
317
344
 
318
345
  def test_reset
319
346
  parser = HTTPTools::Parser.new
320
347
  method = nil
321
- method_calls = 0
322
348
  path = nil
323
- path_calls = 0
324
349
  headers = nil
325
- header_calls = 0
350
+ calls = 0
326
351
 
327
- parser.add_listener(:method) {|m| method = m; method_calls += 1}
328
- parser.add_listener(:path) {|p, q| path = p; path_calls += 1}
329
- parser.add_listener(:headers) {|h| headers = h; header_calls += 1}
352
+ parser.add_listener(:header) do
353
+ method = parser.request_method
354
+ path = parser.path_info
355
+ headers = parser.header
356
+ calls += 1
357
+ end
330
358
 
331
359
  parser << "GET / HTTP/1.1\r\n"
332
360
  parser << "Host: www.example.com\r\n"
@@ -336,7 +364,7 @@ class RequestTest < Test::Unit::TestCase
336
364
  assert_equal("GET", method)
337
365
  assert_equal("/", path)
338
366
  assert_equal({"Host"=>"www.example.com", "Accept"=>"text/plain"}, headers)
339
- assert_equal([1, 1, 1], [method_calls, path_calls, header_calls])
367
+ assert_equal(1, calls)
340
368
 
341
369
  parser.reset
342
370
 
@@ -348,7 +376,7 @@ class RequestTest < Test::Unit::TestCase
348
376
  assert_equal("POST", method)
349
377
  assert_equal("/example", path)
350
378
  assert_equal({"Host"=>"www.test.co.uk", "Accept"=>"text/html"}, headers)
351
- assert_equal([2, 2, 2], [method_calls, path_calls, header_calls])
379
+ assert_equal(2, calls)
352
380
  end
353
381
 
354
382
  def test_not_a_http_request
@@ -371,11 +399,11 @@ class RequestTest < Test::Unit::TestCase
371
399
  parser = HTTPTools::Parser.new
372
400
  result = nil
373
401
 
374
- parser.add_listener(:method) do |method|
375
- result = method
402
+ parser.add_listener(:header) do
403
+ result = parser.request_method
376
404
  end
377
405
 
378
- parser << "get / HTTP/1.1\r\n"
406
+ parser << "get / HTTP/1.1\r\n\r\n"
379
407
 
380
408
  assert_equal("GET", result)
381
409
  end
@@ -384,67 +412,19 @@ class RequestTest < Test::Unit::TestCase
384
412
  parser = HTTPTools::Parser.new
385
413
  version = nil
386
414
 
387
- parser.add_listener(:version) {|v| version = v}
415
+ parser.add_listener(:header) {version = parser.version}
388
416
 
389
- parser << "GET / http/1.1\r\n"
417
+ parser << "GET / http/1.1\r\n\r\n"
390
418
 
391
419
  assert_equal("1.1", version)
392
420
  end
393
421
 
394
- def test_delegate
395
- request_class = Class.new
396
- request_class.class_eval do
397
- attr_reader :http_method, :path, :headers, :body
398
- def on_method(name)
399
- @http_method = name
400
- end
401
- def on_path(path, query)
402
- @path = path
403
- @query = query
404
- end
405
- def on_headers(headers)
406
- @headers = headers
407
- end
408
- def on_body(body)
409
- @body = body
410
- end
411
- end
412
- request = request_class.new
413
-
414
- parser = HTTPTools::Parser.new(request)
415
- parser << "POST /test HTTP/1.1\r\n"
416
- parser << "Content-Length: 13\r\n"
417
- parser << "\r\n"
418
- parser << "query=example"
419
-
420
- assert_equal("POST", request.http_method)
421
- assert_equal("/test", request.path)
422
- assert_equal({"Content-Length" => "13"}, request.headers)
423
- assert_equal("query=example", request.body)
424
- end
425
-
426
422
  def test_invalid_version
427
423
  parser = HTTPTools::Parser.new
428
424
 
429
425
  assert_raise(HTTPTools::ParseError) {parser << "GET / HTTP/one dot one\r\n"}
430
426
  end
431
427
 
432
- def test_invalid_header_key_with_space
433
- parser = HTTPTools::Parser.new
434
-
435
- assert_raise(HTTPTools::ParseError) do
436
- parser << "GET / HTTP/1.1\r\nx-invalid key: text/plain\r\n"
437
- end
438
- end
439
-
440
- def test_invalid_header_key_with_colon
441
- parser = HTTPTools::Parser.new
442
-
443
- assert_raise(HTTPTools::ParseError) do
444
- parser << "GET / HTTP/1.1\r\nx-invalid:key: text/plain\r\n"
445
- end
446
- end
447
-
448
428
  def test_invalid_header_key_with_control_character
449
429
  parser = HTTPTools::Parser.new
450
430
 
@@ -457,7 +437,7 @@ class RequestTest < Test::Unit::TestCase
457
437
  parser = HTTPTools::Parser.new
458
438
 
459
439
  assert_raise(HTTPTools::ParseError) do
460
- parser << "GET / HTTP/1.1\r\nx-invalid-kéy: text/plain\r\n"
440
+ parser << "GET / HTTP/1.1\r\nx-invalid\000key: text/plain\r\n"
461
441
  end
462
442
  end
463
443
 
@@ -465,7 +445,7 @@ class RequestTest < Test::Unit::TestCase
465
445
  parser = HTTPTools::Parser.new
466
446
 
467
447
  assert_raise(HTTPTools::ParseError) do
468
- parser << "GET / HTTP/1.1\r\nAccept: téxt/plain\r\n"
448
+ parser << "GET / HTTP/1.1\r\nAccept: \000text/plain\r\n"
469
449
  end
470
450
  end
471
451
 
@@ -478,4 +458,67 @@ class RequestTest < Test::Unit::TestCase
478
458
  assert_instance_of(HTTPTools::ParseError, error)
479
459
  end
480
460
 
461
+ def test_env
462
+ parser = HTTPTools::Parser.new
463
+ env = nil
464
+ parser.on(:header) {env = parser.env}
465
+
466
+ parser << "GET /test?q=foo HTTP/1.1\r\n"
467
+ parser << "Host: www.example.com\r\n"
468
+ parser << "Accept: text/html\r\n"
469
+ parser << "\r\n"
470
+
471
+ assert_equal("GET", env["REQUEST_METHOD"])
472
+ assert_equal("", env["SCRIPT_NAME"])
473
+ assert_equal("/test", env["PATH_INFO"])
474
+ assert_equal("q=foo", env["QUERY_STRING"])
475
+ assert_equal(nil, env["SERVER_NAME"])
476
+ assert_equal(nil, env["SERVER_PORT"])
477
+ assert_equal("www.example.com", env["HTTP_HOST"])
478
+ assert_equal("text/html", env["HTTP_ACCEPT"])
479
+
480
+ assert_equal([1,1], env["rack.version"])
481
+ assert_equal("http", env["rack.url_scheme"])
482
+ assert_equal(nil, env["rack.input"])
483
+ assert_equal(STDERR, env["rack.errors"])
484
+ assert_equal(false, env["rack.multithread"])
485
+ assert_equal(false, env["rack.multiprocess"])
486
+ assert_equal(false, env["rack.run_once"])
487
+ end
488
+
489
+ def test_env_with_trailer
490
+ parser = HTTPTools::Parser.new
491
+ env = nil
492
+ parser.on(:finish) {env = parser.env}
493
+
494
+ parser << "POST /submit HTTP/1.1\r\n"
495
+ parser << "Host: www.example.com\r\n"
496
+ parser << "Transfer-Encoding: chunked\r\n"
497
+ parser << "Trailer: X-Checksum\r\n"
498
+ parser << "\r\n"
499
+ parser << "5\r\nHello\r\n"
500
+ parser << "6\r\n world\r\n0\r\n"
501
+ parser << "X-Checksum: 3e25960a79dbc69b674cd4ec67a72c62\r\n"
502
+ parser << "\r\n"
503
+
504
+ assert_equal("POST", env["REQUEST_METHOD"])
505
+ assert_equal("", env["SCRIPT_NAME"])
506
+ assert_equal("/submit", env["PATH_INFO"])
507
+ assert_equal("", env["QUERY_STRING"])
508
+ assert_equal(nil, env["SERVER_NAME"])
509
+ assert_equal(nil, env["SERVER_PORT"])
510
+ assert_equal("www.example.com", env["HTTP_HOST"])
511
+ assert_equal("chunked", env["HTTP_TRANSFER_ENCODING"])
512
+ assert_equal("X-Checksum", env["HTTP_TRAILER"])
513
+ assert_equal("3e25960a79dbc69b674cd4ec67a72c62", env["HTTP_X_CHECKSUM"])
514
+
515
+ assert_equal([1,1], env["rack.version"])
516
+ assert_equal("http", env["rack.url_scheme"])
517
+ assert_equal(nil, env["rack.input"])
518
+ assert_equal(STDERR, env["rack.errors"])
519
+ assert_equal(false, env["rack.multithread"])
520
+ assert_equal(false, env["rack.multiprocess"])
521
+ assert_equal(false, env["rack.run_once"])
522
+ end
523
+
481
524
  end