biryani 0.0.1 → 0.0.3
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 +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +7 -2
- data/example/echo.rb +2 -2
- data/example/hello_world.rb +2 -2
- data/lib/biryani/connection.rb +157 -139
- data/lib/biryani/data_buffer.rb +24 -16
- data/lib/biryani/frame/headers.rb +0 -2
- data/lib/biryani/http_response.rb +4 -20
- data/lib/biryani/state.rb +15 -3
- data/lib/biryani/streams_context.rb +54 -8
- data/lib/biryani/utils.rb +23 -0
- data/lib/biryani/version.rb +1 -1
- data/lib/biryani/window.rb +17 -12
- data/lib/biryani.rb +3 -2
- data/spec/connection/handle_connection_window_update_spec.rb +1 -1
- data/spec/connection/handle_data_spec.rb +58 -0
- data/spec/connection/handle_headers_spec.rb +19 -0
- data/spec/connection/handle_rst_stream_spec.rb +4 -9
- data/spec/connection/handle_settings_spec.rb +8 -2
- data/spec/connection/handle_stream_window_update_spec.rb +5 -5
- data/spec/connection/send_spec.rb +38 -48
- data/spec/connection/transition_state_send_spec.rb +4 -4
- data/spec/data_buffer_spec.rb +48 -48
- data/spec/hpack/decoder_spec.rb +33 -33
- data/spec/hpack/encoder_spec.rb +10 -10
- data/spec/hpack/fields_spec.rb +3 -3
- data/spec/streams_context_spec.rb +79 -0
- data/spec/utils_spec.rb +41 -0
- metadata +10 -7
- data/spec/connection/close_all_streams_spec.rb +0 -17
- data/spec/connection/remove_closed_streams_spec.rb +0 -51
- data/spec/connection/unwrap_spec.rb +0 -28
|
@@ -34,28 +34,12 @@ module Biryani
|
|
|
34
34
|
@res.content
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# @param stream_id [Integer]
|
|
38
37
|
# @param encoder [Encoder]
|
|
39
|
-
# @param max_frame_size [Integer]
|
|
40
38
|
#
|
|
41
|
-
# @return [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
frames = fragment.gsub(/.{1,#{max_frame_size}}/m).with_index.map do |s, index|
|
|
46
|
-
if index.zero?
|
|
47
|
-
Frame::Headers.new(len < 2, content.empty?, stream_id, nil, nil, s, nil)
|
|
48
|
-
else
|
|
49
|
-
Frame::Continuation.new(index == len - 1, stream_id, s)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
len = (content.bytesize + max_frame_size - 1) / max_frame_size
|
|
54
|
-
frames += content.gsub(/.{1,#{max_frame_size}}/m).with_index.map do |s, index|
|
|
55
|
-
Frame::Data.new(index == len - 1, stream_id, s, nil)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
frames
|
|
39
|
+
# @return [String] fragment
|
|
40
|
+
# @return [String] data
|
|
41
|
+
def parse(encoder)
|
|
42
|
+
[encoder.encode(fields), content]
|
|
59
43
|
end
|
|
60
44
|
end
|
|
61
45
|
end
|
data/lib/biryani/state.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Biryani
|
|
|
8
8
|
# @param direction [:send, :recv]
|
|
9
9
|
def transition!(frame, direction)
|
|
10
10
|
obj = self.class.next(@state, frame, direction)
|
|
11
|
-
return obj if
|
|
11
|
+
return obj if Biryani.err?(obj)
|
|
12
12
|
|
|
13
13
|
@state = obj
|
|
14
14
|
end
|
|
@@ -76,6 +76,8 @@ module Biryani
|
|
|
76
76
|
# receiving_continuation_data
|
|
77
77
|
in [:receiving_continuation_data, FrameType::RST_STREAM, _]
|
|
78
78
|
:closed
|
|
79
|
+
in [:receiving_continuation_data, FrameType::WINDOW_UPDATE, :recv]
|
|
80
|
+
state
|
|
79
81
|
in [:receiving_continuation_data, FrameType::CONTINUATION, :recv] if frame.end_headers?
|
|
80
82
|
:receiving_data
|
|
81
83
|
in [:receiving_continuation_data, FrameType::CONTINUATION, :recv]
|
|
@@ -86,6 +88,8 @@ module Biryani
|
|
|
86
88
|
# receiving_continuation
|
|
87
89
|
in [:receiving_continuation, FrameType::RST_STREAM, _]
|
|
88
90
|
:closed
|
|
91
|
+
in [:receiving_continuation, FrameType::WINDOW_UPDATE, :recv]
|
|
92
|
+
state
|
|
89
93
|
in [:receiving_continuation, FrameType::CONTINUATION, :recv] if frame.end_headers?
|
|
90
94
|
:half_closed_remote
|
|
91
95
|
in [:receiving_continuation, FrameType::CONTINUATION, :recv]
|
|
@@ -100,6 +104,8 @@ module Biryani
|
|
|
100
104
|
state
|
|
101
105
|
in [:receiving_data, FrameType::RST_STREAM, _]
|
|
102
106
|
:closed
|
|
107
|
+
in [:receiving_data, FrameType::WINDOW_UPDATE, _]
|
|
108
|
+
state
|
|
103
109
|
in [:receiving_data, _, _]
|
|
104
110
|
unexpected(ErrorCode::PROTOCOL_ERROR, state, typ, direction)
|
|
105
111
|
|
|
@@ -126,7 +132,7 @@ module Biryani
|
|
|
126
132
|
state
|
|
127
133
|
in [:half_closed_remote, FrameType::RST_STREAM, _]
|
|
128
134
|
:closed
|
|
129
|
-
in [half_closed_remote, FrameType::WINDOW_UPDATE,
|
|
135
|
+
in [:half_closed_remote, FrameType::WINDOW_UPDATE, _]
|
|
130
136
|
state
|
|
131
137
|
in [:half_closed_remote, _, :recv]
|
|
132
138
|
unexpected(ErrorCode::STREAM_CLOSED, state, typ, direction)
|
|
@@ -136,6 +142,8 @@ module Biryani
|
|
|
136
142
|
# sending_continuation_data
|
|
137
143
|
in [:sending_continuation_data, FrameType::RST_STREAM, :send]
|
|
138
144
|
:closed
|
|
145
|
+
in [:sending_continuation_data, FrameType::WINDOW_UPDATE, :recv]
|
|
146
|
+
state
|
|
139
147
|
in [:sending_continuation_data, FrameType::CONTINUATION, :send] if frame.end_headers?
|
|
140
148
|
:sending_data
|
|
141
149
|
in [:sending_continuation_data, FrameType::CONTINUATION, :send]
|
|
@@ -148,6 +156,8 @@ module Biryani
|
|
|
148
156
|
# sending_continuation
|
|
149
157
|
in [:sending_continuation, FrameType::RST_STREAM, :send]
|
|
150
158
|
:closed
|
|
159
|
+
in [:sending_continuation, FrameType::WINDOW_UPDATE, :recv]
|
|
160
|
+
state
|
|
151
161
|
in [:sending_continuation, FrameType::CONTINUATION, :send] if frame.end_headers?
|
|
152
162
|
:closed
|
|
153
163
|
in [:sending_continuation, FrameType::CONTINUATION, :send]
|
|
@@ -160,6 +170,8 @@ module Biryani
|
|
|
160
170
|
# sending_data
|
|
161
171
|
in [:sending_data, FrameType::DATA, :send] if frame.end_stream?
|
|
162
172
|
:closed
|
|
173
|
+
in [:sending_data, FrameType::WINDOW_UPDATE, :recv]
|
|
174
|
+
state
|
|
163
175
|
in [:sending_data, FrameType::DATA, :send]
|
|
164
176
|
state
|
|
165
177
|
in [:sending_data, FrameType::RST_STREAM, :send]
|
|
@@ -213,7 +225,7 @@ module Biryani
|
|
|
213
225
|
|
|
214
226
|
# @return [Boolean]
|
|
215
227
|
def active?
|
|
216
|
-
|
|
228
|
+
!%i[idle reserved_local reserved_remote closed].include?(@state)
|
|
217
229
|
end
|
|
218
230
|
|
|
219
231
|
# @return [Boolean]
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
module Biryani
|
|
2
2
|
class StreamsContext
|
|
3
|
-
def initialize
|
|
4
|
-
@h = {}
|
|
3
|
+
def initialize(proc)
|
|
4
|
+
@h = {} # Hash<Integer, StreamContext>
|
|
5
|
+
@proc = proc
|
|
5
6
|
end
|
|
6
7
|
|
|
7
8
|
# @param stream_id [Integer]
|
|
8
|
-
# @param
|
|
9
|
+
# @param send_initial_window_size [Integer]
|
|
10
|
+
# @param recv_initial_window_size [Integer]
|
|
9
11
|
#
|
|
10
12
|
# @return [StreamContext]
|
|
11
|
-
def new_context(stream_id,
|
|
12
|
-
ctx = StreamContext.new(stream_id, proc)
|
|
13
|
+
def new_context(stream_id, send_initial_window_size, recv_initial_window_size)
|
|
14
|
+
ctx = StreamContext.new(stream_id, send_initial_window_size, recv_initial_window_size, @proc)
|
|
13
15
|
@h[stream_id] = ctx
|
|
14
16
|
ctx
|
|
15
17
|
end
|
|
@@ -54,18 +56,62 @@ module Biryani
|
|
|
54
56
|
def last_stream_id
|
|
55
57
|
@h.reject { |_, ctx| ctx.idle? }.keys.max || 0
|
|
56
58
|
end
|
|
59
|
+
|
|
60
|
+
# @param stream_id [Integer]
|
|
61
|
+
# @param data [String]
|
|
62
|
+
# @param send_window [Window]
|
|
63
|
+
# @param max_frame_size [Integer]
|
|
64
|
+
#
|
|
65
|
+
# @return [Array<Object>] frames
|
|
66
|
+
# @return [String]
|
|
67
|
+
def sendable_datas(stream_id, data, send_window, max_frame_size)
|
|
68
|
+
len = [data.bytesize, send_window.length, @h[stream_id].send_window.length].min
|
|
69
|
+
|
|
70
|
+
payload = data[0...len]
|
|
71
|
+
remains = data[len..] || ''
|
|
72
|
+
|
|
73
|
+
len = (len + max_frame_size - 1) / max_frame_size
|
|
74
|
+
frames = payload.gsub(/.{1,#{max_frame_size}}/m).with_index.map do |s, index|
|
|
75
|
+
end_stream = remains.empty? && index == len - 1
|
|
76
|
+
Frame::Data.new(end_stream, stream_id, s, nil)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
[frames, remains]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @param data_buffer [DataBuffer]
|
|
83
|
+
def remove_closed(data_buffer)
|
|
84
|
+
closed_ids = closed_stream_ids.filter { |id| !data_buffer.has?(id) }
|
|
85
|
+
closed_ids.each do |id|
|
|
86
|
+
@h[id].tx.close
|
|
87
|
+
@h[id].stream.rx << nil
|
|
88
|
+
@h[id].fragment.close
|
|
89
|
+
@h[id].content.close
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def close_all
|
|
94
|
+
each do |ctx|
|
|
95
|
+
ctx.tx.close
|
|
96
|
+
ctx.fragment.close
|
|
97
|
+
ctx.content.close
|
|
98
|
+
ctx.state.close
|
|
99
|
+
end
|
|
100
|
+
end
|
|
57
101
|
end
|
|
58
102
|
|
|
59
103
|
class StreamContext
|
|
60
104
|
attr_accessor :stream, :tx, :send_window, :recv_window, :fragment, :content, :state
|
|
61
105
|
|
|
62
106
|
# @param stream_id [Integer]
|
|
107
|
+
# @param send_initial_window_size [Integer]
|
|
108
|
+
# @param recv_initial_window_size [Integer]
|
|
63
109
|
# @param proc [Proc]
|
|
64
|
-
def initialize(stream_id, proc)
|
|
110
|
+
def initialize(stream_id, send_initial_window_size, recv_initial_window_size, proc)
|
|
65
111
|
@tx = Ractor::Port.new
|
|
66
112
|
@stream = Stream.new(@tx, stream_id, proc)
|
|
67
|
-
@send_window = Window.new
|
|
68
|
-
@recv_window = Window.new
|
|
113
|
+
@send_window = Window.new(send_initial_window_size)
|
|
114
|
+
@recv_window = Window.new(recv_initial_window_size)
|
|
69
115
|
@fragment = StringIO.new
|
|
70
116
|
@content = StringIO.new
|
|
71
117
|
@state = State.new
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Biryani
|
|
2
|
+
# @param obj [Object]
|
|
3
|
+
#
|
|
4
|
+
# @return [Boolean]
|
|
5
|
+
def self.err?(obj)
|
|
6
|
+
obj.is_a?(StreamError) || obj.is_a?(ConnectionError)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# @param obj [Object, ConnectionError, StreamError] frame or error
|
|
10
|
+
# @param last_stream_id [Integer]
|
|
11
|
+
#
|
|
12
|
+
# @return [Frame]
|
|
13
|
+
def self.unwrap(obj, last_stream_id)
|
|
14
|
+
case obj
|
|
15
|
+
when ConnectionError
|
|
16
|
+
obj.goaway(last_stream_id)
|
|
17
|
+
when StreamError
|
|
18
|
+
obj.rst_stream
|
|
19
|
+
else
|
|
20
|
+
obj
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/biryani/version.rb
CHANGED
data/lib/biryani/window.rb
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
module Biryani
|
|
2
2
|
class Window
|
|
3
|
-
|
|
4
|
-
@window = 2**16 - 1
|
|
5
|
-
end
|
|
3
|
+
attr_reader :length, :capacity
|
|
6
4
|
|
|
7
|
-
# @param
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@window > length
|
|
5
|
+
# @param initial_window_size [Integer]
|
|
6
|
+
def initialize(initial_window_size)
|
|
7
|
+
@length = initial_window_size
|
|
8
|
+
@capacity = initial_window_size
|
|
12
9
|
end
|
|
13
10
|
|
|
14
11
|
# @param length [Integer]
|
|
12
|
+
#
|
|
13
|
+
# @return [Integer]
|
|
15
14
|
def consume!(length)
|
|
16
|
-
@
|
|
15
|
+
@length -= length
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
# @param length [Integer]
|
|
19
|
+
#
|
|
20
|
+
# @return [Integer]
|
|
20
21
|
def increase!(length)
|
|
21
|
-
@
|
|
22
|
+
@length += length
|
|
22
23
|
end
|
|
23
24
|
|
|
25
|
+
# @param initial_window_size [Integer]
|
|
26
|
+
#
|
|
24
27
|
# @return [Integer]
|
|
25
|
-
def
|
|
26
|
-
@
|
|
28
|
+
def update!(initial_window_size)
|
|
29
|
+
@length = initial_window_size - @capacity + @length
|
|
30
|
+
@capacity = initial_window_size
|
|
31
|
+
@length
|
|
27
32
|
end
|
|
28
33
|
end
|
|
29
34
|
end
|
data/lib/biryani.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require 'stringio'
|
|
2
2
|
require 'uri'
|
|
3
3
|
|
|
4
|
-
require_relative 'biryani/connection'
|
|
5
4
|
require_relative 'biryani/connection_error'
|
|
5
|
+
require_relative 'biryani/connection'
|
|
6
6
|
require_relative 'biryani/data_buffer'
|
|
7
7
|
require_relative 'biryani/frame'
|
|
8
8
|
require_relative 'biryani/hpack'
|
|
@@ -10,8 +10,9 @@ require_relative 'biryani/http_request'
|
|
|
10
10
|
require_relative 'biryani/http_response'
|
|
11
11
|
require_relative 'biryani/server'
|
|
12
12
|
require_relative 'biryani/state'
|
|
13
|
-
require_relative 'biryani/streams_context'
|
|
14
13
|
require_relative 'biryani/stream_error'
|
|
15
14
|
require_relative 'biryani/stream'
|
|
15
|
+
require_relative 'biryani/streams_context'
|
|
16
|
+
require_relative 'biryani/utils'
|
|
16
17
|
require_relative 'biryani/version'
|
|
17
18
|
require_relative 'biryani/window'
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Connection do
|
|
4
|
+
context 'handle_data' do
|
|
5
|
+
let(:decoder) do
|
|
6
|
+
HPACK::Decoder.new(4_096)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
let(:recv_window1) do
|
|
10
|
+
Window.new(65_535)
|
|
11
|
+
end
|
|
12
|
+
let(:streams_ctx1) do
|
|
13
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
14
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
15
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
16
|
+
streams_ctx
|
|
17
|
+
end
|
|
18
|
+
it 'should handle' do
|
|
19
|
+
expect(Connection.handle_data(2, 'Hello, world!', recv_window1, streams_ctx1, decoder)).to eq []
|
|
20
|
+
expect(streams_ctx1[2].content.string).to eq 'Hello, world!'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
let(:recv_window2) do
|
|
24
|
+
recv_window = Window.new(65_535)
|
|
25
|
+
recv_window.consume!(65_535 / 2)
|
|
26
|
+
recv_window
|
|
27
|
+
end
|
|
28
|
+
let(:streams_ctx2) do
|
|
29
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
30
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
31
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
32
|
+
streams_ctx[2].recv_window.consume!(65_535 / 2)
|
|
33
|
+
streams_ctx
|
|
34
|
+
end
|
|
35
|
+
it 'should handle' do
|
|
36
|
+
frames = Connection.handle_data(2, 'Hello, world!', recv_window2, streams_ctx2, decoder)
|
|
37
|
+
expect(frames.map(&:f_type)).to eq [FrameType::WINDOW_UPDATE, FrameType::WINDOW_UPDATE]
|
|
38
|
+
expect(frames.map(&:stream_id)).to eq [0, 2]
|
|
39
|
+
expect(frames.map(&:window_size_increment)).to eq [65_535 / 2 + 13, 65_535 / 2 + 13]
|
|
40
|
+
expect(streams_ctx2[2].content.string).to eq 'Hello, world!'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
let(:recv_window3) do
|
|
44
|
+
recv_window = Window.new(65_535)
|
|
45
|
+
recv_window.consume!(65_535)
|
|
46
|
+
recv_window
|
|
47
|
+
end
|
|
48
|
+
let(:streams_ctx3) do
|
|
49
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
50
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
51
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
52
|
+
streams_ctx
|
|
53
|
+
end
|
|
54
|
+
it 'should not handle' do
|
|
55
|
+
expect(Connection.handle_data(2, 'Hello, world!', recv_window3, streams_ctx3, decoder)).to be_kind_of ConnectionError
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Connection do
|
|
4
|
+
context 'handle_headers' do
|
|
5
|
+
let(:headers) do
|
|
6
|
+
Frame::Headers.new(true, false, 2, nil, nil, 'this is dummy', nil)
|
|
7
|
+
end
|
|
8
|
+
let(:ctx) do
|
|
9
|
+
StreamContext.new(2, 65_535, 65_535, do_nothing_proc)
|
|
10
|
+
end
|
|
11
|
+
let(:decoder) do
|
|
12
|
+
HPACK::Decoder.new(4_096)
|
|
13
|
+
end
|
|
14
|
+
it 'should handle' do
|
|
15
|
+
expect(Connection.handle_headers(headers, ctx, decoder)).to eq nil
|
|
16
|
+
expect(ctx.fragment.string).to eq 'this is dummy'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -5,17 +5,12 @@ RSpec.describe Connection do
|
|
|
5
5
|
let(:rst_stream) do
|
|
6
6
|
Frame::RstStream.new(2, 0)
|
|
7
7
|
end
|
|
8
|
-
let(:
|
|
9
|
-
|
|
10
|
-
streams_ctx.new_context(1, do_nothing_proc)
|
|
11
|
-
streams_ctx.new_context(2, do_nothing_proc)
|
|
12
|
-
streams_ctx
|
|
8
|
+
let(:ctx) do
|
|
9
|
+
StreamContext.new(2, 65_535, 65_535, do_nothing_proc)
|
|
13
10
|
end
|
|
14
11
|
it 'should handle' do
|
|
15
|
-
Connection.handle_rst_stream(rst_stream,
|
|
16
|
-
expect(
|
|
17
|
-
expect(streams_ctx.count_active).to eq 0
|
|
18
|
-
expect(streams_ctx.closed_stream_ids.length).to eq 1
|
|
12
|
+
Connection.handle_rst_stream(rst_stream, ctx)
|
|
13
|
+
expect(ctx.closed?).to eq true
|
|
19
14
|
end
|
|
20
15
|
end
|
|
21
16
|
end
|
|
@@ -8,12 +8,18 @@ RSpec.describe Connection do
|
|
|
8
8
|
let(:decoder) do
|
|
9
9
|
HPACK::Decoder.new(4_096)
|
|
10
10
|
end
|
|
11
|
+
let(:streams_ctx) do
|
|
12
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
13
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
14
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
15
|
+
streams_ctx
|
|
16
|
+
end
|
|
11
17
|
|
|
12
18
|
let(:settings1) do
|
|
13
19
|
Frame::Settings.new(false, 0, { SettingsID::SETTINGS_HEADER_TABLE_SIZE => 8_192 })
|
|
14
20
|
end
|
|
15
21
|
it 'should handle' do
|
|
16
|
-
reply_settings = Connection.handle_settings(settings1, send_settings, decoder)
|
|
22
|
+
reply_settings = Connection.handle_settings(settings1, send_settings, decoder, streams_ctx)
|
|
17
23
|
expect(reply_settings.ack?).to eq true
|
|
18
24
|
expect(reply_settings.setting.empty?).to eq true
|
|
19
25
|
expect(send_settings[SettingsID::SETTINGS_MAX_CONCURRENT_STREAMS]).to eq 0xffffffff
|
|
@@ -25,7 +31,7 @@ RSpec.describe Connection do
|
|
|
25
31
|
Frame::Settings.new(true, 0, {})
|
|
26
32
|
end
|
|
27
33
|
it 'should handle' do
|
|
28
|
-
expect(Connection.handle_settings(settings2, send_settings, decoder)).to eq nil
|
|
34
|
+
expect(Connection.handle_settings(settings2, send_settings, decoder, streams_ctx)).to eq nil
|
|
29
35
|
end
|
|
30
36
|
end
|
|
31
37
|
end
|
|
@@ -6,15 +6,15 @@ RSpec.describe Connection do
|
|
|
6
6
|
Frame::WindowUpdate.new(1, 1000)
|
|
7
7
|
end
|
|
8
8
|
let(:streams_ctx) do
|
|
9
|
-
streams_ctx = StreamsContext.new
|
|
10
|
-
streams_ctx.new_context(1,
|
|
11
|
-
streams_ctx.new_context(2,
|
|
9
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
10
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
11
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
12
12
|
streams_ctx
|
|
13
13
|
end
|
|
14
14
|
it 'should handle' do
|
|
15
15
|
expect { Connection.handle_stream_window_update(window_update, streams_ctx) }.not_to raise_error
|
|
16
|
-
expect(streams_ctx[1].send_window.length).to eq
|
|
17
|
-
expect(streams_ctx[2].send_window.length).to eq
|
|
16
|
+
expect(streams_ctx[1].send_window.length).to eq 65_535 + 1000
|
|
17
|
+
expect(streams_ctx[2].send_window.length).to eq 65_535
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -10,29 +10,25 @@ RSpec.describe Connection do
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
let(:headers1) do
|
|
13
|
-
Frame::Headers.new(true,
|
|
14
|
-
end
|
|
15
|
-
let(:data1) do
|
|
16
|
-
Frame::Data.new(true, 2, 'Hello, world!', 'Howdy!')
|
|
13
|
+
Frame::Headers.new(true, true, 2, nil, nil, 'this is dummy'.b, nil)
|
|
17
14
|
end
|
|
18
15
|
let(:send_window1) do
|
|
19
|
-
Window.new
|
|
16
|
+
Window.new(65_535)
|
|
20
17
|
end
|
|
21
18
|
let(:streams_ctx1) do
|
|
22
|
-
streams_ctx = StreamsContext.new
|
|
23
|
-
streams_ctx.new_context(1,
|
|
24
|
-
streams_ctx.new_context(2,
|
|
19
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
20
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
21
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
25
22
|
streams_ctx
|
|
26
23
|
end
|
|
27
24
|
it 'should send' do
|
|
28
25
|
streams_ctx1[2].state.transition!(headers1, :recv)
|
|
29
|
-
|
|
30
|
-
Connection.
|
|
31
|
-
|
|
32
|
-
expect(
|
|
33
|
-
expect(
|
|
34
|
-
expect(streams_ctx1[
|
|
35
|
-
expect(streams_ctx1[2].send_window.length).to eq 2**16 - 21
|
|
26
|
+
Connection.send_headers(io, 2, "\x88".b, false, 16_384, streams_ctx1)
|
|
27
|
+
Connection.send_data(io, 2, 'Hello, world!'.b, send_window1, 16_384, streams_ctx1, data_buffer)
|
|
28
|
+
expect(io.string.force_encoding(Encoding::ASCII_8BIT)).to eq "\x00\x00\x01\x01\x04\x00\x00\x00\x02\x88\x00\x00\x0d\x00\x01\x00\x00\x00\x02Hello, world!".b
|
|
29
|
+
expect(send_window1.length).to eq 65_535 - 13
|
|
30
|
+
expect(streams_ctx1[1].send_window.length).to eq 65_535
|
|
31
|
+
expect(streams_ctx1[2].send_window.length).to eq 65_535 - 13
|
|
36
32
|
expect(data_buffer.length).to eq 0
|
|
37
33
|
end
|
|
38
34
|
|
|
@@ -40,46 +36,43 @@ RSpec.describe Connection do
|
|
|
40
36
|
Frame::Headers.new(true, true, 1, nil, nil, 'this is dummy', nil)
|
|
41
37
|
end
|
|
42
38
|
let(:send_window2) do
|
|
43
|
-
Window.new
|
|
39
|
+
Window.new(65_535)
|
|
44
40
|
end
|
|
45
41
|
let(:streams_ctx2) do
|
|
46
|
-
streams_ctx = StreamsContext.new
|
|
47
|
-
streams_ctx.new_context(1,
|
|
48
|
-
streams_ctx.new_context(2,
|
|
42
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
43
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
44
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
49
45
|
streams_ctx
|
|
50
46
|
end
|
|
51
47
|
it 'should send' do
|
|
52
48
|
streams_ctx2[1].state.transition!(headers2, :recv)
|
|
53
|
-
Connection.
|
|
54
|
-
expect(io.string).to eq "\x00\x00\
|
|
55
|
-
expect(send_window2.length).to eq
|
|
56
|
-
expect(streams_ctx2[1].send_window.length).to eq
|
|
57
|
-
expect(streams_ctx2[2].send_window.length).to eq
|
|
49
|
+
Connection.send_headers(io, 1, "\x88".b, true, 16_384, streams_ctx2)
|
|
50
|
+
expect(io.string.force_encoding(Encoding::ASCII_8BIT)).to eq "\x00\x00\x01\x01\x05\x00\x00\x00\x01\x88".b
|
|
51
|
+
expect(send_window2.length).to eq 65_535
|
|
52
|
+
expect(streams_ctx2[1].send_window.length).to eq 65_535
|
|
53
|
+
expect(streams_ctx2[2].send_window.length).to eq 65_535
|
|
58
54
|
expect(data_buffer.length).to eq 0
|
|
59
55
|
end
|
|
60
56
|
|
|
61
57
|
let(:headers3) do
|
|
62
58
|
Frame::Headers.new(true, true, 2, nil, nil, 'this is dummy', nil)
|
|
63
59
|
end
|
|
64
|
-
let(:data3) do
|
|
65
|
-
Frame::Data.new(false, 2, 'Hello, world!', 'Howdy!')
|
|
66
|
-
end
|
|
67
60
|
let(:send_window3) do
|
|
68
|
-
Window.new
|
|
61
|
+
Window.new(65_535)
|
|
69
62
|
end
|
|
70
63
|
let(:streams_ctx3) do
|
|
71
|
-
streams_ctx = StreamsContext.new
|
|
72
|
-
streams_ctx.new_context(1,
|
|
73
|
-
streams_ctx.new_context(2,
|
|
74
|
-
streams_ctx[2].send_window.consume!(
|
|
64
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
65
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
66
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
67
|
+
streams_ctx[2].send_window.consume!(65_535)
|
|
75
68
|
streams_ctx
|
|
76
69
|
end
|
|
77
70
|
it 'should send' do
|
|
78
71
|
streams_ctx3[2].state.transition!(headers3, :recv)
|
|
79
|
-
Connection.
|
|
80
|
-
expect(io.string).to eq ''
|
|
81
|
-
expect(send_window3.length).to eq
|
|
82
|
-
expect(streams_ctx3[1].send_window.length).to eq
|
|
72
|
+
Connection.send_data(io, 2, 'Hello, world!'.b, send_window3, 16_384, streams_ctx3, data_buffer)
|
|
73
|
+
expect(io.string.force_encoding(Encoding::ASCII_8BIT)).to eq ''.b
|
|
74
|
+
expect(send_window3.length).to eq 65_535
|
|
75
|
+
expect(streams_ctx3[1].send_window.length).to eq 65_535
|
|
83
76
|
expect(streams_ctx3[2].send_window.length).to eq 0
|
|
84
77
|
expect(data_buffer.length).to eq 1
|
|
85
78
|
end
|
|
@@ -87,27 +80,24 @@ RSpec.describe Connection do
|
|
|
87
80
|
let(:headers4) do
|
|
88
81
|
Frame::Headers.new(true, true, 2, nil, nil, 'this is dummy', nil)
|
|
89
82
|
end
|
|
90
|
-
let(:data4) do
|
|
91
|
-
Frame::Data.new(false, 2, 'Hello, world!', 'Howdy!')
|
|
92
|
-
end
|
|
93
83
|
let(:send_window4) do
|
|
94
|
-
send_window = Window.new
|
|
95
|
-
send_window.consume!(
|
|
84
|
+
send_window = Window.new(65_535)
|
|
85
|
+
send_window.consume!(65_535)
|
|
96
86
|
send_window
|
|
97
87
|
end
|
|
98
88
|
let(:streams_ctx4) do
|
|
99
|
-
streams_ctx = StreamsContext.new
|
|
100
|
-
streams_ctx.new_context(1,
|
|
101
|
-
streams_ctx.new_context(2,
|
|
89
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
90
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
91
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
102
92
|
streams_ctx
|
|
103
93
|
end
|
|
104
94
|
it 'should send' do
|
|
105
95
|
streams_ctx4[2].state.transition!(headers4, :recv)
|
|
106
|
-
Connection.
|
|
107
|
-
expect(io.string).to eq ''
|
|
96
|
+
Connection.send_data(io, 2, 'Hello, world!'.b, send_window4, 16_384, streams_ctx4, data_buffer)
|
|
97
|
+
expect(io.string.force_encoding(Encoding::ASCII_8BIT)).to eq ''.b
|
|
108
98
|
expect(send_window4.length).to eq 0
|
|
109
|
-
expect(streams_ctx4[1].send_window.length).to eq
|
|
110
|
-
expect(streams_ctx4[2].send_window.length).to eq
|
|
99
|
+
expect(streams_ctx4[1].send_window.length).to eq 65_535
|
|
100
|
+
expect(streams_ctx4[2].send_window.length).to eq 65_535
|
|
111
101
|
expect(data_buffer.length).to eq 1
|
|
112
102
|
end
|
|
113
103
|
end
|
|
@@ -3,9 +3,9 @@ require_relative '../spec_helper'
|
|
|
3
3
|
RSpec.describe Connection do
|
|
4
4
|
context 'transition_state_send' do
|
|
5
5
|
let(:streams_ctx) do
|
|
6
|
-
streams_ctx = StreamsContext.new
|
|
7
|
-
streams_ctx.new_context(1,
|
|
8
|
-
streams_ctx.new_context(2,
|
|
6
|
+
streams_ctx = StreamsContext.new(do_nothing_proc)
|
|
7
|
+
streams_ctx.new_context(1, 65_535, 65_535)
|
|
8
|
+
streams_ctx.new_context(2, 65_535, 65_535)
|
|
9
9
|
streams_ctx
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -21,7 +21,7 @@ RSpec.describe Connection do
|
|
|
21
21
|
it 'should transition' do
|
|
22
22
|
streams_ctx[1].state.transition!(headers, :recv)
|
|
23
23
|
streams_ctx[2].state.transition!(headers, :recv)
|
|
24
|
-
|
|
24
|
+
streams_ctx.close_all
|
|
25
25
|
expect { streams_ctx[1].tx << nil }.to raise_error Ractor::ClosedError
|
|
26
26
|
expect { streams_ctx[2].tx << nil }.to raise_error Ractor::ClosedError
|
|
27
27
|
end
|