h1p 0.1 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,13 +5,13 @@ require 'h1p'
5
5
  require 'socket'
6
6
  require_relative '../ext/h1p/limits'
7
7
 
8
- class H1PTest < MiniTest::Test
8
+ class H1PRequestTest < MiniTest::Test
9
9
  Error = H1P::Error
10
10
 
11
11
  def setup
12
12
  super
13
13
  @i, @o = IO.pipe
14
- @parser = H1P::Parser.new(@i)
14
+ @parser = H1P::Parser.new(@i, :server)
15
15
  end
16
16
  alias_method :reset_parser, :setup
17
17
 
@@ -22,7 +22,7 @@ class H1PTest < MiniTest::Test
22
22
 
23
23
  assert_equal(
24
24
  {
25
- ':method' => 'get',
25
+ ':method' => 'GET',
26
26
  ':path' => '/',
27
27
  ':protocol' => 'http/1.1',
28
28
  ':rx' => msg.bytesize
@@ -38,7 +38,7 @@ class H1PTest < MiniTest::Test
38
38
 
39
39
  assert_equal(
40
40
  {
41
- ':method' => 'get',
41
+ ':method' => 'GET',
42
42
  ':path' => '/',
43
43
  ':protocol' => 'http/1.1',
44
44
  ':rx' => msg.bytesize
@@ -57,17 +57,17 @@ class H1PTest < MiniTest::Test
57
57
  def test_method_case
58
58
  @o << "GET / HTTP/1.1\r\n\r\n"
59
59
  headers = @parser.parse_headers
60
- assert_equal 'get', headers[':method']
60
+ assert_equal 'GET', headers[':method']
61
61
 
62
62
  reset_parser
63
63
  @o << "post / HTTP/1.1\r\n\r\n"
64
64
  headers = @parser.parse_headers
65
- assert_equal 'post', headers[':method']
65
+ assert_equal 'POST', headers[':method']
66
66
 
67
67
  reset_parser
68
68
  @o << "PoST / HTTP/1.1\r\n\r\n"
69
69
  headers = @parser.parse_headers
70
- assert_equal 'post', headers[':method']
70
+ assert_equal 'POST', headers[':method']
71
71
  end
72
72
 
73
73
  def test_bad_method
@@ -75,12 +75,12 @@ class H1PTest < MiniTest::Test
75
75
  @o.close
76
76
 
77
77
  assert_raises(Error) { @parser.parse_headers }
78
-
78
+
79
79
  max_length = H1P_LIMITS[:max_method_length]
80
80
 
81
81
  reset_parser
82
82
  @o << "#{'a' * max_length} / HTTP/1.1\r\n\r\n"
83
- assert_equal 'a' * max_length, @parser.parse_headers[':method']
83
+ assert_equal 'A' * max_length, @parser.parse_headers[':method']
84
84
 
85
85
  reset_parser
86
86
  @o << "#{'a' * (max_length + 1)} / HTTP/1.1\r\n\r\n"
@@ -96,7 +96,7 @@ class H1PTest < MiniTest::Test
96
96
  def test_bad_path
97
97
  @o << "GET HTTP/1.1\r\n\r\n"
98
98
  assert_raises(Error) { @parser.parse_headers }
99
-
99
+
100
100
  max_length = H1P_LIMITS[:max_path_length]
101
101
 
102
102
  reset_parser
@@ -149,26 +149,26 @@ class H1PTest < MiniTest::Test
149
149
  assert_raises(Error) { @parser.parse_headers }
150
150
 
151
151
  reset_parser
152
- @o << "GET / http/1.1.1\r\n\r\n"
152
+ @o << "GET / HTTP/1.1.1\r\n\r\n"
153
153
  assert_raises(Error) { @parser.parse_headers }
154
154
  end
155
155
 
156
156
  def test_headers_eof
157
157
  @o << "GET / HTTP/1.1\r\na"
158
158
  @o.close
159
-
159
+
160
160
  assert_nil @parser.parse_headers
161
161
 
162
162
  reset_parser
163
163
  @o << "GET / HTTP/1.1\r\na:"
164
164
  @o.close
165
-
165
+
166
166
  assert_nil @parser.parse_headers
167
167
 
168
168
  reset_parser
169
169
  @o << "GET / HTTP/1.1\r\na: "
170
170
  @o.close
171
-
171
+
172
172
  assert_nil @parser.parse_headers
173
173
  end
174
174
 
@@ -197,46 +197,46 @@ class H1PTest < MiniTest::Test
197
197
  end
198
198
 
199
199
  def test_bad_headers
200
- @o << "GET / http/1.1\r\n a: b\r\n\r\n"
200
+ @o << "GET / HTTP/1.1\r\n a: b\r\n\r\n"
201
201
  assert_raises(Error) { @parser.parse_headers }
202
202
 
203
203
  reset_parser
204
- @o << "GET / http/1.1\r\na b\r\n\r\n"
204
+ @o << "GET / HTTP/1.1\r\na b\r\n\r\n"
205
205
  assert_raises(Error) { @parser.parse_headers }
206
206
 
207
207
  max_key_length = H1P_LIMITS[:max_header_key_length]
208
208
 
209
209
  reset_parser
210
- @o << "GET / http/1.1\r\n#{'a' * max_key_length}: b\r\n\r\n"
210
+ @o << "GET / HTTP/1.1\r\n#{'a' * max_key_length}: b\r\n\r\n"
211
211
  headers = @parser.parse_headers
212
212
  assert_equal 'b', headers['a' * max_key_length]
213
213
 
214
214
  reset_parser
215
- @o << "GET / http/1.1\r\n#{'a' * (max_key_length + 1)}: b\r\n\r\n"
215
+ @o << "GET / HTTP/1.1\r\n#{'a' * (max_key_length + 1)}: b\r\n\r\n"
216
216
  assert_raises(Error) { @parser.parse_headers }
217
217
 
218
218
  max_value_length = H1P_LIMITS[:max_header_value_length]
219
219
 
220
220
  reset_parser
221
- @o << "GET / http/1.1\r\nfoo: #{'a' * max_value_length}\r\n\r\n"
221
+ @o << "GET / HTTP/1.1\r\nfoo: #{'a' * max_value_length}\r\n\r\n"
222
222
  headers = @parser.parse_headers
223
223
  assert_equal 'a' * max_value_length, headers['foo']
224
224
 
225
225
  reset_parser
226
- @o << "GET / http/1.1\r\nfoo: #{'a' * (max_value_length + 1)}\r\n\r\n"
226
+ @o << "GET / HTTP/1.1\r\nfoo: #{'a' * (max_value_length + 1)}\r\n\r\n"
227
227
  assert_raises(Error) { @parser.parse_headers }
228
228
 
229
229
  max_header_count = H1P_LIMITS[:max_header_count]
230
230
 
231
231
  reset_parser
232
232
  hdrs = (1..max_header_count).map { |i| "foo#{i}: bar\r\n" }.join
233
- @o << "GET / http/1.1\r\n#{hdrs}\r\n"
233
+ @o << "GET / HTTP/1.1\r\n#{hdrs}\r\n"
234
234
  headers = @parser.parse_headers
235
235
  assert_equal (max_header_count + 4), headers.size
236
236
 
237
237
  reset_parser
238
238
  hdrs = (1..(max_header_count + 1)).map { |i| "foo#{i}: bar\r\n" }.join
239
- @o << "GET / http/1.1\r\n#{hdrs}\r\n"
239
+ @o << "GET / HTTP/1.1\r\n#{hdrs}\r\n"
240
240
  assert_raises(Error) { @parser.parse_headers }
241
241
  end
242
242
 
@@ -245,7 +245,7 @@ class H1PTest < MiniTest::Test
245
245
  @o << msg
246
246
  headers = @parser.parse_headers
247
247
  assert_equal({
248
- ':method' => 'get',
248
+ ':method' => 'GET',
249
249
  ':path' => '/foo',
250
250
  ':protocol' => 'http/1.1',
251
251
  'bar' => 'baz',
@@ -256,7 +256,7 @@ class H1PTest < MiniTest::Test
256
256
  def test_read_body_with_content_length
257
257
  10.times do
258
258
  data = ' ' * rand(20..60000)
259
- msg = "POST /foo HTTP/1.1\r\nContent-Length: #{data.bytesize}\r\n\r\n#{data}"
259
+ msg = "GET / HTTP/1.1\r\nContent-Length: #{data.bytesize}\r\n\r\n#{data}"
260
260
  Thread.new { @o << msg }
261
261
 
262
262
  headers = @parser.parse_headers
@@ -270,7 +270,7 @@ class H1PTest < MiniTest::Test
270
270
 
271
271
  def test_read_body_chunk_with_content_length
272
272
  data = 'abc' * 20000
273
- msg = "POST /foo HTTP/1.1\r\nContent-Length: #{data.bytesize}\r\n\r\n#{data}"
273
+ msg = "GET / HTTP/1.1\r\nContent-Length: #{data.bytesize}\r\n\r\n#{data}"
274
274
  Thread.new { @o << msg }
275
275
  headers = @parser.parse_headers
276
276
  assert_equal data.bytesize.to_s, headers['content-length']
@@ -290,7 +290,7 @@ class H1PTest < MiniTest::Test
290
290
  def test_read_body_with_content_length_incomplete
291
291
  data = ' ' * rand(20..60000)
292
292
  Thread.new do
293
- @o << "POST /foo HTTP/1.1\r\nContent-Length: #{data.bytesize + 1}\r\n\r\n#{data}"
293
+ @o << "GET / HTTP/1.1\r\nContent-Length: #{data.bytesize + 1}\r\n\r\n#{data}"
294
294
  @o.close # !!! otherwise the parser will keep waiting
295
295
  end
296
296
  headers = @parser.parse_headers
@@ -300,7 +300,7 @@ class H1PTest < MiniTest::Test
300
300
 
301
301
  def test_read_body_chunk_with_content_length_incomplete
302
302
  data = 'abc' * 50
303
- @o << "POST /foo HTTP/1.1\r\nContent-Length: #{data.bytesize + 1}\r\n\r\n#{data}"
303
+ @o << "GET / HTTP/1.1\r\nContent-Length: #{data.bytesize + 1}\r\n\r\n#{data}"
304
304
  @o.close
305
305
  headers = @parser.parse_headers
306
306
 
@@ -311,7 +311,7 @@ class H1PTest < MiniTest::Test
311
311
  chunks = []
312
312
  total_sent = 0
313
313
  Thread.new do
314
- msg = "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
314
+ msg = "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
315
315
  @o << msg
316
316
  total_sent += msg.bytesize
317
317
  rand(8..16).times do |i|
@@ -324,7 +324,7 @@ class H1PTest < MiniTest::Test
324
324
  msg = "0\r\n\r\n"
325
325
  @o << msg
326
326
  total_sent += msg.bytesize
327
- end
327
+ end
328
328
  headers = @parser.parse_headers
329
329
  assert_equal 'chunked', headers['transfer-encoding']
330
330
 
@@ -337,7 +337,7 @@ class H1PTest < MiniTest::Test
337
337
  chunks = []
338
338
  total_sent = 0
339
339
  Thread.new do
340
- msg = "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
340
+ msg = "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
341
341
  @o << msg
342
342
  total_sent += msg.bytesize
343
343
  rand(8..16).times do |i|
@@ -350,7 +350,7 @@ class H1PTest < MiniTest::Test
350
350
  msg = "0\r\n\r\n"
351
351
  @o << msg
352
352
  total_sent += msg.bytesize
353
- end
353
+ end
354
354
  headers = @parser.parse_headers
355
355
  assert_equal 'chunked', headers['transfer-encoding']
356
356
 
@@ -364,7 +364,7 @@ class H1PTest < MiniTest::Test
364
364
 
365
365
  def test_read_body_with_chunked_encoding_malformed
366
366
  Thread.new do
367
- @o << "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
367
+ @o << "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
368
368
  chunk = ' '.to_s * rand(40000..360000)
369
369
  @o << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n3"
370
370
  @o << "0\r\n\r\n"
@@ -376,22 +376,22 @@ class H1PTest < MiniTest::Test
376
376
  reset_parser
377
377
  # missing last empty chunk
378
378
  Thread.new do
379
- @o << "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
379
+ @o << "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
380
380
  chunk = ' '.to_s * rand(40000..360000)
381
381
  @o << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
382
382
  @o.close
383
- end
383
+ end
384
384
  headers = @parser.parse_headers
385
385
  assert_raises(H1P::Error) { @parser.read_body }
386
386
 
387
387
  reset_parser
388
388
  # bad chunk size
389
389
  Thread.new do
390
- @o << "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
390
+ @o << "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
391
391
  chunk = ' '.to_s * rand(40000..360000)
392
392
  @o << "-#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
393
393
  @o.close
394
- end
394
+ end
395
395
  headers = @parser.parse_headers
396
396
  assert_raises(H1P::Error) { @parser.read_body }
397
397
  end
@@ -399,7 +399,7 @@ class H1PTest < MiniTest::Test
399
399
  def test_read_body_chunk_with_chunked_encoding_malformed
400
400
  chunk = nil
401
401
  Thread.new do
402
- @o << "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
402
+ @o << "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
403
403
  chunk = ' ' * rand(40000..360000)
404
404
  @o << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n3"
405
405
  @o << "0\r\n\r\n"
@@ -415,7 +415,7 @@ class H1PTest < MiniTest::Test
415
415
  # missing last empty chunk
416
416
  chunk = nil
417
417
  Thread.new do
418
- @o << "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
418
+ @o << "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
419
419
  chunk = ' '.to_s * rand(20..1600)
420
420
  @o << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
421
421
  @o.close
@@ -429,18 +429,18 @@ class H1PTest < MiniTest::Test
429
429
 
430
430
  # bad chunk size
431
431
  Thread.new do
432
- @o << "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
432
+ @o << "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
433
433
  chunk = ' '.to_s * rand(20..1600)
434
434
  @o << "-#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
435
435
  @o.close
436
- end
436
+ end
437
437
  headers = @parser.parse_headers
438
438
  assert_raises(H1P::Error) { @parser.read_body_chunk(false) }
439
439
 
440
440
  reset_parser
441
441
 
442
442
  # missing body
443
- @o << "POST /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
443
+ @o << "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
444
444
  @o.close
445
445
  headers = @parser.parse_headers
446
446
  assert_raises(H1P::Error) { @parser.read_body_chunk(false) }
@@ -519,7 +519,7 @@ class H1PTest < MiniTest::Test
519
519
  server_thread = Thread.new do
520
520
  while (socket = server.accept)
521
521
  Thread.new do
522
- parser = H1P::Parser.new(socket)
522
+ parser = H1P::Parser.new(socket, :server)
523
523
  headers = parser.parse_headers
524
524
  socket << headers.inspect
525
525
  socket.shutdown
@@ -534,7 +534,7 @@ class H1PTest < MiniTest::Test
534
534
  client << msg
535
535
  reply = client.read
536
536
  assert_equal({
537
- ':method' => 'get',
537
+ ':method' => 'GET',
538
538
  ':path' => '/foo',
539
539
  ':protocol' => 'http/1.1',
540
540
  'cookie' => 'abc=def',
@@ -556,11 +556,11 @@ class H1PTest < MiniTest::Test
556
556
  request
557
557
  end
558
558
 
559
- parser = H1P::Parser.new(callable)
559
+ parser = H1P::Parser.new(callable, :server)
560
560
 
561
561
  headers = parser.parse_headers
562
562
  assert_equal({
563
- ':method' => 'get',
563
+ ':method' => 'GET',
564
564
  ':path' => '/foo',
565
565
  ':protocol' => 'http/1.1',
566
566
  'host' => 'bar',
@@ -572,7 +572,7 @@ class H1PTest < MiniTest::Test
572
572
  request = +"GET /bar HTTP/1.1\r\nHost: baz\r\n\r\n"
573
573
  headers = parser.parse_headers
574
574
  assert_equal({
575
- ':method' => 'get',
575
+ ':method' => 'GET',
576
576
  ':path' => '/bar',
577
577
  ':protocol' => 'http/1.1',
578
578
  'host' => 'baz',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: h1p
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-19 00:00:00.000000000 Z
11
+ date: 2022-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -30,42 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 12.3.3
33
+ version: 13.0.6
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 12.3.3
40
+ version: 13.0.6
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 5.11.3
47
+ version: 5.14.4
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 5.11.3
55
- - !ruby/object:Gem::Dependency
56
- name: minitest-reporters
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 1.4.2
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 1.4.2
54
+ version: 5.14.4
69
55
  description:
70
56
  email: sharon@noteflakes.com
71
57
  executables: []
@@ -84,6 +70,8 @@ files:
84
70
  - Rakefile
85
71
  - TODO.md
86
72
  - benchmarks/bm_http1_parser.rb
73
+ - benchmarks/pipelined.rb
74
+ - examples/callable.rb
87
75
  - examples/http_server.rb
88
76
  - ext/h1p/extconf.rb
89
77
  - ext/h1p/h1p.c
@@ -93,7 +81,9 @@ files:
93
81
  - lib/h1p.rb
94
82
  - lib/h1p/version.rb
95
83
  - test/helper.rb
96
- - test/test_h1p.rb
84
+ - test/run.rb
85
+ - test/test_h1p_client.rb
86
+ - test/test_h1p_server.rb
97
87
  homepage: http://github.com/digital-fabric/h1p
98
88
  licenses:
99
89
  - MIT