http-2 0.7.0 → 0.8.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/.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
|