http-2 0.9.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 +44 -8
- data/.rubocop_todo.yml +6 -3
- data/.travis.yml +1 -1
- data/Gemfile +1 -1
- data/Guardfile +0 -1
- data/LICENSE +21 -0
- data/README.md +13 -19
- data/example/client.rb +1 -1
- data/example/server.rb +1 -1
- data/example/upgrade_client.rb +5 -6
- data/example/upgrade_server.rb +2 -2
- data/http-2.gemspec +2 -3
- data/lib/http/2/client.rb +6 -1
- data/lib/http/2/compressor.rb +19 -4
- data/lib/http/2/connection.rb +54 -15
- data/lib/http/2/framer.rb +3 -2
- data/lib/http/2/stream.rb +14 -1
- data/lib/http/2/version.rb +1 -1
- data/spec/client_spec.rb +74 -11
- data/spec/compressor_spec.rb +145 -26
- data/spec/connection_spec.rb +123 -82
- data/spec/framer_spec.rb +5 -5
- data/spec/helper.rb +125 -107
- data/spec/server_spec.rb +2 -1
- data/spec/stream_spec.rb +113 -111
- metadata +8 -8
data/spec/framer_spec.rb
CHANGED
@@ -341,11 +341,11 @@ RSpec.describe HTTP2::Framer do
|
|
341
341
|
length: 44,
|
342
342
|
type: :altsvc,
|
343
343
|
stream: 1,
|
344
|
-
max_age: 1_402_290_402,
|
345
|
-
port: 8080,
|
346
|
-
proto: 'h2-13',
|
347
|
-
host: 'www.example.com',
|
348
|
-
origin: 'www.example.com',
|
344
|
+
max_age: 1_402_290_402, # 4
|
345
|
+
port: 8080, # 2
|
346
|
+
proto: 'h2-13', # 1 + 5
|
347
|
+
host: 'www.example.com', # 1 + 15
|
348
|
+
origin: 'www.example.com', # 15
|
349
349
|
}
|
350
350
|
bytes = f.generate(frame)
|
351
351
|
expected = [0, 43, 0xa, 0, 1, 1_402_290_402, 8080].pack('CnCCNNn')
|
data/spec/helper.rb
CHANGED
@@ -8,117 +8,135 @@ require 'coveralls'
|
|
8
8
|
|
9
9
|
Coveralls.wear! if ENV['CI']
|
10
10
|
|
11
|
+
# rubocop: disable Style/MixinUsage
|
11
12
|
require 'http/2'
|
12
|
-
|
13
13
|
include HTTP2
|
14
14
|
include HTTP2::Header
|
15
15
|
include HTTP2::Error
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
16
|
+
# rubocop: enable Style/MixinUsage
|
17
|
+
|
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
|
122
140
|
|
123
141
|
def set_stream_id(bytes, id)
|
124
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
|
@@ -194,10 +195,11 @@ RSpec.describe HTTP2::Stream do
|
|
194
195
|
it 'should transition to closed if sending RST_STREAM' do
|
195
196
|
@stream.close
|
196
197
|
expect(@stream.state).to eq :closed
|
198
|
+
expect(@stream).to be_closed
|
197
199
|
end
|
198
200
|
|
199
201
|
it 'should transition to closed if receiving RST_STREAM' do
|
200
|
-
@stream.receive
|
202
|
+
@stream.receive rst_stream_frame
|
201
203
|
expect(@stream.state).to eq :closed
|
202
204
|
end
|
203
205
|
|
@@ -208,8 +210,8 @@ RSpec.describe HTTP2::Stream do
|
|
208
210
|
sp.on(:active) { openp = true }
|
209
211
|
sr.on(:active) { openr = true }
|
210
212
|
|
211
|
-
sp.receive
|
212
|
-
sr.send
|
213
|
+
sp.receive headers_frame
|
214
|
+
sr.send headers_frame
|
213
215
|
|
214
216
|
expect(openp).to be_truthy
|
215
217
|
expect(openr).to be_truthy
|
@@ -222,11 +224,11 @@ RSpec.describe HTTP2::Stream do
|
|
222
224
|
stream.on(:half_close) { order << :half_close }
|
223
225
|
stream.on(:close) { order << :close }
|
224
226
|
|
225
|
-
req =
|
227
|
+
req = headers_frame
|
226
228
|
req[:flags] = [:end_headers]
|
227
229
|
|
228
230
|
stream.send req
|
229
|
-
stream.send
|
231
|
+
stream.send data_frame
|
230
232
|
expect(order).to eq [:active, :half_close]
|
231
233
|
end
|
232
234
|
|
@@ -237,7 +239,7 @@ RSpec.describe HTTP2::Stream do
|
|
237
239
|
sp.on(:close) { closep = true }
|
238
240
|
sr.on(:close) { closer = true }
|
239
241
|
|
240
|
-
sp.receive
|
242
|
+
sp.receive rst_stream_frame
|
241
243
|
sr.close
|
242
244
|
|
243
245
|
expect(closep).to be_truthy
|
@@ -252,12 +254,12 @@ RSpec.describe HTTP2::Stream do
|
|
252
254
|
stream.on(:half_close) { order << :half_close }
|
253
255
|
stream.on(:close) { order << :close }
|
254
256
|
|
255
|
-
req =
|
257
|
+
req = headers_frame
|
256
258
|
req[:flags] = [:end_stream, :end_headers]
|
257
259
|
|
258
260
|
stream.send req
|
259
|
-
stream.receive
|
260
|
-
stream.receive
|
261
|
+
stream.receive headers_frame
|
262
|
+
stream.receive data_frame
|
261
263
|
|
262
264
|
expect(order).to eq [:active, :half_close, :data, :close]
|
263
265
|
end
|
@@ -265,31 +267,31 @@ RSpec.describe HTTP2::Stream do
|
|
265
267
|
it 'should emit :close with reason' do
|
266
268
|
reason = nil
|
267
269
|
@stream.on(:close) { |r| reason = r }
|
268
|
-
@stream.receive
|
270
|
+
@stream.receive rst_stream_frame
|
269
271
|
expect(reason).not_to be_nil
|
270
272
|
end
|
271
273
|
|
272
274
|
it 'should reprioritize stream on sent PRIORITY' do
|
273
|
-
expect { @stream.send
|
275
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
274
276
|
expect(@stream.weight).to eq 20
|
275
277
|
end
|
276
278
|
it 'should reprioritize stream on received PRIORITY' do
|
277
|
-
expect { @stream.receive
|
279
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
278
280
|
expect(@stream.weight).to eq 20
|
279
281
|
end
|
280
282
|
end
|
281
283
|
|
282
284
|
context 'half closed (local)' do
|
283
|
-
before(:each) { @stream.send
|
285
|
+
before(:each) { @stream.send headers_frame.merge(flags: [:end_headers, :end_stream]) }
|
284
286
|
|
285
287
|
it 'should raise error on attempt to send invalid frames' do
|
286
|
-
|
288
|
+
frame_types.reject { |frame| %i[priority rst_stream window_update].include?(frame[:type]) }.each do |frame|
|
287
289
|
expect { @stream.dup.send frame }.to raise_error InternalError
|
288
290
|
end
|
289
291
|
end
|
290
292
|
|
291
293
|
it 'should transition to closed on receipt of END_STREAM flag' do
|
292
|
-
[
|
294
|
+
[data_frame, headers_frame, continuation_frame].each do |frame|
|
293
295
|
s, f = @stream.dup, frame.dup
|
294
296
|
f[:flags] = [:end_stream]
|
295
297
|
|
@@ -299,38 +301,38 @@ RSpec.describe HTTP2::Stream do
|
|
299
301
|
end
|
300
302
|
|
301
303
|
it 'should transition to closed on receipt of RST_STREAM frame' do
|
302
|
-
@stream.receive
|
304
|
+
@stream.receive rst_stream_frame
|
303
305
|
expect(@stream.state).to eq :closed
|
304
306
|
end
|
305
307
|
|
306
308
|
it 'should transition to closed if RST_STREAM frame is sent' do
|
307
|
-
@stream.send
|
309
|
+
@stream.send rst_stream_frame
|
308
310
|
expect(@stream.state).to eq :closed
|
309
311
|
end
|
310
312
|
|
311
313
|
it 'should ignore received WINDOW_UPDATE frames' do
|
312
|
-
expect { @stream.receive
|
314
|
+
expect { @stream.receive window_update_frame }.to_not raise_error
|
313
315
|
expect(@stream.state).to eq :half_closed_local
|
314
316
|
end
|
315
317
|
|
316
318
|
it 'should ignore received PRIORITY frames' do
|
317
|
-
expect { @stream.receive
|
319
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
318
320
|
expect(@stream.state).to eq :half_closed_local
|
319
321
|
end
|
320
322
|
|
321
323
|
it 'should reprioritize stream on sent PRIORITY' do
|
322
|
-
expect { @stream.send
|
324
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
323
325
|
expect(@stream.weight).to eq 20
|
324
326
|
end
|
325
327
|
|
326
328
|
it 'should reprioritize stream (and decendants) on received PRIORITY' do
|
327
|
-
expect { @stream.receive
|
329
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
328
330
|
expect(@stream.weight).to eq 20
|
329
331
|
end
|
330
332
|
|
331
333
|
it 'should increment local_window on sent WINDOW_UPDATE' do
|
332
|
-
expect { @stream.send
|
333
|
-
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]
|
334
336
|
end
|
335
337
|
|
336
338
|
it 'should emit :half_close event on transition' do
|
@@ -339,7 +341,7 @@ RSpec.describe HTTP2::Stream do
|
|
339
341
|
stream.on(:active) { order << :active }
|
340
342
|
stream.on(:half_close) { order << :half_close }
|
341
343
|
|
342
|
-
req =
|
344
|
+
req = headers_frame
|
343
345
|
req[:flags] = [:end_stream, :end_headers]
|
344
346
|
|
345
347
|
stream.send req
|
@@ -349,7 +351,7 @@ RSpec.describe HTTP2::Stream do
|
|
349
351
|
it 'should emit :close event on transition to closed' do
|
350
352
|
closed = false
|
351
353
|
@stream.on(:close) { closed = true }
|
352
|
-
@stream.receive
|
354
|
+
@stream.receive rst_stream_frame
|
353
355
|
|
354
356
|
expect(@stream.state).to eq :closed
|
355
357
|
expect(closed).to be_truthy
|
@@ -357,10 +359,10 @@ RSpec.describe HTTP2::Stream do
|
|
357
359
|
end
|
358
360
|
|
359
361
|
context 'half closed (remote)' do
|
360
|
-
before(:each) { @stream.receive
|
362
|
+
before(:each) { @stream.receive headers_frame.merge(flags: [:end_headers, :end_stream]) }
|
361
363
|
|
362
364
|
it 'should raise STREAM_CLOSED error on reciept of frames' do
|
363
|
-
(
|
365
|
+
(frame_types - [priority_frame, rst_stream_frame, window_update_frame]).each do |frame|
|
364
366
|
expect do
|
365
367
|
@stream.dup.receive frame
|
366
368
|
end.to raise_error(StreamClosed)
|
@@ -368,7 +370,7 @@ RSpec.describe HTTP2::Stream do
|
|
368
370
|
end
|
369
371
|
|
370
372
|
it 'should transition to closed if END_STREAM flag is sent' do
|
371
|
-
[
|
373
|
+
[data_frame, headers_frame].each do |frame|
|
372
374
|
s, f = @stream.dup, frame.deep_dup
|
373
375
|
f[:flags] = [:end_stream]
|
374
376
|
|
@@ -408,26 +410,26 @@ RSpec.describe HTTP2::Stream do
|
|
408
410
|
end
|
409
411
|
|
410
412
|
it 'should transition to closed on reciept of RST_STREAM frame' do
|
411
|
-
@stream.receive
|
413
|
+
@stream.receive rst_stream_frame
|
412
414
|
expect(@stream.state).to eq :closed
|
413
415
|
end
|
414
416
|
|
415
417
|
it 'should ignore sent WINDOW_UPDATE frames' do
|
416
|
-
expect { @stream.send
|
418
|
+
expect { @stream.send window_update_frame }.to_not raise_error
|
417
419
|
expect(@stream.state).to eq :half_closed_remote
|
418
420
|
end
|
419
421
|
|
420
422
|
it 'should increment remote_window on received WINDOW_UPDATE' do
|
421
|
-
expect { @stream.receive
|
422
|
-
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]
|
423
425
|
end
|
424
426
|
|
425
427
|
it 'should reprioritize stream on sent PRIORITY' do
|
426
|
-
expect { @stream.send
|
428
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
427
429
|
expect(@stream.weight).to eq 20
|
428
430
|
end
|
429
431
|
it 'should reprioritize stream on received PRIORITY' do
|
430
|
-
expect { @stream.receive
|
432
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
431
433
|
expect(@stream.weight).to eq 20
|
432
434
|
end
|
433
435
|
|
@@ -437,7 +439,7 @@ RSpec.describe HTTP2::Stream do
|
|
437
439
|
stream.on(:active) { order << :active }
|
438
440
|
stream.on(:half_close) { order << :half_close }
|
439
441
|
|
440
|
-
req =
|
442
|
+
req = headers_frame
|
441
443
|
req[:flags] = [:end_stream, :end_headers]
|
442
444
|
|
443
445
|
stream.receive req
|
@@ -457,12 +459,12 @@ RSpec.describe HTTP2::Stream do
|
|
457
459
|
context 'closed' do
|
458
460
|
context 'remote closed stream' do
|
459
461
|
before(:each) do
|
460
|
-
@stream.send
|
461
|
-
@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
|
462
464
|
end
|
463
465
|
|
464
466
|
it 'should raise STREAM_CLOSED on attempt to send frames' do
|
465
|
-
(
|
467
|
+
(frame_types - [priority_frame, rst_stream_frame]).each do |frame|
|
466
468
|
expect do
|
467
469
|
@stream.dup.send frame
|
468
470
|
end.to raise_error(StreamClosed)
|
@@ -470,7 +472,7 @@ RSpec.describe HTTP2::Stream do
|
|
470
472
|
end
|
471
473
|
|
472
474
|
it 'should raise STREAM_CLOSED on receipt of frame' do
|
473
|
-
(
|
475
|
+
(frame_types - [priority_frame, rst_stream_frame, window_update_frame]).each do |frame|
|
474
476
|
expect do
|
475
477
|
@stream.dup.receive frame
|
476
478
|
end.to raise_error(StreamClosed)
|
@@ -478,38 +480,38 @@ RSpec.describe HTTP2::Stream do
|
|
478
480
|
end
|
479
481
|
|
480
482
|
it 'should allow PRIORITY, RST_STREAM to be sent' do
|
481
|
-
expect { @stream.send
|
482
|
-
expect { @stream.send
|
483
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
484
|
+
expect { @stream.send rst_stream_frame }.to_not raise_error
|
483
485
|
end
|
484
486
|
|
485
487
|
it 'should allow PRIORITY, RST_STREAM to be received' do
|
486
|
-
expect { @stream.receive
|
487
|
-
expect { @stream.receive
|
488
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
489
|
+
expect { @stream.receive rst_stream_frame }.to_not raise_error
|
488
490
|
end
|
489
491
|
|
490
492
|
it 'should reprioritize stream on sent PRIORITY' do
|
491
|
-
expect { @stream.send
|
493
|
+
expect { @stream.send priority_frame }.to_not raise_error
|
492
494
|
expect(@stream.weight).to eq 20
|
493
495
|
end
|
494
496
|
it 'should reprioritize stream on received PRIORITY' do
|
495
|
-
expect { @stream.receive
|
497
|
+
expect { @stream.receive priority_frame }.to_not raise_error
|
496
498
|
expect(@stream.weight).to eq 20
|
497
499
|
end
|
498
500
|
|
499
501
|
it 'should ignore received WINDOW_UPDATE frames' do
|
500
|
-
expect { @stream.receive
|
502
|
+
expect { @stream.receive window_update_frame }.to_not raise_error
|
501
503
|
expect(@stream.state).to eq :closed
|
502
504
|
end
|
503
505
|
end
|
504
506
|
|
505
507
|
context 'local closed via RST_STREAM frame' do
|
506
508
|
before(:each) do
|
507
|
-
@stream.send
|
508
|
-
@stream.send
|
509
|
+
@stream.send headers_frame # open
|
510
|
+
@stream.send rst_stream_frame # closed by local
|
509
511
|
end
|
510
512
|
|
511
513
|
it 'should ignore received frames' do
|
512
|
-
(
|
514
|
+
(frame_types - [push_promise_frame]).each do |frame|
|
513
515
|
expect do
|
514
516
|
cb = []
|
515
517
|
@stream.on(:data) { cb << :data }
|
@@ -532,12 +534,12 @@ RSpec.describe HTTP2::Stream do
|
|
532
534
|
# FIXME: Isn't this test same as "half closed (local)"?
|
533
535
|
# context "local closed via END_STREAM flag" do
|
534
536
|
# before(:each) do
|
535
|
-
# @stream.send
|
536
|
-
# @stream.send
|
537
|
+
# @stream.send headers_frame # open
|
538
|
+
# @stream.send data_frame # contains end_stream flag
|
537
539
|
# end
|
538
540
|
|
539
541
|
# it "should ignore received frames" do
|
540
|
-
#
|
542
|
+
# frame_types.each do |frame|
|
541
543
|
# expect { @stream.dup.receive frame }.to_not raise_error
|
542
544
|
# end
|
543
545
|
# end
|
@@ -553,31 +555,31 @@ RSpec.describe HTTP2::Stream do
|
|
553
555
|
end
|
554
556
|
|
555
557
|
it 'should update window size on DATA frames only' do
|
556
|
-
@stream.send
|
558
|
+
@stream.send headers_frame # go to open
|
557
559
|
expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW
|
558
560
|
|
559
|
-
(
|
561
|
+
(frame_types - [data_frame, ping_frame, goaway_frame, settings_frame]).each do |frame|
|
560
562
|
s = @stream.dup
|
561
563
|
s.send frame.deep_dup
|
562
564
|
expect(s.remote_window).to eq DEFAULT_FLOW_WINDOW
|
563
565
|
end
|
564
566
|
|
565
|
-
@stream.send
|
566
|
-
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
|
567
569
|
end
|
568
570
|
|
569
571
|
it 'should update window size on receipt of WINDOW_UPDATE' do
|
570
|
-
@stream.send
|
571
|
-
@stream.send
|
572
|
-
@stream.receive
|
572
|
+
@stream.send headers_frame
|
573
|
+
@stream.send data_frame
|
574
|
+
@stream.receive window_update_frame
|
573
575
|
|
574
576
|
expect(@stream.remote_window).to eq(
|
575
|
-
DEFAULT_FLOW_WINDOW -
|
577
|
+
DEFAULT_FLOW_WINDOW - data_frame[:payload].bytesize + window_update_frame[:increment],
|
576
578
|
)
|
577
579
|
end
|
578
580
|
|
579
581
|
it 'should observe session flow control' do
|
580
|
-
settings, data =
|
582
|
+
settings, data = settings_frame, data_frame
|
581
583
|
settings[:payload] = [[:settings_initial_window_size, 1000]]
|
582
584
|
settings[:stream] = 0
|
583
585
|
|
@@ -585,7 +587,7 @@ RSpec.describe HTTP2::Stream do
|
|
585
587
|
@client << framer.generate(settings)
|
586
588
|
|
587
589
|
s1 = @client.new_stream
|
588
|
-
s1.send
|
590
|
+
s1.send headers_frame
|
589
591
|
s1.send data.merge(payload: 'x' * 900, flags: [])
|
590
592
|
expect(s1.remote_window).to eq 100
|
591
593
|
|
@@ -593,31 +595,31 @@ RSpec.describe HTTP2::Stream do
|
|
593
595
|
expect(s1.remote_window).to eq 0
|
594
596
|
expect(s1.buffered_amount).to eq 100
|
595
597
|
|
596
|
-
@client << framer.generate(
|
598
|
+
@client << framer.generate(window_update_frame.merge(stream: s1.id, increment: 1000))
|
597
599
|
expect(s1.buffered_amount).to eq 0
|
598
600
|
expect(s1.remote_window).to eq 900
|
599
601
|
end
|
600
602
|
|
601
603
|
it 'should not update window when data received is less than half of maximum local window size' do
|
602
|
-
data =
|
604
|
+
data = data_frame
|
603
605
|
datalen = data[:payload].bytesize
|
604
606
|
expect(@stream).not_to receive(:send) do |frame|
|
605
607
|
expect(frame[:type]).to eq :window_update
|
606
608
|
expect(frame[:increment]).to eq datalen
|
607
609
|
end
|
608
|
-
@stream.receive
|
610
|
+
@stream.receive headers_frame
|
609
611
|
@stream.receive data
|
610
612
|
end
|
611
613
|
|
612
614
|
it 'should update window when data received is over half of the maximum local window size' do
|
613
|
-
data1 =
|
614
|
-
data2 =
|
615
|
+
data1 = data_frame.merge(payload: 'a'*16_384, flags: [])
|
616
|
+
data2 = data_frame.merge(payload: 'a'*16_384)
|
615
617
|
datalen = 16_384 * 2
|
616
618
|
expect(@stream).to receive(:send) do |frame|
|
617
619
|
expect(frame[:type]).to eq :window_update
|
618
620
|
expect(frame[:increment]).to eq datalen
|
619
621
|
end
|
620
|
-
@stream.receive
|
622
|
+
@stream.receive headers_frame
|
621
623
|
@stream.receive data1
|
622
624
|
@stream.receive data2
|
623
625
|
end
|
@@ -749,7 +751,7 @@ RSpec.describe HTTP2::Stream do
|
|
749
751
|
end
|
750
752
|
|
751
753
|
it 'should emit received headers via on(:headers)' do
|
752
|
-
headers, recv =
|
754
|
+
headers, recv = REQUEST_HEADERS, nil
|
753
755
|
@srv.on(:stream) do |stream|
|
754
756
|
stream.on(:headers) { |h| recv = h }
|
755
757
|
end
|
@@ -766,7 +768,7 @@ RSpec.describe HTTP2::Stream do
|
|
766
768
|
end
|
767
769
|
end
|
768
770
|
|
769
|
-
@client_stream.headers(
|
771
|
+
@client_stream.headers(REQUEST_HEADERS)
|
770
772
|
@client_stream.data(payload)
|
771
773
|
end
|
772
774
|
|
@@ -782,7 +784,7 @@ RSpec.describe HTTP2::Stream do
|
|
782
784
|
end
|
783
785
|
end
|
784
786
|
|
785
|
-
@client_stream.headers(
|
787
|
+
@client_stream.headers(REQUEST_HEADERS)
|
786
788
|
@client_stream.reprioritize(weight: new_weight, dependency: new_dependency)
|
787
789
|
expect(callback_called).to be
|
788
790
|
end
|
@@ -794,18 +796,18 @@ RSpec.describe HTTP2::Stream do
|
|
794
796
|
@server_stream = stream
|
795
797
|
end
|
796
798
|
|
797
|
-
@client_stream.headers(
|
799
|
+
@client_stream.headers(REQUEST_HEADERS)
|
798
800
|
end
|
799
801
|
|
800
802
|
it '.promise should emit server initiated stream' do
|
801
803
|
push = nil
|
802
|
-
@server_stream.promise(
|
804
|
+
@server_stream.promise(REQUEST_HEADERS) { |pstream| push = pstream }
|
803
805
|
expect(push.id).to eq 2
|
804
806
|
end
|
805
807
|
|
806
808
|
it '.promise push stream should have parent stream' do
|
807
809
|
push = nil
|
808
|
-
@server_stream.promise(
|
810
|
+
@server_stream.promise(REQUEST_HEADERS) { |pstream| push = pstream }
|
809
811
|
|
810
812
|
expect(push.state).to eq :reserved_local
|
811
813
|
expect(push.parent.id).to eq @server_stream.id
|
@@ -814,7 +816,7 @@ RSpec.describe HTTP2::Stream do
|
|
814
816
|
context 'stream states' do
|
815
817
|
it 'server: active > half close > close' do
|
816
818
|
order = []
|
817
|
-
@server_stream.promise(
|
819
|
+
@server_stream.promise(REQUEST_HEADERS) do |push|
|
818
820
|
stream = push
|
819
821
|
|
820
822
|
expect(push.state).to eq :reserved_local
|
@@ -824,8 +826,8 @@ RSpec.describe HTTP2::Stream do
|
|
824
826
|
push.on(:half_close) { order << :half_close }
|
825
827
|
push.on(:close) { order << :close }
|
826
828
|
|
827
|
-
push.headers(
|
828
|
-
push.send
|
829
|
+
push.headers(RESPONSE_HEADERS)
|
830
|
+
push.send data_frame.merge(stream: stream.id)
|
829
831
|
end
|
830
832
|
|
831
833
|
expect(order).to eq [:reserved, :active, :half_close, :close]
|
@@ -853,13 +855,13 @@ RSpec.describe HTTP2::Stream do
|
|
853
855
|
expect(push.id).to be_even
|
854
856
|
end
|
855
857
|
|
856
|
-
@server_stream.promise(
|
857
|
-
push.headers(
|
858
|
+
@server_stream.promise(REQUEST_HEADERS) do |push|
|
859
|
+
push.headers(RESPONSE_HEADERS)
|
858
860
|
push.data('somedata')
|
859
861
|
end
|
860
862
|
|
861
|
-
expect(promise_headers).to eq(
|
862
|
-
expect(headers).to eq(
|
863
|
+
expect(promise_headers).to eq(REQUEST_HEADERS)
|
864
|
+
expect(headers).to eq(RESPONSE_HEADERS)
|
863
865
|
expect(order).to eq [
|
864
866
|
:reserved,
|
865
867
|
:promise_headers,
|