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.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +30 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +36 -0
- data/.ruby-version +1 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +48 -0
- data/Rakefile +8 -0
- data/biryani.gemspec +21 -0
- data/example/echo.rb +27 -0
- data/example/hello_world.rb +22 -0
- data/lib/biryani/connection.rb +464 -0
- data/lib/biryani/connection_error.rb +17 -0
- data/lib/biryani/data_buffer.rb +42 -0
- data/lib/biryani/frame/continuation.rb +48 -0
- data/lib/biryani/frame/data.rb +70 -0
- data/lib/biryani/frame/goaway.rb +44 -0
- data/lib/biryani/frame/headers.rb +110 -0
- data/lib/biryani/frame/ping.rb +49 -0
- data/lib/biryani/frame/priority.rb +44 -0
- data/lib/biryani/frame/push_promise.rb +75 -0
- data/lib/biryani/frame/rst_stream.rb +40 -0
- data/lib/biryani/frame/settings.rb +66 -0
- data/lib/biryani/frame/unknown.rb +42 -0
- data/lib/biryani/frame/window_update.rb +43 -0
- data/lib/biryani/frame.rb +146 -0
- data/lib/biryani/hpack/decoder.rb +22 -0
- data/lib/biryani/hpack/dynamic_table.rb +65 -0
- data/lib/biryani/hpack/encoder.rb +22 -0
- data/lib/biryani/hpack/error.rb +12 -0
- data/lib/biryani/hpack/field.rb +357 -0
- data/lib/biryani/hpack/fields.rb +28 -0
- data/lib/biryani/hpack/huffman.rb +309 -0
- data/lib/biryani/hpack/integer.rb +66 -0
- data/lib/biryani/hpack/option.rb +24 -0
- data/lib/biryani/hpack/string.rb +40 -0
- data/lib/biryani/hpack.rb +84 -0
- data/lib/biryani/http_request.rb +83 -0
- data/lib/biryani/http_response.rb +61 -0
- data/lib/biryani/server.rb +19 -0
- data/lib/biryani/state.rb +224 -0
- data/lib/biryani/stream.rb +19 -0
- data/lib/biryani/stream_error.rb +17 -0
- data/lib/biryani/streams_context.rb +89 -0
- data/lib/biryani/version.rb +3 -0
- data/lib/biryani/window.rb +29 -0
- data/lib/biryani.rb +17 -0
- data/spec/connection/close_all_streams_spec.rb +17 -0
- data/spec/connection/handle_connection_window_update_spec.rb +16 -0
- data/spec/connection/handle_ping_spec.rb +21 -0
- data/spec/connection/handle_rst_stream_spec.rb +21 -0
- data/spec/connection/handle_settings_spec.rb +31 -0
- data/spec/connection/handle_stream_window_update_spec.rb +20 -0
- data/spec/connection/read_http2_magic_spec.rb +26 -0
- data/spec/connection/remove_closed_streams_spec.rb +51 -0
- data/spec/connection/send_spec.rb +114 -0
- data/spec/connection/transition_state_send_spec.rb +39 -0
- data/spec/connection/unwrap_spec.rb +28 -0
- data/spec/data_buffer_spec.rb +135 -0
- data/spec/frame/continuation_spec.rb +39 -0
- data/spec/frame/data_spec.rb +25 -0
- data/spec/frame/goaway_spec.rb +23 -0
- data/spec/frame/headers_spec.rb +52 -0
- data/spec/frame/ping_spec.rb +22 -0
- data/spec/frame/priority_spec.rb +22 -0
- data/spec/frame/push_promise_spec.rb +24 -0
- data/spec/frame/read_spec.rb +30 -0
- data/spec/frame/rst_stream_spec.rb +21 -0
- data/spec/frame/settings_spec.rb +23 -0
- data/spec/frame/window_update_spec.rb +21 -0
- data/spec/hpack/decoder_spec.rb +170 -0
- data/spec/hpack/encoder_spec.rb +48 -0
- data/spec/hpack/field_spec.rb +42 -0
- data/spec/hpack/fields_spec.rb +17 -0
- data/spec/hpack/huffman_spec.rb +20 -0
- data/spec/hpack/integer_spec.rb +27 -0
- data/spec/hpack/string_spec.rb +19 -0
- data/spec/http_request_builder_spec.rb +45 -0
- data/spec/spec_helper.rb +9 -0
- 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
|