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,114 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Connection do
4
+ context 'send' do
5
+ let(:io) do
6
+ StringIO.new
7
+ end
8
+ let(:data_buffer) do
9
+ DataBuffer.new
10
+ end
11
+
12
+ let(:headers1) do
13
+ Frame::Headers.new(true, false, 2, nil, nil, 'this is dummy', nil)
14
+ end
15
+ let(:data1) do
16
+ Frame::Data.new(true, 2, 'Hello, world!', 'Howdy!')
17
+ end
18
+ let(:send_window1) do
19
+ Window.new
20
+ end
21
+ let(:streams_ctx1) do
22
+ streams_ctx = StreamsContext.new
23
+ streams_ctx.new_context(1, do_nothing_proc)
24
+ streams_ctx.new_context(2, do_nothing_proc)
25
+ streams_ctx
26
+ end
27
+ it 'should send' do
28
+ streams_ctx1[2].state.transition!(headers1, :recv)
29
+ streams_ctx1[2].state.transition!(data1, :recv)
30
+ Connection.send(io, headers1, send_window1, streams_ctx1, data_buffer)
31
+ Connection.send(io, data1, send_window1, streams_ctx1, data_buffer)
32
+ expect(io.string).to eq "\x00\x00\x0d\x01\x04\x00\x00\x00\x02this is dummy\x00\x00\x14\x00\x09\x00\x00\x00\x02\x06\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x48\x6f\x77\x64\x79\x21".b
33
+ expect(send_window1.length).to eq 2**16 - 21
34
+ expect(streams_ctx1[1].send_window.length).to eq 2**16 - 1
35
+ expect(streams_ctx1[2].send_window.length).to eq 2**16 - 21
36
+ expect(data_buffer.length).to eq 0
37
+ end
38
+
39
+ let(:headers2) do
40
+ Frame::Headers.new(true, true, 1, nil, nil, 'this is dummy', nil)
41
+ end
42
+ let(:send_window2) do
43
+ Window.new
44
+ end
45
+ let(:streams_ctx2) do
46
+ streams_ctx = StreamsContext.new
47
+ streams_ctx.new_context(1, do_nothing_proc)
48
+ streams_ctx.new_context(2, do_nothing_proc)
49
+ streams_ctx
50
+ end
51
+ it 'should send' do
52
+ streams_ctx2[1].state.transition!(headers2, :recv)
53
+ Connection.send(io, headers2, send_window2, streams_ctx2, data_buffer)
54
+ expect(io.string).to eq "\x00\x00\x0d\x01\x05\x00\x00\x00\x01\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79".b
55
+ expect(send_window2.length).to eq 2**16 - 1
56
+ expect(streams_ctx2[1].send_window.length).to eq 2**16 - 1
57
+ expect(streams_ctx2[2].send_window.length).to eq 2**16 - 1
58
+ expect(data_buffer.length).to eq 0
59
+ end
60
+
61
+ let(:headers3) do
62
+ Frame::Headers.new(true, true, 2, nil, nil, 'this is dummy', nil)
63
+ end
64
+ let(:data3) do
65
+ Frame::Data.new(false, 2, 'Hello, world!', 'Howdy!')
66
+ end
67
+ let(:send_window3) do
68
+ Window.new
69
+ end
70
+ let(:streams_ctx3) do
71
+ streams_ctx = StreamsContext.new
72
+ streams_ctx.new_context(1, do_nothing_proc)
73
+ streams_ctx.new_context(2, do_nothing_proc)
74
+ streams_ctx[2].send_window.consume!(2**16 - 1)
75
+ streams_ctx
76
+ end
77
+ it 'should send' do
78
+ streams_ctx3[2].state.transition!(headers3, :recv)
79
+ Connection.send(io, data3, send_window3, streams_ctx3, data_buffer)
80
+ expect(io.string).to eq ''
81
+ expect(send_window3.length).to eq 2**16 - 1
82
+ expect(streams_ctx3[1].send_window.length).to eq 2**16 - 1
83
+ expect(streams_ctx3[2].send_window.length).to eq 0
84
+ expect(data_buffer.length).to eq 1
85
+ end
86
+
87
+ let(:headers4) do
88
+ Frame::Headers.new(true, true, 2, nil, nil, 'this is dummy', nil)
89
+ end
90
+ let(:data4) do
91
+ Frame::Data.new(false, 2, 'Hello, world!', 'Howdy!')
92
+ end
93
+ let(:send_window4) do
94
+ send_window = Window.new
95
+ send_window.consume!(2**16 - 1)
96
+ send_window
97
+ end
98
+ let(:streams_ctx4) do
99
+ streams_ctx = StreamsContext.new
100
+ streams_ctx.new_context(1, do_nothing_proc)
101
+ streams_ctx.new_context(2, do_nothing_proc)
102
+ streams_ctx
103
+ end
104
+ it 'should send' do
105
+ streams_ctx4[2].state.transition!(headers4, :recv)
106
+ Connection.send(io, data4, send_window4, streams_ctx4, data_buffer)
107
+ expect(io.string).to eq ''
108
+ expect(send_window4.length).to eq 0
109
+ expect(streams_ctx4[1].send_window.length).to eq 2**16 - 1
110
+ expect(streams_ctx4[2].send_window.length).to eq 2**16 - 1
111
+ expect(data_buffer.length).to eq 1
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Connection do
4
+ context 'transition_state_send' do
5
+ let(:streams_ctx) do
6
+ streams_ctx = StreamsContext.new
7
+ streams_ctx.new_context(1, do_nothing_proc)
8
+ streams_ctx.new_context(2, do_nothing_proc)
9
+ streams_ctx
10
+ end
11
+
12
+ let(:headers) do
13
+ Frame::Headers.new(true, true, 2, nil, nil, 'this is dummy', nil)
14
+ end
15
+ it 'should transition' do
16
+ streams_ctx[2].state.transition!(headers, :recv)
17
+ Connection.transition_state_send(headers, streams_ctx)
18
+ expect(streams_ctx.length).to eq 2
19
+ end
20
+
21
+ it 'should transition' do
22
+ streams_ctx[1].state.transition!(headers, :recv)
23
+ streams_ctx[2].state.transition!(headers, :recv)
24
+ Connection.close_all_streams(streams_ctx)
25
+ expect { streams_ctx[1].tx << nil }.to raise_error Ractor::ClosedError
26
+ expect { streams_ctx[2].tx << nil }.to raise_error Ractor::ClosedError
27
+ end
28
+
29
+ let(:rst_stream) do
30
+ Frame::RstStream.new(2, 0)
31
+ end
32
+ it 'should transition' do
33
+ streams_ctx[2].state.transition!(headers, :recv)
34
+ Connection.transition_state_send(rst_stream, streams_ctx)
35
+ expect { streams_ctx[1].tx << nil }.to_not raise_error
36
+ expect { streams_ctx[2].tx << nil }.to_not raise_error
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Connection do
4
+ context 'unwrap' do
5
+ let(:data) do
6
+ Frame::Data.new(false, 2, 'Hello, world!', 'Howdy!')
7
+ end
8
+ it 'should ensure' do
9
+ expect(Connection.unwrap(data, 0x01)).to eq data
10
+ end
11
+
12
+ let(:connection_error) do
13
+ ConnectionError.new(ErrorCode::NO_ERROR, 'debug')
14
+ end
15
+ it 'should ensure' do
16
+ frame = Connection.unwrap(connection_error, 0x01)
17
+ expect(frame).to be_kind_of Frame::Goaway
18
+ end
19
+
20
+ let(:stream_error) do
21
+ StreamError.new(ErrorCode::NO_ERROR, 0x01, 'debug')
22
+ end
23
+ it 'should ensure' do
24
+ frame = Connection.unwrap(stream_error, 0x01)
25
+ expect(frame).to be_kind_of Frame::RstStream
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,135 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe DataBuffer do
4
+ context 'take!' do
5
+ let(:data_buffer1) do
6
+ DataBuffer.new
7
+ end
8
+ let(:send_window1) do
9
+ Window.new
10
+ end
11
+ let(:streams_ctx1) do
12
+ streams_ctx = StreamsContext.new
13
+ streams_ctx.new_context(1, do_nothing_proc)
14
+ streams_ctx.new_context(2, do_nothing_proc)
15
+ streams_ctx
16
+ end
17
+ it 'should take' do
18
+ expect(data_buffer1.take!(send_window1, streams_ctx1).length).to eq 0
19
+ expect(send_window1.length).to eq 2**16 - 1
20
+ expect(streams_ctx1[1].send_window.length).to eq 2**16 - 1
21
+ expect(streams_ctx1[2].send_window.length).to eq 2**16 - 1
22
+ end
23
+
24
+ let(:data_buffer2) do
25
+ data_buffer = DataBuffer.new
26
+ data_buffer << Frame::Data.new(false, 1, 'one', nil)
27
+ data_buffer << Frame::Data.new(false, 2, 'two', nil)
28
+ data_buffer
29
+ end
30
+ let(:send_window2) do
31
+ Window.new
32
+ end
33
+ let(:streams_ctx2) do
34
+ streams_ctx = StreamsContext.new
35
+ streams_ctx.new_context(1, do_nothing_proc)
36
+ streams_ctx.new_context(2, do_nothing_proc)
37
+ streams_ctx
38
+ end
39
+ it 'should take' do
40
+ datas = data_buffer2.take!(send_window2, streams_ctx2)
41
+ expect(datas.length).to eq 2
42
+ expect(datas.map(&:stream_id)).to eq [1, 2]
43
+ expect(datas.map(&:data)).to eq %w[one two]
44
+ expect(send_window2.length).to eq 2**16 - 7
45
+ expect(streams_ctx2[1].send_window.length).to eq 2**16 - 4
46
+ expect(streams_ctx2[2].send_window.length).to eq 2**16 - 4
47
+ end
48
+
49
+ let(:data_buffer3) do
50
+ data_buffer = DataBuffer.new
51
+ data_buffer << Frame::Data.new(false, 2, 'two', nil)
52
+ data_buffer
53
+ end
54
+ let(:send_window3) do
55
+ Window.new
56
+ end
57
+ let(:streams_ctx3) do
58
+ streams_ctx = StreamsContext.new
59
+ streams_ctx.new_context(1, do_nothing_proc)
60
+ streams_ctx.new_context(2, do_nothing_proc)
61
+ streams_ctx
62
+ end
63
+ it 'should take' do
64
+ datas = data_buffer3.take!(send_window3, streams_ctx3)
65
+ expect(datas.length).to eq 1
66
+ expect(datas.first.stream_id).to eq 2
67
+ expect(datas.first.data).to eq 'two'
68
+ expect(send_window3.length).to eq 2**16 - 4
69
+ expect(streams_ctx3[1].send_window.length).to eq 2**16 - 1
70
+ expect(streams_ctx3[2].send_window.length).to eq 2**16 - 4
71
+ end
72
+
73
+ let(:data_buffer4) do
74
+ data_buffer = DataBuffer.new
75
+ data_buffer << Frame::Data.new(false, 1, 'one', nil)
76
+ data_buffer << Frame::Data.new(false, 2, 'two', nil)
77
+ data_buffer
78
+ end
79
+ let(:send_window4) do
80
+ Window.new
81
+ end
82
+ let(:streams_ctx4) do
83
+ streams_ctx = StreamsContext.new
84
+ streams_ctx.new_context(1, do_nothing_proc)
85
+ streams_ctx[1].send_window.consume!(2**16 - 1)
86
+ streams_ctx.new_context(2, do_nothing_proc)
87
+ streams_ctx
88
+ end
89
+ it 'should take' do
90
+ datas = data_buffer4.take!(send_window4, streams_ctx4)
91
+ expect(datas.length).to eq 1
92
+ expect(datas.first.stream_id).to eq 2
93
+ expect(datas.first.data).to eq 'two'
94
+ expect(send_window4.length).to eq 2**16 - 4
95
+ expect(streams_ctx4[1].send_window.length).to eq 0
96
+ expect(streams_ctx4[2].send_window.length).to eq 2**16 - 4
97
+ end
98
+
99
+ let(:data_buffer5) do
100
+ data_buffer = DataBuffer.new
101
+ data_buffer << Frame::Data.new(false, 1, 'one', nil)
102
+ data_buffer << Frame::Data.new(false, 2, 'two', nil)
103
+ data_buffer
104
+ end
105
+ let(:send_window5) do
106
+ send_window = Window.new
107
+ send_window.consume!(2**16 - 1)
108
+ send_window
109
+ end
110
+ let(:streams_ctx5) do
111
+ streams_ctx = StreamsContext.new
112
+ streams_ctx.new_context(1, do_nothing_proc)
113
+ streams_ctx.new_context(2, do_nothing_proc)
114
+ streams_ctx
115
+ end
116
+ it 'should take' do
117
+ expect(data_buffer5.take!(send_window5, streams_ctx5).length).to eq 0
118
+ expect(send_window5.length).to eq 0
119
+ expect(streams_ctx5[1].send_window.length).to eq 2**16 - 1
120
+ expect(streams_ctx5[2].send_window.length).to eq 2**16 - 1
121
+ end
122
+ end
123
+
124
+ context 'has?' do
125
+ let(:data_buffer6) do
126
+ data_buffer = DataBuffer.new
127
+ data_buffer << Frame::Data.new(false, 1, 'one', nil)
128
+ data_buffer
129
+ end
130
+ it 'should take' do
131
+ expect(data_buffer6.has?(1)).to eq true
132
+ expect(data_buffer6.has?(2)).to eq false
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::Continuation do
4
+ context do
5
+ let(:continuation1) do
6
+ Frame::Continuation.new(false, 50, '')
7
+ end
8
+ it 'should encode' do
9
+ expect(continuation1.to_binary_s).to eq "\x00\x00\x00\x09\x00\x00\x00\x00\x32".b
10
+ end
11
+
12
+ let(:continuation2) do
13
+ Frame::Continuation.new(false, 50, 'this is dummy')
14
+ end
15
+ it 'should encode' do
16
+ expect(continuation2.to_binary_s).to eq "\x00\x00\x0d\x09\x00\x00\x00\x00\x32\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79".b
17
+ end
18
+
19
+ let(:continuation3) do
20
+ Frame::Continuation.read("\x00\x00\x00\x09\x00\x00\x00\x00\x32".b)
21
+ end
22
+ it 'should decode' do
23
+ expect(continuation3.f_type).to eq FrameType::CONTINUATION
24
+ expect(continuation3.end_headers?).to eq false
25
+ expect(continuation3.stream_id).to eq 50
26
+ expect(continuation3.fragment).to eq ''
27
+ end
28
+
29
+ let(:continuation4) do
30
+ Frame::Continuation.read("\x00\x00\x0d\x09\x00\x00\x00\x00\x32\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79".b)
31
+ end
32
+ it 'should decode' do
33
+ expect(continuation4.f_type).to eq FrameType::CONTINUATION
34
+ expect(continuation4.end_headers?).to eq false
35
+ expect(continuation4.stream_id).to eq 50
36
+ expect(continuation4.fragment).to eq 'this is dummy'
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::Data do
4
+ context do
5
+ let(:data1) do
6
+ Frame::Data.new(false, 2, 'Hello, world!', 'Howdy!')
7
+ end
8
+ it 'should encode' do
9
+ expect(data1.to_binary_s).to eq "\x00\x00\x14\x00\x08\x00\x00\x00\x02\x06\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x48\x6f\x77\x64\x79\x21".b
10
+ end
11
+
12
+ let(:data2) do
13
+ Frame::Data.read("\x00\x00\x14\x00\x08\x00\x00\x00\x02\x06\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x48\x6f\x77\x64\x79\x21".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(data2.f_type).to eq FrameType::DATA
17
+ expect(data2.end_stream?).to eq false
18
+ expect(data2.stream_id).to eq 2
19
+ expect(data2.data).to eq 'Hello, world!'
20
+ expect(data2.padding).to eq 'Howdy!'
21
+ expect(data2.padded?).to eq true
22
+ expect(data2.length).to eq 20
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::Goaway do
4
+ context do
5
+ let(:goaway1) do
6
+ Frame::Goaway.new(0, 30, 9, 'hpack is broken')
7
+ end
8
+ it 'should encode' do
9
+ expect(goaway1.to_binary_s).to eq "\x00\x00\x17\x07\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x09\x68\x70\x61\x63\x6b\x20\x69\x73\x20\x62\x72\x6f\x6b\x65\x6e".b
10
+ end
11
+
12
+ let(:goaway2) do
13
+ Frame::Goaway.read("\x00\x00\x17\x07\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x09\x68\x70\x61\x63\x6b\x20\x69\x73\x20\x62\x72\x6f\x6b\x65\x6e".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(goaway2.f_type).to eq FrameType::GOAWAY
17
+ expect(goaway2.stream_id).to eq 0
18
+ expect(goaway2.last_stream_id).to eq 30
19
+ expect(goaway2.error_code).to eq 9
20
+ expect(goaway2.debug).to eq 'hpack is broken'
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,52 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::Headers do
4
+ context do
5
+ let(:headers1) do
6
+ Frame::Headers.new(true, false, 1, nil, nil, 'this is dummy', nil)
7
+ end
8
+ it 'should encode' do
9
+ expect(headers1.to_binary_s).to eq "\x00\x00\x0d\x01\x04\x00\x00\x00\x01\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79".b
10
+ end
11
+
12
+ let(:headers2) do
13
+ Frame::Headers.new(true, false, 3, 20, 10, 'this is dummy', 'This is padding.')
14
+ end
15
+ it 'should encode' do
16
+ expect(headers2.to_binary_s)
17
+ .to eq "\x00\x00\x23\x01\x2c\x00\x00\x00\x03\x10\x00\x00\x00\x14\x0a\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79\x54\x68\x69\x73\x20\x69\x73\x20\x70\x61\x64\x64\x69\x6e\x67\x2e".b
18
+ end
19
+
20
+ let(:headers3) do
21
+ Frame::Headers.read("\x00\x00\x0d\x01\x04\x00\x00\x00\x01\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79".b)
22
+ end
23
+ it 'should decode' do
24
+ expect(headers3.f_type).to eq FrameType::HEADERS
25
+ expect(headers3.end_headers?).to eq true
26
+ expect(headers3.end_stream?).to eq false
27
+ expect(headers3.stream_id).to eq 1
28
+ expect(headers3.stream_dependency).to eq nil
29
+ expect(headers3.weight).to eq nil
30
+ expect(headers3.fragment).to eq 'this is dummy'
31
+ expect(headers3.padding).to eq nil
32
+ expect(headers3.priority?).to eq false
33
+ expect(headers3.padded?).to eq false
34
+ end
35
+
36
+ let(:headers4) do
37
+ Frame::Headers.read("\x00\x00\x23\x01\x2c\x00\x00\x00\x03\x10\x00\x00\x00\x14\x0a\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79\x54\x68\x69\x73\x20\x69\x73\x20\x70\x61\x64\x64\x69\x6e\x67\x2e".b)
38
+ end
39
+ it 'should decode' do
40
+ expect(headers4.f_type).to eq FrameType::HEADERS
41
+ expect(headers4.end_headers?).to eq true
42
+ expect(headers4.end_stream?).to eq false
43
+ expect(headers4.stream_id).to eq 3
44
+ expect(headers4.stream_dependency).to eq 20
45
+ expect(headers4.weight).to eq 10
46
+ expect(headers4.fragment).to eq 'this is dummy'
47
+ expect(headers4.padding).to eq 'This is padding.'
48
+ expect(headers4.priority?).to eq true
49
+ expect(headers4.padded?).to eq true
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::Ping do
4
+ context do
5
+ let(:ping1) do
6
+ Frame::Ping.new(false, 0, 'deadbeef')
7
+ end
8
+ it 'should encode' do
9
+ expect(ping1.to_binary_s).to eq "\x00\x00\x08\x06\x00\x00\x00\x00\x00\x64\x65\x61\x64\x62\x65\x65\x66".b
10
+ end
11
+
12
+ let(:ping2) do
13
+ Frame::Ping.read("\x00\x00\x08\x06\x00\x00\x00\x00\x00\x64\x65\x61\x64\x62\x65\x65\x66".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(ping2.f_type).to eq FrameType::PING
17
+ expect(ping2.ack?).to eq false
18
+ expect(ping2.stream_id).to eq 0
19
+ expect(ping2.opaque).to eq 'deadbeef'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::Priority do
4
+ context do
5
+ let(:priority1) do
6
+ Frame::Priority.new(9, 11, 8)
7
+ end
8
+ it 'should encode' do
9
+ expect(priority1.to_binary_s).to eq "\x00\x00\x05\x02\x00\x00\x00\x00\x09\x00\x00\x00\x0b\x08".b
10
+ end
11
+
12
+ let(:priority2) do
13
+ Frame::Priority.read("\x00\x00\x05\x02\x00\x00\x00\x00\x09\x00\x00\x00\x0b\x08".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(priority2.f_type).to eq FrameType::PRIORITY
17
+ expect(priority2.stream_id).to eq 9
18
+ expect(priority2.stream_dependency).to eq 11
19
+ expect(priority2.weight).to eq 8
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::PushPromise do
4
+ context do
5
+ let(:push_promise1) do
6
+ Frame::PushPromise.new(true, 10, 12, 'this is dummy', 'Howdy!')
7
+ end
8
+ it 'should encode' do
9
+ expect(push_promise1.to_binary_s).to eq "\x00\x00\x18\x05\x0c\x00\x00\x00\x0a\x06\x00\x00\x00\x0c\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79\x48\x6f\x77\x64\x79\x21".b
10
+ end
11
+
12
+ let(:push_promise2) do
13
+ Frame::PushPromise.read("\x00\x00\x18\x05\x0c\x00\x00\x00\x0a\x06\x00\x00\x00\x0c\x74\x68\x69\x73\x20\x69\x73\x20\x64\x75\x6d\x6d\x79\x48\x6f\x77\x64\x79\x21".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(push_promise2.f_type).to eq FrameType::PUSH_PROMISE
17
+ expect(push_promise2.padded?).to eq true
18
+ expect(push_promise2.stream_id).to eq 10
19
+ expect(push_promise2.promised_stream_id).to eq 12
20
+ expect(push_promise2.fragment).to eq 'this is dummy'
21
+ expect(push_promise2.padding).to eq 'Howdy!'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame do
4
+ context do
5
+ let(:empty) do
6
+ StringIO.new(''.b)
7
+ end
8
+ it 'should not read' do
9
+ expect(Frame.read(empty)).to eq nil
10
+ end
11
+
12
+ let(:invalid_header) do
13
+ StringIO.new("\x12\x34\x56\x00\x00".b)
14
+ end
15
+ it 'should not read' do
16
+ expect(Frame.read(invalid_header)).to be_kind_of ConnectionError
17
+ end
18
+
19
+ let(:unknown) do
20
+ StringIO.new("\x00\x00\x01\x0a\x01\x00\x00\x00\x01\xff".b)
21
+ end
22
+ it 'should read' do
23
+ frame = Frame.read(unknown)
24
+ expect(frame.f_type).to eq 0x0a
25
+ expect(frame.flags).to eq 0x01
26
+ expect(frame.stream_id).to eq 0x01
27
+ expect(frame.payload).to eq "\xff".b
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::RstStream do
4
+ context do
5
+ let(:rst_stream1) do
6
+ Frame::RstStream.new(5, 8)
7
+ end
8
+ it 'should encode' do
9
+ expect(rst_stream1.to_binary_s).to eq "\x00\x00\x04\x03\x00\x00\x00\x00\x05\x00\x00\x00\x08".b
10
+ end
11
+
12
+ let(:rst_stream2) do
13
+ Frame::RstStream.read("\x00\x00\x04\x03\x00\x00\x00\x00\x05\x00\x00\x00\x08".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(rst_stream2.f_type).to eq FrameType::RST_STREAM
17
+ expect(rst_stream2.stream_id).to eq 5
18
+ expect(rst_stream2.error_code).to eq 8
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::Settings do
4
+ context do
5
+ let(:settings1) do
6
+ Frame::Settings.new(false, 0, { 1 => 8192, 3 => 5000 })
7
+ end
8
+ it 'should encode' do
9
+ expect(settings1.to_binary_s).to eq "\x00\x00\x0c\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x20\x00\x00\x03\x00\x00\x13\x88".b
10
+ end
11
+
12
+ let(:settings2) do
13
+ Frame::Settings.read("\x00\x00\x0c\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x20\x00\x00\x03\x00\x00\x13\x88".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(settings2.f_type).to eq FrameType::SETTINGS
17
+ expect(settings2.ack?).to eq false
18
+ expect(settings2.stream_id).to eq 0
19
+ expect(settings2.setting[1]).to eq 8192
20
+ expect(settings2.setting[3]).to eq 5000
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../spec_helper'
2
+
3
+ RSpec.describe Frame::WindowUpdate do
4
+ context do
5
+ let(:window_update1) do
6
+ Frame::WindowUpdate.new(50, 1000)
7
+ end
8
+ it 'should encode' do
9
+ expect(window_update1.to_binary_s).to eq "\x00\x00\x04\x08\x00\x00\x00\x00\x32\x00\x00\x03\xe8".b
10
+ end
11
+
12
+ let(:window_update2) do
13
+ Frame::WindowUpdate.read("\x00\x00\x04\x08\x00\x00\x00\x00\x32\x00\x00\x03\xe8".b)
14
+ end
15
+ it 'should decode' do
16
+ expect(window_update2.f_type).to eq FrameType::WINDOW_UPDATE
17
+ expect(window_update2.stream_id).to eq 50
18
+ expect(window_update2.window_size_increment).to eq 1000
19
+ end
20
+ end
21
+ end