http-2 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.rubocop.yml +18 -0
- data/.rubocop_todo.yml +46 -0
- data/.travis.yml +10 -2
- data/Gemfile +7 -5
- data/README.md +35 -37
- data/Rakefile +9 -10
- data/example/README.md +0 -13
- data/example/client.rb +12 -15
- data/example/helper.rb +2 -2
- data/example/server.rb +19 -19
- data/example/upgrade_server.rb +191 -0
- data/http-2.gemspec +10 -9
- data/lib/http/2.rb +13 -13
- data/lib/http/2/buffer.rb +6 -10
- data/lib/http/2/client.rb +5 -10
- data/lib/http/2/compressor.rb +134 -146
- data/lib/http/2/connection.rb +104 -100
- data/lib/http/2/emitter.rb +2 -4
- data/lib/http/2/error.rb +7 -7
- data/lib/http/2/flow_buffer.rb +11 -10
- data/lib/http/2/framer.rb +78 -87
- data/lib/http/2/huffman.rb +265 -274
- data/lib/http/2/huffman_statemachine.rb +257 -257
- data/lib/http/2/server.rb +81 -6
- data/lib/http/2/stream.rb +195 -130
- data/lib/http/2/version.rb +1 -1
- data/lib/tasks/generate_huffman_table.rb +30 -24
- data/spec/buffer_spec.rb +11 -13
- data/spec/client_spec.rb +41 -42
- data/spec/compressor_spec.rb +243 -242
- data/spec/connection_spec.rb +252 -248
- data/spec/emitter_spec.rb +12 -12
- data/spec/framer_spec.rb +177 -179
- data/spec/helper.rb +56 -57
- data/spec/huffman_spec.rb +33 -33
- data/spec/server_spec.rb +15 -15
- data/spec/stream_spec.rb +356 -265
- metadata +7 -6
- data/spec/hpack_test_spec.rb +0 -83
data/lib/http/2/emitter.rb
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
module HTTP2
|
2
|
-
|
3
2
|
# Basic event emitter implementation with support for persistent and
|
4
3
|
# one-time event callbacks.
|
5
4
|
#
|
6
5
|
module Emitter
|
7
|
-
|
8
6
|
# Subscribe to all future events for specified type.
|
9
7
|
#
|
10
8
|
# @param event [Symbol]
|
11
9
|
# @param block [Proc] callback function
|
12
10
|
def add_listener(event, &block)
|
13
|
-
|
11
|
+
fail ArgumentError, 'must provide callback' unless block_given?
|
14
12
|
listeners(event.to_sym).push block
|
15
13
|
end
|
16
|
-
|
14
|
+
alias_method :on, :add_listener
|
17
15
|
|
18
16
|
# Subscribe to next event (at most once) for specified type.
|
19
17
|
#
|
data/lib/http/2/error.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
module HTTP2
|
2
|
-
|
3
2
|
# Stream, connection, and compressor exceptions.
|
4
3
|
module Error
|
4
|
+
class Error < StandardError; end
|
5
5
|
|
6
6
|
# Raised if connection header is missing or invalid indicating that
|
7
7
|
# this is an invalid HTTP 2.0 request - no frames are emitted and the
|
8
8
|
# connection must be aborted.
|
9
|
-
class HandshakeError <
|
9
|
+
class HandshakeError < Error; end
|
10
10
|
|
11
11
|
# Raised by stream or connection handlers, results in GOAWAY frame
|
12
12
|
# which signals termination of the current connection. You *cannot*
|
13
13
|
# recover from this exception, or any exceptions subclassed from it.
|
14
|
-
class ProtocolError <
|
14
|
+
class ProtocolError < Error; end
|
15
15
|
|
16
16
|
# Raised on any header encoding / decoding exception.
|
17
17
|
#
|
@@ -25,20 +25,20 @@ module HTTP2
|
|
25
25
|
|
26
26
|
# Raised on invalid stream processing: invalid frame type received or
|
27
27
|
# sent, or invalid command issued.
|
28
|
-
class
|
28
|
+
class InternalError < ProtocolError; end
|
29
29
|
|
30
30
|
#
|
31
31
|
# -- Recoverable errors -------------------------------------------------
|
32
32
|
#
|
33
33
|
|
34
34
|
# Raised if stream has been closed and new frames cannot be sent.
|
35
|
-
class StreamClosed <
|
35
|
+
class StreamClosed < Error; end
|
36
36
|
|
37
37
|
# Raised if connection has been closed (or draining) and new stream
|
38
38
|
# cannot be opened.
|
39
|
-
class ConnectionClosed <
|
39
|
+
class ConnectionClosed < Error; end
|
40
40
|
|
41
41
|
# Raised if stream limit has been reached and new stream cannot be opened.
|
42
|
-
class StreamLimitExceeded <
|
42
|
+
class StreamLimitExceeded < Error; end
|
43
43
|
end
|
44
44
|
end
|
data/lib/http/2/flow_buffer.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
module HTTP2
|
2
|
-
|
3
2
|
# Implementation of stream and connection DATA flow control: frames may
|
4
3
|
# be split and / or may be buffered based on current flow control window.
|
5
4
|
#
|
6
5
|
module FlowBuffer
|
7
|
-
|
8
6
|
# Amount of buffered data. Only DATA payloads are subject to flow stream
|
9
7
|
# and connection flow control.
|
10
8
|
#
|
11
9
|
# @return [Integer]
|
12
10
|
def buffered_amount
|
13
|
-
@send_buffer.map {|f| f[:length] }.reduce(:+) || 0
|
11
|
+
@send_buffer.map { |f| f[:length] }.reduce(:+) || 0
|
14
12
|
end
|
15
13
|
|
16
14
|
private
|
@@ -25,12 +23,12 @@ module HTTP2
|
|
25
23
|
# @param frame [Hash]
|
26
24
|
# @param encode [Boolean] set to true by co
|
27
25
|
def send_data(frame = nil, encode = false)
|
28
|
-
@send_buffer.push frame
|
26
|
+
@send_buffer.push frame unless frame.nil?
|
29
27
|
|
30
28
|
# FIXME: Frames with zero length with the END_STREAM flag set (that
|
31
29
|
# is, an empty DATA frame) MAY be sent if there is no available space
|
32
30
|
# in either flow control window.
|
33
|
-
while @remote_window > 0 && !@send_buffer.empty?
|
31
|
+
while @remote_window > 0 && !@send_buffer.empty?
|
34
32
|
frame = @send_buffer.shift
|
35
33
|
|
36
34
|
sent, frame_size = 0, frame[:payload].bytesize
|
@@ -46,9 +44,7 @@ module HTTP2
|
|
46
44
|
chunk[:payload] = payload
|
47
45
|
|
48
46
|
# if no longer last frame in sequence...
|
49
|
-
if frame[:flags].include? :end_stream
|
50
|
-
frame[:flags] -= [:end_stream]
|
51
|
-
end
|
47
|
+
frame[:flags] -= [:end_stream] if frame[:flags].include? :end_stream
|
52
48
|
|
53
49
|
@send_buffer.unshift chunk
|
54
50
|
sent = @remote_window
|
@@ -57,10 +53,15 @@ module HTTP2
|
|
57
53
|
end
|
58
54
|
|
59
55
|
frames = encode ? encode(frame) : [frame]
|
60
|
-
frames.each {|f| emit(:frame, f) }
|
56
|
+
frames.each { |f| emit(:frame, f) }
|
61
57
|
@remote_window -= sent
|
62
58
|
end
|
63
59
|
end
|
64
|
-
end
|
65
60
|
|
61
|
+
def process_window_update(frame)
|
62
|
+
return if frame[:ignore]
|
63
|
+
@remote_window += frame[:increment]
|
64
|
+
send_data
|
65
|
+
end
|
66
|
+
end
|
66
67
|
end
|
data/lib/http/2/framer.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module HTTP2
|
2
|
-
|
3
2
|
# Performs encoding, decoding, and validation of binary HTTP/2 frames.
|
4
3
|
#
|
5
4
|
class Framer
|
@@ -30,19 +29,22 @@ module HTTP2
|
|
30
29
|
window_update: 0x8,
|
31
30
|
continuation: 0x9,
|
32
31
|
altsvc: 0xa,
|
33
|
-
}
|
32
|
+
}.freeze
|
34
33
|
|
35
|
-
FRAME_TYPES_WITH_PADDING = [
|
34
|
+
FRAME_TYPES_WITH_PADDING = [:data, :headers, :push_promise].freeze
|
36
35
|
|
37
36
|
# Per frame flags as defined by the spec
|
38
37
|
FRAME_FLAGS = {
|
39
38
|
data: {
|
40
39
|
end_stream: 0,
|
41
|
-
padded: 3,
|
40
|
+
padded: 3,
|
41
|
+
compressed: 5,
|
42
42
|
},
|
43
43
|
headers: {
|
44
|
-
end_stream: 0,
|
45
|
-
|
44
|
+
end_stream: 0,
|
45
|
+
end_headers: 2,
|
46
|
+
padded: 3,
|
47
|
+
priority: 5,
|
46
48
|
},
|
47
49
|
priority: {},
|
48
50
|
rst_stream: {},
|
@@ -53,10 +55,10 @@ module HTTP2
|
|
53
55
|
},
|
54
56
|
ping: { ack: 0 },
|
55
57
|
goaway: {},
|
56
|
-
window_update:{},
|
58
|
+
window_update: {},
|
57
59
|
continuation: { end_headers: 2 },
|
58
60
|
altsvc: {},
|
59
|
-
}
|
61
|
+
}.each_value(&:freeze).freeze
|
60
62
|
|
61
63
|
# Default settings as defined by the spec
|
62
64
|
DEFINED_SETTINGS = {
|
@@ -66,7 +68,7 @@ module HTTP2
|
|
66
68
|
settings_initial_window_size: 4,
|
67
69
|
settings_max_frame_size: 5,
|
68
70
|
settings_max_header_list_size: 6,
|
69
|
-
}
|
71
|
+
}.freeze
|
70
72
|
|
71
73
|
# Default error types as defined by the spec
|
72
74
|
DEFINED_ERRORS = {
|
@@ -83,20 +85,20 @@ module HTTP2
|
|
83
85
|
connect_error: 10,
|
84
86
|
enhance_your_calm: 11,
|
85
87
|
inadequate_security: 12,
|
86
|
-
|
88
|
+
http_1_1_required: 13,
|
89
|
+
}.freeze
|
87
90
|
|
88
91
|
RBIT = 0x7fffffff
|
89
92
|
RBYTE = 0x0fffffff
|
90
93
|
EBIT = 0x80000000
|
91
|
-
UINT32 =
|
92
|
-
UINT16 =
|
93
|
-
UINT8 =
|
94
|
+
UINT32 = 'N'.freeze
|
95
|
+
UINT16 = 'n'.freeze
|
96
|
+
UINT8 = 'C'.freeze
|
94
97
|
HEADERPACK = (UINT8 + UINT16 + UINT8 + UINT8 + UINT32).freeze
|
95
98
|
FRAME_LENGTH_HISHIFT = 16
|
96
99
|
FRAME_LENGTH_LOMASK = 0xFFFF
|
97
|
-
BINARY = 'binary'.freeze
|
98
100
|
|
99
|
-
private_constant :RBIT, :RBYTE, :EBIT, :HEADERPACK, :UINT32, :UINT16, :UINT8
|
101
|
+
private_constant :RBIT, :RBYTE, :EBIT, :HEADERPACK, :UINT32, :UINT16, :UINT8
|
100
102
|
|
101
103
|
# Initializes new framer object.
|
102
104
|
#
|
@@ -105,31 +107,31 @@ module HTTP2
|
|
105
107
|
end
|
106
108
|
|
107
109
|
# Generates common 9-byte frame header.
|
108
|
-
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-
|
110
|
+
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-4.1
|
109
111
|
#
|
110
112
|
# @param frame [Hash]
|
111
113
|
# @return [String]
|
112
|
-
def
|
114
|
+
def common_header(frame)
|
113
115
|
header = []
|
114
116
|
|
115
|
-
|
116
|
-
|
117
|
+
unless FRAME_TYPES[frame[:type]]
|
118
|
+
fail CompressionError, "Invalid frame type (#{frame[:type]})"
|
117
119
|
end
|
118
120
|
|
119
121
|
if frame[:length] > @max_frame_size
|
120
|
-
|
122
|
+
fail CompressionError, "Frame size is too large: #{frame[:length]}"
|
121
123
|
end
|
122
124
|
|
123
125
|
if frame[:length] < 0
|
124
|
-
|
126
|
+
fail CompressionError, "Frame size is invalid: #{frame[:length]}"
|
125
127
|
end
|
126
128
|
|
127
129
|
if frame[:stream] > MAX_STREAM_ID
|
128
|
-
|
130
|
+
fail CompressionError, "Stream ID (#{frame[:stream]}) is too large"
|
129
131
|
end
|
130
132
|
|
131
133
|
if frame[:type] == :window_update && frame[:increment] > MAX_WINDOWINC
|
132
|
-
|
134
|
+
fail CompressionError, "Window increment (#{frame[:increment]}) is too large"
|
133
135
|
end
|
134
136
|
|
135
137
|
header << (frame[:length] >> FRAME_LENGTH_HISHIFT)
|
@@ -137,12 +139,11 @@ module HTTP2
|
|
137
139
|
header << FRAME_TYPES[frame[:type]]
|
138
140
|
header << frame[:flags].reduce(0) do |acc, f|
|
139
141
|
position = FRAME_FLAGS[frame[:type]][f]
|
140
|
-
|
141
|
-
|
142
|
+
unless position
|
143
|
+
fail CompressionError, "Invalid frame flag (#{f}) for #{frame[:type]}"
|
142
144
|
end
|
143
145
|
|
144
|
-
acc
|
145
|
-
acc
|
146
|
+
acc | (1 << position)
|
146
147
|
end
|
147
148
|
|
148
149
|
header << frame[:stream]
|
@@ -152,16 +153,15 @@ module HTTP2
|
|
152
153
|
# Decodes common 9-byte header.
|
153
154
|
#
|
154
155
|
# @param buf [Buffer]
|
155
|
-
def
|
156
|
+
def read_common_header(buf)
|
156
157
|
frame = {}
|
157
|
-
len_hi, len_lo, type, flags, stream = buf.slice(0,9).unpack(HEADERPACK)
|
158
|
+
len_hi, len_lo, type, flags, stream = buf.slice(0, 9).unpack(HEADERPACK)
|
158
159
|
|
159
160
|
frame[:length] = (len_hi << FRAME_LENGTH_HISHIFT) | len_lo
|
160
|
-
frame[:type], _ = FRAME_TYPES.
|
161
|
+
frame[:type], _ = FRAME_TYPES.find { |_t, pos| type == pos }
|
161
162
|
if frame[:type]
|
162
|
-
frame[:flags] = FRAME_FLAGS[frame[:type]].
|
163
|
+
frame[:flags] = FRAME_FLAGS[frame[:type]].each_with_object([]) do |(name, pos), acc|
|
163
164
|
acc << name if (flags & (1 << pos)) > 0
|
164
|
-
acc
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
@@ -177,111 +177,106 @@ module HTTP2
|
|
177
177
|
bytes = Buffer.new
|
178
178
|
length = 0
|
179
179
|
|
180
|
-
frame[:flags]
|
180
|
+
frame[:flags] ||= []
|
181
181
|
frame[:stream] ||= 0
|
182
182
|
|
183
183
|
case frame[:type]
|
184
184
|
when :data
|
185
|
-
bytes
|
185
|
+
bytes << frame[:payload]
|
186
186
|
length += frame[:payload].bytesize
|
187
187
|
|
188
188
|
when :headers
|
189
189
|
if frame[:weight] || frame[:stream_dependency] || !frame[:exclusive].nil?
|
190
190
|
unless frame[:weight] && frame[:stream_dependency] && !frame[:exclusive].nil?
|
191
|
-
|
191
|
+
fail CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
|
192
192
|
end
|
193
|
-
frame[:flags] += [:priority]
|
193
|
+
frame[:flags] += [:priority] unless frame[:flags].include? :priority
|
194
194
|
end
|
195
195
|
|
196
196
|
if frame[:flags].include? :priority
|
197
|
-
bytes << [(frame[:exclusive] ? EBIT : 0) |
|
198
|
-
(frame[:stream_dependency] & RBIT)].pack(UINT32)
|
197
|
+
bytes << [(frame[:exclusive] ? EBIT : 0) | (frame[:stream_dependency] & RBIT)].pack(UINT32)
|
199
198
|
bytes << [frame[:weight] - 1].pack(UINT8)
|
200
199
|
length += 5
|
201
200
|
end
|
202
201
|
|
203
|
-
bytes
|
202
|
+
bytes << frame[:payload]
|
204
203
|
length += frame[:payload].bytesize
|
205
204
|
|
206
205
|
when :priority
|
207
206
|
unless frame[:weight] && frame[:stream_dependency] && !frame[:exclusive].nil?
|
208
|
-
|
207
|
+
fail CompressionError, "Must specify all of priority parameters for #{frame[:type]}"
|
209
208
|
end
|
210
|
-
bytes << [(frame[:exclusive] ? EBIT : 0) |
|
211
|
-
(frame[:stream_dependency] & RBIT)].pack(UINT32)
|
209
|
+
bytes << [(frame[:exclusive] ? EBIT : 0) | (frame[:stream_dependency] & RBIT)].pack(UINT32)
|
212
210
|
bytes << [frame[:weight] - 1].pack(UINT8)
|
213
211
|
length += 5
|
214
212
|
|
215
213
|
when :rst_stream
|
216
|
-
bytes
|
214
|
+
bytes << pack_error(frame[:error])
|
217
215
|
length += 4
|
218
216
|
|
219
217
|
when :settings
|
220
218
|
if frame[:stream] != 0
|
221
|
-
|
219
|
+
fail CompressionError, "Invalid stream ID (#{frame[:stream]})"
|
222
220
|
end
|
223
221
|
|
224
|
-
frame[:payload].each do |(k,v)|
|
222
|
+
frame[:payload].each do |(k, v)|
|
225
223
|
if k.is_a? Integer
|
226
|
-
DEFINED_SETTINGS.
|
224
|
+
DEFINED_SETTINGS.value?(k) || next
|
227
225
|
else
|
228
226
|
k = DEFINED_SETTINGS[k]
|
229
227
|
|
230
|
-
if k.nil?
|
231
|
-
raise CompressionError.new("Unknown settings ID for #{k}")
|
232
|
-
end
|
228
|
+
fail CompressionError, "Unknown settings ID for #{k}" if k.nil?
|
233
229
|
end
|
234
230
|
|
235
|
-
bytes
|
236
|
-
bytes
|
231
|
+
bytes << [k].pack(UINT16)
|
232
|
+
bytes << [v].pack(UINT32)
|
237
233
|
length += 6
|
238
234
|
end
|
239
235
|
|
240
236
|
when :push_promise
|
241
|
-
bytes
|
242
|
-
bytes
|
237
|
+
bytes << [frame[:promise_stream] & RBIT].pack(UINT32)
|
238
|
+
bytes << frame[:payload]
|
243
239
|
length += 4 + frame[:payload].bytesize
|
244
240
|
|
245
241
|
when :ping
|
246
242
|
if frame[:payload].bytesize != 8
|
247
|
-
|
248
|
-
(#{frame[:payload].size} != 8 bytes)")
|
243
|
+
fail CompressionError, "Invalid payload size (#{frame[:payload].size} != 8 bytes)"
|
249
244
|
end
|
250
|
-
bytes
|
245
|
+
bytes << frame[:payload]
|
251
246
|
length += 8
|
252
247
|
|
253
248
|
when :goaway
|
254
|
-
bytes
|
255
|
-
bytes
|
249
|
+
bytes << [frame[:last_stream] & RBIT].pack(UINT32)
|
250
|
+
bytes << pack_error(frame[:error])
|
256
251
|
length += 8
|
257
252
|
|
258
253
|
if frame[:payload]
|
259
|
-
bytes
|
254
|
+
bytes << frame[:payload]
|
260
255
|
length += frame[:payload].bytesize
|
261
256
|
end
|
262
257
|
|
263
258
|
when :window_update
|
264
|
-
bytes
|
259
|
+
bytes << [frame[:increment] & RBIT].pack(UINT32)
|
265
260
|
length += 4
|
266
261
|
|
267
262
|
when :continuation
|
268
|
-
bytes
|
263
|
+
bytes << frame[:payload]
|
269
264
|
length += frame[:payload].bytesize
|
270
265
|
|
271
266
|
when :altsvc
|
272
267
|
bytes << [frame[:max_age], frame[:port]].pack(UINT32 + UINT16)
|
273
268
|
length += 6
|
274
269
|
if frame[:proto]
|
275
|
-
frame[:proto].bytesize > 255
|
276
|
-
bytes << [frame[:proto].bytesize].pack(UINT8) << frame[:proto].force_encoding(BINARY)
|
270
|
+
fail CompressionError, 'Proto too long' if frame[:proto].bytesize > 255
|
271
|
+
bytes << [frame[:proto].bytesize].pack(UINT8) << frame[:proto].force_encoding(Encoding::BINARY)
|
277
272
|
length += 1 + frame[:proto].bytesize
|
278
273
|
else
|
279
274
|
bytes << [0].pack(UINT8)
|
280
275
|
length += 1
|
281
276
|
end
|
282
277
|
if frame[:host]
|
283
|
-
frame[:host].bytesize > 255
|
284
|
-
bytes << [frame[:host].bytesize].pack(UINT8) << frame[:host].force_encoding(BINARY)
|
278
|
+
fail CompressionError, 'Host too long' if frame[:host].bytesize > 255
|
279
|
+
bytes << [frame[:host].bytesize].pack(UINT8) << frame[:host].force_encoding(Encoding::BINARY)
|
285
280
|
length += 1 + frame[:host].bytesize
|
286
281
|
else
|
287
282
|
bytes << [0].pack(UINT8)
|
@@ -295,16 +290,16 @@ module HTTP2
|
|
295
290
|
|
296
291
|
# Process padding.
|
297
292
|
# frame[:padding] gives number of extra octets to be added.
|
298
|
-
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-
|
293
|
+
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.1
|
299
294
|
if frame[:padding]
|
300
295
|
unless FRAME_TYPES_WITH_PADDING.include?(frame[:type])
|
301
|
-
|
296
|
+
fail CompressionError, "Invalid padding flag for #{frame[:type]}"
|
302
297
|
end
|
303
298
|
|
304
299
|
padlen = frame[:padding]
|
305
300
|
|
306
301
|
if padlen <= 0 || padlen > 256 || padlen + length > @max_frame_size
|
307
|
-
|
302
|
+
fail CompressionError, "Invalid padding #{padlen}"
|
308
303
|
end
|
309
304
|
|
310
305
|
length += padlen
|
@@ -318,7 +313,7 @@ module HTTP2
|
|
318
313
|
end
|
319
314
|
|
320
315
|
frame[:length] = length
|
321
|
-
bytes.prepend(
|
316
|
+
bytes.prepend(common_header(frame))
|
322
317
|
end
|
323
318
|
|
324
319
|
# Decodes complete HTTP/2 frame from provided buffer. If the buffer
|
@@ -327,7 +322,7 @@ module HTTP2
|
|
327
322
|
# @param buf [Buffer]
|
328
323
|
def parse(buf)
|
329
324
|
return nil if buf.size < 9
|
330
|
-
frame =
|
325
|
+
frame = read_common_header(buf)
|
331
326
|
return nil if buf.size < 9 + frame[:length]
|
332
327
|
|
333
328
|
buf.read(9)
|
@@ -335,7 +330,7 @@ module HTTP2
|
|
335
330
|
|
336
331
|
# Implementations MUST discard frames
|
337
332
|
# that have unknown or unsupported types.
|
338
|
-
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-
|
333
|
+
# - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.5
|
339
334
|
return nil if frame[:type].nil?
|
340
335
|
|
341
336
|
# Process padding
|
@@ -345,8 +340,8 @@ module HTTP2
|
|
345
340
|
if padded
|
346
341
|
padlen = payload.read(1).unpack(UINT8).first
|
347
342
|
frame[:padding] = padlen + 1
|
348
|
-
padlen > payload.bytesize
|
349
|
-
|
343
|
+
fail ProtocolError, 'padding too long' if padlen > payload.bytesize
|
344
|
+
payload.slice!(-padlen, padlen) if padlen > 0
|
350
345
|
frame[:length] -= frame[:padding]
|
351
346
|
frame[:flags].delete(:padded)
|
352
347
|
end
|
@@ -376,11 +371,11 @@ module HTTP2
|
|
376
371
|
# because unknown extensions are ignored.
|
377
372
|
frame[:payload] = []
|
378
373
|
unless frame[:length] % 6 == 0
|
379
|
-
|
374
|
+
fail ProtocolError, 'Invalid settings payload length'
|
380
375
|
end
|
381
376
|
|
382
377
|
if frame[:stream] != 0
|
383
|
-
|
378
|
+
fail ProtocolError, "Invalid stream ID (#{frame[:stream]})"
|
384
379
|
end
|
385
380
|
|
386
381
|
(frame[:length] / 6).times do
|
@@ -389,7 +384,7 @@ module HTTP2
|
|
389
384
|
|
390
385
|
# Unsupported or unrecognized settings MUST be ignored.
|
391
386
|
# Here we send it along.
|
392
|
-
name, _ = DEFINED_SETTINGS.
|
387
|
+
name, _ = DEFINED_SETTINGS.find { |_name, v| v == id }
|
393
388
|
frame[:payload] << [name, val] if name
|
394
389
|
end
|
395
390
|
when :push_promise
|
@@ -411,16 +406,13 @@ module HTTP2
|
|
411
406
|
frame[:max_age], frame[:port] = payload.read(6).unpack(UINT32 + UINT16)
|
412
407
|
|
413
408
|
len = payload.getbyte
|
414
|
-
|
409
|
+
frame[:proto] = payload.read(len) if len > 0
|
415
410
|
|
416
411
|
len = payload.getbyte
|
417
|
-
|
412
|
+
frame[:host] = payload.read(len) if len > 0
|
418
413
|
|
419
|
-
if payload.size > 0
|
420
|
-
|
421
|
-
end
|
422
|
-
else
|
423
|
-
# Unknown frame type is explicitly allowed
|
414
|
+
frame[:origin] = payload.read(payload.size) if payload.size > 0
|
415
|
+
# else # Unknown frame type is explicitly allowed
|
424
416
|
end
|
425
417
|
|
426
418
|
frame
|
@@ -429,9 +421,9 @@ module HTTP2
|
|
429
421
|
private
|
430
422
|
|
431
423
|
def pack_error(e)
|
432
|
-
|
424
|
+
unless e.is_a? Integer
|
433
425
|
if DEFINED_ERRORS[e].nil?
|
434
|
-
|
426
|
+
fail CompressionError, "Unknown error ID for #{e}"
|
435
427
|
end
|
436
428
|
|
437
429
|
e = DEFINED_ERRORS[e]
|
@@ -441,9 +433,8 @@ module HTTP2
|
|
441
433
|
end
|
442
434
|
|
443
435
|
def unpack_error(e)
|
444
|
-
name, _ = DEFINED_ERRORS.
|
436
|
+
name, _ = DEFINED_ERRORS.find { |_name, v| v == e }
|
445
437
|
name || error
|
446
438
|
end
|
447
|
-
|
448
439
|
end
|
449
440
|
end
|