biryani 0.0.1

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.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +30 -0
  3. data/.gitignore +17 -0
  4. data/.rubocop.yml +36 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +48 -0
  9. data/Rakefile +8 -0
  10. data/biryani.gemspec +21 -0
  11. data/example/echo.rb +27 -0
  12. data/example/hello_world.rb +22 -0
  13. data/lib/biryani/connection.rb +464 -0
  14. data/lib/biryani/connection_error.rb +17 -0
  15. data/lib/biryani/data_buffer.rb +42 -0
  16. data/lib/biryani/frame/continuation.rb +48 -0
  17. data/lib/biryani/frame/data.rb +70 -0
  18. data/lib/biryani/frame/goaway.rb +44 -0
  19. data/lib/biryani/frame/headers.rb +110 -0
  20. data/lib/biryani/frame/ping.rb +49 -0
  21. data/lib/biryani/frame/priority.rb +44 -0
  22. data/lib/biryani/frame/push_promise.rb +75 -0
  23. data/lib/biryani/frame/rst_stream.rb +40 -0
  24. data/lib/biryani/frame/settings.rb +66 -0
  25. data/lib/biryani/frame/unknown.rb +42 -0
  26. data/lib/biryani/frame/window_update.rb +43 -0
  27. data/lib/biryani/frame.rb +146 -0
  28. data/lib/biryani/hpack/decoder.rb +22 -0
  29. data/lib/biryani/hpack/dynamic_table.rb +65 -0
  30. data/lib/biryani/hpack/encoder.rb +22 -0
  31. data/lib/biryani/hpack/error.rb +12 -0
  32. data/lib/biryani/hpack/field.rb +357 -0
  33. data/lib/biryani/hpack/fields.rb +28 -0
  34. data/lib/biryani/hpack/huffman.rb +309 -0
  35. data/lib/biryani/hpack/integer.rb +66 -0
  36. data/lib/biryani/hpack/option.rb +24 -0
  37. data/lib/biryani/hpack/string.rb +40 -0
  38. data/lib/biryani/hpack.rb +84 -0
  39. data/lib/biryani/http_request.rb +83 -0
  40. data/lib/biryani/http_response.rb +61 -0
  41. data/lib/biryani/server.rb +19 -0
  42. data/lib/biryani/state.rb +224 -0
  43. data/lib/biryani/stream.rb +19 -0
  44. data/lib/biryani/stream_error.rb +17 -0
  45. data/lib/biryani/streams_context.rb +89 -0
  46. data/lib/biryani/version.rb +3 -0
  47. data/lib/biryani/window.rb +29 -0
  48. data/lib/biryani.rb +17 -0
  49. data/spec/connection/close_all_streams_spec.rb +17 -0
  50. data/spec/connection/handle_connection_window_update_spec.rb +16 -0
  51. data/spec/connection/handle_ping_spec.rb +21 -0
  52. data/spec/connection/handle_rst_stream_spec.rb +21 -0
  53. data/spec/connection/handle_settings_spec.rb +31 -0
  54. data/spec/connection/handle_stream_window_update_spec.rb +20 -0
  55. data/spec/connection/read_http2_magic_spec.rb +26 -0
  56. data/spec/connection/remove_closed_streams_spec.rb +51 -0
  57. data/spec/connection/send_spec.rb +114 -0
  58. data/spec/connection/transition_state_send_spec.rb +39 -0
  59. data/spec/connection/unwrap_spec.rb +28 -0
  60. data/spec/data_buffer_spec.rb +135 -0
  61. data/spec/frame/continuation_spec.rb +39 -0
  62. data/spec/frame/data_spec.rb +25 -0
  63. data/spec/frame/goaway_spec.rb +23 -0
  64. data/spec/frame/headers_spec.rb +52 -0
  65. data/spec/frame/ping_spec.rb +22 -0
  66. data/spec/frame/priority_spec.rb +22 -0
  67. data/spec/frame/push_promise_spec.rb +24 -0
  68. data/spec/frame/read_spec.rb +30 -0
  69. data/spec/frame/rst_stream_spec.rb +21 -0
  70. data/spec/frame/settings_spec.rb +23 -0
  71. data/spec/frame/window_update_spec.rb +21 -0
  72. data/spec/hpack/decoder_spec.rb +170 -0
  73. data/spec/hpack/encoder_spec.rb +48 -0
  74. data/spec/hpack/field_spec.rb +42 -0
  75. data/spec/hpack/fields_spec.rb +17 -0
  76. data/spec/hpack/huffman_spec.rb +20 -0
  77. data/spec/hpack/integer_spec.rb +27 -0
  78. data/spec/hpack/string_spec.rb +19 -0
  79. data/spec/http_request_builder_spec.rb +45 -0
  80. data/spec/spec_helper.rb +9 -0
  81. metadata +165 -0
