http-2 0.11.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -9
  3. data/lib/http/2/base64.rb +45 -0
  4. data/lib/http/2/client.rb +19 -6
  5. data/lib/http/2/connection.rb +235 -163
  6. data/lib/http/2/emitter.rb +7 -5
  7. data/lib/http/2/error.rb +24 -1
  8. data/lib/http/2/extensions.rb +53 -0
  9. data/lib/http/2/flow_buffer.rb +91 -33
  10. data/lib/http/2/framer.rb +184 -157
  11. data/lib/http/2/header/compressor.rb +157 -0
  12. data/lib/http/2/header/decompressor.rb +144 -0
  13. data/lib/http/2/header/encoding_context.rb +337 -0
  14. data/lib/http/2/{huffman.rb → header/huffman.rb} +25 -19
  15. data/lib/http/2/{huffman_statemachine.rb → header/huffman_statemachine.rb} +2 -0
  16. data/lib/http/2/header.rb +35 -0
  17. data/lib/http/2/server.rb +47 -20
  18. data/lib/http/2/stream.rb +130 -61
  19. data/lib/http/2/version.rb +3 -1
  20. data/lib/http/2.rb +14 -13
  21. data/sig/client.rbs +9 -0
  22. data/sig/connection.rbs +93 -0
  23. data/sig/emitter.rbs +13 -0
  24. data/sig/error.rbs +35 -0
  25. data/sig/extensions.rbs +5 -0
  26. data/sig/flow_buffer.rbs +21 -0
  27. data/sig/frame_buffer.rbs +13 -0
  28. data/sig/framer.rbs +54 -0
  29. data/sig/header/compressor.rbs +27 -0
  30. data/sig/header/decompressor.rbs +22 -0
  31. data/sig/header/encoding_context.rbs +34 -0
  32. data/sig/header/huffman.rbs +9 -0
  33. data/sig/header.rbs +27 -0
  34. data/sig/next.rbs +101 -0
  35. data/sig/server.rbs +12 -0
  36. data/sig/stream.rbs +91 -0
  37. metadata +38 -79
  38. data/.autotest +0 -20
  39. data/.coveralls.yml +0 -1
  40. data/.gitignore +0 -20
  41. data/.gitmodules +0 -3
  42. data/.rspec +0 -5
  43. data/.rubocop.yml +0 -93
  44. data/.rubocop_todo.yml +0 -131
  45. data/.travis.yml +0 -17
  46. data/Gemfile +0 -16
  47. data/Guardfile +0 -18
  48. data/Guardfile.h2spec +0 -12
  49. data/LICENSE +0 -21
  50. data/Rakefile +0 -49
  51. data/example/Gemfile +0 -3
  52. data/example/README.md +0 -44
  53. data/example/client.rb +0 -122
  54. data/example/helper.rb +0 -19
  55. data/example/keys/server.crt +0 -20
  56. data/example/keys/server.key +0 -27
  57. data/example/server.rb +0 -139
  58. data/example/upgrade_client.rb +0 -153
  59. data/example/upgrade_server.rb +0 -203
  60. data/http-2.gemspec +0 -22
  61. data/lib/http/2/buffer.rb +0 -76
  62. data/lib/http/2/compressor.rb +0 -572
  63. data/lib/tasks/generate_huffman_table.rb +0 -166
  64. data/spec/buffer_spec.rb +0 -28
  65. data/spec/client_spec.rb +0 -188
  66. data/spec/compressor_spec.rb +0 -666
  67. data/spec/connection_spec.rb +0 -681
  68. data/spec/emitter_spec.rb +0 -54
  69. data/spec/framer_spec.rb +0 -487
  70. data/spec/h2spec/h2spec.darwin +0 -0
  71. data/spec/h2spec/output/non_secure.txt +0 -317
  72. data/spec/helper.rb +0 -147
  73. data/spec/hpack_test_spec.rb +0 -84
  74. data/spec/huffman_spec.rb +0 -68
  75. data/spec/server_spec.rb +0 -52
  76. data/spec/stream_spec.rb +0 -878
  77. data/spec/support/deep_dup.rb +0 -55
  78. data/spec/support/duplicable.rb +0 -98
