http-2 0.10.1 → 0.10.2
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 +5 -5
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +3 -0
- data/LICENSE +21 -0
- data/example/upgrade_client.rb +10 -10
- data/example/upgrade_server.rb +5 -5
- data/http-2.gemspec +1 -1
- data/lib/http/2/compressor.rb +3 -0
- data/lib/http/2/connection.rb +22 -7
- data/lib/http/2/version.rb +1 -1
- data/spec/client_spec.rb +21 -20
- data/spec/compressor_spec.rb +6 -0
- data/spec/connection_spec.rb +95 -79
- data/spec/helper.rb +123 -107
- data/spec/server_spec.rb +2 -1
- data/spec/stream_spec.rb +112 -111
- metadata +8 -8
data/spec/helper.rb
CHANGED
@@ -8,119 +8,135 @@ require 'coveralls'
|
|
8
8
|
|
9
9
|
Coveralls.wear! if ENV['CI']
|
10
10
|
|
11
|
-
require 'http/2'
|
12
|
-
|
13
11
|
# rubocop: disable Style/MixinUsage
|
12
|
+
require 'http/2'
|
14
13
|
include HTTP2
|
15
14
|
include HTTP2::Header
|
16
15
|
include HTTP2::Error
|
17
16
|
# rubocop: enable Style/MixinUsage
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
}
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
}
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
18
|
+
REQUEST_HEADERS = [%w(:scheme https),
|
19
|
+
%w(:path /),
|
20
|
+
%w(:authority example.com),
|
21
|
+
%w(:method GET),
|
22
|
+
%w(a b)].freeze
|
23
|
+
RESPONSE_HEADERS = [%w(:status 200)].freeze
|
24
|
+
|
25
|
+
module FrameHelpers
|
26
|
+
def data_frame
|
27
|
+
{
|
28
|
+
type: :data,
|
29
|
+
flags: [:end_stream],
|
30
|
+
stream: 1,
|
31
|
+
payload: 'text',
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def headers_frame
|
36
|
+
{
|
37
|
+
type: :headers,
|
38
|
+
flags: [:end_headers].freeze,
|
39
|
+
stream: 1,
|
40
|
+
payload: Compressor.new.encode(REQUEST_HEADERS),
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def priority_frame
|
45
|
+
{
|
46
|
+
type: :priority,
|
47
|
+
stream: 1,
|
48
|
+
exclusive: false,
|
49
|
+
stream_dependency: 0,
|
50
|
+
weight: 20,
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def rst_stream_frame
|
55
|
+
{
|
56
|
+
type: :rst_stream,
|
57
|
+
stream: 1,
|
58
|
+
error: :stream_closed,
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def settings_frame
|
63
|
+
{
|
64
|
+
type: :settings,
|
65
|
+
stream: 0,
|
66
|
+
payload: [
|
67
|
+
[:settings_max_concurrent_streams, 10],
|
68
|
+
[:settings_initial_window_size, 0x7fffffff],
|
69
|
+
],
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def push_promise_frame
|
74
|
+
{
|
75
|
+
type: :push_promise,
|
76
|
+
flags: [:end_headers],
|
77
|
+
stream: 1,
|
78
|
+
promise_stream: 2,
|
79
|
+
payload: Compressor.new.encode([%w(a b)]),
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def ping_frame
|
84
|
+
{
|
85
|
+
stream: 0,
|
86
|
+
type: :ping,
|
87
|
+
payload: '12345678',
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def pong_frame
|
92
|
+
{
|
93
|
+
stream: 0,
|
94
|
+
type: :ping,
|
95
|
+
flags: [:ack],
|
96
|
+
payload: '12345678',
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def goaway_frame
|
101
|
+
{
|
102
|
+
type: :goaway,
|
103
|
+
last_stream: 2,
|
104
|
+
error: :no_error,
|
105
|
+
payload: 'debug',
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
def window_update_frame
|
110
|
+
{
|
111
|
+
type: :window_update,
|
112
|
+
increment: 10,
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def continuation_frame
|
117
|
+
{
|
118
|
+
type: :continuation,
|
119
|
+
flags: [:end_headers],
|
120
|
+
payload: '-second-block',
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def altsvc_frame
|
125
|
+
{
|
126
|
+
type: :altsvc,
|
127
|
+
max_age: 1_402_290_402, # 4
|
128
|
+
port: 8080, # 2 reserved 1
|
129
|
+
proto: 'h2-12', # 1 + 5
|
130
|
+
host: 'www.example.com', # 1 + 15
|
131
|
+
origin: 'www.example.com' # 15
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
def frame_types
|
136
|
+
methods.select { |meth| meth.to_s.end_with?('_frame') }
|
137
|
+
.map { |meth| __send__(meth) }
|
138
|
+
end
|
139
|
+
end
|
124
140
|
|
125
141
|
def set_stream_id(bytes, id)
|
126
142
|
scheme = 'CnCCN'.freeze
|
data/spec/server_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
RSpec.describe HTTP2::Server do
|
4
|
+
include FrameHelpers
|
4
5
|
before(:each) do
|
5
6
|
@srv = Server.new
|
6
7
|
end
|
@@ -46,6 +47,6 @@ RSpec.describe HTTP2::Server do
|
|
46
47
|
end
|
47
48
|
|
48
49
|
client.new_stream
|
49
|
-
client.send
|
50
|
+
client.send headers_frame
|
50
51
|
end
|
51
52
|
end
|
data/spec/stream_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
RSpec.describe HTTP2::Stream do
|
4
|
+
include FrameHelpers
|
4
5
|
before(:each) do
|
5
6
|
@client = Client.new
|
6
7
|
@stream = @client.new_stream
|
@@ -18,57 +19,57 @@ RSpec.describe HTTP2::Stream do
|
|
18
19
|
|
19
20
|
context 'idle' do
|
20
21
|
it 'should transition to open on sent HEADERS' do
|
21
|
-
@stream.send
|
22
|
+
@stream.send headers_frame
|
22
23
|
expect(@stream.state).to eq :open
|
23
24
|
end
|
24
25
|
it 'should transition to open on received HEADERS' do
|
25
|
-
@stream.receive
|
26
|
+
@stream.receive headers_frame
|
26
27
|
expect(@stream.state).to eq :open
|
27
28
|
end
|
28
29
|
it 'should transition to reserved (local) on sent PUSH_PROMISE' do
|
29
|
-
@stream.send
|
30
|
+
@stream.send push_promise_frame
|
30
31
|
expect(@stream.state).to eq :reserved_local
|
31
32
|
end
|
32
33
|
it 'should transition to reserved (remote) on received PUSH_PROMISE' do
|
33
|
-
@stream.receive
|
34
|
+
@stream.receive push_promise_frame
|
34
35
|
expect(@stream.state).to eq :reserved_remote
|
35
36
|
end
|
36
37
|
it 'should reprioritize stream on sent PRIORITY' do
|
37
|
-
expect { @stream.send
|
38
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
38
39
|
expect(@stream.weight).to eq 20
|
39
40
|
end
|
40
41
|
it 'should reprioritize stream on received PRIORITY' do
|
41
|
-
expect { @stream.send
|
42
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
42
43
|
expect(@stream.weight).to eq 20
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
47
|
context 'reserved (local)' do
|
47
|
-
before(:each) { @stream.send
|
48
|
+
before(:each) { @stream.send push_promise_frame }
|
48
49
|
|
49
50
|
it 'should transition on sent PUSH_PROMISE' do
|
50
51
|
expect(@stream.state).to eq :reserved_local
|
51
52
|
end
|
52
53
|
|
53
54
|
it 'should allow HEADERS to be sent' do
|
54
|
-
expect { @stream.send
|
55
|
+
expect { @stream.send headers_frame }.to_not raise_error
|
55
56
|
end
|
56
57
|
|
57
58
|
it 'should raise error if sending invalid frames' do
|
58
|
-
|
59
|
+
frame_types.reject { |frame| %i[headers rst_stream].include?(frame[:type]) }.each do |type|
|
59
60
|
expect { @stream.dup.send type }.to raise_error InternalError
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
63
64
|
it 'should raise error on receipt of invalid frames' do
|
64
|
-
what_types =
|
65
|
+
what_types = frame_types.reject { |frame| %i[priority window_update rst_stream].include?(frame[:type]) }
|
65
66
|
what_types.each do |type|
|
66
67
|
expect { @stream.dup.receive type }.to raise_error InternalError
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
70
71
|
it 'should transition to half closed (remote) on sent HEADERS' do
|
71
|
-
@stream.send
|
72
|
+
@stream.send headers_frame
|
72
73
|
expect(@stream.state).to eq :half_closed_remote
|
73
74
|
end
|
74
75
|
|
@@ -78,42 +79,42 @@ RSpec.describe HTTP2::Stream do
|
|
78
79
|
end
|
79
80
|
|
80
81
|
it 'should transition to closed on received RST_STREAM' do
|
81
|
-
@stream.receive
|
82
|
+
@stream.receive rst_stream_frame
|
82
83
|
expect(@stream.state).to eq :closed
|
83
84
|
end
|
84
85
|
|
85
86
|
it 'should reprioritize stream on PRIORITY' do
|
86
|
-
expect { @stream.receive
|
87
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
87
88
|
expect(@stream.weight).to eq 20
|
88
89
|
end
|
89
90
|
|
90
91
|
it 'should increment remote_window on received WINDOW_UPDATE' do
|
91
|
-
expect { @stream.receive
|
92
|
-
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW +
|
92
|
+
expect { @stream.receive window_update_frame }.to_not raise_error
|
93
|
+
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW + window_update_frame[:increment]
|
93
94
|
end
|
94
95
|
end
|
95
96
|
|
96
97
|
context 'reserved (remote)' do
|
97
|
-
before(:each) { @stream.receive
|
98
|
+
before(:each) { @stream.receive push_promise_frame }
|
98
99
|
|
99
100
|
it 'should transition on received PUSH_PROMISE' do
|
100
101
|
expect(@stream.state).to eq :reserved_remote
|
101
102
|
end
|
102
103
|
|
103
104
|
it 'should raise error if sending invalid frames' do
|
104
|
-
|
105
|
+
frame_types.reject { |frame| %i[priority rst_stream window_update].include?(frame[:type]) }.each do |type|
|
105
106
|
expect { @stream.dup.send type }.to raise_error InternalError
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
109
110
|
it 'should raise error on receipt of invalid frames' do
|
110
|
-
|
111
|
+
frame_types.reject { |frame| %i[headers rst_stream].include?(frame[:type]) }.each do |type|
|
111
112
|
expect { @stream.dup.receive type }.to raise_error InternalError
|
112
113
|
end
|
113
114
|
end
|
114
115
|
|
115
116
|
it 'should transition to half closed (local) on received HEADERS' do
|
116
|
-
@stream.receive
|
117
|
+
@stream.receive headers_frame
|
117
118
|
expect(@stream.state).to eq :half_closed_local
|
118
119
|
end
|
119
120
|
|
@@ -123,38 +124,38 @@ RSpec.describe HTTP2::Stream do
|
|
123
124
|
end
|
124
125
|
|
125
126
|
it 'should transition to closed on received RST_STREAM' do
|
126
|
-
@stream.receive
|
127
|
+
@stream.receive rst_stream_frame
|
127
128
|
expect(@stream.state).to eq :closed
|
128
129
|
end
|
129
130
|
|
130
131
|
it 'should reprioritize stream on PRIORITY' do
|
131
|
-
expect { @stream.send
|
132
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
132
133
|
expect(@stream.weight).to eq 20
|
133
134
|
end
|
134
135
|
|
135
136
|
it 'should increment local_window on sent WINDOW_UPDATE' do
|
136
|
-
expect { @stream.send
|
137
|
-
expect(@stream.local_window).to eq DEFAULT_FLOW_WINDOW +
|
137
|
+
expect { @stream.send window_update_frame }.to_not raise_error
|
138
|
+
expect(@stream.local_window).to eq DEFAULT_FLOW_WINDOW + window_update_frame[:increment]
|
138
139
|
end
|
139
140
|
end
|
140
141
|
|
141
142
|
context 'open' do
|
142
|
-
before(:each) { @stream.receive
|
143
|
+
before(:each) { @stream.receive headers_frame }
|
143
144
|
|
144
145
|
it 'should allow any valid frames types to be sent' do
|
145
|
-
(
|
146
|
+
(frame_types - [ping_frame, goaway_frame, settings_frame]).each do |type|
|
146
147
|
expect { @stream.dup.send type.deep_dup }.to_not raise_error
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
150
151
|
it 'should allow frames of any type to be received' do
|
151
|
-
|
152
|
+
frame_types.each do |type|
|
152
153
|
expect { @stream.dup.receive type }.to_not raise_error
|
153
154
|
end
|
154
155
|
end
|
155
156
|
|
156
157
|
it 'should transition to half closed (local) if sending END_STREAM' do
|
157
|
-
[
|
158
|
+
[data_frame, headers_frame].each do |frame|
|
158
159
|
s, f = @stream.dup, frame.deep_dup
|
159
160
|
f[:flags] = [:end_stream]
|
160
161
|
|
@@ -164,7 +165,7 @@ RSpec.describe HTTP2::Stream do
|
|
164
165
|
end
|
165
166
|
|
166
167
|
it 'should transition to half closed (remote) if receiving END_STREAM' do
|
167
|
-
[
|
168
|
+
[data_frame, headers_frame].each do |frame|
|
168
169
|
s, f = @stream.dup, frame.dup
|
169
170
|
f[:flags] = [:end_stream]
|
170
171
|
|
@@ -175,7 +176,7 @@ RSpec.describe HTTP2::Stream do
|
|
175
176
|
|
176
177
|
it 'should transition to half closed if remote opened with END_STREAM' do
|
177
178
|
s = @client.new_stream
|
178
|
-
hclose =
|
179
|
+
hclose = headers_frame
|
179
180
|
hclose[:flags] = [:end_stream]
|
180
181
|
|
181
182
|
s.receive hclose
|
@@ -184,7 +185,7 @@ RSpec.describe HTTP2::Stream do
|
|
184
185
|
|
185
186
|
it 'should transition to half closed if local opened with END_STREAM' do
|
186
187
|
s = @client.new_stream
|
187
|
-
hclose =
|
188
|
+
hclose = headers_frame
|
188
189
|
hclose[:flags] = [:end_stream]
|
189
190
|
|
190
191
|
s.send hclose
|
@@ -198,7 +199,7 @@ RSpec.describe HTTP2::Stream do
|
|
198
199
|
end
|
199
200
|
|
200
201
|
it 'should transition to closed if receiving RST_STREAM' do
|
201
|
-
@stream.receive
|
202
|
+
@stream.receive rst_stream_frame
|
202
203
|
expect(@stream.state).to eq :closed
|
203
204
|
end
|
204
205
|
|
@@ -209,8 +210,8 @@ RSpec.describe HTTP2::Stream do
|
|
209
210
|
sp.on(:active) { openp = true }
|
210
211
|
sr.on(:active) { openr = true }
|
211
212
|
|
212
|
-
sp.receive
|
213
|
-
sr.send
|
213
|
+
sp.receive headers_frame
|
214
|
+
sr.send headers_frame
|
214
215
|
|
215
216
|
expect(openp).to be_truthy
|
216
217
|
expect(openr).to be_truthy
|
@@ -223,11 +224,11 @@ RSpec.describe HTTP2::Stream do
|
|
223
224
|
stream.on(:half_close) { order << :half_close }
|
224
225
|
stream.on(:close) { order << :close }
|
225
226
|
|
226
|
-
req =
|
227
|
+
req = headers_frame
|
227
228
|
req[:flags] = [:end_headers]
|
228
229
|
|
229
230
|
stream.send req
|
230
|
-
stream.send
|
231
|
+
stream.send data_frame
|
231
232
|
expect(order).to eq [:active, :half_close]
|
232
233
|
end
|
233
234
|
|
@@ -238,7 +239,7 @@ RSpec.describe HTTP2::Stream do
|
|
238
239
|
sp.on(:close) { closep = true }
|
239
240
|
sr.on(:close) { closer = true }
|
240
241
|
|
241
|
-
sp.receive
|
242
|
+
sp.receive rst_stream_frame
|
242
243
|
sr.close
|
243
244
|
|
244
245
|
expect(closep).to be_truthy
|
@@ -253,12 +254,12 @@ RSpec.describe HTTP2::Stream do
|
|
253
254
|
stream.on(:half_close) { order << :half_close }
|
254
255
|
stream.on(:close) { order << :close }
|
255
256
|
|
256
|
-
req =
|
257
|
+
req = headers_frame
|
257
258
|
req[:flags] = [:end_stream, :end_headers]
|
258
259
|
|
259
260
|
stream.send req
|
260
|
-
stream.receive
|
261
|
-
stream.receive
|
261
|
+
stream.receive headers_frame
|
262
|
+
stream.receive data_frame
|
262
263
|
|
263
264
|
expect(order).to eq [:active, :half_close, :data, :close]
|
264
265
|
end
|
@@ -266,31 +267,31 @@ RSpec.describe HTTP2::Stream do
|
|
266
267
|
it 'should emit :close with reason' do
|
267
268
|
reason = nil
|
268
269
|
@stream.on(:close) { |r| reason = r }
|
269
|
-
@stream.receive
|
270
|
+
@stream.receive rst_stream_frame
|
270
271
|
expect(reason).not_to be_nil
|
271
272
|
end
|
272
273
|
|
273
274
|
it 'should reprioritize stream on sent PRIORITY' do
|
274
|
-
expect { @stream.send
|
275
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
275
276
|
expect(@stream.weight).to eq 20
|
276
277
|
end
|
277
278
|
it 'should reprioritize stream on received PRIORITY' do
|
278
|
-
expect { @stream.receive
|
279
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
279
280
|
expect(@stream.weight).to eq 20
|
280
281
|
end
|
281
282
|
end
|
282
283
|
|
283
284
|
context 'half closed (local)' do
|
284
|
-
before(:each) { @stream.send
|
285
|
+
before(:each) { @stream.send headers_frame.merge(flags: [:end_headers, :end_stream]) }
|
285
286
|
|
286
287
|
it 'should raise error on attempt to send invalid frames' do
|
287
|
-
|
288
|
+
frame_types.reject { |frame| %i[priority rst_stream window_update].include?(frame[:type]) }.each do |frame|
|
288
289
|
expect { @stream.dup.send frame }.to raise_error InternalError
|
289
290
|
end
|
290
291
|
end
|
291
292
|
|
292
293
|
it 'should transition to closed on receipt of END_STREAM flag' do
|
293
|
-
[
|
294
|
+
[data_frame, headers_frame, continuation_frame].each do |frame|
|
294
295
|
s, f = @stream.dup, frame.dup
|
295
296
|
f[:flags] = [:end_stream]
|
296
297
|
|
@@ -300,38 +301,38 @@ RSpec.describe HTTP2::Stream do
|
|
300
301
|
end
|
301
302
|
|
302
303
|
it 'should transition to closed on receipt of RST_STREAM frame' do
|
303
|
-
@stream.receive
|
304
|
+
@stream.receive rst_stream_frame
|
304
305
|
expect(@stream.state).to eq :closed
|
305
306
|
end
|
306
307
|
|
307
308
|
it 'should transition to closed if RST_STREAM frame is sent' do
|
308
|
-
@stream.send
|
309
|
+
@stream.send rst_stream_frame
|
309
310
|
expect(@stream.state).to eq :closed
|
310
311
|
end
|
311
312
|
|
312
313
|
it 'should ignore received WINDOW_UPDATE frames' do
|
313
|
-
expect { @stream.receive
|
314
|
+
expect { @stream.receive window_update_frame }.to_not raise_error
|
314
315
|
expect(@stream.state).to eq :half_closed_local
|
315
316
|
end
|
316
317
|
|
317
318
|
it 'should ignore received PRIORITY frames' do
|
318
|
-
expect { @stream.receive
|
319
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
319
320
|
expect(@stream.state).to eq :half_closed_local
|
320
321
|
end
|
321
322
|
|
322
323
|
it 'should reprioritize stream on sent PRIORITY' do
|
323
|
-
expect { @stream.send
|
324
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
324
325
|
expect(@stream.weight).to eq 20
|
325
326
|
end
|
326
327
|
|
327
328
|
it 'should reprioritize stream (and decendants) on received PRIORITY' do
|
328
|
-
expect { @stream.receive
|
329
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
329
330
|
expect(@stream.weight).to eq 20
|
330
331
|
end
|
331
332
|
|
332
333
|
it 'should increment local_window on sent WINDOW_UPDATE' do
|
333
|
-
expect { @stream.send
|
334
|
-
expect(@stream.local_window).to eq DEFAULT_FLOW_WINDOW +
|
334
|
+
expect { @stream.send window_update_frame }.to_not raise_error
|
335
|
+
expect(@stream.local_window).to eq DEFAULT_FLOW_WINDOW + window_update_frame[:increment]
|
335
336
|
end
|
336
337
|
|
337
338
|
it 'should emit :half_close event on transition' do
|
@@ -340,7 +341,7 @@ RSpec.describe HTTP2::Stream do
|
|
340
341
|
stream.on(:active) { order << :active }
|
341
342
|
stream.on(:half_close) { order << :half_close }
|
342
343
|
|
343
|
-
req =
|
344
|
+
req = headers_frame
|
344
345
|
req[:flags] = [:end_stream, :end_headers]
|
345
346
|
|
346
347
|
stream.send req
|
@@ -350,7 +351,7 @@ RSpec.describe HTTP2::Stream do
|
|
350
351
|
it 'should emit :close event on transition to closed' do
|
351
352
|
closed = false
|
352
353
|
@stream.on(:close) { closed = true }
|
353
|
-
@stream.receive
|
354
|
+
@stream.receive rst_stream_frame
|
354
355
|
|
355
356
|
expect(@stream.state).to eq :closed
|
356
357
|
expect(closed).to be_truthy
|
@@ -358,10 +359,10 @@ RSpec.describe HTTP2::Stream do
|
|
358
359
|
end
|
359
360
|
|
360
361
|
context 'half closed (remote)' do
|
361
|
-
before(:each) { @stream.receive
|
362
|
+
before(:each) { @stream.receive headers_frame.merge(flags: [:end_headers, :end_stream]) }
|
362
363
|
|
363
364
|
it 'should raise STREAM_CLOSED error on reciept of frames' do
|
364
|
-
(
|
365
|
+
(frame_types - [priority_frame, rst_stream_frame, window_update_frame]).each do |frame|
|
365
366
|
expect do
|
366
367
|
@stream.dup.receive frame
|
367
368
|
end.to raise_error(StreamClosed)
|
@@ -369,7 +370,7 @@ RSpec.describe HTTP2::Stream do
|
|
369
370
|
end
|
370
371
|
|
371
372
|
it 'should transition to closed if END_STREAM flag is sent' do
|
372
|
-
[
|
373
|
+
[data_frame, headers_frame].each do |frame|
|
373
374
|
s, f = @stream.dup, frame.deep_dup
|
374
375
|
f[:flags] = [:end_stream]
|
375
376
|
|
@@ -409,26 +410,26 @@ RSpec.describe HTTP2::Stream do
|
|
409
410
|
end
|
410
411
|
|
411
412
|
it 'should transition to closed on reciept of RST_STREAM frame' do
|
412
|
-
@stream.receive
|
413
|
+
@stream.receive rst_stream_frame
|
413
414
|
expect(@stream.state).to eq :closed
|
414
415
|
end
|
415
416
|
|
416
417
|
it 'should ignore sent WINDOW_UPDATE frames' do
|
417
|
-
expect { @stream.send
|
418
|
+
expect { @stream.send window_update_frame }.to_not raise_error
|
418
419
|
expect(@stream.state).to eq :half_closed_remote
|
419
420
|
end
|
420
421
|
|
421
422
|
it 'should increment remote_window on received WINDOW_UPDATE' do
|
422
|
-
expect { @stream.receive
|
423
|
-
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW +
|
423
|
+
expect { @stream.receive window_update_frame }.to_not raise_error
|
424
|
+
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW + window_update_frame[:increment]
|
424
425
|
end
|
425
426
|
|
426
427
|
it 'should reprioritize stream on sent PRIORITY' do
|
427
|
-
expect { @stream.send
|
428
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
428
429
|
expect(@stream.weight).to eq 20
|
429
430
|
end
|
430
431
|
it 'should reprioritize stream on received PRIORITY' do
|
431
|
-
expect { @stream.receive
|
432
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
432
433
|
expect(@stream.weight).to eq 20
|
433
434
|
end
|
434
435
|
|
@@ -438,7 +439,7 @@ RSpec.describe HTTP2::Stream do
|
|
438
439
|
stream.on(:active) { order << :active }
|
439
440
|
stream.on(:half_close) { order << :half_close }
|
440
441
|
|
441
|
-
req =
|
442
|
+
req = headers_frame
|
442
443
|
req[:flags] = [:end_stream, :end_headers]
|
443
444
|
|
444
445
|
stream.receive req
|
@@ -458,12 +459,12 @@ RSpec.describe HTTP2::Stream do
|
|
458
459
|
context 'closed' do
|
459
460
|
context 'remote closed stream' do
|
460
461
|
before(:each) do
|
461
|
-
@stream.send
|
462
|
-
@stream.receive
|
462
|
+
@stream.send headers_frame.merge(flags: [:end_headers, :end_stream]) # half closed local
|
463
|
+
@stream.receive headers_frame.merge(flags: [:end_headers, :end_stream]) # closed by remote
|
463
464
|
end
|
464
465
|
|
465
466
|
it 'should raise STREAM_CLOSED on attempt to send frames' do
|
466
|
-
(
|
467
|
+
(frame_types - [priority_frame, rst_stream_frame]).each do |frame|
|
467
468
|
expect do
|
468
469
|
@stream.dup.send frame
|
469
470
|
end.to raise_error(StreamClosed)
|
@@ -471,7 +472,7 @@ RSpec.describe HTTP2::Stream do
|
|
471
472
|
end
|
472
473
|
|
473
474
|
it 'should raise STREAM_CLOSED on receipt of frame' do
|
474
|
-
(
|
475
|
+
(frame_types - [priority_frame, rst_stream_frame, window_update_frame]).each do |frame|
|
475
476
|
expect do
|
476
477
|
@stream.dup.receive frame
|
477
478
|
end.to raise_error(StreamClosed)
|
@@ -479,38 +480,38 @@ RSpec.describe HTTP2::Stream do
|
|
479
480
|
end
|
480
481
|
|
481
482
|
it 'should allow PRIORITY, RST_STREAM to be sent' do
|
482
|
-
expect { @stream.send
|
483
|
-
expect { @stream.send
|
483
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
484
|
+
expect { @stream.send rst_stream_frame }.to_not raise_error
|
484
485
|
end
|
485
486
|
|
486
487
|
it 'should allow PRIORITY, RST_STREAM to be received' do
|
487
|
-
expect { @stream.receive
|
488
|
-
expect { @stream.receive
|
488
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
489
|
+
expect { @stream.receive rst_stream_frame }.to_not raise_error
|
489
490
|
end
|
490
491
|
|
491
492
|
it 'should reprioritize stream on sent PRIORITY' do
|
492
|
-
expect { @stream.send
|
493
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
493
494
|
expect(@stream.weight).to eq 20
|
494
495
|
end
|
495
496
|
it 'should reprioritize stream on received PRIORITY' do
|
496
|
-
expect { @stream.receive
|
497
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
497
498
|
expect(@stream.weight).to eq 20
|
498
499
|
end
|
499
500
|
|
500
501
|
it 'should ignore received WINDOW_UPDATE frames' do
|
501
|
-
expect { @stream.receive
|
502
|
+
expect { @stream.receive window_update_frame }.to_not raise_error
|
502
503
|
expect(@stream.state).to eq :closed
|
503
504
|
end
|
504
505
|
end
|
505
506
|
|
506
507
|
context 'local closed via RST_STREAM frame' do
|
507
508
|
before(:each) do
|
508
|
-
@stream.send
|
509
|
-
@stream.send
|
509
|
+
@stream.send headers_frame # open
|
510
|
+
@stream.send rst_stream_frame # closed by local
|
510
511
|
end
|
511
512
|
|
512
513
|
it 'should ignore received frames' do
|
513
|
-
(
|
514
|
+
(frame_types - [push_promise_frame]).each do |frame|
|
514
515
|
expect do
|
515
516
|
cb = []
|
516
517
|
@stream.on(:data) { cb << :data }
|
@@ -533,12 +534,12 @@ RSpec.describe HTTP2::Stream do
|
|
533
534
|
# FIXME: Isn't this test same as "half closed (local)"?
|
534
535
|
# context "local closed via END_STREAM flag" do
|
535
536
|
# before(:each) do
|
536
|
-
# @stream.send
|
537
|
-
# @stream.send
|
537
|
+
# @stream.send headers_frame # open
|
538
|
+
# @stream.send data_frame # contains end_stream flag
|
538
539
|
# end
|
539
540
|
|
540
541
|
# it "should ignore received frames" do
|
541
|
-
#
|
542
|
+
# frame_types.each do |frame|
|
542
543
|
# expect { @stream.dup.receive frame }.to_not raise_error
|
543
544
|
# end
|
544
545
|
# end
|
@@ -554,31 +555,31 @@ RSpec.describe HTTP2::Stream do
|
|
554
555
|
end
|
555
556
|
|
556
557
|
it 'should update window size on DATA frames only' do
|
557
|
-
@stream.send
|
558
|
+
@stream.send headers_frame # go to open
|
558
559
|
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW
|
559
560
|
|
560
|
-
(
|
561
|
+
(frame_types - [data_frame, ping_frame, goaway_frame, settings_frame]).each do |frame|
|
561
562
|
s = @stream.dup
|
562
563
|
s.send frame.deep_dup
|
563
564
|
expect(s.remote_window).to eq DEFAULT_FLOW_WINDOW
|
564
565
|
end
|
565
566
|
|
566
|
-
@stream.send
|
567
|
-
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW -
|
567
|
+
@stream.send data_frame
|
568
|
+
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW - data_frame[:payload].bytesize
|
568
569
|
end
|
569
570
|
|
570
571
|
it 'should update window size on receipt of WINDOW_UPDATE' do
|
571
|
-
@stream.send
|
572
|
-
@stream.send
|
573
|
-
@stream.receive
|
572
|
+
@stream.send headers_frame
|
573
|
+
@stream.send data_frame
|
574
|
+
@stream.receive window_update_frame
|
574
575
|
|
575
576
|
expect(@stream.remote_window).to eq(
|
576
|
-
DEFAULT_FLOW_WINDOW -
|
577
|
+
DEFAULT_FLOW_WINDOW - data_frame[:payload].bytesize + window_update_frame[:increment],
|
577
578
|
)
|
578
579
|
end
|
579
580
|
|
580
581
|
it 'should observe session flow control' do
|
581
|
-
settings, data =
|
582
|
+
settings, data = settings_frame, data_frame
|
582
583
|
settings[:payload] = [[:settings_initial_window_size, 1000]]
|
583
584
|
settings[:stream] = 0
|
584
585
|
|
@@ -586,7 +587,7 @@ RSpec.describe HTTP2::Stream do
|
|
586
587
|
@client << framer.generate(settings)
|
587
588
|
|
588
589
|
s1 = @client.new_stream
|
589
|
-
s1.send
|
590
|
+
s1.send headers_frame
|
590
591
|
s1.send data.merge(payload: 'x' * 900, flags: [])
|
591
592
|
expect(s1.remote_window).to eq 100
|
592
593
|
|
@@ -594,31 +595,31 @@ RSpec.describe HTTP2::Stream do
|
|
594
595
|
expect(s1.remote_window).to eq 0
|
595
596
|
expect(s1.buffered_amount).to eq 100
|
596
597
|
|
597
|
-
@client << framer.generate(
|
598
|
+
@client << framer.generate(window_update_frame.merge(stream: s1.id, increment: 1000))
|
598
599
|
expect(s1.buffered_amount).to eq 0
|
599
600
|
expect(s1.remote_window).to eq 900
|
600
601
|
end
|
601
602
|
|
602
603
|
it 'should not update window when data received is less than half of maximum local window size' do
|
603
|
-
data =
|
604
|
+
data = data_frame
|
604
605
|
datalen = data[:payload].bytesize
|
605
606
|
expect(@stream).not_to receive(:send) do |frame|
|
606
607
|
expect(frame[:type]).to eq :window_update
|
607
608
|
expect(frame[:increment]).to eq datalen
|
608
609
|
end
|
609
|
-
@stream.receive
|
610
|
+
@stream.receive headers_frame
|
610
611
|
@stream.receive data
|
611
612
|
end
|
612
613
|
|
613
614
|
it 'should update window when data received is over half of the maximum local window size' do
|
614
|
-
data1 =
|
615
|
-
data2 =
|
615
|
+
data1 = data_frame.merge(payload: 'a'*16_384, flags: [])
|
616
|
+
data2 = data_frame.merge(payload: 'a'*16_384)
|
616
617
|
datalen = 16_384 * 2
|
617
618
|
expect(@stream).to receive(:send) do |frame|
|
618
619
|
expect(frame[:type]).to eq :window_update
|
619
620
|
expect(frame[:increment]).to eq datalen
|
620
621
|
end
|
621
|
-
@stream.receive
|
622
|
+
@stream.receive headers_frame
|
622
623
|
@stream.receive data1
|
623
624
|
@stream.receive data2
|
624
625
|
end
|
@@ -750,7 +751,7 @@ RSpec.describe HTTP2::Stream do
|
|
750
751
|
end
|
751
752
|
|
752
753
|
it 'should emit received headers via on(:headers)' do
|
753
|
-
headers, recv =
|
754
|
+
headers, recv = REQUEST_HEADERS, nil
|
754
755
|
@srv.on(:stream) do |stream|
|
755
756
|
stream.on(:headers) { |h| recv = h }
|
756
757
|
end
|
@@ -767,7 +768,7 @@ RSpec.describe HTTP2::Stream do
|
|
767
768
|
end
|
768
769
|
end
|
769
770
|
|
770
|
-
@client_stream.headers(
|
771
|
+
@client_stream.headers(REQUEST_HEADERS)
|
771
772
|
@client_stream.data(payload)
|
772
773
|
end
|
773
774
|
|
@@ -783,7 +784,7 @@ RSpec.describe HTTP2::Stream do
|
|
783
784
|
end
|
784
785
|
end
|
785
786
|
|
786
|
-
@client_stream.headers(
|
787
|
+
@client_stream.headers(REQUEST_HEADERS)
|
787
788
|
@client_stream.reprioritize(weight: new_weight, dependency: new_dependency)
|
788
789
|
expect(callback_called).to be
|
789
790
|
end
|
@@ -795,18 +796,18 @@ RSpec.describe HTTP2::Stream do
|
|
795
796
|
@server_stream = stream
|
796
797
|
end
|
797
798
|
|
798
|
-
@client_stream.headers(
|
799
|
+
@client_stream.headers(REQUEST_HEADERS)
|
799
800
|
end
|
800
801
|
|
801
802
|
it '.promise should emit server initiated stream' do
|
802
803
|
push = nil
|
803
|
-
@server_stream.promise(
|
804
|
+
@server_stream.promise(REQUEST_HEADERS) { |pstream| push = pstream }
|
804
805
|
expect(push.id).to eq 2
|
805
806
|
end
|
806
807
|
|
807
808
|
it '.promise push stream should have parent stream' do
|
808
809
|
push = nil
|
809
|
-
@server_stream.promise(
|
810
|
+
@server_stream.promise(REQUEST_HEADERS) { |pstream| push = pstream }
|
810
811
|
|
811
812
|
expect(push.state).to eq :reserved_local
|
812
813
|
expect(push.parent.id).to eq @server_stream.id
|
@@ -815,7 +816,7 @@ RSpec.describe HTTP2::Stream do
|
|
815
816
|
context 'stream states' do
|
816
817
|
it 'server: active > half close > close' do
|
817
818
|
order = []
|
818
|
-
@server_stream.promise(
|
819
|
+
@server_stream.promise(REQUEST_HEADERS) do |push|
|
819
820
|
stream = push
|
820
821
|
|
821
822
|
expect(push.state).to eq :reserved_local
|
@@ -825,8 +826,8 @@ RSpec.describe HTTP2::Stream do
|
|
825
826
|
push.on(:half_close) { order << :half_close }
|
826
827
|
push.on(:close) { order << :close }
|
827
828
|
|
828
|
-
push.headers(
|
829
|
-
push.send
|
829
|
+
push.headers(RESPONSE_HEADERS)
|
830
|
+
push.send data_frame.merge(stream: stream.id)
|
830
831
|
end
|
831
832
|
|
832
833
|
expect(order).to eq [:reserved, :active, :half_close, :close]
|
@@ -854,13 +855,13 @@ RSpec.describe HTTP2::Stream do
|
|
854
855
|
expect(push.id).to be_even
|
855
856
|
end
|
856
857
|
|
857
|
-
@server_stream.promise(
|
858
|
-
push.headers(
|
858
|
+
@server_stream.promise(REQUEST_HEADERS) do |push|
|
859
|
+
push.headers(RESPONSE_HEADERS)
|
859
860
|
push.data('somedata')
|
860
861
|
end
|
861
862
|
|
862
|
-
expect(promise_headers).to eq(
|
863
|
-
expect(headers).to eq(
|
863
|
+
expect(promise_headers).to eq(REQUEST_HEADERS)
|
864
|
+
expect(headers).to eq(RESPONSE_HEADERS)
|
864
865
|
expect(order).to eq [
|
865
866
|
:reserved,
|
866
867
|
:promise_headers,
|