http-2 0.11.0 → 0.12.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 +4 -4
- data/README.md +0 -2
- data/lib/http/2/buffer.rb +6 -4
- data/lib/http/2/client.rb +5 -1
- data/lib/http/2/compressor.rb +42 -34
- data/lib/http/2/connection.rb +72 -86
- data/lib/http/2/emitter.rb +4 -1
- data/lib/http/2/error.rb +2 -0
- data/lib/http/2/flow_buffer.rb +8 -3
- data/lib/http/2/framer.rb +83 -94
- data/lib/http/2/huffman.rb +19 -17
- data/lib/http/2/server.rb +9 -7
- data/lib/http/2/stream.rb +48 -48
- data/lib/http/2/version.rb +3 -1
- data/lib/http/2.rb +2 -0
- metadata +7 -60
- data/.autotest +0 -20
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -20
- data/.gitmodules +0 -3
- data/.rspec +0 -5
- data/.rubocop.yml +0 -93
- data/.rubocop_todo.yml +0 -131
- data/.travis.yml +0 -17
- data/Gemfile +0 -16
- data/Guardfile +0 -18
- data/Guardfile.h2spec +0 -12
- data/Rakefile +0 -49
- data/example/Gemfile +0 -3
- data/example/README.md +0 -44
- data/example/client.rb +0 -122
- data/example/helper.rb +0 -19
- data/example/keys/server.crt +0 -20
- data/example/keys/server.key +0 -27
- data/example/server.rb +0 -139
- data/example/upgrade_client.rb +0 -153
- data/example/upgrade_server.rb +0 -203
- data/http-2.gemspec +0 -22
- data/lib/tasks/generate_huffman_table.rb +0 -166
- data/spec/buffer_spec.rb +0 -28
- data/spec/client_spec.rb +0 -188
- data/spec/compressor_spec.rb +0 -666
- data/spec/connection_spec.rb +0 -681
- data/spec/emitter_spec.rb +0 -54
- data/spec/framer_spec.rb +0 -487
- data/spec/h2spec/h2spec.darwin +0 -0
- data/spec/h2spec/output/non_secure.txt +0 -317
- data/spec/helper.rb +0 -147
- data/spec/hpack_test_spec.rb +0 -84
- data/spec/huffman_spec.rb +0 -68
- data/spec/server_spec.rb +0 -52
- data/spec/stream_spec.rb +0 -878
- data/spec/support/deep_dup.rb +0 -55
- data/spec/support/duplicable.rb +0 -98
data/spec/emitter_spec.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
RSpec.describe HTTP2::Emitter do
|
4
|
-
class Worker
|
5
|
-
include Emitter
|
6
|
-
end
|
7
|
-
|
8
|
-
before(:each) do
|
9
|
-
@w = Worker.new
|
10
|
-
@cnt = 0
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should raise error on missing callback' do
|
14
|
-
expect { @w.on(:a) {} }.to_not raise_error
|
15
|
-
expect { @w.on(:a) }.to raise_error
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should allow multiple callbacks on single event' do
|
19
|
-
@w.on(:a) { @cnt += 1 }
|
20
|
-
@w.on(:a) { @cnt += 1 }
|
21
|
-
@w.emit(:a)
|
22
|
-
|
23
|
-
expect(@cnt).to eq 2
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'should execute callback with optional args' do
|
27
|
-
args = nil
|
28
|
-
@w.on(:a) { |a| args = a }
|
29
|
-
@w.emit(:a, 123)
|
30
|
-
|
31
|
-
expect(args).to eq 123
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'should pass emitted callbacks to listeners' do
|
35
|
-
@w.on(:a) { |&block| block.call }
|
36
|
-
@w.once(:a) { |&block| block.call }
|
37
|
-
@w.emit(:a) { @cnt += 1 }
|
38
|
-
|
39
|
-
expect(@cnt).to eq 2
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'should allow events with no callbacks' do
|
43
|
-
expect { @w.emit(:missing) }.to_not raise_error
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'should execute callback exactly once' do
|
47
|
-
@w.on(:a) { @cnt += 1 }
|
48
|
-
@w.once(:a) { @cnt += 1 }
|
49
|
-
@w.emit(:a)
|
50
|
-
@w.emit(:a)
|
51
|
-
|
52
|
-
expect(@cnt).to eq 3
|
53
|
-
end
|
54
|
-
end
|
data/spec/framer_spec.rb
DELETED
@@ -1,487 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
RSpec.describe HTTP2::Framer do
|
4
|
-
let(:f) { Framer.new }
|
5
|
-
|
6
|
-
context 'common header' do
|
7
|
-
let(:frame) do
|
8
|
-
{
|
9
|
-
length: 4,
|
10
|
-
type: :headers,
|
11
|
-
flags: [:end_stream, :end_headers],
|
12
|
-
stream: 15,
|
13
|
-
}
|
14
|
-
end
|
15
|
-
|
16
|
-
let(:bytes) { [0, 0x04, 0x01, 0x5, 0x0000000F].pack('CnCCN') }
|
17
|
-
|
18
|
-
it 'should generate common 9 byte header' do
|
19
|
-
expect(f.common_header(frame)).to eq bytes
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should parse common 9 byte header' do
|
23
|
-
expect(f.read_common_header(Buffer.new(bytes))).to eq frame
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'should generate a large frame' do
|
27
|
-
f = Framer.new
|
28
|
-
f.max_frame_size = 2**24 - 1
|
29
|
-
frame = {
|
30
|
-
length: 2**18 + 2**16 + 17,
|
31
|
-
type: :headers,
|
32
|
-
flags: [:end_stream, :end_headers],
|
33
|
-
stream: 15,
|
34
|
-
}
|
35
|
-
bytes = [5, 17, 0x01, 0x5, 0x0000000F].pack('CnCCN')
|
36
|
-
expect(f.common_header(frame)).to eq bytes
|
37
|
-
expect(f.read_common_header(Buffer.new(bytes))).to eq frame
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should raise exception on invalid frame type when sending' do
|
41
|
-
expect do
|
42
|
-
frame[:type] = :bogus
|
43
|
-
f.common_header(frame)
|
44
|
-
end.to raise_error(CompressionError, /invalid.*type/i)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'should raise exception on invalid stream ID' do
|
48
|
-
expect do
|
49
|
-
frame[:stream] = Framer::MAX_STREAM_ID + 1
|
50
|
-
f.common_header(frame)
|
51
|
-
end.to raise_error(CompressionError, /stream/i)
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'should raise exception on invalid frame flag' do
|
55
|
-
expect do
|
56
|
-
frame[:flags] = [:bogus]
|
57
|
-
f.common_header(frame)
|
58
|
-
end.to raise_error(CompressionError, /frame flag/)
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'should raise exception on invalid frame size' do
|
62
|
-
expect do
|
63
|
-
frame[:length] = 2**24
|
64
|
-
f.common_header(frame)
|
65
|
-
end.to raise_error(CompressionError, /too large/)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
context 'DATA' do
|
70
|
-
it 'should generate and parse bytes' do
|
71
|
-
frame = {
|
72
|
-
length: 4,
|
73
|
-
type: :data,
|
74
|
-
flags: [:end_stream],
|
75
|
-
stream: 1,
|
76
|
-
payload: 'text',
|
77
|
-
}
|
78
|
-
|
79
|
-
bytes = f.generate(frame)
|
80
|
-
expect(bytes).to eq [0, 0x4, 0x0, 0x1, 0x1, *'text'.bytes].pack('CnCCNC*')
|
81
|
-
|
82
|
-
expect(f.parse(bytes)).to eq frame
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
context 'HEADERS' do
|
87
|
-
it 'should generate and parse bytes' do
|
88
|
-
frame = {
|
89
|
-
length: 12,
|
90
|
-
type: :headers,
|
91
|
-
flags: [:end_stream, :end_headers],
|
92
|
-
stream: 1,
|
93
|
-
payload: 'header-block',
|
94
|
-
}
|
95
|
-
|
96
|
-
bytes = f.generate(frame)
|
97
|
-
expect(bytes).to eq [0, 0xc, 0x1, 0x5, 0x1, *'header-block'.bytes].pack('CnCCNC*')
|
98
|
-
expect(f.parse(bytes)).to eq frame
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'should carry an optional stream priority' do
|
102
|
-
frame = {
|
103
|
-
length: 16,
|
104
|
-
type: :headers,
|
105
|
-
flags: [:end_headers],
|
106
|
-
stream: 1,
|
107
|
-
stream_dependency: 15,
|
108
|
-
weight: 12,
|
109
|
-
exclusive: false,
|
110
|
-
payload: 'header-block',
|
111
|
-
}
|
112
|
-
|
113
|
-
bytes = f.generate(frame)
|
114
|
-
expect(bytes).to eq [0, 0x11, 0x1, 0x24, 0x1, 0xf, 0xb, *'header-block'.bytes].pack('CnCCNNCC*')
|
115
|
-
expect(f.parse(bytes)).to eq frame
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context 'PRIORITY' do
|
120
|
-
it 'should generate and parse bytes' do
|
121
|
-
frame = {
|
122
|
-
length: 5,
|
123
|
-
type: :priority,
|
124
|
-
stream: 1,
|
125
|
-
stream_dependency: 15,
|
126
|
-
weight: 12,
|
127
|
-
exclusive: true,
|
128
|
-
}
|
129
|
-
|
130
|
-
bytes = f.generate(frame)
|
131
|
-
expect(bytes).to eq [0, 0x5, 0x2, 0x0, 0x1, 0x8000000f, 0xb].pack('CnCCNNC')
|
132
|
-
expect(f.parse(bytes)).to eq frame
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
context 'RST_STREAM' do
|
137
|
-
it 'should generate and parse bytes' do
|
138
|
-
frame = {
|
139
|
-
length: 4,
|
140
|
-
type: :rst_stream,
|
141
|
-
stream: 1,
|
142
|
-
error: :stream_closed,
|
143
|
-
}
|
144
|
-
|
145
|
-
bytes = f.generate(frame)
|
146
|
-
expect(bytes).to eq [0, 0x4, 0x3, 0x0, 0x1, 0x5].pack('CnCCNN')
|
147
|
-
expect(f.parse(bytes)).to eq frame
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
context 'SETTINGS' do
|
152
|
-
let(:frame) do
|
153
|
-
{
|
154
|
-
type: :settings,
|
155
|
-
flags: [],
|
156
|
-
stream: 0,
|
157
|
-
payload: [
|
158
|
-
[:settings_max_concurrent_streams, 10],
|
159
|
-
[:settings_header_table_size, 2048],
|
160
|
-
],
|
161
|
-
}
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'should generate and parse bytes' do
|
165
|
-
bytes = f.generate(frame)
|
166
|
-
expect(bytes).to eq [0, 12, 0x4, 0x0, 0x0, 3, 10, 1, 2048].pack('CnCCNnNnN')
|
167
|
-
parsed = f.parse(bytes)
|
168
|
-
parsed.delete(:length)
|
169
|
-
frame.delete(:length)
|
170
|
-
expect(parsed).to eq frame
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'should generate settings when id is given as an integer' do
|
174
|
-
frame[:payload][1][0] = 1
|
175
|
-
bytes = f.generate(frame)
|
176
|
-
expect(bytes).to eq [0, 12, 0x4, 0x0, 0x0, 3, 10, 1, 2048].pack('CnCCNnNnN')
|
177
|
-
end
|
178
|
-
|
179
|
-
it 'should ignore custom settings when sending' do
|
180
|
-
frame[:payload] = [
|
181
|
-
[:settings_max_concurrent_streams, 10],
|
182
|
-
[:settings_initial_window_size, 20],
|
183
|
-
[55, 30],
|
184
|
-
]
|
185
|
-
|
186
|
-
buf = f.generate(frame)
|
187
|
-
frame[:payload].slice!(2) # cut off the extension
|
188
|
-
frame[:length] = 12 # frame length should be computed WITHOUT extensions
|
189
|
-
expect(f.parse(buf)).to eq frame
|
190
|
-
end
|
191
|
-
|
192
|
-
it 'should ignore custom settings when receiving' do
|
193
|
-
frame[:payload] = [
|
194
|
-
[:settings_max_concurrent_streams, 10],
|
195
|
-
[:settings_initial_window_size, 20],
|
196
|
-
]
|
197
|
-
|
198
|
-
buf = f.generate(frame)
|
199
|
-
buf.setbyte(2, 18) # add 6 to the frame length
|
200
|
-
buf << "\x00\x37\x00\x00\x00\x1e"
|
201
|
-
parsed = f.parse(buf)
|
202
|
-
parsed.delete(:length)
|
203
|
-
frame.delete(:length)
|
204
|
-
expect(parsed).to eq frame
|
205
|
-
end
|
206
|
-
|
207
|
-
it 'should raise exception on sending invalid stream ID' do
|
208
|
-
expect do
|
209
|
-
frame[:stream] = 1
|
210
|
-
f.generate(frame)
|
211
|
-
end.to raise_error(CompressionError, /Invalid stream ID/)
|
212
|
-
end
|
213
|
-
|
214
|
-
it 'should raise exception on receiving invalid stream ID' do
|
215
|
-
expect do
|
216
|
-
buf = f.generate(frame)
|
217
|
-
buf.setbyte(8, 1)
|
218
|
-
f.parse(buf)
|
219
|
-
end.to raise_error(ProtocolError, /Invalid stream ID/)
|
220
|
-
end
|
221
|
-
|
222
|
-
it 'should raise exception on sending invalid setting' do
|
223
|
-
expect do
|
224
|
-
frame[:payload] = [[:random, 23]]
|
225
|
-
f.generate(frame)
|
226
|
-
end.to raise_error(CompressionError, /Unknown settings ID/)
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'should raise exception on receiving invalid payload length' do
|
230
|
-
expect do
|
231
|
-
buf = f.generate(frame)
|
232
|
-
buf.setbyte(2, 11) # change payload length
|
233
|
-
f.parse(buf)
|
234
|
-
end.to raise_error(ProtocolError, /Invalid settings payload length/)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
context 'PUSH_PROMISE' do
|
239
|
-
it 'should generate and parse bytes' do
|
240
|
-
frame = {
|
241
|
-
length: 11,
|
242
|
-
type: :push_promise,
|
243
|
-
flags: [:end_headers],
|
244
|
-
stream: 1,
|
245
|
-
promise_stream: 2,
|
246
|
-
payload: 'headers',
|
247
|
-
}
|
248
|
-
|
249
|
-
bytes = f.generate(frame)
|
250
|
-
expect(bytes).to eq [0, 0xb, 0x5, 0x4, 0x1, 0x2, *'headers'.bytes].pack('CnCCNNC*')
|
251
|
-
expect(f.parse(bytes)).to eq frame
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
context 'PING' do
|
256
|
-
let(:frame) do
|
257
|
-
{
|
258
|
-
length: 8,
|
259
|
-
stream: 1,
|
260
|
-
type: :ping,
|
261
|
-
flags: [:ack],
|
262
|
-
payload: '12345678',
|
263
|
-
}
|
264
|
-
end
|
265
|
-
|
266
|
-
it 'should generate and parse bytes' do
|
267
|
-
bytes = f.generate(frame)
|
268
|
-
expect(bytes).to eq [0, 0x8, 0x6, 0x1, 0x1, *'12345678'.bytes].pack('CnCCNC*')
|
269
|
-
expect(f.parse(bytes)).to eq frame
|
270
|
-
end
|
271
|
-
|
272
|
-
it 'should raise exception on invalid payload' do
|
273
|
-
expect do
|
274
|
-
frame[:payload] = '1234'
|
275
|
-
f.generate(frame)
|
276
|
-
end.to raise_error(CompressionError, /Invalid payload size/)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
context 'GOAWAY' do
|
281
|
-
let(:frame) do
|
282
|
-
{
|
283
|
-
length: 13,
|
284
|
-
stream: 1,
|
285
|
-
type: :goaway,
|
286
|
-
last_stream: 2,
|
287
|
-
error: :no_error,
|
288
|
-
payload: 'debug',
|
289
|
-
}
|
290
|
-
end
|
291
|
-
|
292
|
-
it 'should generate and parse bytes' do
|
293
|
-
bytes = f.generate(frame)
|
294
|
-
expect(bytes).to eq [0, 0xd, 0x7, 0x0, 0x1, 0x2, 0x0, *'debug'.bytes].pack('CnCCNNNC*')
|
295
|
-
expect(f.parse(bytes)).to eq frame
|
296
|
-
end
|
297
|
-
|
298
|
-
it 'should treat debug payload as optional' do
|
299
|
-
frame.delete :payload
|
300
|
-
frame[:length] = 0x8
|
301
|
-
|
302
|
-
bytes = f.generate(frame)
|
303
|
-
expect(bytes).to eq [0, 0x8, 0x7, 0x0, 0x1, 0x2, 0x0].pack('CnCCNNN')
|
304
|
-
expect(f.parse(bytes)).to eq frame
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
context 'WINDOW_UPDATE' do
|
309
|
-
it 'should generate and parse bytes' do
|
310
|
-
frame = {
|
311
|
-
length: 4,
|
312
|
-
type: :window_update,
|
313
|
-
increment: 10,
|
314
|
-
}
|
315
|
-
|
316
|
-
bytes = f.generate(frame)
|
317
|
-
expect(bytes).to eq [0, 0x4, 0x8, 0x0, 0x0, 0xa].pack('CnCCNN')
|
318
|
-
expect(f.parse(bytes)).to eq frame
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
context 'CONTINUATION' do
|
323
|
-
it 'should generate and parse bytes' do
|
324
|
-
frame = {
|
325
|
-
length: 12,
|
326
|
-
type: :continuation,
|
327
|
-
stream: 1,
|
328
|
-
flags: [:end_headers],
|
329
|
-
payload: 'header-block',
|
330
|
-
}
|
331
|
-
|
332
|
-
bytes = f.generate(frame)
|
333
|
-
expect(bytes).to eq [0, 0xc, 0x9, 0x4, 0x1, *'header-block'.bytes].pack('CnCCNC*')
|
334
|
-
expect(f.parse(bytes)).to eq frame
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
context 'ALTSVC' do
|
339
|
-
it 'should generate and parse bytes' do
|
340
|
-
frame = {
|
341
|
-
length: 44,
|
342
|
-
type: :altsvc,
|
343
|
-
stream: 1,
|
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
|
-
}
|
350
|
-
bytes = f.generate(frame)
|
351
|
-
expected = [0, 43, 0xa, 0, 1, 1_402_290_402, 8080].pack('CnCCNNn')
|
352
|
-
expected << [5, *'h2-13'.bytes].pack('CC*')
|
353
|
-
expected << [15, *'www.example.com'.bytes].pack('CC*')
|
354
|
-
expected << [*'www.example.com'.bytes].pack('C*')
|
355
|
-
expect(bytes).to eq expected
|
356
|
-
expect(f.parse(bytes)).to eq frame
|
357
|
-
end
|
358
|
-
end
|
359
|
-
|
360
|
-
context 'Padding' do
|
361
|
-
[:data, :headers, :push_promise].each do |type|
|
362
|
-
[1, 256].each do |padlen|
|
363
|
-
context "generating #{type} frame padded #{padlen}" do
|
364
|
-
before do
|
365
|
-
@frame = {
|
366
|
-
length: 12,
|
367
|
-
type: type,
|
368
|
-
stream: 1,
|
369
|
-
payload: 'example data',
|
370
|
-
}
|
371
|
-
@frame[:promise_stream] = 2 if type == :push_promise
|
372
|
-
@normal = f.generate(@frame)
|
373
|
-
@padded = f.generate(@frame.merge(padding: padlen))
|
374
|
-
end
|
375
|
-
it 'should generate a frame with padding' do
|
376
|
-
expect(@padded.bytesize).to eq @normal.bytesize + padlen
|
377
|
-
end
|
378
|
-
it 'should fill padded octets with zero' do
|
379
|
-
trailer_len = padlen - 1
|
380
|
-
expect(@padded[-trailer_len, trailer_len]).to match(/\A\0*\z/)
|
381
|
-
end
|
382
|
-
it 'should parse a frame with padding' do
|
383
|
-
expect(f.parse(Buffer.new(@padded))).to eq \
|
384
|
-
f.parse(Buffer.new(@normal)).merge(padding: padlen)
|
385
|
-
end
|
386
|
-
it 'should preserve payload' do
|
387
|
-
expect(f.parse(Buffer.new(@padded))[:payload]).to eq @frame[:payload]
|
388
|
-
end
|
389
|
-
end
|
390
|
-
end
|
391
|
-
end
|
392
|
-
context 'generating with invalid padding length' do
|
393
|
-
before do
|
394
|
-
@frame = {
|
395
|
-
length: 12,
|
396
|
-
type: :data,
|
397
|
-
stream: 1,
|
398
|
-
payload: 'example data',
|
399
|
-
}
|
400
|
-
end
|
401
|
-
[0, 257, 1334].each do |padlen|
|
402
|
-
it "should raise error on trying to generate data frame padded with invalid #{padlen}" do
|
403
|
-
expect do
|
404
|
-
f.generate(@frame.merge(padding: padlen))
|
405
|
-
end.to raise_error(CompressionError, /padding/i)
|
406
|
-
end
|
407
|
-
end
|
408
|
-
it 'should raise error when adding a padding would make frame too large' do
|
409
|
-
@frame[:payload] = 'q' * (f.max_frame_size - 200)
|
410
|
-
@frame[:length] = @frame[:payload].size
|
411
|
-
@frame[:padding] = 210 # would exceed 4096
|
412
|
-
expect do
|
413
|
-
f.generate(@frame)
|
414
|
-
end.to raise_error(CompressionError, /padding/i)
|
415
|
-
end
|
416
|
-
end
|
417
|
-
context 'parsing frames with invalid paddings' do
|
418
|
-
before do
|
419
|
-
@frame = {
|
420
|
-
length: 12,
|
421
|
-
type: :data,
|
422
|
-
stream: 1,
|
423
|
-
payload: 'example data',
|
424
|
-
}
|
425
|
-
@padlen = 123
|
426
|
-
@padded = f.generate(@frame.merge(padding: @padlen))
|
427
|
-
end
|
428
|
-
it 'should raise exception when the given padding is longer than the payload' do
|
429
|
-
@padded.setbyte(9, 240)
|
430
|
-
expect { f.parse(Buffer.new(@padded)) }.to raise_error(ProtocolError, /padding/)
|
431
|
-
end
|
432
|
-
end
|
433
|
-
end
|
434
|
-
|
435
|
-
it 'should determine frame length' do
|
436
|
-
frames = [
|
437
|
-
[{ type: :data, stream: 1, flags: [:end_stream], payload: 'abc' }, 3],
|
438
|
-
[{ type: :headers, stream: 1, payload: 'abc' }, 3],
|
439
|
-
[{ type: :priority, stream: 3, stream_dependency: 30, exclusive: false, weight: 1 }, 5],
|
440
|
-
[{ type: :rst_stream, stream: 3, error: 100 }, 4],
|
441
|
-
[{ type: :settings, payload: [[:settings_max_concurrent_streams, 10]] }, 6],
|
442
|
-
[{ type: :push_promise, promise_stream: 5, payload: 'abc' }, 7],
|
443
|
-
[{ type: :ping, payload: 'blob' * 2 }, 8],
|
444
|
-
[{ type: :goaway, last_stream: 5, error: 20, payload: 'blob' }, 12],
|
445
|
-
[{ type: :window_update, stream: 1, increment: 1024 }, 4],
|
446
|
-
[{ type: :continuation, stream: 1, payload: 'abc' }, 3],
|
447
|
-
]
|
448
|
-
|
449
|
-
frames.each do |(frame, size)|
|
450
|
-
bytes = f.generate(frame)
|
451
|
-
expect(bytes.slice(1, 2).unpack('n').first).to eq size
|
452
|
-
expect(bytes.readbyte(0)).to eq 0
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
it 'should parse single frame at a time' do
|
457
|
-
frames = [
|
458
|
-
{ type: :headers, stream: 1, payload: 'headers' },
|
459
|
-
{ type: :data, stream: 1, flags: [:end_stream], payload: 'abc' },
|
460
|
-
]
|
461
|
-
|
462
|
-
buf = f.generate(frames[0]) << f.generate(frames[1])
|
463
|
-
|
464
|
-
expect(f.parse(buf)).to eq frames[0]
|
465
|
-
expect(f.parse(buf)).to eq frames[1]
|
466
|
-
end
|
467
|
-
|
468
|
-
it 'should process full frames only' do
|
469
|
-
frame = { type: :headers, stream: 1, payload: 'headers' }
|
470
|
-
bytes = f.generate(frame)
|
471
|
-
|
472
|
-
expect(f.parse(bytes[0...-1])).to be_nil
|
473
|
-
expect(f.parse(bytes)).to eq frame
|
474
|
-
expect(bytes).to be_empty
|
475
|
-
end
|
476
|
-
|
477
|
-
it 'should ignore unknown extension frames' do
|
478
|
-
frame = { type: :headers, stream: 1, payload: 'headers' }
|
479
|
-
bytes = f.generate(frame)
|
480
|
-
bytes = Buffer.new(bytes + bytes) # Two HEADERS frames in bytes
|
481
|
-
bytes.setbyte(3, 42) # Make the first unknown type 42
|
482
|
-
|
483
|
-
expect(f.parse(bytes)).to be_nil # first frame should be ignored
|
484
|
-
expect(f.parse(bytes)).to eq frame # should generate only one HEADERS
|
485
|
-
expect(bytes).to be_empty
|
486
|
-
end
|
487
|
-
end
|
data/spec/h2spec/h2spec.darwin
DELETED
Binary file
|