data/spec/stream_spec.rb DELETED
@@ -1,878 +0,0 @@
1
- require 'helper'
2
-
3
- RSpec.describe HTTP2::Stream do
4
- include FrameHelpers
5
- before(:each) do
6
- @client = Client.new
7
- @stream = @client.new_stream
8
- end
9
-
10
- context 'stream states' do
11
- it 'should initiliaze all streams to IDLE' do
12
- expect(@stream.state).to eq :idle
13
- end
14
-
15
- it 'should set custom stream priority' do
16
- stream = @client.new_stream(weight: 3, dependency: 2, exclusive: true)
17
- expect(stream.weight).to eq 3
18
- end
19
-
20
- context 'idle' do
21
- it 'should transition to open on sent HEADERS' do
22
- @stream.send headers_frame
23
- expect(@stream.state).to eq :open
24
- end
25
- it 'should transition to open on received HEADERS' do
26
- @stream.receive headers_frame
27
- expect(@stream.state).to eq :open
28
- end
29
- it 'should transition to reserved (local) on sent PUSH_PROMISE' do
30
- @stream.send push_promise_frame
31
- expect(@stream.state).to eq :reserved_local
32
- end
33
- it 'should transition to reserved (remote) on received PUSH_PROMISE' do
34
- @stream.receive push_promise_frame
35
- expect(@stream.state).to eq :reserved_remote
36
- end
37
- it 'should reprioritize stream on sent PRIORITY' do
38
- expect { @stream.send priority_frame }.to_not raise_error
39
- expect(@stream.weight).to eq 20
40
- end
41
- it 'should reprioritize stream on received PRIORITY' do
42
- expect { @stream.send priority_frame }.to_not raise_error
43
- expect(@stream.weight).to eq 20
44
- end
45
- end
46
-
47
- context 'reserved (local)' do
48
- before(:each) { @stream.send push_promise_frame }
49
-
50
- it 'should transition on sent PUSH_PROMISE' do
51
- expect(@stream.state).to eq :reserved_local
52
- end
53
-
54
- it 'should allow HEADERS to be sent' do
55
- expect { @stream.send headers_frame }.to_not raise_error
56
- end
57
-
58
- it 'should raise error if sending invalid frames' do
59
- frame_types.reject { |frame| %i[headers rst_stream].include?(frame[:type]) }.each do |type|
60
- expect { @stream.dup.send type }.to raise_error InternalError
61
- end
62
- end
63
-
64
- it 'should raise error on receipt of invalid frames' do
65
- what_types = frame_types.reject { |frame| %i[priority window_update rst_stream].include?(frame[:type]) }
66
- what_types.each do |type|
67
- expect { @stream.dup.receive type }.to raise_error InternalError
68
- end
69
- end
70
-
71
- it 'should transition to half closed (remote) on sent HEADERS' do
72
- @stream.send headers_frame
73
- expect(@stream.state).to eq :half_closed_remote
74
- end
75
-
76
- it 'should transition to closed on sent RST_STREAM' do
77
- @stream.close
78
- expect(@stream.state).to eq :closed
79
- end
80
-
81
- it 'should transition to closed on received RST_STREAM' do
82
- @stream.receive rst_stream_frame
83
- expect(@stream.state).to eq :closed
84
- end
85
-
86
- it 'should reprioritize stream on PRIORITY' do
87
- expect { @stream.receive priority_frame }.to_not raise_error
88
- expect(@stream.weight).to eq 20
89
- end
90
-
91
- it 'should increment remote_window on received WINDOW_UPDATE' do
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]
94
- end
95
- end
96
-
97
- context 'reserved (remote)' do
98
- before(:each) { @stream.receive push_promise_frame }
99
-
100
- it 'should transition on received PUSH_PROMISE' do
101
- expect(@stream.state).to eq :reserved_remote
102
- end
103
-
104
- it 'should raise error if sending invalid frames' do
105
- frame_types.reject { |frame| %i[priority rst_stream window_update].include?(frame[:type]) }.each do |type|
106
- expect { @stream.dup.send type }.to raise_error InternalError
107
- end
108
- end
109
-
110
- it 'should raise error on receipt of invalid frames' do
111
- frame_types.reject { |frame| %i[headers rst_stream].include?(frame[:type]) }.each do |type|
112
- expect { @stream.dup.receive type }.to raise_error InternalError
113
- end
114
- end
115
-
116
- it 'should transition to half closed (local) on received HEADERS' do
117
- @stream.receive headers_frame
118
- expect(@stream.state).to eq :half_closed_local
119
- end
120
-
121
- it 'should transition to closed on sent RST_STREAM' do
122
- @stream.close
123
- expect(@stream.state).to eq :closed
124
- end
125
-
126
- it 'should transition to closed on received RST_STREAM' do
127
- @stream.receive rst_stream_frame
128
- expect(@stream.state).to eq :closed
129
- end
130
-
131
- it 'should reprioritize stream on PRIORITY' do
132
- expect { @stream.send priority_frame }.to_not raise_error
133
- expect(@stream.weight).to eq 20
134
- end
135
-
136
- it 'should increment local_window on sent WINDOW_UPDATE' do
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]
139
- end
140
- end
141
-
142
- context 'open' do
143
- before(:each) { @stream.receive headers_frame }
144
-
145
- it 'should allow any valid frames types to be sent' do
146
- (frame_types - [ping_frame, goaway_frame, settings_frame]).each do |type|
147
- expect { @stream.dup.send type.deep_dup }.to_not raise_error
148
- end
149
- end
150
-
151
- it 'should allow frames of any type to be received' do
152
- frame_types.each do |type|
153
- expect { @stream.dup.receive type }.to_not raise_error
154
- end
155
- end
156
-
157
- it 'should transition to half closed (local) if sending END_STREAM' do
158
- [data_frame, headers_frame].each do |frame|
159
- s, f = @stream.dup, frame.deep_dup
160
- f[:flags] = [:end_stream]
161
-
162
- s.send f
163
- expect(s.state).to eq :half_closed_local
164
- end
165
- end
166
-
167
- it 'should transition to half closed (remote) if receiving END_STREAM' do
168
- [data_frame, headers_frame].each do |frame|
169
- s, f = @stream.dup, frame.dup
170
- f[:flags] = [:end_stream]
171
-
172
- s.receive f
173
- expect(s.state).to eq :half_closed_remote
174
- end
175
- end
176
-
177
- it 'should transition to half closed if remote opened with END_STREAM' do
178
- s = @client.new_stream
179
- hclose = headers_frame
180
- hclose[:flags] = [:end_stream]
181
-
182
- s.receive hclose
183
- expect(s.state).to eq :half_closed_remote
184
- end
185
-
186
- it 'should transition to half closed if local opened with END_STREAM' do
187
- s = @client.new_stream
188
- hclose = headers_frame
189
- hclose[:flags] = [:end_stream]
190
-
191
- s.send hclose
192
- expect(s.state).to eq :half_closed_local
193
- end
194
-
195
- it 'should transition to closed if sending RST_STREAM' do
196
- @stream.close
197
- expect(@stream.state).to eq :closed
198
- expect(@stream).to be_closed
199
- end
200
-
201
- it 'should transition to closed if receiving RST_STREAM' do
202
- @stream.receive rst_stream_frame
203
- expect(@stream.state).to eq :closed
204
- end
205
-
206
- it 'should emit :active on open transition' do
207
- openp, openr = false, false
208
- sp = @client.new_stream
209
- sr = @client.new_stream
210
- sp.on(:active) { openp = true }
211
- sr.on(:active) { openr = true }
212
-
213
- sp.receive headers_frame
214
- sr.send headers_frame
215
-
216
- expect(openp).to be_truthy
217
- expect(openr).to be_truthy
218
- end
219
-
220
- it 'should not emit :active on transition from open' do
221
- order, stream = [], @client.new_stream
222
-
223
- stream.on(:active) { order << :active }
224
- stream.on(:half_close) { order << :half_close }
225
- stream.on(:close) { order << :close }
226
-
227
- req = headers_frame
228
- req[:flags] = [:end_headers]
229
-
230
- stream.send req
231
- stream.send data_frame
232
- expect(order).to eq [:active, :half_close]
233
- end
234
-
235
- it 'should emit :close on close transition' do
236
- closep, closer = false, false
237
- sp, sr = @stream.dup, @stream.dup
238
-
239
- sp.on(:close) { closep = true }
240
- sr.on(:close) { closer = true }
241
-
242
- sp.receive rst_stream_frame
243
- sr.close
244
-
245
- expect(closep).to be_truthy
246
- expect(closer).to be_truthy
247
- end
248
-
249
- it 'should emit :close after frame is processed' do
250
- order, stream = [], @client.new_stream
251
-
252
- stream.on(:active) { order << :active }
253
- stream.on(:data) { order << :data }
254
- stream.on(:half_close) { order << :half_close }
255
- stream.on(:close) { order << :close }
256
-
257
- req = headers_frame
258
- req[:flags] = [:end_stream, :end_headers]
259
-
260
- stream.send req
261
- stream.receive headers_frame
262
- stream.receive data_frame
263
-
264
- expect(order).to eq [:active, :half_close, :data, :close]
265
- end
266
-
267
- it 'should emit :close with reason' do
268
- reason = nil
269
- @stream.on(:close) { |r| reason = r }
270
- @stream.receive rst_stream_frame
271
- expect(reason).not_to be_nil
272
- end
273
-
274
- it 'should reprioritize stream on sent PRIORITY' do
275
- expect { @stream.send priority_frame }.to_not raise_error
276
- expect(@stream.weight).to eq 20
277
- end
278
- it 'should reprioritize stream on received PRIORITY' do
279
- expect { @stream.receive priority_frame }.to_not raise_error
280
- expect(@stream.weight).to eq 20
281
- end
282
- end
283
-
284
- context 'half closed (local)' do
285
- before(:each) { @stream.send headers_frame.merge(flags: [:end_headers, :end_stream]) }
286
-
287
- it 'should raise error on attempt to send invalid frames' do
288
- frame_types.reject { |frame| %i[priority rst_stream window_update].include?(frame[:type]) }.each do |frame|
289
- expect { @stream.dup.send frame }.to raise_error InternalError
290
- end
291
- end
292
-
293
- it 'should transition to closed on receipt of END_STREAM flag' do
294
- [data_frame, headers_frame, continuation_frame].each do |frame|
295
- s, f = @stream.dup, frame.dup
296
- f[:flags] = [:end_stream]
297
-
298
- s.receive f
299
- expect(s.state).to eq :closed
300
- end
301
- end
302
-
303
- it 'should transition to closed on receipt of RST_STREAM frame' do
304
- @stream.receive rst_stream_frame
305
- expect(@stream.state).to eq :closed
306
- end
307
-
308
- it 'should transition to closed if RST_STREAM frame is sent' do
309
- @stream.send rst_stream_frame
310
- expect(@stream.state).to eq :closed
311
- end
312
-
313
- it 'should ignore received WINDOW_UPDATE frames' do
314
- expect { @stream.receive window_update_frame }.to_not raise_error
315
- expect(@stream.state).to eq :half_closed_local
316
- end
317
-
318
- it 'should ignore received PRIORITY frames' do
319
- expect { @stream.receive priority_frame }.to_not raise_error
320
- expect(@stream.state).to eq :half_closed_local
321
- end
322
-
323
- it 'should reprioritize stream on sent PRIORITY' do
324
- expect { @stream.send priority_frame }.to_not raise_error
325
- expect(@stream.weight).to eq 20
326
- end
327
-
328
- it 'should reprioritize stream (and decendants) on received PRIORITY' do
329
- expect { @stream.receive priority_frame }.to_not raise_error
330
- expect(@stream.weight).to eq 20
331
- end
332
-
333
- it 'should increment local_window on sent WINDOW_UPDATE' do
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]
336
- end
337
-
338
- it 'should emit :half_close event on transition' do
339
- order = []
340
- stream = @client.new_stream
341
- stream.on(:active) { order << :active }
342
- stream.on(:half_close) { order << :half_close }
343
-
344
- req = headers_frame
345
- req[:flags] = [:end_stream, :end_headers]
346
-
347
- stream.send req
348
- expect(order).to eq [:active, :half_close]
349
- end
350
-
351
- it 'should emit :close event on transition to closed' do
352
- closed = false
353
- @stream.on(:close) { closed = true }
354
- @stream.receive rst_stream_frame
355
-
356
- expect(@stream.state).to eq :closed
357
- expect(closed).to be_truthy
358
- end
359
- end
360
-
361
- context 'half closed (remote)' do
362
- before(:each) { @stream.receive headers_frame.merge(flags: [:end_headers, :end_stream]) }
363
-
364
- it 'should raise STREAM_CLOSED error on reciept of frames' do
365
- (frame_types - [priority_frame, rst_stream_frame, window_update_frame]).each do |frame|
366
- expect do
367
- @stream.dup.receive frame
368
- end.to raise_error(StreamClosed)
369
- end
370
- end
371
-
372
- it 'should transition to closed if END_STREAM flag is sent' do
373
- [data_frame, headers_frame].each do |frame|
374
- s, f = @stream.dup, frame.deep_dup
375
- f[:flags] = [:end_stream]
376
-
377
- s.on(:close) { expect(s.state).to eq :closed }
378
- s.send f
379
- expect(s.state).to eq :closed
380
- end
381
- end
382
-
383
- it 'should not transition to closed if END_STREAM flag is sent when overflowing window' do
384
- @stream.on(:close) { fail 'should not have closed' }
385
- data = { type: :data, flags: [], stream: @stream.id }
386
- 4.times do
387
- data = data.merge(flags: [:end_stream]) if @stream.remote_window < 16_384
388
- @stream.send data.merge(payload: 'x' * 16_384)
389
- end
390
- end
391
-
392
- it 'should transition to closed when send buffer is emptied' do
393
- o = Object.new
394
- expect(o).to receive(:tap).once
395
- @stream.on(:close) do
396
- expect(@stream.buffered_amount).to eq 0
397
- o.tap
398
- end
399
- data = { type: :data, flags: [], stream: @stream.id }
400
- 4.times do
401
- data = data.merge(flags: [:end_stream]) if @stream.remote_window < 16_384
402
- @stream.send data.merge(payload: 'x' * 16_384)
403
- end
404
- @client << Framer.new.generate(type: :window_update, stream: @stream.id, increment: 16_384)
405
- end
406
-
407
- it 'should transition to closed if RST_STREAM is sent' do
408
- @stream.close
409
- expect(@stream.state).to eq :closed
410
- end
411
-
412
- it 'should transition to closed on reciept of RST_STREAM frame' do
413
- @stream.receive rst_stream_frame
414
- expect(@stream.state).to eq :closed
415
- end
416
-
417
- it 'should ignore sent WINDOW_UPDATE frames' do
418
- expect { @stream.send window_update_frame }.to_not raise_error
419
- expect(@stream.state).to eq :half_closed_remote
420
- end
421
-
422
- it 'should increment remote_window on received WINDOW_UPDATE' do
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]
425
- end
426
-
427
- it 'should reprioritize stream on sent PRIORITY' do
428
- expect { @stream.send priority_frame }.to_not raise_error
429
- expect(@stream.weight).to eq 20
430
- end
431
- it 'should reprioritize stream on received PRIORITY' do
432
- expect { @stream.receive priority_frame }.to_not raise_error
433
- expect(@stream.weight).to eq 20
434
- end
435
-
436
- it 'should emit :half_close event on transition' do
437
- order = []
438
- stream = @client.new_stream
439
- stream.on(:active) { order << :active }
440
- stream.on(:half_close) { order << :half_close }
441
-
442
- req = headers_frame
443
- req[:flags] = [:end_stream, :end_headers]
444
-
445
- stream.receive req
446
- expect(order).to eq [:active, :half_close]
447
- end
448
-
449
- it 'should emit :close event on close transition' do
450
- closed = false
451
- @stream.on(:close) { closed = true }
452
- @stream.close
453
-
454
- expect(@stream.state).to eq :closed
455
- expect(closed).to be_truthy
456
- end
457
- end
458
-
459
- context 'closed' do
460
- context 'remote closed stream' do
461
- before(:each) do
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
464
- end
465
-
466
- it 'should raise STREAM_CLOSED on attempt to send frames' do
467
- (frame_types - [priority_frame, rst_stream_frame]).each do |frame|
468
- expect do
469
- @stream.dup.send frame
470
- end.to raise_error(StreamClosed)
471
- end
472
- end
473
-
474
- it 'should raise STREAM_CLOSED on receipt of frame' do
475
- (frame_types - [priority_frame, rst_stream_frame, window_update_frame]).each do |frame|
476
- expect do
477
- @stream.dup.receive frame
478
- end.to raise_error(StreamClosed)
479
- end
480
- end
481
-
482
- it 'should allow PRIORITY, RST_STREAM to be sent' do
483
- expect { @stream.send priority_frame }.to_not raise_error
484
- expect { @stream.send rst_stream_frame }.to_not raise_error
485
- end
486
-
487
- it 'should allow PRIORITY, RST_STREAM to be received' do
488
- expect { @stream.receive priority_frame }.to_not raise_error
489
- expect { @stream.receive rst_stream_frame }.to_not raise_error
490
- end
491
-
492
- it 'should reprioritize stream on sent PRIORITY' do
493
- expect { @stream.send priority_frame }.to_not raise_error
494
- expect(@stream.weight).to eq 20
495
- end
496
- it 'should reprioritize stream on received PRIORITY' do
497
- expect { @stream.receive priority_frame }.to_not raise_error
498
- expect(@stream.weight).to eq 20
499
- end
500
-
501
- it 'should ignore received WINDOW_UPDATE frames' do
502
- expect { @stream.receive window_update_frame }.to_not raise_error
503
- expect(@stream.state).to eq :closed
504
- end
505
- end
506
-
507
- context 'local closed via RST_STREAM frame' do
508
- before(:each) do
509
- @stream.send headers_frame # open
510
- @stream.send rst_stream_frame # closed by local
511
- end
512
-
513
- it 'should ignore received frames' do
514
- (frame_types - [push_promise_frame]).each do |frame|
515
- expect do
516
- cb = []
517
- @stream.on(:data) { cb << :data }
518
- @stream.on(:headers) { cb << :headers }
519
- @stream.dup.receive frame.dup
520
- expect(cb).to be_empty
521
- end.to_not raise_error
522
- end
523
- end
524
-
525
- # it "should transition to reserved remote on PUSH_PROMISE" do
526
- # An endpoint might receive a PUSH_PROMISE frame after it sends
527
- # RST_STREAM. PUSH_PROMISE causes a stream to become "reserved".
528
- # ...
529
- # We're auto RST'ing PUSH streams in connection class, hence
530
- # skipping this transition for now.
531
- # end
532
- end
533
-
534
- # FIXME: Isn't this test same as "half closed (local)"?
535
- # context "local closed via END_STREAM flag" do
536
- # before(:each) do
537
- # @stream.send headers_frame # open
538
- # @stream.send data_frame # contains end_stream flag
539
- # end
540
-
541
- # it "should ignore received frames" do
542
- # frame_types.each do |frame|
543
- # expect { @stream.dup.receive frame }.to_not raise_error
544
- # end
545
- # end
546
- # end
547
- end
548
- end # end stream states
549
-
550
- # TODO: add test cases to ensure on(:priority) emitted after close
551
-
552
- context 'flow control' do
553
- it 'should initialize to default flow control window' do
554
- expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW
555
- end
556
-
557
- it 'should update window size on DATA frames only' do
558
- @stream.send headers_frame # go to open
559
- expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW
560
-
561
- (frame_types - [data_frame, ping_frame, goaway_frame, settings_frame]).each do |frame|
562
- s = @stream.dup
563
- s.send frame.deep_dup
564
- expect(s.remote_window).to eq DEFAULT_FLOW_WINDOW
565
- end
566
-
567
- @stream.send data_frame
568
- expect(@stream.remote_window).to eq DEFAULT_FLOW_WINDOW - data_frame[:payload].bytesize
569
- end
570
-
571
- it 'should update window size on receipt of WINDOW_UPDATE' do
572
- @stream.send headers_frame
573
- @stream.send data_frame
574
- @stream.receive window_update_frame
575
-
576
- expect(@stream.remote_window).to eq(
577
- DEFAULT_FLOW_WINDOW - data_frame[:payload].bytesize + window_update_frame[:increment],
578
- )
579
- end
580
-
581
- it 'should observe session flow control' do
582
- settings, data = settings_frame, data_frame
583
- settings[:payload] = [[:settings_initial_window_size, 1000]]
584
- settings[:stream] = 0
585
-
586
- framer = Framer.new
587
- @client << framer.generate(settings)
588
-
589
- s1 = @client.new_stream
590
- s1.send headers_frame
591
- s1.send data.merge(payload: 'x' * 900, flags: [])
592
- expect(s1.remote_window).to eq 100
593
-
594
- s1.send data.merge(payload: 'x' * 200)
595
- expect(s1.remote_window).to eq 0
596
- expect(s1.buffered_amount).to eq 100
597
-
598
- @client << framer.generate(window_update_frame.merge(stream: s1.id, increment: 1000))
599
- expect(s1.buffered_amount).to eq 0
600
- expect(s1.remote_window).to eq 900
601
- end
602
-
603
- it 'should not update window when data received is less than half of maximum local window size' do
604
- data = data_frame
605
- datalen = data[:payload].bytesize
606
- expect(@stream).not_to receive(:send) do |frame|
607
- expect(frame[:type]).to eq :window_update
608
- expect(frame[:increment]).to eq datalen
609
- end
610
- @stream.receive headers_frame
611
- @stream.receive data
612
- end
613
-
614
- it 'should update window when data received is over half of the maximum local window size' do
615
- data1 = data_frame.merge(payload: 'a'*16_384, flags: [])
616
- data2 = data_frame.merge(payload: 'a'*16_384)
617
- datalen = 16_384 * 2
618
- expect(@stream).to receive(:send) do |frame|
619
- expect(frame[:type]).to eq :window_update
620
- expect(frame[:increment]).to eq datalen
621
- end
622
- @stream.receive headers_frame
623
- @stream.receive data1
624
- @stream.receive data2
625
- end
626
- end
627
-
628
- context 'client API' do
629
- it '.reprioritize should emit PRIORITY frame' do
630
- expect(@stream).to receive(:send) do |frame|
631
- expect(frame[:type]).to eq :priority
632
- expect(frame[:weight]).to eq 30
633
- end
634
-
635
- @stream.reprioritize weight: 30
636
- end
637
-
638
- it '.reprioritize should raise error if invoked by server' do
639
- srv = Server.new
640
- stream = srv.new_stream
641
-
642
- expect { stream.reprioritize(weight: 10) }.to raise_error(InternalError)
643
- end
644
-
645
- it '.headers should emit HEADERS frames' do
646
- payload = {
647
- ':method' => 'GET',
648
- ':scheme' => 'http',
649
- ':host' => 'www.example.org',
650
- ':path' => '/resource',
651
- 'custom' => 'value',
652
- }
653
-
654
- expect(@stream).to receive(:send) do |frame|
655
- expect(frame[:type]).to eq :headers
656
- expect(frame[:payload]).to eq payload
657
- expect(frame[:flags]).to eq [:end_headers]
658
- end
659
-
660
- @stream.headers(payload, end_stream: false, end_headers: true)
661
- end
662
-
663
- it '.data should emit DATA frames' do
664
- expect(@stream).to receive(:send) do |frame|
665
- expect(frame[:type]).to eq :data
666
- expect(frame[:payload]).to eq 'text'
667
- expect(frame[:flags]).to be_empty
668
- end
669
- @stream.data('text', end_stream: false)
670
-
671
- expect(@stream).to receive(:send) do |frame|
672
- expect(frame[:flags]).to eq [:end_stream]
673
- end
674
- @stream.data('text')
675
- end
676
-
677
- it '.data should split large DATA frames' do
678
- data = 'x' * 16_384 * 2
679
-
680
- want = [
681
- { type: :data, flags: [], length: 16_384 },
682
- { type: :data, flags: [], length: 16_384 },
683
- { type: :data, flags: [:end_stream], length: 1 },
684
- ]
685
- want.each do |w|
686
- expect(@stream).to receive(:send) do |frame|
687
- expect(frame[:type]).to eq w[:type]
688
- expect(frame[:flags]).to eq w[:flags]
689
- expect(frame[:payload].bytesize).to eq w[:length]
690
- end
691
- end
692
-
693
- @stream.data(data + 'x')
694
- end
695
-
696
- it '.data should split large multibyte DATA frames' do
697
- data = '🐼' * 16_384
698
-
699
- want = [
700
- { type: :data, flags: [], length: 16_384 },
701
- { type: :data, flags: [], length: 16_384 },
702
- { type: :data, flags: [], length: 16_384 },
703
- { type: :data, flags: [], length: 16_384 },
704
- { type: :data, flags: [:end_stream], length: 1 },
705
- ]
706
- want.each do |w|
707
- expect(@stream).to receive(:send) do |frame|
708
- expect(frame[:type]).to eq w[:type]
709
- expect(frame[:flags]).to eq w[:flags]
710
- expect(frame[:payload].bytesize).to eq w[:length]
711
- end
712
- end
713
-
714
- @stream.data(data + 'x')
715
- end
716
-
717
- it '.cancel should reset stream with cancel error code' do
718
- expect(@stream).to receive(:send) do |frame|
719
- expect(frame[:type]).to eq :rst_stream
720
- expect(frame[:error]).to eq :cancel
721
- end
722
-
723
- @stream.cancel
724
- end
725
-
726
- it '.refuse should reset stream with refused stream error code' do
727
- expect(@stream).to receive(:send) do |frame|
728
- expect(frame[:type]).to eq :rst_stream
729
- expect(frame[:error]).to eq :refused_stream
730
- end
731
-
732
- @stream.refuse
733
- end
734
-
735
- it '.window_update should emit WINDOW_UPDATE frames' do
736
- expect(@stream).to receive(:send) do |frame|
737
- expect(frame[:type]).to eq :window_update
738
- expect(frame[:increment]).to eq 20
739
- end
740
- @stream.window_update(20)
741
- end
742
- end
743
-
744
- context 'server API' do
745
- before(:each) do
746
- @srv = Server.new
747
- @frm = Framer.new
748
-
749
- @client.on(:frame) { |bytes| @srv << bytes }
750
- @client_stream = @client.new_stream
751
- end
752
-
753
- it 'should emit received headers via on(:headers)' do
754
- headers, recv = REQUEST_HEADERS, nil
755
- @srv.on(:stream) do |stream|
756
- stream.on(:headers) { |h| recv = h }
757
- end
758
-
759
- @client_stream.headers(headers)
760
- expect(recv).to eq headers
761
- end
762
-
763
- it 'should emit received payload via on(:data)' do
764
- payload = 'some-payload'
765
- @srv.on(:stream) do |stream|
766
- stream.on(:data) do |recv|
767
- expect(recv).to eq payload
768
- end
769
- end
770
-
771
- @client_stream.headers(REQUEST_HEADERS)
772
- @client_stream.data(payload)
773
- end
774
-
775
- it 'should emit received priority parameters via on(:priority)' do
776
- new_weight, new_dependency = 15, @client_stream.id + 2
777
- callback_called = false
778
- @srv.on(:stream) do |stream|
779
- stream.on(:priority) do |pri|
780
- callback_called = true
781
- expect(pri.is_a?(Hash)).to be
782
- expect(pri[:weight]).to eq new_weight
783
- expect(pri[:dependency]).to eq new_dependency
784
- end
785
- end
786
-
787
- @client_stream.headers(REQUEST_HEADERS)
788
- @client_stream.reprioritize(weight: new_weight, dependency: new_dependency)
789
- expect(callback_called).to be
790
- end
791
-
792
- context 'push' do
793
- before(:each) do
794
- @srv.on(:frame) { |bytes| @client << bytes }
795
- @srv.on(:stream) do |stream|
796
- @server_stream = stream
797
- end
798
-
799
- @client_stream.headers(REQUEST_HEADERS)
800
- end
801
-
802
- it '.promise should emit server initiated stream' do
803
- push = nil
804
- @server_stream.promise(REQUEST_HEADERS) { |pstream| push = pstream }
805
- expect(push.id).to eq 2
806
- end
807
-
808
- it '.promise push stream should have parent stream' do
809
- push = nil
810
- @server_stream.promise(REQUEST_HEADERS) { |pstream| push = pstream }
811
-
812
- expect(push.state).to eq :reserved_local
813
- expect(push.parent.id).to eq @server_stream.id
814
- end
815
-
816
- context 'stream states' do
817
- it 'server: active > half close > close' do
818
- order = []
819
- @server_stream.promise(REQUEST_HEADERS) do |push|
820
- stream = push
821
-
822
- expect(push.state).to eq :reserved_local
823
- order << :reserved
824
-
825
- push.on(:active) { order << :active }
826
- push.on(:half_close) { order << :half_close }
827
- push.on(:close) { order << :close }
828
-
829
- push.headers(RESPONSE_HEADERS)
830
- push.send data_frame.merge(stream: stream.id)
831
- end
832
-
833
- expect(order).to eq [:reserved, :active, :half_close, :close]
834
- end
835
-
836
- it 'client: promise_headers > active > headers > .. > data > close' do
837
- order, headers, promise_headers = [], [], []
838
- @client.on(:promise) do |push|
839
- order << :reserved
840
-
841
- push.on(:active) { order << :active }
842
- push.on(:data) { order << :data }
843
- push.on(:half_close) { order << :half_close }
844
- push.on(:close) { order << :close }
845
-
846
- push.on(:promise_headers) do |h|
847
- order << :promise_headers
848
- promise_headers += h
849
- end
850
- push.on(:headers) do |h|
851
- order << :headers
852
- headers += h
853
- end
854
-
855
- expect(push.id).to be_even
856
- end
857
-
858
- @server_stream.promise(REQUEST_HEADERS) do |push|
859
- push.headers(RESPONSE_HEADERS)
860
- push.data('somedata')
861
- end
862
-
863
- expect(promise_headers).to eq(REQUEST_HEADERS)
864
- expect(headers).to eq(RESPONSE_HEADERS)
865
- expect(order).to eq [
866
- :reserved,
867
- :promise_headers,
868
- :active,
869
- :headers,
870
- :half_close,
871
- :data,
872
- :close,
873
- ]
874
- end
875
- end
876
- end
877
- end
878
- end