http-2 1.0.1 → 1.1.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/lib/http/2/client.rb +1 -0
- data/lib/http/2/connection.rb +118 -99
- data/lib/http/2/emitter.rb +2 -9
- data/lib/http/2/extensions.rb +33 -15
- data/lib/http/2/flow_buffer.rb +45 -35
- data/lib/http/2/framer.rb +134 -107
- data/lib/http/2/header/compressor.rb +47 -31
- data/lib/http/2/header/decompressor.rb +32 -25
- data/lib/http/2/header/encoding_context.rb +84 -85
- data/lib/http/2/header/huffman.rb +13 -11
- data/lib/http/2/header/huffman_statemachine.rb +2 -2
- data/lib/http/2/server.rb +7 -1
- data/lib/http/2/stream.rb +9 -4
- 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 +21 -8
- data/sig/emitter.rbs +2 -4
- data/sig/extensions.rbs +11 -1
- data/sig/flow_buffer.rbs +7 -5
- data/sig/frame_buffer.rbs +1 -1
- data/sig/framer.rbs +6 -0
- data/sig/header/compressor.rbs +6 -4
- data/sig/header/decompressor.rbs +5 -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
@@ -4,10 +4,9 @@ module HTTP2
|
|
4
4
|
# Performs encoding, decoding, and validation of binary HTTP/2 frames.
|
5
5
|
#
|
6
6
|
class Framer
|
7
|
-
using StringExtensions
|
8
|
-
|
9
7
|
include Error
|
10
8
|
include PackingExtensions
|
9
|
+
include BufferUtils
|
11
10
|
|
12
11
|
# Default value of max frame size (16384 bytes)
|
13
12
|
DEFAULT_MAX_FRAME_SIZE = 2 << 13
|
@@ -37,6 +36,8 @@ module HTTP2
|
|
37
36
|
origin: 0xc
|
38
37
|
}.freeze
|
39
38
|
|
39
|
+
FRAME_TYPES_BY_NAME = FRAME_TYPES.invert.freeze
|
40
|
+
|
40
41
|
FRAME_TYPES_WITH_PADDING = %i[data headers push_promise].freeze
|
41
42
|
|
42
43
|
# Per frame flags as defined by the spec
|
@@ -127,30 +128,43 @@ module HTTP2
|
|
127
128
|
# @param buffer [String] buffer to pack bytes into
|
128
129
|
# @return [String]
|
129
130
|
def common_header(frame, buffer:)
|
130
|
-
|
131
|
+
type = frame[:type]
|
132
|
+
|
133
|
+
raise CompressionError, "Invalid frame type (#{type})" unless FRAME_TYPES[type]
|
134
|
+
|
135
|
+
length = frame[:length]
|
131
136
|
|
132
|
-
raise CompressionError, "Frame size is too large: #{
|
137
|
+
raise CompressionError, "Frame size is too large: #{length}" if length > @remote_max_frame_size
|
133
138
|
|
134
|
-
raise CompressionError, "Frame size is invalid: #{
|
139
|
+
raise CompressionError, "Frame size is invalid: #{length}" if length < 0
|
135
140
|
|
136
|
-
|
141
|
+
stream_id = frame.fetch(:stream, 0)
|
137
142
|
|
138
|
-
|
143
|
+
raise CompressionError, "Stream ID (#{stream_id}) is too large" if stream_id > MAX_STREAM_ID
|
144
|
+
|
145
|
+
if type == :window_update && frame[:increment] > MAX_WINDOWINC
|
139
146
|
raise CompressionError, "Window increment (#{frame[:increment]}) is too large"
|
140
147
|
end
|
141
148
|
|
149
|
+
header = buffer
|
150
|
+
|
151
|
+
if buffer.frozen?
|
152
|
+
header = String.new("", encoding: Encoding::BINARY, capacity: buffer.bytesize + 9) # header length
|
153
|
+
header << buffer
|
154
|
+
end
|
155
|
+
|
142
156
|
pack([
|
143
|
-
(
|
144
|
-
(
|
145
|
-
FRAME_TYPES[
|
157
|
+
(length >> FRAME_LENGTH_HISHIFT),
|
158
|
+
(length & FRAME_LENGTH_LOMASK),
|
159
|
+
FRAME_TYPES[type],
|
146
160
|
frame[:flags].reduce(0) do |acc, f|
|
147
|
-
position = FRAME_FLAGS[
|
148
|
-
raise CompressionError, "Invalid frame flag (#{f}) for #{
|
161
|
+
position = FRAME_FLAGS[type][f]
|
162
|
+
raise CompressionError, "Invalid frame flag (#{f}) for #{type}" unless position
|
149
163
|
|
150
164
|
acc | (1 << position)
|
151
165
|
end,
|
152
|
-
|
153
|
-
], HEADERPACK, buffer:
|
166
|
+
stream_id
|
167
|
+
], HEADERPACK, buffer: header, offset: 0) # 8+16,8,8,32
|
154
168
|
end
|
155
169
|
|
156
170
|
# Decodes common 9-byte header.
|
@@ -158,19 +172,21 @@ module HTTP2
|
|
158
172
|
# @param buf [Buffer]
|
159
173
|
# @return [Hash] the corresponding frame
|
160
174
|
def read_common_header(buf)
|
161
|
-
frame = {}
|
162
175
|
len_hi, len_lo, type, flags, stream = buf.byteslice(0, 9).unpack(HEADERPACK)
|
163
176
|
|
164
|
-
|
165
|
-
|
166
|
-
if frame[:type]
|
167
|
-
frame[:flags] = FRAME_FLAGS[frame[:type]].each_with_object([]) do |(name, pos), acc|
|
168
|
-
acc << name if (flags & (1 << pos)) > 0
|
169
|
-
end
|
170
|
-
end
|
177
|
+
type = FRAME_TYPES_BY_NAME[type]
|
178
|
+
length = (len_hi << FRAME_LENGTH_HISHIFT) | len_lo
|
171
179
|
|
172
|
-
|
173
|
-
|
180
|
+
return { length: length } unless type
|
181
|
+
|
182
|
+
{
|
183
|
+
type: type,
|
184
|
+
flags: FRAME_FLAGS[type].filter_map do |name, pos|
|
185
|
+
name if flags.anybits?((1 << pos))
|
186
|
+
end,
|
187
|
+
length: length,
|
188
|
+
stream: stream & RBIT
|
189
|
+
}
|
174
190
|
end
|
175
191
|
|
176
192
|
# Generates encoded HTTP/2 frame.
|
@@ -178,53 +194,60 @@ module HTTP2
|
|
178
194
|
#
|
179
195
|
# @param frame [Hash]
|
180
196
|
def generate(frame)
|
181
|
-
bytes = "".b
|
182
197
|
length = 0
|
183
|
-
|
184
|
-
frame[:flags] ||= []
|
185
|
-
frame[:stream] ||= 0
|
198
|
+
frame[:flags] ||= EMPTY
|
186
199
|
|
187
200
|
case frame[:type]
|
188
|
-
when :data
|
189
|
-
bytes
|
190
|
-
bytes.
|
191
|
-
length += frame[:payload].bytesize
|
201
|
+
when :data, :continuation
|
202
|
+
bytes = frame[:payload]
|
203
|
+
length = bytes.bytesize
|
192
204
|
|
193
205
|
when :headers
|
206
|
+
headers = frame[:payload]
|
207
|
+
|
194
208
|
if frame[:weight] || frame[:dependency] || !frame[:exclusive].nil?
|
195
209
|
unless frame[:weight] && frame[:dependency] && !frame[:exclusive].nil?
|
196
210
|
raise CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
|
197
211
|
end
|
198
212
|
|
199
|
-
frame[:flags] += [:priority] unless frame[:flags].include?
|
213
|
+
frame[:flags] += [:priority] unless frame[:flags].include?(:priority)
|
200
214
|
end
|
201
215
|
|
202
|
-
if frame[:flags].include?
|
216
|
+
if frame[:flags].include?(:priority)
|
217
|
+
length = 5 + headers.bytesize
|
218
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
203
219
|
pack([(frame[:exclusive] ? EBIT : 0) | (frame[:dependency] & RBIT)], UINT32, buffer: bytes)
|
204
220
|
pack([frame[:weight] - 1], UINT8, buffer: bytes)
|
205
|
-
|
221
|
+
append_str(bytes, headers)
|
222
|
+
else
|
223
|
+
length = headers.bytesize
|
224
|
+
bytes = headers
|
206
225
|
end
|
207
226
|
|
208
|
-
bytes << frame[:payload]
|
209
|
-
length += frame[:payload].bytesize
|
210
|
-
|
211
227
|
when :priority
|
212
228
|
unless frame[:weight] && frame[:dependency] && !frame[:exclusive].nil?
|
213
229
|
raise CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
|
214
230
|
end
|
215
231
|
|
232
|
+
length = 5
|
233
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
216
234
|
pack([(frame[:exclusive] ? EBIT : 0) | (frame[:dependency] & RBIT)], UINT32, buffer: bytes)
|
217
235
|
pack([frame[:weight] - 1], UINT8, buffer: bytes)
|
218
|
-
length += 5
|
219
236
|
|
220
237
|
when :rst_stream
|
238
|
+
length = 4
|
239
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
221
240
|
pack_error(frame[:error], buffer: bytes)
|
222
|
-
length += 4
|
223
241
|
|
224
242
|
when :settings
|
225
|
-
|
243
|
+
if (stream_id = frame[:stream]) && stream_id.nonzero?
|
244
|
+
raise CompressionError, "Invalid stream ID (#{stream_id})"
|
245
|
+
end
|
226
246
|
|
227
|
-
frame[:payload]
|
247
|
+
settings = frame[:payload]
|
248
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
249
|
+
|
250
|
+
settings.each do |(k, v)|
|
228
251
|
if k.is_a? Integer # rubocop:disable Style/GuardClause
|
229
252
|
DEFINED_SETTINGS.value?(k) || next
|
230
253
|
else
|
@@ -239,42 +262,42 @@ module HTTP2
|
|
239
262
|
end
|
240
263
|
|
241
264
|
when :push_promise
|
265
|
+
length = 4 + frame[:payload].bytesize
|
266
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
242
267
|
pack([frame[:promise_stream] & RBIT], UINT32, buffer: bytes)
|
243
|
-
bytes
|
244
|
-
length += 4 + frame[:payload].bytesize
|
268
|
+
append_str(bytes, frame[:payload])
|
245
269
|
|
246
270
|
when :ping
|
247
|
-
|
271
|
+
bytes = frame[:payload]
|
272
|
+
raise CompressionError, "Invalid payload size (#{bytes.size} != 8 bytes)" if bytes.bytesize != 8
|
248
273
|
|
249
|
-
|
250
|
-
length += 8
|
274
|
+
length = 8
|
251
275
|
|
252
276
|
when :goaway
|
277
|
+
data = frame[:payload]
|
278
|
+
length = 8
|
279
|
+
length += data.bytesize if data
|
280
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
281
|
+
|
253
282
|
pack([frame[:last_stream] & RBIT], UINT32, buffer: bytes)
|
254
283
|
pack_error(frame[:error], buffer: bytes)
|
255
|
-
length += 8
|
256
284
|
|
257
|
-
if
|
258
|
-
bytes << frame[:payload]
|
259
|
-
length += frame[:payload].bytesize
|
260
|
-
end
|
285
|
+
append_str(bytes, data) if data
|
261
286
|
|
262
287
|
when :window_update
|
288
|
+
length = 4
|
289
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
263
290
|
pack([frame[:increment] & RBIT], UINT32, buffer: bytes)
|
264
|
-
length += 4
|
265
|
-
|
266
|
-
when :continuation
|
267
|
-
bytes << frame[:payload]
|
268
|
-
length += frame[:payload].bytesize
|
269
291
|
|
270
292
|
when :altsvc
|
293
|
+
length = 6
|
294
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
271
295
|
pack([frame[:max_age], frame[:port]], UINT32 + UINT16, buffer: bytes)
|
272
|
-
length += 6
|
273
296
|
if frame[:proto]
|
274
297
|
raise CompressionError, "Proto too long" if frame[:proto].bytesize > 255
|
275
298
|
|
276
299
|
pack([frame[:proto].bytesize], UINT8, buffer: bytes)
|
277
|
-
bytes
|
300
|
+
append_str(bytes, frame[:proto])
|
278
301
|
length += 1 + frame[:proto].bytesize
|
279
302
|
else
|
280
303
|
pack([0], UINT8, buffer: bytes)
|
@@ -284,24 +307,25 @@ module HTTP2
|
|
284
307
|
raise CompressionError, "Host too long" if frame[:host].bytesize > 255
|
285
308
|
|
286
309
|
pack([frame[:host].bytesize], UINT8, buffer: bytes)
|
287
|
-
bytes
|
310
|
+
append_str(bytes, frame[:host])
|
288
311
|
length += 1 + frame[:host].bytesize
|
289
312
|
else
|
290
313
|
pack([0], UINT8, buffer: bytes)
|
291
314
|
length += 1
|
292
315
|
end
|
293
316
|
if frame[:origin]
|
294
|
-
bytes
|
317
|
+
append_str(bytes, frame[:origin])
|
295
318
|
length += frame[:origin].bytesize
|
296
319
|
end
|
297
320
|
|
298
321
|
when :origin
|
299
|
-
frame[:payload]
|
322
|
+
origins = frame[:payload]
|
323
|
+
length = origins.sum(&:bytesize) + (2 * origins.size)
|
324
|
+
bytes = String.new("", encoding: Encoding::BINARY, capacity: length)
|
325
|
+
origins.each do |origin|
|
300
326
|
pack([origin.bytesize], UINT16, buffer: bytes)
|
301
|
-
bytes
|
302
|
-
length += 2 + origin.bytesize
|
327
|
+
append_str(bytes, origin)
|
303
328
|
end
|
304
|
-
|
305
329
|
end
|
306
330
|
|
307
331
|
# Process padding.
|
@@ -320,12 +344,12 @@ module HTTP2
|
|
320
344
|
|
321
345
|
length += padlen
|
322
346
|
pack([padlen -= 1], UINT8, buffer: bytes, offset: 0)
|
323
|
-
frame[:flags]
|
347
|
+
frame[:flags] += [:padded]
|
324
348
|
|
325
349
|
# Padding: Padding octets that contain no application semantic value.
|
326
350
|
# Padding octets MUST be set to zero when sending and ignored when
|
327
351
|
# receiving.
|
328
|
-
bytes
|
352
|
+
append_str(bytes, ("\0" * padlen))
|
329
353
|
end
|
330
354
|
|
331
355
|
frame[:length] = length
|
@@ -340,71 +364,76 @@ module HTTP2
|
|
340
364
|
return if buf.size < 9
|
341
365
|
|
342
366
|
frame = read_common_header(buf)
|
343
|
-
return if buf.size < 9 + frame[:length]
|
344
367
|
|
345
|
-
|
368
|
+
type = frame[:type]
|
369
|
+
length = frame[:length]
|
370
|
+
flags = frame[:flags]
|
371
|
+
|
372
|
+
return if buf.size < 9 + length
|
346
373
|
|
347
|
-
|
348
|
-
|
374
|
+
raise ProtocolError, "payload too large" if length > @local_max_frame_size
|
375
|
+
|
376
|
+
read_str(buf, 9)
|
377
|
+
payload = read_str(buf, length)
|
349
378
|
|
350
379
|
# Implementations MUST discard frames
|
351
380
|
# that have unknown or unsupported types.
|
352
381
|
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.5
|
353
|
-
return frame
|
382
|
+
return frame unless type
|
354
383
|
|
355
384
|
# Process padding
|
356
385
|
padlen = 0
|
357
|
-
if FRAME_TYPES_WITH_PADDING.include?(
|
358
|
-
padded =
|
386
|
+
if FRAME_TYPES_WITH_PADDING.include?(type)
|
387
|
+
padded = flags.include?(:padded)
|
359
388
|
if padded
|
360
|
-
padlen = payload
|
389
|
+
padlen = read_str(payload, 1).unpack1(UINT8)
|
361
390
|
frame[:padding] = padlen + 1
|
362
391
|
raise ProtocolError, "padding too long" if padlen > payload.bytesize
|
363
392
|
|
364
393
|
payload = payload.byteslice(0, payload.bytesize - padlen) if padlen > 0
|
365
394
|
frame[:length] -= frame[:padding]
|
366
|
-
|
395
|
+
flags.delete(:padded)
|
367
396
|
end
|
368
397
|
end
|
369
398
|
|
370
|
-
case
|
399
|
+
case type
|
371
400
|
when :data, :ping, :continuation
|
372
|
-
frame[:payload] = payload
|
401
|
+
frame[:payload] = read_str(payload, length)
|
373
402
|
when :headers
|
374
|
-
if
|
375
|
-
e_sd = payload
|
403
|
+
if flags.include?(:priority)
|
404
|
+
e_sd = read_uint32(payload)
|
376
405
|
frame[:dependency] = e_sd & RBIT
|
377
|
-
frame[:exclusive] = (
|
406
|
+
frame[:exclusive] = e_sd.anybits?(EBIT)
|
378
407
|
weight = payload.byteslice(0, 1).ord + 1
|
379
408
|
frame[:weight] = weight
|
380
409
|
payload = payload.byteslice(1..-1)
|
381
410
|
end
|
382
|
-
frame[:payload] = payload
|
411
|
+
frame[:payload] = read_str(payload, length)
|
383
412
|
when :priority
|
384
|
-
raise FrameSizeError, "Invalid length for PRIORITY_STREAM (#{
|
413
|
+
raise FrameSizeError, "Invalid length for PRIORITY_STREAM (#{length} != 5)" if length != 5
|
385
414
|
|
386
|
-
e_sd = payload
|
415
|
+
e_sd = read_uint32(payload)
|
387
416
|
frame[:dependency] = e_sd & RBIT
|
388
|
-
frame[:exclusive] = (
|
417
|
+
frame[:exclusive] = e_sd.anybits?(EBIT)
|
389
418
|
weight = payload.byteslice(0, 1).ord + 1
|
390
419
|
frame[:weight] = weight
|
391
420
|
payload = payload.byteslice(1..-1)
|
392
421
|
when :rst_stream
|
393
|
-
raise FrameSizeError, "Invalid length for RST_STREAM (#{
|
422
|
+
raise FrameSizeError, "Invalid length for RST_STREAM (#{length} != 4)" if length != 4
|
394
423
|
|
395
|
-
frame[:error] = unpack_error payload
|
424
|
+
frame[:error] = unpack_error read_uint32(payload)
|
396
425
|
|
397
426
|
when :settings
|
398
427
|
# NOTE: frame[:length] might not match the number of frame[:payload]
|
399
428
|
# because unknown extensions are ignored.
|
400
429
|
frame[:payload] = []
|
401
|
-
raise ProtocolError, "Invalid settings payload length" unless (
|
430
|
+
raise ProtocolError, "Invalid settings payload length" unless (length % 6).zero?
|
402
431
|
|
403
|
-
raise ProtocolError, "Invalid stream ID (#{frame[:stream]})" if
|
432
|
+
raise ProtocolError, "Invalid stream ID (#{frame[:stream]})" if frame[:stream].nonzero?
|
404
433
|
|
405
434
|
(frame[:length] / 6).times do
|
406
|
-
id = payload
|
407
|
-
val = payload
|
435
|
+
id = read_str(payload, 2).unpack1(UINT16)
|
436
|
+
val = read_uint32(payload)
|
408
437
|
|
409
438
|
# Unsupported or unrecognized settings MUST be ignored.
|
410
439
|
# Here we send it along.
|
@@ -412,39 +441,37 @@ module HTTP2
|
|
412
441
|
frame[:payload] << [name, val] if name
|
413
442
|
end
|
414
443
|
when :push_promise
|
415
|
-
frame[:promise_stream] = payload
|
416
|
-
frame[:payload] = payload
|
444
|
+
frame[:promise_stream] = read_uint32(payload) & RBIT
|
445
|
+
frame[:payload] = read_str(payload, length)
|
417
446
|
when :goaway
|
418
|
-
frame[:last_stream] = payload
|
419
|
-
frame[:error] = unpack_error payload
|
447
|
+
frame[:last_stream] = read_uint32(payload) & RBIT
|
448
|
+
frame[:error] = unpack_error read_uint32(payload)
|
420
449
|
|
421
|
-
size =
|
422
|
-
frame[:payload] = payload
|
450
|
+
size = length - 8 # for last_stream and error
|
451
|
+
frame[:payload] = read_str(payload, size) if size > 0
|
423
452
|
when :window_update
|
424
|
-
if
|
425
|
-
raise FrameSizeError, "Invalid length for WINDOW_UPDATE (#{frame[:length]} not multiple of 4)"
|
426
|
-
end
|
453
|
+
raise FrameSizeError, "Invalid length for WINDOW_UPDATE (#{length} not multiple of 4)" if length % 4 != 0
|
427
454
|
|
428
|
-
frame[:increment] = payload
|
455
|
+
frame[:increment] = read_uint32(payload) & RBIT
|
429
456
|
when :altsvc
|
430
|
-
frame[:max_age], frame[:port] = payload
|
457
|
+
frame[:max_age], frame[:port] = read_str(payload, 6).unpack(UINT32 + UINT16)
|
431
458
|
|
432
459
|
len = payload.byteslice(0, 1).ord
|
433
460
|
payload = payload.byteslice(1..-1)
|
434
|
-
frame[:proto] = payload
|
461
|
+
frame[:proto] = read_str(payload, len) if len > 0
|
435
462
|
|
436
463
|
len = payload.byteslice(0, 1).ord
|
437
464
|
payload = payload.byteslice(1..-1)
|
438
|
-
frame[:host] = payload
|
465
|
+
frame[:host] = read_str(payload, len) if len > 0
|
439
466
|
|
440
|
-
frame[:origin] =
|
467
|
+
frame[:origin] = read_str(payload, payload.size) unless payload.empty?
|
441
468
|
|
442
469
|
when :origin
|
443
470
|
origins = []
|
444
471
|
|
445
472
|
until payload.empty?
|
446
|
-
len = payload
|
447
|
-
origins << payload
|
473
|
+
len = read_str(payload, 2).unpack1(UINT16)
|
474
|
+
origins << read_str(payload, len)
|
448
475
|
end
|
449
476
|
|
450
477
|
frame[:payload] = origins
|