@@ -0,0 +1,170 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe HPACK::Decoder do
4
+ context do
5
+ let(:decoder) do
6
+ HPACK::Decoder.new(256)
7
+ end
8
+
9
+ it 'should decode' do
10
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.3.1
11
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
12
+ 8286 8441 0f77 7777 2e65 7861 6d70 6c65
13
+ 2e63 6f6d
14
+ HEXDUMP
15
+ )).to eq [
16
+ [':method', 'GET'],
17
+ [':scheme', 'http'],
18
+ [':path', '/'],
19
+ [':authority', 'www.example.com']
20
+ ]
21
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.3.2
22
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
23
+ 8286 84be 5808 6e6f 2d63 6163 6865
24
+ HEXDUMP
25
+ )).to eq [
26
+ [':method', 'GET'],
27
+ [':scheme', 'http'],
28
+ [':path', '/'],
29
+ [':authority', 'www.example.com'],
30
+ ['cache-control', 'no-cache']
31
+ ]
32
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.3.3
33
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
34
+ 8287 85bf 400a 6375 7374 6f6d 2d6b 6579
35
+ 0c63 7573 746f 6d2d 7661 6c75 65
36
+ HEXDUMP
37
+ )).to eq [
38
+ [':method', 'GET'],
39
+ [':scheme', 'https'],
40
+ [':path', '/index.html'],
41
+ [':authority', 'www.example.com'],
42
+ ['custom-key', 'custom-value']
43
+ ]
44
+ end
45
+
46
+ it 'should decode' do
47
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.4.1
48
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
49
+ 8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4
50
+ ff
51
+ HEXDUMP
52
+ )).to eq [
53
+ [':method', 'GET'],
54
+ [':scheme', 'http'],
55
+ [':path', '/'],
56
+ [':authority', 'www.example.com']
57
+ ]
58
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.4.2
59
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
60
+ 8286 84be 5886 a8eb 1064 9cbf
61
+ HEXDUMP
62
+ )).to eq [
63
+ [':method', 'GET'],
64
+ [':scheme', 'http'],
65
+ [':path', '/'],
66
+ [':authority', 'www.example.com'],
67
+ ['cache-control', 'no-cache']
68
+ ]
69
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.4.3
70
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
71
+ 8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925
72
+ a849 e95b b8e8 b4bf
73
+ HEXDUMP
74
+ )).to eq [
75
+ [':method', 'GET'],
76
+ [':scheme', 'https'],
77
+ [':path', '/index.html'],
78
+ [':authority', 'www.example.com'],
79
+ ['custom-key', 'custom-value']
80
+ ]
81
+ end
82
+
83
+ it 'should decode' do
84
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.5.1
85
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
86
+ 4803 3330 3258 0770 7269 7661 7465 611d
87
+ 4d6f 6e2c 2032 3120 4f63 7420 3230 3133
88
+ 2032 303a 3133 3a32 3120 474d 546e 1768
89
+ 7474 7073 3a2f 2f77 7777 2e65 7861 6d70
90
+ 6c65 2e63 6f6d
91
+ HEXDUMP
92
+ )).to eq [
93
+ [':status', '302'],
94
+ ['cache-control', 'private'],
95
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
96
+ ['location', 'https://www.example.com']
97
+ ]
98
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.5.2
99
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
100
+ 4803 3330 37c1 c0bf
101
+ HEXDUMP
102
+ )).to eq [
103
+ [':status', '307'],
104
+ ['cache-control', 'private'],
105
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
106
+ ['location', 'https://www.example.com']
107
+ ]
108
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.5.3
109
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
110
+ 88c1 611d 4d6f 6e2c 2032 3120 4f63 7420
111
+ 3230 3133 2032 303a 3133 3a32 3220 474d
112
+ 54c0 5a04 677a 6970 7738 666f 6f3d 4153
113
+ 444a 4b48 514b 425a 584f 5157 454f 5049
114
+ 5541 5851 5745 4f49 553b 206d 6178 2d61
115
+ 6765 3d33 3630 303b 2076 6572 7369 6f6e
116
+ 3d31
117
+ HEXDUMP
118
+ )).to eq [
119
+ [':status', '200'],
120
+ ['cache-control', 'private'],
121
+ ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'],
122
+ ['location', 'https://www.example.com'],
123
+ ['content-encoding', 'gzip'],
124
+ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1']
125
+ ]
126
+ end
127
+
128
+ it 'should decode' do
129
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.6.1
130
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
131
+ 4882 6402 5885 aec3 771a 4b61 96d0 7abe
132
+ 9410 54d4 44a8 2005 9504 0b81 66e0 82a6
133
+ 2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
134
+ e9ae 82ae 43d3
135
+ HEXDUMP
136
+ )).to eq [
137
+ [':status', '302'],
138
+ ['cache-control', 'private'],
139
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
140
+ ['location', 'https://www.example.com']
141
+ ]
142
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.6.2
143
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
144
+ 4883 640e ffc1 c0bf
145
+ HEXDUMP
146
+ )).to eq [
147
+ [':status', '307'],
148
+ ['cache-control', 'private'],
149
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
150
+ ['location', 'https://www.example.com']
151
+ ]
152
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.6.3
153
+ expect(decoder.decode([<<HEXDUMP.split.join].pack('H*')
154
+ 88c1 6196 d07a be94 1054 d444 a820 0595
155
+ 040b 8166 e084 a62d 1bff c05a 839b d9ab
156
+ 77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
157
+ 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
158
+ 9587 3160 65c0 03ed 4ee5 b106 3d50 07
159
+ HEXDUMP
160
+ )).to eq [
161
+ [':status', '200'],
162
+ ['cache-control', 'private'],
163
+ ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'],
164
+ ['location', 'https://www.example.com'],
165
+ ['content-encoding', 'gzip'],
166
+ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1']
167
+ ]
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,48 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe HPACK::Encoder do
4
+ context do
5
+ let(:encoder) do
6
+ HPACK::Encoder.new(256)
7
+ end
8
+
9
+ it 'should encode' do
10
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.6.1
11
+ expect(encoder.encode([
12
+ [':status', '302'],
13
+ ['cache-control', 'private'],
14
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
15
+ ['location', 'https://www.example.com']
16
+ ])).to eq [<<HEXDUMP.split.join].pack('H*')
17
+ 4882 6402 5885 aec3 771a 4b61 96d0 7abe
18
+ 9410 54d4 44a8 2005 9504 0b81 66e0 82a6
19
+ 2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
20
+ e9ae 82ae 43d3
21
+ HEXDUMP
22
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.6.2
23
+ expect(encoder.encode([
24
+ [':status', '307'],
25
+ ['cache-control', 'private'],
26
+ ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'],
27
+ ['location', 'https://www.example.com']
28
+ ])).to eq [<<HEXDUMP.split.join].pack('H*')
29
+ 4883 640e ffc1 c0bf
30
+ HEXDUMP
31
+ # https://datatracker.ietf.org/doc/html/rfc7541#appendix-C.6.3
32
+ expect(encoder.encode([
33
+ [':status', '200'],
34
+ ['cache-control', 'private'],
35
+ ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'],
36
+ ['location', 'https://www.example.com'],
37
+ ['content-encoding', 'gzip'],
38
+ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1']
39
+ ])).to eq [<<HEXDUMP.split.join].pack('H*')
40
+ 88c1 6196 d07a be94 1054 d444 a820 0595
41
+ 040b 8166 e084 a62d 1bff c05a 839b d9ab
42
+ 77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
43
+ 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
44
+ 9587 3160 65c0 03ed 4ee5 b106 3d50 07
45
+ HEXDUMP
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe HPACK::Field do
4
+ context do
5
+ let(:dynamic_table) do
6
+ HPACK::DynamicTable.new(4096)
7
+ end
8
+
9
+ it 'should encode' do
10
+ expect(HPACK::Field.encode(':method', 'GET', dynamic_table)).to eq "\x82".b
11
+ expect(HPACK::Field.encode(':status', '302', dynamic_table)).to eq "\x48\x82\x64\x02".b
12
+ expect(HPACK::Field.encode('location', 'https://www.example.com', dynamic_table)).to eq "\x6e\x91\x9d\x29\xad\x17\x18\x63\xc7\x8f\x0b\x97\xc8\xe9\xae\x82\xae\x43\xd3".b
13
+ expect(HPACK::Field.encode('custom-key', 'custom-header', dynamic_table)).to eq "\x40\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9".b
14
+ end
15
+
16
+ let(:cursor) do
17
+ 0
18
+ end
19
+
20
+ it 'should decode' do
21
+ expect(HPACK::Field.decode("\x82".b, cursor, dynamic_table)).to eq [%w[:method GET], 1]
22
+ expect(HPACK::Field.decode("\x48\x82\x64\x02".b, cursor, dynamic_table)).to eq [%w[:status 302], 4]
23
+ expect(HPACK::Field.decode("\x6e\x91\x9d\x29\xad\x17\x18\x63\xc7\x8f\x0b\x97\xc8\xe9\xae\x82\xae\x43\xd3".b, cursor, dynamic_table)).to eq [%w[location https://www.example.com], 19]
24
+ expect(HPACK::Field.decode("\x40\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9".b, cursor, dynamic_table)).to eq [%w[custom-key custom-header], 20]
25
+ expect(HPACK::Field.decode("\x10\x08\x70\x61\x73\x73\x77\x6f\x72\x64\x06\x73\x65\x63\x72\x65\x74".b, cursor, dynamic_table)).to eq [%w[password secret], 17]
26
+ end
27
+
28
+ it 'should decode' do
29
+ expect(HPACK::Field.decode("\x40\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9".b, cursor, dynamic_table)).to eq [%w[custom-key custom-header], 20]
30
+ expect(dynamic_table.limit).to eq 4096
31
+ expect(dynamic_table.size).to eq 'custom-keycustom-header'.bytesize + 32
32
+ expect(HPACK::Field.decode("\x20".b, cursor, dynamic_table)).to eq [nil, 1]
33
+ expect(dynamic_table.limit).to eq 4096
34
+ expect(dynamic_table.size).to eq 0
35
+ end
36
+
37
+ it 'should not decode' do
38
+ expect { HPACK::Field.decode("\xbe".b, cursor, dynamic_table) }.to raise_error HPACK::Error::HPACKDecodeError
39
+ expect { HPACK::Field.decode("\x3f\xe2\x1f".b, cursor, dynamic_table) }.to raise_error HPACK::Error::HPACKDecodeError
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe HPACK::Fields do
4
+ context do
5
+ let(:dynamic_table) do
6
+ HPACK::DynamicTable.new(4096)
7
+ end
8
+ it 'should decode' do
9
+ expect(HPACK::Fields.decode([<<HEXDUMP.split.join].pack('H*'),
10
+ 8286 8441 8a08 9d5c 0b81 70dc 79e7
11
+ 9e40 8721 eaa8 a449 8f57 88ea 52d6
12
+ b0e8 3772 ff
13
+ HEXDUMP
14
+ dynamic_table)).to eq [[':method', 'GET'], [':scheme', 'http'], [':path', '/'], [':authority', '127.0.0.1:8888'], ['connection', 'keep-alive']]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe HPACK::Huffman do
4
+ context do
5
+ it 'should encode' do
6
+ expect(HPACK::Huffman.encode('www.example.com')).to eq "\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff".b
7
+ expect(HPACK::Huffman.encode('no-cache')).to eq "\xa8\xeb\x10\x64\x9c\xbf".b
8
+ end
9
+
10
+ it 'should decode' do
11
+ expect(HPACK::Huffman.decode("\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff".b)).to eq 'www.example.com'
12
+ expect(HPACK::Huffman.decode("\xa8\xeb\x10\x64\x9c\xbf".b)).to eq 'no-cache'
13
+ end
14
+
15
+ it 'should not decode' do
16
+ expect { HPACK::Huffman.decode("\xff\xff\xff\xff".b) }.to raise_error HPACK::Error::HuffmanDecodeError
17
+ expect { HPACK::Huffman.decode("\xf8\xff".b) }.to raise_error HPACK::Error::HuffmanDecodeError
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe HPACK::Integer do
4
+ context do
5
+ let(:mask) do
6
+ 0b00000000
7
+ end
8
+
9
+ it 'should encode' do
10
+ expect(HPACK::Integer.encode(10, 5, mask)).to eq "\x0a".b
11
+ expect(HPACK::Integer.encode(1337, 5, mask)).to eq "\x1f\x9a\x0a".b
12
+ expect(HPACK::Integer.encode(42, 8, mask)).to eq "\x2a".b
13
+ end
14
+
15
+ let(:cursor) do
16
+ 0
17
+ end
18
+
19
+ it 'should decode' do
20
+ expect(HPACK::Integer.decode("\x0a".b, 5, cursor)).to eq [10, 1]
21
+ expect(HPACK::Integer.decode("\x1f\x9a\x0a".b, 5, cursor)).to eq [1337, 3]
22
+ expect(HPACK::Integer.decode("\x2a".b, 8, cursor)).to eq [42, 1]
23
+ expect(HPACK::Integer.decode("\x8a".b, 5, cursor)).to eq [10, 1]
24
+ expect(HPACK::Integer.decode("\x0a\x0b".b, 5, 1)).to eq [11, 2]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe HPACK::String do
4
+ context do
5
+ it 'should encode' do
6
+ expect(HPACK::String.encode('custom-key')).to eq "\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f".b
7
+ expect(HPACK::String.encode('\\')).to eq "\x01\x5c".b
8
+ end
9
+
10
+ let(:cursor) do
11
+ 0
12
+ end
13
+
14
+ it 'should decode' do
15
+ expect(HPACK::String.decode("\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f".b, cursor)).to eq ['custom-key', 9]
16
+ expect(HPACK::String.decode("\x01\x5c".b, cursor)).to eq ['\\', 2]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe HTTPRequestBuilder do
4
+ context 'field' do
5
+ let(:builder) do
6
+ HTTPRequestBuilder.new
7
+ end
8
+ it 'should field' do
9
+ expect(builder.field('key', 'value')).to eq nil
10
+ end
11
+ it 'should not field' do
12
+ expect(builder.field('KEY', 'VALUE')).to be_kind_of ConnectionError
13
+ expect(builder.field(':key', 'value')).to be_kind_of ConnectionError
14
+ expect(builder.field(':path', '')).to be_kind_of ConnectionError
15
+ expect(builder.field('connection', 'keep-alive')).to be_kind_of ConnectionError
16
+ expect(builder.field(':authority', 'localhost:8888')).to eq nil
17
+ expect(builder.field(':authority', 'localhost:8888')).to be_kind_of ConnectionError
18
+ end
19
+ end
20
+
21
+ context 'http_request' do
22
+ it 'should build' do
23
+ expect(HTTPRequestBuilder.http_request({ ':method' => 'GET', ':scheme' => 'http', ':path' => '/', ':authority' => 'localhost:8888' }, '')).to be_kind_of HTTPRequest
24
+ end
25
+ it 'should not build' do
26
+ expect(HTTPRequestBuilder.http_request({ ':scheme' => 'http', ':path' => '/', ':authority' => 'localhost:8888' }, '')).to be_kind_of ConnectionError
27
+ expect(HTTPRequestBuilder.http_request({ ':method' => 'GET', ':scheme' => 'http', ':path' => '/', ':authority' => 'localhost:8888', 'content-length' => '0' }, '1')).to be_kind_of ConnectionError
28
+ end
29
+ end
30
+
31
+ context 'cookie' do
32
+ let(:request) do
33
+ builder = HTTPRequestBuilder.new
34
+ builder.fields({ ':method' => 'GET', ':scheme' => 'http', ':path' => '/', ':authority' => 'localhost:8888' })
35
+ builder.field('cookie', 'a=1')
36
+ builder.field('cookie', 'b=2')
37
+ builder.field('cookie', 'c=3')
38
+ builder.field('cookie', 'd=4')
39
+ builder.build('')
40
+ end
41
+ it 'should field' do
42
+ expect(request.fields['cookie']).to eq 'a=1; b=2; c=3; d=4'
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,9 @@
1
+ require 'biryani'
2
+
3
+ # rubocop: disable Style/MixinUsage
4
+ include Biryani
5
+ # rubocop: enable Style/MixinUsage
6
+
7
+ def do_nothing_proc
8
+ Ractor.shareable_proc { |_, _| }
9
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: biryani
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - thekuwayama
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bundler
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ description: An HTTP/2 server implemented using Ruby Ractor
27
+ email:
28
+ - thekuwayama@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - ".github/workflows/ci.yml"
34
+ - ".gitignore"
35
+ - ".rubocop.yml"
36
+ - ".ruby-version"
37
+ - Gemfile
38
+ - LICENSE.txt
39
+ - README.md
40
+ - Rakefile
41
+ - biryani.gemspec
42
+ - example/echo.rb
43
+ - example/hello_world.rb
44
+ - lib/biryani.rb
45
+ - lib/biryani/connection.rb
46
+ - lib/biryani/connection_error.rb
47
+ - lib/biryani/data_buffer.rb
48
+ - lib/biryani/frame.rb
49
+ - lib/biryani/frame/continuation.rb
50
+ - lib/biryani/frame/data.rb
51
+ - lib/biryani/frame/goaway.rb
52
+ - lib/biryani/frame/headers.rb
53
+ - lib/biryani/frame/ping.rb
54
+ - lib/biryani/frame/priority.rb
55
+ - lib/biryani/frame/push_promise.rb
56
+ - lib/biryani/frame/rst_stream.rb
57
+ - lib/biryani/frame/settings.rb
58
+ - lib/biryani/frame/unknown.rb
59
+ - lib/biryani/frame/window_update.rb
60
+ - lib/biryani/hpack.rb
61
+ - lib/biryani/hpack/decoder.rb
62
+ - lib/biryani/hpack/dynamic_table.rb
63
+ - lib/biryani/hpack/encoder.rb
64
+ - lib/biryani/hpack/error.rb
65
+ - lib/biryani/hpack/field.rb
66
+ - lib/biryani/hpack/fields.rb
67
+ - lib/biryani/hpack/huffman.rb
68
+ - lib/biryani/hpack/integer.rb
69
+ - lib/biryani/hpack/option.rb
70
+ - lib/biryani/hpack/string.rb
71
+ - lib/biryani/http_request.rb
72
+ - lib/biryani/http_response.rb
73
+ - lib/biryani/server.rb
74
+ - lib/biryani/state.rb
75
+ - lib/biryani/stream.rb
76
+ - lib/biryani/stream_error.rb
77
+ - lib/biryani/streams_context.rb
78
+ - lib/biryani/version.rb
79
+ - lib/biryani/window.rb
80
+ - spec/connection/close_all_streams_spec.rb
81
+ - spec/connection/handle_connection_window_update_spec.rb
82
+ - spec/connection/handle_ping_spec.rb
83
+ - spec/connection/handle_rst_stream_spec.rb
84
+ - spec/connection/handle_settings_spec.rb
85
+ - spec/connection/handle_stream_window_update_spec.rb
86
+ - spec/connection/read_http2_magic_spec.rb
87
+ - spec/connection/remove_closed_streams_spec.rb
88
+ - spec/connection/send_spec.rb
89
+ - spec/connection/transition_state_send_spec.rb
90
+ - spec/connection/unwrap_spec.rb
91
+ - spec/data_buffer_spec.rb
92
+ - spec/frame/continuation_spec.rb
93
+ - spec/frame/data_spec.rb
94
+ - spec/frame/goaway_spec.rb
95
+ - spec/frame/headers_spec.rb
96
+ - spec/frame/ping_spec.rb
97
+ - spec/frame/priority_spec.rb
98
+ - spec/frame/push_promise_spec.rb
99
+ - spec/frame/read_spec.rb
100
+ - spec/frame/rst_stream_spec.rb
101
+ - spec/frame/settings_spec.rb
102
+ - spec/frame/window_update_spec.rb
103
+ - spec/hpack/decoder_spec.rb
104
+ - spec/hpack/encoder_spec.rb
105
+ - spec/hpack/field_spec.rb
106
+ - spec/hpack/fields_spec.rb
107
+ - spec/hpack/huffman_spec.rb
108
+ - spec/hpack/integer_spec.rb
109
+ - spec/hpack/string_spec.rb
110
+ - spec/http_request_builder_spec.rb
111
+ - spec/spec_helper.rb
112
+ homepage: https://github.com/thekuwayama/biryani
113
+ licenses:
114
+ - MIT
115
+ metadata: {}
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '4.0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubygems_version: 4.0.3
131
+ specification_version: 4
132
+ summary: An HTTP/2 server implemented using Ruby Ractor
133
+ test_files:
134
+ - spec/connection/close_all_streams_spec.rb
135
+ - spec/connection/handle_connection_window_update_spec.rb
136
+ - spec/connection/handle_ping_spec.rb
137
+ - spec/connection/handle_rst_stream_spec.rb
138
+ - spec/connection/handle_settings_spec.rb
139
+ - spec/connection/handle_stream_window_update_spec.rb
140
+ - spec/connection/read_http2_magic_spec.rb
141
+ - spec/connection/remove_closed_streams_spec.rb
142
+ - spec/connection/send_spec.rb
143
+ - spec/connection/transition_state_send_spec.rb
144
+ - spec/connection/unwrap_spec.rb
145
+ - spec/data_buffer_spec.rb
146
+ - spec/frame/continuation_spec.rb
147
+ - spec/frame/data_spec.rb
148
+ - spec/frame/goaway_spec.rb
149
+ - spec/frame/headers_spec.rb
150
+ - spec/frame/ping_spec.rb
151
+ - spec/frame/priority_spec.rb
152
+ - spec/frame/push_promise_spec.rb
153
+ - spec/frame/read_spec.rb
154
+ - spec/frame/rst_stream_spec.rb
155
+ - spec/frame/settings_spec.rb
156
+ - spec/frame/window_update_spec.rb
157
+ - spec/hpack/decoder_spec.rb
158
+ - spec/hpack/encoder_spec.rb
159
+ - spec/hpack/field_spec.rb
160
+ - spec/hpack/fields_spec.rb
161
+ - spec/hpack/huffman_spec.rb
162
+ - spec/hpack/integer_spec.rb
163
+ - spec/hpack/string_spec.rb
164
+ - spec/http_request_builder_spec.rb
165
+ - spec/spec_helper.rb