http-2 0.9.0 → 0.11.0
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/.rspec +1 -0
- data/.rubocop.yml +44 -8
- data/.rubocop_todo.yml +15 -3
- data/.travis.yml +7 -4
- 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 +21 -6
- data/lib/http/2/connection.rb +62 -20
- 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 +155 -84
- data/spec/framer_spec.rb +5 -5
- data/spec/helper.rb +125 -107
- data/spec/server_spec.rb +3 -2
- data/spec/stream_spec.rb +113 -111
- metadata +11 -11
data/spec/connection_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
RSpec.describe HTTP2::Connection do
|
4
|
+
include FrameHelpers
|
4
5
|
before(:each) do
|
5
6
|
@conn = Client.new
|
6
7
|
end
|
@@ -8,18 +9,21 @@ RSpec.describe HTTP2::Connection do
|
|
8
9
|
let(:f) { Framer.new }
|
9
10
|
|
10
11
|
context 'initialization and settings' do
|
11
|
-
it 'should raise error if first frame is not
|
12
|
-
(
|
13
|
-
|
14
|
-
expect
|
12
|
+
it 'should raise error if first frame is not settings' do
|
13
|
+
(frame_types - [settings_frame]).each do |frame|
|
14
|
+
expect { @conn << frame }.to raise_error(ProtocolError)
|
15
|
+
expect(@conn).to be_closed
|
15
16
|
end
|
17
|
+
end
|
16
18
|
|
17
|
-
|
19
|
+
it 'should not raise error if first frame is SETTINGS' do
|
20
|
+
expect { @conn << f.generate(settings_frame) }.to_not raise_error
|
18
21
|
expect(@conn.state).to eq :connected
|
22
|
+
expect(@conn).to_not be_closed
|
19
23
|
end
|
20
24
|
|
21
25
|
it 'should raise error if SETTINGS stream != 0' do
|
22
|
-
frame = set_stream_id(f.generate(
|
26
|
+
frame = set_stream_id(f.generate(settings_frame), 0x1)
|
23
27
|
expect { @conn << frame }.to raise_error(ProtocolError)
|
24
28
|
end
|
25
29
|
end
|
@@ -38,7 +42,7 @@ RSpec.describe HTTP2::Connection do
|
|
38
42
|
|
39
43
|
it 'should reflect incoming settings when SETTINGS is received' do
|
40
44
|
expect(@conn.remote_settings[:settings_header_table_size]).to eq 4096
|
41
|
-
settings =
|
45
|
+
settings = settings_frame
|
42
46
|
settings[:payload] = [[:settings_header_table_size, 256]]
|
43
47
|
|
44
48
|
@conn << f.generate(settings)
|
@@ -46,17 +50,39 @@ RSpec.describe HTTP2::Connection do
|
|
46
50
|
expect(@conn.remote_settings[:settings_header_table_size]).to eq 256
|
47
51
|
end
|
48
52
|
|
53
|
+
it 'should reflect settings_max_frame_size recevied from peer' do
|
54
|
+
settings = settings_frame
|
55
|
+
settings[:payload] = [[:settings_max_frame_size, 16_385]]
|
56
|
+
|
57
|
+
@conn << f.generate(settings)
|
58
|
+
|
59
|
+
frame = {
|
60
|
+
length: 16_385,
|
61
|
+
type: :data,
|
62
|
+
flags: [:end_stream],
|
63
|
+
stream: 1,
|
64
|
+
payload: 'a' * 16_385,
|
65
|
+
}
|
66
|
+
expect { @conn.send(frame) }.not_to raise_error(CompressionError)
|
67
|
+
end
|
68
|
+
|
49
69
|
it 'should send SETTINGS ACK when SETTINGS is received' do
|
50
|
-
settings =
|
70
|
+
settings = settings_frame
|
51
71
|
settings[:payload] = [[:settings_header_table_size, 256]]
|
52
72
|
|
53
|
-
expect(
|
54
|
-
|
55
|
-
|
56
|
-
|
73
|
+
# We should expect two frames here (append .twice) - one for the connection setup, and one for the settings ack.
|
74
|
+
frames = []
|
75
|
+
expect(@conn).to receive(:send).twice do |frame|
|
76
|
+
frames << frame
|
57
77
|
end
|
58
78
|
|
79
|
+
@conn.send_connection_preface
|
59
80
|
@conn << f.generate(settings)
|
81
|
+
|
82
|
+
frame = frames.last
|
83
|
+
expect(frame[:type]).to eq :settings
|
84
|
+
expect(frame[:flags]).to eq [:ack]
|
85
|
+
expect(frame[:payload]).to eq []
|
60
86
|
end
|
61
87
|
end
|
62
88
|
|
@@ -66,44 +92,47 @@ RSpec.describe HTTP2::Connection do
|
|
66
92
|
end
|
67
93
|
|
68
94
|
it 'should change stream limit to received SETTINGS value' do
|
69
|
-
@conn << f.generate(
|
95
|
+
@conn << f.generate(settings_frame)
|
70
96
|
expect(@conn.remote_settings[:settings_max_concurrent_streams]).to eq 10
|
71
97
|
end
|
72
98
|
|
73
99
|
it 'should count open streams against stream limit' do
|
74
100
|
s = @conn.new_stream
|
75
101
|
expect(@conn.active_stream_count).to eq 0
|
76
|
-
s.receive
|
102
|
+
s.receive headers_frame
|
77
103
|
expect(@conn.active_stream_count).to eq 1
|
78
104
|
end
|
79
105
|
|
80
106
|
it 'should not count reserved streams against stream limit' do
|
81
107
|
s1 = @conn.new_stream
|
82
|
-
s1.receive
|
108
|
+
s1.receive push_promise_frame
|
83
109
|
expect(@conn.active_stream_count).to eq 0
|
84
110
|
|
85
111
|
s2 = @conn.new_stream
|
86
|
-
s2.send
|
112
|
+
s2.send push_promise_frame
|
87
113
|
expect(@conn.active_stream_count).to eq 0
|
88
114
|
|
89
115
|
# transition to half closed
|
90
|
-
s1.receive
|
91
|
-
s2.send
|
116
|
+
s1.receive headers_frame
|
117
|
+
s2.send headers_frame
|
92
118
|
expect(@conn.active_stream_count).to eq 2
|
93
119
|
|
94
120
|
# transition to closed
|
95
|
-
s1.receive
|
96
|
-
s2.send
|
121
|
+
s1.receive data_frame
|
122
|
+
s2.send data_frame
|
97
123
|
expect(@conn.active_stream_count).to eq 0
|
124
|
+
|
125
|
+
expect(s1).to be_closed
|
126
|
+
expect(s2).to be_closed
|
98
127
|
end
|
99
128
|
|
100
129
|
it 'should not exceed stream limit set by peer' do
|
101
|
-
@conn << f.generate(
|
130
|
+
@conn << f.generate(settings_frame)
|
102
131
|
|
103
132
|
expect do
|
104
133
|
10.times do
|
105
134
|
s = @conn.new_stream
|
106
|
-
s.send
|
135
|
+
s.send headers_frame
|
107
136
|
end
|
108
137
|
end.to_not raise_error
|
109
138
|
|
@@ -111,9 +140,9 @@ RSpec.describe HTTP2::Connection do
|
|
111
140
|
end
|
112
141
|
|
113
142
|
it 'should initialize stream with HEADERS priority value' do
|
114
|
-
@conn << f.generate(
|
143
|
+
@conn << f.generate(settings_frame)
|
115
144
|
|
116
|
-
stream, headers = nil,
|
145
|
+
stream, headers = nil, headers_frame
|
117
146
|
headers[:weight] = 20
|
118
147
|
headers[:stream_dependency] = 0
|
119
148
|
headers[:exclusive] = false
|
@@ -125,16 +154,33 @@ RSpec.describe HTTP2::Connection do
|
|
125
154
|
end
|
126
155
|
|
127
156
|
it 'should initialize idle stream on PRIORITY frame' do
|
128
|
-
@conn << f.generate(
|
157
|
+
@conn << f.generate(settings_frame)
|
129
158
|
|
130
159
|
stream = nil
|
131
160
|
@conn.on(:stream) { |s| stream = s }
|
132
|
-
@conn << f.generate(
|
161
|
+
@conn << f.generate(priority_frame)
|
133
162
|
|
134
163
|
expect(stream.state).to eq :idle
|
135
164
|
end
|
136
165
|
end
|
137
166
|
|
167
|
+
context 'cleanup_recently_closed' do
|
168
|
+
it 'should cleanup old connections' do
|
169
|
+
now_ts = Time.now.to_i
|
170
|
+
stream_ids = Array.new(4) { @conn.new_stream.id }
|
171
|
+
expect(@conn.instance_variable_get('@streams').size).to eq(4)
|
172
|
+
|
173
|
+
# Assume that the first 3 streams were closed in different time
|
174
|
+
recently_closed = stream_ids[0, 3].zip([now_ts - 100, now_ts - 50, now_ts - 5]).to_h
|
175
|
+
@conn.instance_variable_set('@streams_recently_closed', recently_closed)
|
176
|
+
|
177
|
+
# Cleanup should delete streams that were closed earlier than 15s ago
|
178
|
+
@conn.__send__(:cleanup_recently_closed)
|
179
|
+
expect(@conn.instance_variable_get('@streams').size).to eq(2)
|
180
|
+
expect(@conn.instance_variable_get('@streams_recently_closed')).to eq(stream_ids[2] => now_ts - 5)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
138
184
|
context 'Headers pre/post processing' do
|
139
185
|
it 'should not concatenate multiple occurences of a header field with the same name' do
|
140
186
|
input = [
|
@@ -161,16 +207,14 @@ RSpec.describe HTTP2::Connection do
|
|
161
207
|
end
|
162
208
|
|
163
209
|
it 'should not split zero-concatenated header field values' do
|
164
|
-
input = [
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
['cookie', "a=b\0c=d; e=f"],
|
173
|
-
]
|
210
|
+
input = [*RESPONSE_HEADERS,
|
211
|
+
['cache-control', "max-age=60, private\0must-revalidate"],
|
212
|
+
['content-type', 'text/html'],
|
213
|
+
['cookie', "a=b\0c=d; e=f"]]
|
214
|
+
expected = [*RESPONSE_HEADERS,
|
215
|
+
['cache-control', "max-age=60, private\0must-revalidate"],
|
216
|
+
['content-type', 'text/html'],
|
217
|
+
['cookie', "a=b\0c=d; e=f"]]
|
174
218
|
|
175
219
|
result = nil
|
176
220
|
@conn.on(:stream) do |stream|
|
@@ -192,13 +236,13 @@ RSpec.describe HTTP2::Connection do
|
|
192
236
|
end
|
193
237
|
|
194
238
|
it 'should update connection and stream windows on SETTINGS' do
|
195
|
-
settings, data =
|
239
|
+
settings, data = settings_frame, data_frame
|
196
240
|
settings[:payload] = [[:settings_initial_window_size, 1024]]
|
197
241
|
data[:payload] = 'x' * 2048
|
198
242
|
|
199
243
|
stream = @conn.new_stream
|
200
244
|
|
201
|
-
stream.send
|
245
|
+
stream.send headers_frame
|
202
246
|
stream.send data
|
203
247
|
expect(stream.remote_window).to eq(DEFAULT_FLOW_WINDOW - 2048)
|
204
248
|
expect(@conn.remote_window).to eq(DEFAULT_FLOW_WINDOW - 2048)
|
@@ -209,7 +253,7 @@ RSpec.describe HTTP2::Connection do
|
|
209
253
|
end
|
210
254
|
|
211
255
|
it 'should initialize streams with window specified by peer' do
|
212
|
-
settings =
|
256
|
+
settings = settings_frame
|
213
257
|
settings[:payload] = [[:settings_initial_window_size, 1024]]
|
214
258
|
|
215
259
|
@conn << f.generate(settings)
|
@@ -217,37 +261,37 @@ RSpec.describe HTTP2::Connection do
|
|
217
261
|
end
|
218
262
|
|
219
263
|
it 'should observe connection flow control' do
|
220
|
-
settings, data =
|
264
|
+
settings, data = settings_frame, data_frame
|
221
265
|
settings[:payload] = [[:settings_initial_window_size, 1000]]
|
222
266
|
|
223
267
|
@conn << f.generate(settings)
|
224
268
|
s1 = @conn.new_stream
|
225
269
|
s2 = @conn.new_stream
|
226
270
|
|
227
|
-
s1.send
|
271
|
+
s1.send headers_frame
|
228
272
|
s1.send data.merge(payload: 'x' * 900)
|
229
273
|
expect(@conn.remote_window).to eq 100
|
230
274
|
|
231
|
-
s2.send
|
275
|
+
s2.send headers_frame
|
232
276
|
s2.send data.merge(payload: 'x' * 200)
|
233
277
|
expect(@conn.remote_window).to eq 0
|
234
278
|
expect(@conn.buffered_amount).to eq 100
|
235
279
|
|
236
|
-
@conn << f.generate(
|
280
|
+
@conn << f.generate(window_update_frame.merge(stream: 0, increment: 1000))
|
237
281
|
expect(@conn.buffered_amount).to eq 0
|
238
282
|
expect(@conn.remote_window).to eq 900
|
239
283
|
end
|
240
284
|
|
241
285
|
it 'should update window when data received is over half of the maximum local window size' do
|
242
|
-
settings, data =
|
286
|
+
settings, data = settings_frame, data_frame
|
243
287
|
conn = Client.new(settings_initial_window_size: 500)
|
244
288
|
|
245
289
|
conn.receive f.generate(settings)
|
246
290
|
s1 = conn.new_stream
|
247
291
|
s2 = conn.new_stream
|
248
292
|
|
249
|
-
s1.send
|
250
|
-
s2.send
|
293
|
+
s1.send headers_frame
|
294
|
+
s2.send headers_frame
|
251
295
|
expect(conn).to receive(:send) do |frame|
|
252
296
|
expect(frame[:type]).to eq :window_update
|
253
297
|
expect(frame[:stream]).to eq 0
|
@@ -263,11 +307,11 @@ RSpec.describe HTTP2::Connection do
|
|
263
307
|
|
264
308
|
context 'framing' do
|
265
309
|
it 'should buffer incomplete frames' do
|
266
|
-
settings =
|
310
|
+
settings = settings_frame
|
267
311
|
settings[:payload] = [[:settings_initial_window_size, 1000]]
|
268
312
|
@conn << f.generate(settings)
|
269
313
|
|
270
|
-
frame = f.generate(
|
314
|
+
frame = f.generate(window_update_frame.merge(stream: 0, increment: 1000))
|
271
315
|
@conn << frame
|
272
316
|
expect(@conn.remote_window).to eq 2000
|
273
317
|
|
@@ -283,10 +327,10 @@ RSpec.describe HTTP2::Connection do
|
|
283
327
|
]
|
284
328
|
|
285
329
|
cc = Compressor.new
|
286
|
-
headers =
|
330
|
+
headers = headers_frame
|
287
331
|
headers[:payload] = cc.encode(req_headers)
|
288
332
|
|
289
|
-
@conn << f.generate(
|
333
|
+
@conn << f.generate(settings_frame)
|
290
334
|
@conn.on(:stream) do |stream|
|
291
335
|
expect(stream).to receive(:<<) do |frame|
|
292
336
|
expect(frame[:payload]).to eq req_headers
|
@@ -303,7 +347,7 @@ RSpec.describe HTTP2::Connection do
|
|
303
347
|
]
|
304
348
|
|
305
349
|
cc = Compressor.new
|
306
|
-
h1, h2 =
|
350
|
+
h1, h2 = headers_frame, continuation_frame
|
307
351
|
|
308
352
|
# Header block fragment might not complete for decompression
|
309
353
|
payload = cc.encode(req_headers)
|
@@ -314,7 +358,7 @@ RSpec.describe HTTP2::Connection do
|
|
314
358
|
h2[:payload] = payload # the remaining
|
315
359
|
h2[:stream] = 5
|
316
360
|
|
317
|
-
@conn << f.generate(
|
361
|
+
@conn << f.generate(settings_frame)
|
318
362
|
@conn.on(:stream) do |stream|
|
319
363
|
expect(stream).to receive(:<<) do |frame|
|
320
364
|
expect(frame[:payload]).to eq req_headers
|
@@ -326,28 +370,28 @@ RSpec.describe HTTP2::Connection do
|
|
326
370
|
end
|
327
371
|
|
328
372
|
it 'should require that split header blocks are a contiguous sequence' do
|
329
|
-
headers =
|
373
|
+
headers = headers_frame
|
330
374
|
headers[:flags] = []
|
331
375
|
|
332
|
-
@conn << f.generate(
|
376
|
+
@conn << f.generate(settings_frame)
|
333
377
|
@conn << f.generate(headers)
|
334
|
-
(
|
378
|
+
(frame_types - [continuation_frame]).each do |frame|
|
335
379
|
expect { @conn << f.generate(frame.deep_dup) }.to raise_error(ProtocolError)
|
336
380
|
end
|
337
381
|
end
|
338
382
|
|
339
383
|
it 'should raise compression error on encode of invalid frame' do
|
340
|
-
@conn << f.generate(
|
384
|
+
@conn << f.generate(settings_frame)
|
341
385
|
stream = @conn.new_stream
|
342
386
|
|
343
387
|
expect do
|
344
|
-
stream.headers('name' => Float::INFINITY)
|
388
|
+
stream.headers({ 'name' => Float::INFINITY })
|
345
389
|
end.to raise_error(CompressionError)
|
346
390
|
end
|
347
391
|
|
348
392
|
it 'should raise connection error on decode of invalid frame' do
|
349
|
-
@conn << f.generate(
|
350
|
-
frame = f.generate(
|
393
|
+
@conn << f.generate(settings_frame)
|
394
|
+
frame = f.generate(data_frame) # Receiving DATA on unopened stream 1 is an error.
|
351
395
|
# Connection errors emit protocol error frames
|
352
396
|
expect { @conn << frame }.to raise_error(ProtocolError)
|
353
397
|
end
|
@@ -358,7 +402,7 @@ RSpec.describe HTTP2::Connection do
|
|
358
402
|
@conn.settings(settings_max_concurrent_streams: 10,
|
359
403
|
settings_initial_window_size: 0x7fffffff)
|
360
404
|
|
361
|
-
expect(bytes).to eq f.generate(
|
405
|
+
expect(bytes).to eq f.generate(settings_frame)
|
362
406
|
end
|
363
407
|
|
364
408
|
it 'should compress stream headers' do
|
@@ -369,10 +413,10 @@ RSpec.describe HTTP2::Connection do
|
|
369
413
|
end
|
370
414
|
|
371
415
|
stream = @conn.new_stream
|
372
|
-
stream.headers(':method' => 'get',
|
373
|
-
|
374
|
-
|
375
|
-
|
416
|
+
stream.headers({ ':method' => 'get',
|
417
|
+
':scheme' => 'http',
|
418
|
+
':authority' => 'www.example.org',
|
419
|
+
':path' => '/resource' })
|
376
420
|
end
|
377
421
|
|
378
422
|
it 'should generate CONTINUATION if HEADERS is too long' do
|
@@ -470,79 +514,106 @@ RSpec.describe HTTP2::Connection do
|
|
470
514
|
context 'connection management' do
|
471
515
|
it 'should raise error on invalid connection header' do
|
472
516
|
srv = Server.new
|
473
|
-
expect { srv << f.generate(
|
517
|
+
expect { srv << f.generate(settings_frame) }.to raise_error(HandshakeError)
|
474
518
|
|
475
519
|
srv = Server.new
|
476
520
|
expect do
|
477
521
|
srv << CONNECTION_PREFACE_MAGIC
|
478
|
-
srv << f.generate(
|
522
|
+
srv << f.generate(settings_frame)
|
479
523
|
end.to_not raise_error
|
480
524
|
end
|
481
525
|
|
482
526
|
it 'should respond to PING frames' do
|
483
|
-
@conn << f.generate(
|
527
|
+
@conn << f.generate(settings_frame)
|
484
528
|
expect(@conn).to receive(:send) do |frame|
|
485
529
|
expect(frame[:type]).to eq :ping
|
486
530
|
expect(frame[:flags]).to eq [:ack]
|
487
531
|
expect(frame[:payload]).to eq '12345678'
|
488
532
|
end
|
489
533
|
|
490
|
-
@conn << f.generate(
|
534
|
+
@conn << f.generate(ping_frame)
|
491
535
|
end
|
492
536
|
|
493
537
|
it 'should fire callback on PONG' do
|
494
|
-
@conn << f.generate(
|
538
|
+
@conn << f.generate(settings_frame)
|
495
539
|
|
496
540
|
pong = nil
|
497
541
|
@conn.ping('12345678') { |d| pong = d }
|
498
|
-
@conn << f.generate(
|
542
|
+
@conn << f.generate(pong_frame)
|
499
543
|
expect(pong).to eq '12345678'
|
500
544
|
end
|
501
545
|
|
502
546
|
it 'should fire callback on receipt of GOAWAY' do
|
503
547
|
last_stream, payload, error = nil
|
504
|
-
@conn << f.generate(
|
548
|
+
@conn << f.generate(settings_frame)
|
505
549
|
@conn.on(:goaway) do |s, e, p|
|
506
550
|
last_stream = s
|
507
551
|
error = e
|
508
552
|
payload = p
|
509
553
|
end
|
510
|
-
@conn << f.generate(
|
554
|
+
@conn << f.generate(goaway_frame.merge(last_stream: 17, payload: 'test'))
|
511
555
|
|
512
556
|
expect(last_stream).to eq 17
|
513
557
|
expect(error).to eq :no_error
|
514
558
|
expect(payload).to eq 'test'
|
559
|
+
|
560
|
+
expect(@conn).to be_closed
|
515
561
|
end
|
516
562
|
|
517
563
|
it 'should raise error when opening new stream after sending GOAWAY' do
|
518
564
|
@conn.goaway
|
565
|
+
expect(@conn).to be_closed
|
566
|
+
|
519
567
|
expect { @conn.new_stream }.to raise_error(ConnectionClosed)
|
520
568
|
end
|
521
569
|
|
522
570
|
it 'should raise error when opening new stream after receiving GOAWAY' do
|
523
|
-
@conn << f.generate(
|
524
|
-
@conn << f.generate(
|
571
|
+
@conn << f.generate(settings_frame)
|
572
|
+
@conn << f.generate(goaway_frame)
|
525
573
|
expect { @conn.new_stream }.to raise_error(ConnectionClosed)
|
526
574
|
end
|
527
575
|
|
576
|
+
it 'should not raise error when receiving connection management frames immediately after emitting goaway' do
|
577
|
+
@conn.goaway
|
578
|
+
expect(@conn).to be_closed
|
579
|
+
|
580
|
+
expect { @conn << f.generate(settings_frame) }.not_to raise_error(ProtocolError)
|
581
|
+
expect { @conn << f.generate(ping_frame) }.not_to raise_error(ProtocolError)
|
582
|
+
expect { @conn << f.generate(goaway_frame) }.not_to raise_error(ProtocolError)
|
583
|
+
end
|
584
|
+
|
528
585
|
it 'should process connection management frames after GOAWAY' do
|
529
|
-
@conn << f.generate(
|
530
|
-
@conn << f.generate(
|
531
|
-
@conn << f.generate(
|
532
|
-
@conn << f.generate(
|
533
|
-
@conn << f.generate(
|
586
|
+
@conn << f.generate(settings_frame)
|
587
|
+
@conn << f.generate(headers_frame)
|
588
|
+
@conn << f.generate(goaway_frame)
|
589
|
+
@conn << f.generate(headers_frame.merge(stream: 7))
|
590
|
+
@conn << f.generate(push_promise_frame)
|
534
591
|
|
535
592
|
expect(@conn.active_stream_count).to eq 1
|
536
593
|
end
|
537
594
|
|
538
595
|
it 'should raise error on frame for invalid stream ID' do
|
539
|
-
@conn << f.generate(
|
596
|
+
@conn << f.generate(settings_frame)
|
540
597
|
|
541
598
|
expect do
|
542
|
-
@conn << f.generate(
|
599
|
+
@conn << f.generate(data_frame.merge(stream: 31))
|
543
600
|
end.to raise_error(ProtocolError)
|
544
601
|
end
|
545
602
|
|
603
|
+
it 'should not raise an error on frame for a closed stream ID' do
|
604
|
+
srv = Server.new
|
605
|
+
srv << CONNECTION_PREFACE_MAGIC
|
606
|
+
|
607
|
+
stream = srv.new_stream
|
608
|
+
stream.send headers_frame
|
609
|
+
stream.send data_frame
|
610
|
+
stream.close
|
611
|
+
|
612
|
+
expect do
|
613
|
+
srv << f.generate(rst_stream_frame.merge(stream: stream.id))
|
614
|
+
end.to_not raise_error
|
615
|
+
end
|
616
|
+
|
546
617
|
it 'should send GOAWAY frame on connection error' do
|
547
618
|
stream = @conn.new_stream
|
548
619
|
|
@@ -557,7 +628,7 @@ RSpec.describe HTTP2::Connection do
|
|
557
628
|
[frame]
|
558
629
|
end
|
559
630
|
|
560
|
-
expect { @conn << f.generate(
|
631
|
+
expect { @conn << f.generate(data_frame) }.to raise_error(ProtocolError)
|
561
632
|
end
|
562
633
|
end
|
563
634
|
|
@@ -586,8 +657,8 @@ RSpec.describe HTTP2::Connection do
|
|
586
657
|
end
|
587
658
|
|
588
659
|
it '.goaway should generate GOAWAY frame with last processed stream ID' do
|
589
|
-
@conn << f.generate(
|
590
|
-
@conn << f.generate(
|
660
|
+
@conn << f.generate(settings_frame)
|
661
|
+
@conn << f.generate(headers_frame.merge(stream: 17))
|
591
662
|
|
592
663
|
expect(@conn).to receive(:send) do |frame|
|
593
664
|
expect(frame[:type]).to eq :goaway
|