http-2 1.0.2 → 1.1.1
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/lib/http/2/client.rb +1 -0
- data/lib/http/2/connection.rb +118 -97
- data/lib/http/2/emitter.rb +2 -9
- data/lib/http/2/extensions.rb +21 -1
- data/lib/http/2/flow_buffer.rb +45 -35
- data/lib/http/2/framer.rb +123 -85
- data/lib/http/2/header/compressor.rb +47 -31
- data/lib/http/2/header/decompressor.rb +27 -20
- data/lib/http/2/header/encoding_context.rb +77 -80
- data/lib/http/2/header/huffman.rb +14 -10
- data/lib/http/2/header/huffman_statemachine.rb +1 -1
- data/lib/http/2/server.rb +7 -1
- data/lib/http/2/stream.rb +54 -60
- data/lib/http/2/version.rb +1 -1
- data/lib/http/2.rb +5 -0
- data/sig/{next.rbs → 2.rbs} +29 -18
- data/sig/client.rbs +2 -0
- data/sig/connection.rbs +20 -8
- data/sig/emitter.rbs +2 -4
- data/sig/extensions.rbs +3 -1
- data/sig/flow_buffer.rbs +7 -5
- data/sig/frame_buffer.rbs +1 -1
- data/sig/framer.rbs +5 -0
- data/sig/header/compressor.rbs +6 -4
- data/sig/header/decompressor.rbs +3 -2
- data/sig/header/encoding_context.rbs +24 -6
- data/sig/header/huffman.rbs +19 -3
- data/sig/header.rbs +11 -8
- data/sig/stream.rbs +8 -5
- metadata +4 -7
data/lib/http/2/flow_buffer.rb
CHANGED
@@ -7,6 +7,8 @@ module HTTP2
|
|
7
7
|
module FlowBuffer
|
8
8
|
include Error
|
9
9
|
|
10
|
+
attr_reader :send_buffer
|
11
|
+
|
10
12
|
MAX_WINDOW_SIZE = (2 << 30) - 1
|
11
13
|
|
12
14
|
# Amount of buffered data. Only DATA payloads are subject to flow stream
|
@@ -14,7 +16,7 @@ module HTTP2
|
|
14
16
|
#
|
15
17
|
# @return [Integer]
|
16
18
|
def buffered_amount
|
17
|
-
send_buffer.bytesize
|
19
|
+
@send_buffer.bytesize
|
18
20
|
end
|
19
21
|
|
20
22
|
def flush
|
@@ -23,13 +25,9 @@ module HTTP2
|
|
23
25
|
|
24
26
|
private
|
25
27
|
|
26
|
-
def send_buffer
|
27
|
-
@send_buffer ||= FrameBuffer.new
|
28
|
-
end
|
29
|
-
|
30
28
|
def update_local_window(frame)
|
31
29
|
frame_size = frame[:payload].bytesize
|
32
|
-
frame_size += frame
|
30
|
+
frame_size += frame.fetch(:padding, 0)
|
33
31
|
@local_window -= frame_size
|
34
32
|
end
|
35
33
|
|
@@ -69,31 +67,47 @@ module HTTP2
|
|
69
67
|
# @param frame [Hash]
|
70
68
|
# @param encode [Boolean] set to true by connection
|
71
69
|
def send_data(frame = nil, encode = false)
|
72
|
-
|
70
|
+
if frame
|
71
|
+
if @send_buffer.empty?
|
72
|
+
frame_size = frame[:payload].bytesize
|
73
|
+
end_stream = frame[:flags].include?(:end_stream)
|
74
|
+
# if buffer is empty, and frame is either end 0 length OR
|
75
|
+
# is within available window size, skip buffering and send immediately.
|
76
|
+
if @remote_window.positive?
|
77
|
+
return send_frame(frame, encode) if frame_size <= @remote_window
|
78
|
+
elsif frame_size.zero? && end_stream
|
79
|
+
return send_frame(frame, encode)
|
80
|
+
end
|
81
|
+
end
|
73
82
|
|
74
|
-
|
83
|
+
@send_buffer << frame
|
84
|
+
end
|
75
85
|
|
76
|
-
|
77
|
-
|
86
|
+
while (frame = @send_buffer.retrieve(@remote_window))
|
87
|
+
send_frame(frame, encode)
|
88
|
+
end
|
89
|
+
end
|
78
90
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
91
|
+
def send_frame(frame, encode)
|
92
|
+
sent = frame[:payload].bytesize
|
93
|
+
|
94
|
+
manage_state(frame) do
|
95
|
+
if encode
|
96
|
+
encode(frame)
|
97
|
+
else
|
98
|
+
emit(:frame, frame)
|
86
99
|
end
|
100
|
+
@remote_window -= sent
|
87
101
|
end
|
88
102
|
end
|
89
103
|
|
90
104
|
def process_window_update(frame:, encode: false)
|
91
105
|
return if frame[:ignore]
|
92
106
|
|
93
|
-
if frame[:increment]
|
94
|
-
raise ProtocolError, "increment MUST be higher than zero" if
|
107
|
+
if (increment = frame[:increment])
|
108
|
+
raise ProtocolError, "increment MUST be higher than zero" if increment.zero?
|
95
109
|
|
96
|
-
@remote_window +=
|
110
|
+
@remote_window += increment
|
97
111
|
error(:flow_control_error, msg: "window size too large") if @remote_window > MAX_WINDOW_SIZE
|
98
112
|
end
|
99
113
|
send_data(nil, encode)
|
@@ -114,45 +128,41 @@ module HTTP2
|
|
114
128
|
end
|
115
129
|
|
116
130
|
def empty?
|
117
|
-
@
|
131
|
+
@buffer.empty?
|
118
132
|
end
|
119
133
|
|
120
134
|
def retrieve(window_size)
|
121
135
|
frame = @buffer.first or return
|
122
136
|
|
123
137
|
frame_size = frame[:payload].bytesize
|
124
|
-
end_stream = frame[:flags].include?
|
138
|
+
end_stream = frame[:flags].include?(:end_stream)
|
125
139
|
|
126
140
|
# Frames with zero length with the END_STREAM flag set (that
|
127
141
|
# is, an empty DATA frame) MAY be sent if there is no available space
|
128
142
|
# in either flow control window.
|
129
|
-
return if window_size <= 0 && !(frame_size
|
130
|
-
|
131
|
-
@buffer.shift
|
143
|
+
return if window_size <= 0 && !(frame_size.zero? && end_stream)
|
132
144
|
|
133
145
|
if frame_size > window_size
|
134
|
-
payload = frame[:payload]
|
135
146
|
chunk = frame.dup
|
147
|
+
payload = frame[:payload]
|
136
148
|
|
137
149
|
# Split frame so that it fits in the window
|
138
150
|
# TODO: consider padding!
|
139
|
-
frame_bytes = payload.byteslice(0, window_size)
|
140
|
-
payload = payload.byteslice(window_size..-1)
|
141
151
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
152
|
+
chunk[:payload] = payload.byteslice(0, window_size)
|
153
|
+
chunk[:length] = window_size
|
154
|
+
frame[:payload] = payload.byteslice(window_size..-1)
|
155
|
+
frame[:length] = frame_size - window_size
|
146
156
|
|
147
157
|
# if no longer last frame in sequence...
|
148
|
-
|
158
|
+
chunk[:flags] -= [:end_stream] if end_stream
|
149
159
|
|
150
|
-
@buffer.unshift(chunk)
|
151
160
|
@bytesize -= window_size
|
161
|
+
chunk
|
152
162
|
else
|
153
163
|
@bytesize -= frame_size
|
164
|
+
@buffer.shift
|
154
165
|
end
|
155
|
-
frame
|
156
166
|
end
|
157
167
|
end
|
158
168
|
end
|
data/lib/http/2/framer.rb
CHANGED
@@ -36,6 +36,8 @@ module HTTP2
|
|
36
36
|
origin: 0xc
|
37
37
|
}.freeze
|
38
38
|
|
39
|
+
FRAME_TYPES_BY_NAME = FRAME_TYPES.invert.freeze
|
40
|
+
|
39
41
|
FRAME_TYPES_WITH_PADDING = %i[data headers push_promise].freeze
|
40
42
|
|
41
43
|
# Per frame flags as defined by the spec
|
@@ -126,30 +128,46 @@ module HTTP2
|
|
126
128
|
# @param buffer [String] buffer to pack bytes into
|
127
129
|
# @return [String]
|
128
130
|
def common_header(frame, buffer:)
|
129
|
-
|
131
|
+
type = frame[:type]
|
132
|
+
|
133
|
+
raise CompressionError, "Invalid frame type (#{type})" unless FRAME_TYPES[type]
|
134
|
+
|
135
|
+
length = frame[:length]
|
136
|
+
|
137
|
+
raise CompressionError, "Frame size is too large: #{length}" if length > @remote_max_frame_size
|
130
138
|
|
131
|
-
raise CompressionError, "Frame size is
|
139
|
+
raise CompressionError, "Frame size is invalid: #{length}" if length < 0
|
132
140
|
|
133
|
-
|
141
|
+
stream_id = frame.fetch(:stream, 0)
|
134
142
|
|
135
|
-
raise CompressionError, "Stream ID (#{
|
143
|
+
raise CompressionError, "Stream ID (#{stream_id}) is too large" if stream_id > MAX_STREAM_ID
|
136
144
|
|
137
|
-
if
|
145
|
+
if type == :window_update && frame[:increment] > MAX_WINDOWINC
|
138
146
|
raise CompressionError, "Window increment (#{frame[:increment]}) is too large"
|
139
147
|
end
|
140
148
|
|
149
|
+
header = buffer
|
150
|
+
|
151
|
+
# make sure the buffer is binary and unfrozen
|
152
|
+
if buffer.frozen?
|
153
|
+
header = String.new("", encoding: Encoding::BINARY, capacity: buffer.bytesize + 9) # header length
|
154
|
+
append_str(header, buffer)
|
155
|
+
else
|
156
|
+
header.force_encoding(Encoding::BINARY)
|
157
|
+
end
|
158
|
+
|
141
159
|
pack([
|
142
|
-
(
|
143
|
-
(
|
144
|
-
FRAME_TYPES[
|
160
|
+
(length >> FRAME_LENGTH_HISHIFT),
|
161
|
+
(length & FRAME_LENGTH_LOMASK),
|
162
|
+
FRAME_TYPES[type],
|
145
163
|
frame[:flags].reduce(0) do |acc, f|
|
146
|
-
position = FRAME_FLAGS[
|
147
|
-
raise CompressionError, "Invalid frame flag (#{f}) for #{
|
164
|
+
position = FRAME_FLAGS[type][f]
|
165
|
+
raise CompressionError, "Invalid frame flag (#{f}) for #{type}" unless position
|
148
166
|
|
149
167
|
acc | (1 << position)
|
150
168
|
end,
|
151
|
-
|
152
|
-
], HEADERPACK, buffer:
|
169
|
+
stream_id
|
170
|
+
], HEADERPACK, buffer: header, offset: 0) # 8+16,8,8,32
|
153
171
|
end
|
154
172
|
|
155
173
|
# Decodes common 9-byte header.
|
@@ -157,19 +175,21 @@ module HTTP2
|
|
157
175
|
# @param buf [Buffer]
|
158
176
|
# @return [Hash] the corresponding frame
|
159
177
|
def read_common_header(buf)
|
160
|
-
frame = {}
|
161
178
|
len_hi, len_lo, type, flags, stream = buf.byteslice(0, 9).unpack(HEADERPACK)
|
162
179
|
|
163
|
-
|
164
|
-
|
165
|
-
if frame[:type]
|
166
|
-
frame[:flags] = FRAME_FLAGS[frame[:type]].each_with_object([]) do |(name, pos), acc|
|
167
|
-
acc << name if flags.anybits?((1 << pos))
|
168
|
-
end
|
169
|
-
end
|
180
|
+
type = FRAME_TYPES_BY_NAME[type]
|
181
|
+
length = (len_hi << FRAME_LENGTH_HISHIFT) | len_lo
|
170
182
|
|
171
|
-
|
172
|
-
|
183
|
+
return { length: length } unless type
|
184
|
+
|
185
|
+
{
|
186
|
+
type: type,
|
187
|
+
flags: FRAME_FLAGS[type].filter_map do |name, pos|
|
188
|
+
name if flags.anybits?((1 << pos))
|
189
|
+
end,
|
190
|
+
length: length,
|
191
|
+
stream: stream & RBIT
|
192
|
+
}
|
173
193
|
end
|
174
194
|
|
175
195
|
# Generates encoded HTTP/2 frame.
|
@@ -177,53 +197,60 @@ module HTTP2
|
|
177
197
|
#
|
178
198
|
# @param frame [Hash]
|
179
199
|
def generate(frame)
|
180
|
-
bytes = "".b
|
181
200
|
length = 0
|
182
|
-
|
183
|
-
frame[:flags] ||= []
|
184
|
-
frame[:stream] ||= 0
|
201
|
+
frame[:flags] ||= EMPTY
|
185
202
|
|
186
203
|
case frame[:type]
|
187
|
-
when :data
|
188
|
-
bytes
|
189
|
-
bytes.
|
190
|
-
length += frame[:payload].bytesize
|
204
|
+
when :data, :continuation
|
205
|
+
bytes = frame[:payload]
|
206
|
+
length = bytes.bytesize
|
191
207
|
|
192
208
|
when :headers
|
209
|
+
headers = frame[:payload]
|
210
|
+
|
193
211
|
if frame[:weight] || frame[:dependency] || !frame[:exclusive].nil?
|
194
212
|
unless frame[:weight] && frame[:dependency] && !frame[:exclusive].nil?
|
195
213
|
raise CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
|
196
214
|
end
|
197
215
|
|
198
|
-
frame[:flags] += [:priority] unless frame[:flags].include?
|
216
|
+
frame[:flags] += [:priority] unless frame[:flags].include?(:priority)
|
199
217
|
end
|
200
218
|
|
201
|
-
if frame[:flags].include?
|
219
|
+
if frame[:flags].include?(:priority)
|
220
|
+
length = 5 + headers.bytesize
|
221
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
202
222
|
pack([(frame[:exclusive] ? EBIT : 0) | (frame[:dependency] & RBIT)], UINT32, buffer: bytes)
|
203
223
|
pack([frame[:weight] - 1], UINT8, buffer: bytes)
|
204
|
-
|
224
|
+
append_str(bytes, headers)
|
225
|
+
else
|
226
|
+
length = headers.bytesize
|
227
|
+
bytes = headers
|
205
228
|
end
|
206
229
|
|
207
|
-
bytes << frame[:payload]
|
208
|
-
length += frame[:payload].bytesize
|
209
|
-
|
210
230
|
when :priority
|
211
231
|
unless frame[:weight] && frame[:dependency] && !frame[:exclusive].nil?
|
212
232
|
raise CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
|
213
233
|
end
|
214
234
|
|
235
|
+
length = 5
|
236
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
215
237
|
pack([(frame[:exclusive] ? EBIT : 0) | (frame[:dependency] & RBIT)], UINT32, buffer: bytes)
|
216
238
|
pack([frame[:weight] - 1], UINT8, buffer: bytes)
|
217
|
-
length += 5
|
218
239
|
|
219
240
|
when :rst_stream
|
241
|
+
length = 4
|
242
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
220
243
|
pack_error(frame[:error], buffer: bytes)
|
221
|
-
length += 4
|
222
244
|
|
223
245
|
when :settings
|
224
|
-
|
246
|
+
if (stream_id = frame[:stream]) && stream_id.nonzero?
|
247
|
+
raise CompressionError, "Invalid stream ID (#{stream_id})"
|
248
|
+
end
|
225
249
|
|
226
|
-
frame[:payload]
|
250
|
+
settings = frame[:payload]
|
251
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
252
|
+
|
253
|
+
settings.each do |(k, v)|
|
227
254
|
if k.is_a? Integer # rubocop:disable Style/GuardClause
|
228
255
|
DEFINED_SETTINGS.value?(k) || next
|
229
256
|
else
|
@@ -238,42 +265,42 @@ module HTTP2
|
|
238
265
|
end
|
239
266
|
|
240
267
|
when :push_promise
|
268
|
+
length = 4 + frame[:payload].bytesize
|
269
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
241
270
|
pack([frame[:promise_stream] & RBIT], UINT32, buffer: bytes)
|
242
|
-
bytes
|
243
|
-
length += 4 + frame[:payload].bytesize
|
271
|
+
append_str(bytes, frame[:payload])
|
244
272
|
|
245
273
|
when :ping
|
246
|
-
|
274
|
+
bytes = frame[:payload].b
|
275
|
+
raise CompressionError, "Invalid payload size (#{bytes.size} != 8 bytes)" if bytes.bytesize != 8
|
247
276
|
|
248
|
-
|
249
|
-
length += 8
|
277
|
+
length = 8
|
250
278
|
|
251
279
|
when :goaway
|
280
|
+
data = frame[:payload]
|
281
|
+
length = 8
|
282
|
+
length += data.bytesize if data
|
283
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
284
|
+
|
252
285
|
pack([frame[:last_stream] & RBIT], UINT32, buffer: bytes)
|
253
286
|
pack_error(frame[:error], buffer: bytes)
|
254
|
-
length += 8
|
255
287
|
|
256
|
-
if
|
257
|
-
bytes << frame[:payload]
|
258
|
-
length += frame[:payload].bytesize
|
259
|
-
end
|
288
|
+
append_str(bytes, data) if data
|
260
289
|
|
261
290
|
when :window_update
|
291
|
+
length = 4
|
292
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
262
293
|
pack([frame[:increment] & RBIT], UINT32, buffer: bytes)
|
263
|
-
length += 4
|
264
|
-
|
265
|
-
when :continuation
|
266
|
-
bytes << frame[:payload]
|
267
|
-
length += frame[:payload].bytesize
|
268
294
|
|
269
295
|
when :altsvc
|
296
|
+
length = 6
|
297
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
270
298
|
pack([frame[:max_age], frame[:port]], UINT32 + UINT16, buffer: bytes)
|
271
|
-
length += 6
|
272
299
|
if frame[:proto]
|
273
300
|
raise CompressionError, "Proto too long" if frame[:proto].bytesize > 255
|
274
301
|
|
275
302
|
pack([frame[:proto].bytesize], UINT8, buffer: bytes)
|
276
|
-
bytes
|
303
|
+
append_str(bytes, frame[:proto])
|
277
304
|
length += 1 + frame[:proto].bytesize
|
278
305
|
else
|
279
306
|
pack([0], UINT8, buffer: bytes)
|
@@ -283,24 +310,25 @@ module HTTP2
|
|
283
310
|
raise CompressionError, "Host too long" if frame[:host].bytesize > 255
|
284
311
|
|
285
312
|
pack([frame[:host].bytesize], UINT8, buffer: bytes)
|
286
|
-
bytes
|
313
|
+
append_str(bytes, frame[:host])
|
287
314
|
length += 1 + frame[:host].bytesize
|
288
315
|
else
|
289
316
|
pack([0], UINT8, buffer: bytes)
|
290
317
|
length += 1
|
291
318
|
end
|
292
319
|
if frame[:origin]
|
293
|
-
bytes
|
320
|
+
append_str(bytes, frame[:origin])
|
294
321
|
length += frame[:origin].bytesize
|
295
322
|
end
|
296
323
|
|
297
324
|
when :origin
|
298
|
-
frame[:payload]
|
325
|
+
origins = frame[:payload]
|
326
|
+
length = origins.sum(&:bytesize) + (2 * origins.size)
|
327
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
328
|
+
origins.each do |origin|
|
299
329
|
pack([origin.bytesize], UINT16, buffer: bytes)
|
300
|
-
bytes
|
301
|
-
length += 2 + origin.bytesize
|
330
|
+
append_str(bytes, origin)
|
302
331
|
end
|
303
|
-
|
304
332
|
end
|
305
333
|
|
306
334
|
# Process padding.
|
@@ -317,14 +345,21 @@ module HTTP2
|
|
317
345
|
raise CompressionError, "Invalid padding #{padlen}"
|
318
346
|
end
|
319
347
|
|
348
|
+
# make sure the buffer is binary and unfrozen
|
349
|
+
if bytes.frozen?
|
350
|
+
bytes = bytes.b
|
351
|
+
else
|
352
|
+
bytes.force_encoding(Encoding::BINARY)
|
353
|
+
end
|
354
|
+
|
320
355
|
length += padlen
|
321
356
|
pack([padlen -= 1], UINT8, buffer: bytes, offset: 0)
|
322
|
-
frame[:flags]
|
357
|
+
frame[:flags] += [:padded]
|
323
358
|
|
324
359
|
# Padding: Padding octets that contain no application semantic value.
|
325
360
|
# Padding octets MUST be set to zero when sending and ignored when
|
326
361
|
# receiving.
|
327
|
-
bytes
|
362
|
+
append_str(bytes, ("\0" * padlen))
|
328
363
|
end
|
329
364
|
|
330
365
|
frame[:length] = length
|
@@ -339,22 +374,27 @@ module HTTP2
|
|
339
374
|
return if buf.size < 9
|
340
375
|
|
341
376
|
frame = read_common_header(buf)
|
342
|
-
return if buf.size < 9 + frame[:length]
|
343
377
|
|
344
|
-
|
378
|
+
type = frame[:type]
|
379
|
+
length = frame[:length]
|
380
|
+
flags = frame[:flags]
|
381
|
+
|
382
|
+
return if buf.size < 9 + length
|
383
|
+
|
384
|
+
raise ProtocolError, "payload too large" if length > @local_max_frame_size
|
345
385
|
|
346
386
|
read_str(buf, 9)
|
347
|
-
payload = read_str(buf,
|
387
|
+
payload = read_str(buf, length)
|
348
388
|
|
349
389
|
# Implementations MUST discard frames
|
350
390
|
# that have unknown or unsupported types.
|
351
391
|
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.5
|
352
|
-
return frame
|
392
|
+
return frame unless type
|
353
393
|
|
354
394
|
# Process padding
|
355
395
|
padlen = 0
|
356
|
-
if FRAME_TYPES_WITH_PADDING.include?(
|
357
|
-
padded =
|
396
|
+
if FRAME_TYPES_WITH_PADDING.include?(type)
|
397
|
+
padded = flags.include?(:padded)
|
358
398
|
if padded
|
359
399
|
padlen = read_str(payload, 1).unpack1(UINT8)
|
360
400
|
frame[:padding] = padlen + 1
|
@@ -362,15 +402,15 @@ module HTTP2
|
|
362
402
|
|
363
403
|
payload = payload.byteslice(0, payload.bytesize - padlen) if padlen > 0
|
364
404
|
frame[:length] -= frame[:padding]
|
365
|
-
|
405
|
+
flags.delete(:padded)
|
366
406
|
end
|
367
407
|
end
|
368
408
|
|
369
|
-
case
|
409
|
+
case type
|
370
410
|
when :data, :ping, :continuation
|
371
|
-
frame[:payload] = read_str(payload,
|
411
|
+
frame[:payload] = read_str(payload, length)
|
372
412
|
when :headers
|
373
|
-
if
|
413
|
+
if flags.include?(:priority)
|
374
414
|
e_sd = read_uint32(payload)
|
375
415
|
frame[:dependency] = e_sd & RBIT
|
376
416
|
frame[:exclusive] = e_sd.anybits?(EBIT)
|
@@ -378,9 +418,9 @@ module HTTP2
|
|
378
418
|
frame[:weight] = weight
|
379
419
|
payload = payload.byteslice(1..-1)
|
380
420
|
end
|
381
|
-
frame[:payload] = read_str(payload,
|
421
|
+
frame[:payload] = read_str(payload, length)
|
382
422
|
when :priority
|
383
|
-
raise FrameSizeError, "Invalid length for PRIORITY_STREAM (#{
|
423
|
+
raise FrameSizeError, "Invalid length for PRIORITY_STREAM (#{length} != 5)" if length != 5
|
384
424
|
|
385
425
|
e_sd = read_uint32(payload)
|
386
426
|
frame[:dependency] = e_sd & RBIT
|
@@ -389,7 +429,7 @@ module HTTP2
|
|
389
429
|
frame[:weight] = weight
|
390
430
|
payload = payload.byteslice(1..-1)
|
391
431
|
when :rst_stream
|
392
|
-
raise FrameSizeError, "Invalid length for RST_STREAM (#{
|
432
|
+
raise FrameSizeError, "Invalid length for RST_STREAM (#{length} != 4)" if length != 4
|
393
433
|
|
394
434
|
frame[:error] = unpack_error read_uint32(payload)
|
395
435
|
|
@@ -397,9 +437,9 @@ module HTTP2
|
|
397
437
|
# NOTE: frame[:length] might not match the number of frame[:payload]
|
398
438
|
# because unknown extensions are ignored.
|
399
439
|
frame[:payload] = []
|
400
|
-
raise ProtocolError, "Invalid settings payload length" unless (
|
440
|
+
raise ProtocolError, "Invalid settings payload length" unless (length % 6).zero?
|
401
441
|
|
402
|
-
raise ProtocolError, "Invalid stream ID (#{frame[:stream]})" if
|
442
|
+
raise ProtocolError, "Invalid stream ID (#{frame[:stream]})" if frame[:stream].nonzero?
|
403
443
|
|
404
444
|
(frame[:length] / 6).times do
|
405
445
|
id = read_str(payload, 2).unpack1(UINT16)
|
@@ -412,17 +452,15 @@ module HTTP2
|
|
412
452
|
end
|
413
453
|
when :push_promise
|
414
454
|
frame[:promise_stream] = read_uint32(payload) & RBIT
|
415
|
-
frame[:payload] = read_str(payload,
|
455
|
+
frame[:payload] = read_str(payload, length)
|
416
456
|
when :goaway
|
417
457
|
frame[:last_stream] = read_uint32(payload) & RBIT
|
418
458
|
frame[:error] = unpack_error read_uint32(payload)
|
419
459
|
|
420
|
-
size =
|
460
|
+
size = length - 8 # for last_stream and error
|
421
461
|
frame[:payload] = read_str(payload, size) if size > 0
|
422
462
|
when :window_update
|
423
|
-
if
|
424
|
-
raise FrameSizeError, "Invalid length for WINDOW_UPDATE (#{frame[:length]} not multiple of 4)"
|
425
|
-
end
|
463
|
+
raise FrameSizeError, "Invalid length for WINDOW_UPDATE (#{length} not multiple of 4)" if length % 4 != 0
|
426
464
|
|
427
465
|
frame[:increment] = read_uint32(payload) & RBIT
|
428
466
|
when :altsvc
|