http_tools 0.1.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.
@@ -0,0 +1,446 @@
1
+ base = File.expand_path(File.dirname(__FILE__) + '/../../lib')
2
+ require base + '/http_tools'
3
+ require 'test/unit'
4
+
5
+ class ResponseTest < Test::Unit::TestCase
6
+
7
+ def test_version
8
+ parser = HTTPTools::Parser.new
9
+ version = nil
10
+
11
+ parser.add_listener(:version) {|v| version = v}
12
+
13
+ parser << "HTTP/1.1 "
14
+
15
+ assert_equal("1.1", version)
16
+ end
17
+
18
+ def test_ok
19
+ parser = HTTPTools::Parser.new
20
+ code, message = nil
21
+
22
+ parser.add_listener(:status) {|c, m| code, message = c, m}
23
+
24
+ parser << "HTTP/1.1 200 OK\r\n\r\n"
25
+
26
+ assert_equal(200, code)
27
+ assert_equal("OK", message)
28
+ assert(!parser.finished?, "parser should not be finished")
29
+ end
30
+
31
+ def test_not_found
32
+ parser = HTTPTools::Parser.new
33
+ code, message = nil
34
+
35
+ parser.add_listener(:status) {|c, m| code, message = c, m}
36
+
37
+ parser << "HTTP/1.1 404 Not Found\r\n\r\n"
38
+
39
+ assert_equal(404, code)
40
+ assert_equal("Not Found", message)
41
+ assert(!parser.finished?, "parser should not be finished")
42
+ end
43
+
44
+ def test_no_content
45
+ parser = HTTPTools::Parser.new
46
+ code, message = nil
47
+
48
+ parser.add_listener(:status) {|c, m| code, message = c, m}
49
+
50
+ parser << "HTTP/1.1 204 No Content\r\n\r\n"
51
+
52
+ assert_equal(204, code)
53
+ assert_equal("No Content", message)
54
+ assert(parser.finished?, "parser should be finished")
55
+ end
56
+
57
+ def test_not_modified
58
+ parser = HTTPTools::Parser.new
59
+ code, message = nil
60
+
61
+ parser.add_listener(:status) {|c, m| code, message = c, m}
62
+
63
+ parser << "HTTP/1.1 304 Not Modified\r\n\r\n"
64
+
65
+ assert_equal(304, code)
66
+ assert_equal("Not Modified", message)
67
+ assert(parser.finished?, "parser should be finished")
68
+ end
69
+
70
+ def test_force_no_body
71
+ parser = HTTPTools::Parser.new
72
+ parser.force_no_body = true
73
+ headers = nil
74
+
75
+ parser.add_listener(:headers) {|h| headers = h}
76
+
77
+ parser << "HTTP/1.1 200 OK\r\n"
78
+ parser << "Content-Length: 20\r\n"
79
+ parser << "\r\n"
80
+
81
+ assert_equal({"Content-Length" => "20"}, headers)
82
+ assert(parser.finished?, "parser should be finished")
83
+ end
84
+
85
+ def test_apple_dot_com
86
+ parser = HTTPTools::Parser.new
87
+ code, message, headers = nil
88
+
89
+ parser.add_listener(:status) {|c, m| code, message = c, m}
90
+ parser.add_listener(:headers) {|h| headers = h}
91
+
92
+ parser << "HTTP/1.1 200 OK\r\n"
93
+ parser << "Server: Apache/2.2.11 (Unix)\r\n"
94
+ parser << "Content-Type: text/html; charset=utf-8\r\n"
95
+ parser << "Cache-Control: max-age=319\r\n"
96
+ parser << "Expires: Sun, 16 May 2010 18:15:18 GMT\r\n"
97
+ parser << "Date: Sun, 16 May 2010 18:09:59 GMT\r\n"
98
+ parser << "Connection: keep-alive\r\n"
99
+ parser << "\r\n"
100
+
101
+ assert_equal(200, code)
102
+ assert_equal("OK", message)
103
+ assert_equal({
104
+ "Server" => "Apache/2.2.11 (Unix)",
105
+ "Content-Type" => "text/html; charset=utf-8",
106
+ "Cache-Control" => "max-age=319",
107
+ "Expires" => "Sun, 16 May 2010 18:15:18 GMT",
108
+ "Date" => "Sun, 16 May 2010 18:09:59 GMT",
109
+ "Connection" => "keep-alive"}, headers)
110
+ end
111
+
112
+ def test_stream
113
+ parser = HTTPTools::Parser.new
114
+ code, message, headers = nil
115
+ body = []
116
+
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}
120
+
121
+ parser << "HTTP/1.1 200 OK\r\n"
122
+ parser << "Content-Length: 20\r\n"
123
+ parser << "\r\n"
124
+ parser << "<h1>Hello"
125
+ parser << " world</h1>"
126
+
127
+ assert_equal(200, code)
128
+ assert_equal("OK", message)
129
+ assert_equal({"Content-Length" => "20"}, headers)
130
+ assert_equal(["<h1>Hello", " world</h1>"], body)
131
+ assert(parser.finished?, "parser should be finished")
132
+ end
133
+
134
+ def test_body
135
+ parser = HTTPTools::Parser.new
136
+ code, message, headers, body = nil
137
+
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}
141
+
142
+ parser << "HTTP/1.1 200 OK\r\n"
143
+ parser << "Content-Length: 20\r\n"
144
+ parser << "\r\n"
145
+ parser << "<h1>Hello"
146
+ parser << " world</h1>"
147
+
148
+ assert_equal(200, code)
149
+ assert_equal("OK", message)
150
+ assert_equal({"Content-Length" => "20"}, headers)
151
+ assert_equal("<h1>Hello world</h1>", body)
152
+ assert(parser.finished?, "parser should be finished")
153
+ end
154
+
155
+ def test_sub_line_chunks
156
+ parser = HTTPTools::Parser.new
157
+ code, message, headers, body = nil
158
+
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}
162
+
163
+ parser << "HTTP/"
164
+ parser << "1."
165
+ parser << "1 "
166
+ parser << "200"
167
+ parser << " OK\r\n"
168
+ parser << "Content-"
169
+ parser << "Length: 20\r\n\r\n"
170
+ parser << "<h1>Hello"
171
+ parser << " world</h1>"
172
+
173
+ assert_equal(200, code)
174
+ assert_equal("OK", message)
175
+ assert_equal({"Content-Length" => "20"}, headers)
176
+ assert_equal("<h1>Hello world</h1>", body)
177
+ assert(parser.finished?, "parser should be finished")
178
+ end
179
+
180
+ def test_body_with_key_terminator_like_value
181
+ parser = HTTPTools::Parser.new
182
+ code, message, headers, body = nil
183
+
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}
187
+
188
+ parser << "HTTP/1.1 200 OK\r\n"
189
+ parser << "Content-Length: 21\r\n"
190
+ parser << "\r\n<h1>Hello: world</h1>"
191
+
192
+ assert_equal(200, code)
193
+ assert_equal("OK", message)
194
+ assert_equal({"Content-Length" => "21"}, headers)
195
+ assert_equal("<h1>Hello: world</h1>", body)
196
+ assert(parser.finished?, "parser should be finished")
197
+ end
198
+
199
+ def test_lazy_server
200
+ parser = HTTPTools::Parser.new
201
+ code, message, headers, body = nil
202
+
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}
206
+
207
+ parser << "HTTP/1.1 200 OK\n"
208
+ parser << "Content-Type: text/html; charset=utf-8\n"
209
+ parser << "Connection: close\n\n"
210
+ parser << "<h1>hello world</h1>"
211
+ parser.finish # notify parser the connection has closed
212
+
213
+ assert_equal(200, code)
214
+ assert_equal("OK", message)
215
+ assert_equal({"Content-Type" => "text/html; charset=utf-8", "Connection" => "close"}, headers)
216
+ assert_equal("<h1>hello world</h1>", body)
217
+ assert(parser.finished?, "parser should be finished")
218
+ end
219
+
220
+ def test_chunked
221
+ parser = HTTPTools::Parser.new
222
+ code, message, headers, body = nil
223
+
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}
227
+
228
+ parser << "HTTP/1.1 200 OK\r\n"
229
+ parser << "Transfer-Encoding: chunked\r\n"
230
+ parser << "\r\n"
231
+ parser << "14\r\n"
232
+ parser << "<h1>Hello world</h1>\r\n"
233
+ parser << "0\r\n"
234
+
235
+ assert_equal(200, code)
236
+ assert_equal("OK", message)
237
+ assert_equal({"Transfer-Encoding" => "chunked"}, headers)
238
+ assert_equal("<h1>Hello world</h1>", body)
239
+ assert(parser.finished?, "parser should be finished")
240
+ end
241
+
242
+ def test_chunked_stream
243
+ parser = HTTPTools::Parser.new
244
+ code, message, headers = nil
245
+ body = []
246
+
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}
250
+
251
+ parser << "HTTP/1.1 200 OK\r\n"
252
+ parser << "Transfer-Encoding: chunked\r\n"
253
+ parser << "\r\n"
254
+ parser << "9\r\n<h1>Hello\r\n"
255
+ parser << "b\r\n world</h1>\r\n"
256
+ parser << "0\r\n"
257
+
258
+ assert_equal(200, code)
259
+ assert_equal("OK", message)
260
+ assert_equal({"Transfer-Encoding" => "chunked"}, headers)
261
+ assert_equal(["<h1>Hello", " world</h1>"], body)
262
+ assert(parser.finished?, "parser should be finished")
263
+ end
264
+
265
+ def test_chunked_stream_with_multiple_chunks_at_once
266
+ parser = HTTPTools::Parser.new
267
+ code, message, headers = nil
268
+ body = []
269
+
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}
273
+
274
+ parser << "HTTP/1.1 200 OK\r\n"
275
+ parser << "Transfer-Encoding: chunked\r\n"
276
+ parser << "\r\n"
277
+ parser << "9\r\n<h1>Hello\r\nb\r\n world</h1>\r\n"
278
+ parser << "12\r\n<p>Lorem ipsum</p>\r\n"
279
+ parser << "0\r\n"
280
+
281
+ assert_equal(200, code)
282
+ assert_equal("OK", message)
283
+ assert_equal({"Transfer-Encoding" => "chunked"}, headers)
284
+ assert_equal(["<h1>Hello world</h1>", "<p>Lorem ipsum</p>"], body)
285
+ assert(parser.finished?, "parser should be finished")
286
+ end
287
+
288
+ def test_finished
289
+ parser = HTTPTools::Parser.new
290
+ code, message, body, remainder = nil
291
+
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}
295
+
296
+ parser << "HTTP/1.1 200 OK\r\nContent-Length: 20\r\n\r\n"
297
+ parser << "<h1>Hello world</h1>HTTP/1.1 404 Not Found\r\n"
298
+
299
+ assert_equal(200, code)
300
+ assert_equal("OK", message)
301
+ assert_equal("<h1>Hello world</h1>", body)
302
+ assert_equal("HTTP/1.1 404 Not Found\r\n", remainder)
303
+ assert(parser.finished?, "parser should be finished")
304
+ end
305
+
306
+ def test_finished_chunked
307
+ parser = HTTPTools::Parser.new
308
+ code, message, body, remainder = nil
309
+
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}
313
+
314
+ parser << "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
315
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\nHTTP/1.1 404 Not Found\r\n"
316
+
317
+ assert_equal(200, code)
318
+ assert_equal("OK", message)
319
+ assert_equal("<h1>Hello world</h1>", body)
320
+ assert_equal("HTTP/1.1 404 Not Found\r\n", remainder)
321
+ assert(parser.finished?, "parser should be finished")
322
+ end
323
+
324
+ def test_trailer
325
+ parser = HTTPTools::Parser.new
326
+ trailer = nil
327
+
328
+ parser.add_listener(:trailer) {|t| trailer = t}
329
+
330
+ parser << "HTTP/1.1 200 OK\r\n"
331
+ parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
332
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
333
+ parser << "X-Checksum: 2a2e12c8edad17de62354ea4531ac82c\r\n\r\n"
334
+
335
+ assert_equal({"X-Checksum" => "2a2e12c8edad17de62354ea4531ac82c"}, trailer)
336
+ assert(parser.finished?, "parser should be finished")
337
+ end
338
+
339
+ def test_trailer_sub_line_chunks
340
+ parser = HTTPTools::Parser.new
341
+ trailer = nil
342
+
343
+ parser.add_listener(:trailer) {|t| trailer = t}
344
+
345
+ parser << "HTTP/1.1 200 OK\r\n"
346
+ parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
347
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\nX-Chec"
348
+ parser << "ksum: 2a2e12c8eda"
349
+ parser << "d17de62354ea4531ac82c\r\n\r\n"
350
+
351
+ assert_equal({"X-Checksum" => "2a2e12c8edad17de62354ea4531ac82c"}, trailer)
352
+ assert(parser.finished?, "parser should be finished")
353
+ end
354
+
355
+ def test_force_trailer
356
+ parser = HTTPTools::Parser.new
357
+ trailer = nil
358
+
359
+ parser.add_listener(:trailer) {|t| trailer = t}
360
+
361
+ parser.force_trailer = true
362
+
363
+ parser << "HTTP/1.1 200 OK\r\n"
364
+ parser << "Transfer-Encoding: chunked\r\n\r\n"
365
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
366
+ parser << "X-Checksum: 2a2e12c8edad17de62354ea4531ac82c\r\n\r\n"
367
+
368
+ assert_equal({"X-Checksum" => "2a2e12c8edad17de62354ea4531ac82c"}, trailer)
369
+ assert(parser.finished?, "parser should be finished")
370
+ end
371
+
372
+ def test_error_on_unallowed_trailer
373
+ parser = HTTPTools::Parser.new
374
+
375
+ parser << "HTTP/1.1 200 OK\r\n"
376
+ parser << "Content-Length: 20\r\n\r\n"
377
+ parser << "<h1>Hello world</h1>"
378
+
379
+ assert_raise(HTTPTools::EndOfMessageError) do
380
+ parser << "X-Checksum: 2a2e12c8edad17de62354ea4531ac82c\r\n\r\n"
381
+ end
382
+ end
383
+
384
+ def test_error_on_unexpected_trailer
385
+ parser = HTTPTools::Parser.new
386
+
387
+ parser << "HTTP/1.1 200 OK\r\n"
388
+ parser << "Transfer-Encoding: chunked\r\n\r\n"
389
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
390
+
391
+ assert_raise(HTTPTools::EndOfMessageError) do
392
+ parser << "X-Checksum: 2a2e12c8edad17de62354ea4531ac82c\r\n\r\n"
393
+ end
394
+ end
395
+
396
+ def test_invalid_trailer_key
397
+ parser = HTTPTools::Parser.new
398
+ trailer = nil
399
+
400
+ parser.add_listener(:trailer) {|t| trailer = t}
401
+
402
+ parser << "HTTP/1.1 200 OK\r\n"
403
+ parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
404
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
405
+
406
+ assert_raise(HTTPTools::ParseError) do
407
+ parser << "x-invalid key: value\r\n\r\n"
408
+ end
409
+ end
410
+
411
+ def test_invalid_trailer_value
412
+ parser = HTTPTools::Parser.new
413
+ trailer = nil
414
+
415
+ parser.add_listener(:trailer) {|t| trailer = t}
416
+
417
+ parser << "HTTP/1.1 200 OK\r\n"
418
+ parser << "Transfer-Encoding: chunked\r\nTrailer: X-Checksum\r\n\r\n"
419
+ parser << "14\r\n<h1>Hello world</h1>\r\n0\r\n"
420
+
421
+ assert_raise(HTTPTools::ParseError) do
422
+ parser << "x-test: inva\0lid\r\n\r\n"
423
+ end
424
+ end
425
+
426
+ def test_invalid_version
427
+ parser = HTTPTools::Parser.new
428
+
429
+ assert_raise(HTTPTools::ParseError) {parser << "HTTP/one dot one 200 OK"}
430
+ end
431
+
432
+ def test_invalid_status
433
+ parser = HTTPTools::Parser.new
434
+
435
+ assert_raise(HTTPTools::ParseError) {parser << "HTTP/1.1 0 Fail"}
436
+ end
437
+
438
+ def test_finish_early
439
+ parser = HTTPTools::Parser.new
440
+
441
+ parser << "HTTP/1.1 200 OK\r\n"
442
+
443
+ assert_raise(HTTPTools::MessageIncompleteError) {parser.finish}
444
+ end
445
+
446
+ end
data/test/runner.rb ADDED
@@ -0,0 +1 @@
1
+ Dir["**/*_test.rb"].each {|test| require test}
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_tools
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Matthew Sadler
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-09 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: A collection of lower level utilities to aid working with HTTP, including a fast-as-possible pure Ruby HTTP parser.
23
+ email: mat@sourcetagsandcodes.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ files:
31
+ - lib/http_tools/builder.rb
32
+ - lib/http_tools/encoding.rb
33
+ - lib/http_tools/errors.rb
34
+ - lib/http_tools/parser.rb
35
+ - lib/http_tools.rb
36
+ - test/builder/request_test.rb
37
+ - test/builder/response_test.rb
38
+ - test/cover.rb
39
+ - test/encoding/transfer_encoding_chunked_test.rb
40
+ - test/encoding/url_encoding_test.rb
41
+ - test/encoding/www_form_test.rb
42
+ - test/parser/request_test.rb
43
+ - test/parser/response_test.rb
44
+ - test/runner.rb
45
+ - bench/parser/request_bench.rb
46
+ - bench/parser/response_bench.rb
47
+ - profile/parser/request_profile.rb
48
+ - profile/parser/response_profile.rb
49
+ - example/http_client.rb
50
+ - README.rdoc
51
+ has_rdoc: true
52
+ homepage: http://github.com/matsadler/http_tools
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --main
58
+ - README.rdoc
59
+ - --charset
60
+ - utf-8
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Pure Ruby HTTP parser and friends
88
+ test_files: []
89
+