http-2-next 0.2.5 → 0.4.2
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 +1 -1
- data/lib/http/2/next.rb +1 -4
- data/lib/http/2/next/connection.rb +48 -30
- data/lib/http/2/next/emitter.rb +3 -4
- data/lib/http/2/next/error.rb +1 -0
- data/lib/http/2/next/extensions.rb +26 -1
- data/lib/http/2/next/flow_buffer.rb +7 -3
- data/lib/http/2/next/framer.rb +26 -17
- data/lib/http/2/next/header.rb +35 -0
- data/lib/http/2/next/header/compressor.rb +137 -0
- data/lib/http/2/next/header/decompressor.rb +144 -0
- data/lib/http/2/next/{compressor.rb → header/encoding_context.rb} +7 -298
- data/lib/http/2/next/{huffman.rb → header/huffman.rb} +5 -2
- data/lib/http/2/next/{huffman_statemachine.rb → header/huffman_statemachine.rb} +0 -0
- data/lib/http/2/next/server.rb +8 -5
- data/lib/http/2/next/stream.rb +12 -8
- data/lib/http/2/next/version.rb +1 -1
- data/lib/tasks/generate_huffman_table.rb +4 -4
- data/sig/client.rbs +9 -0
- data/sig/connection.rbs +73 -0
- data/sig/emitter.rbs +13 -0
- data/sig/flow_buffer.rbs +23 -0
- data/sig/frame_buffer.rbs +13 -0
- data/sig/framer.rbs +25 -0
- data/sig/header.rbs +15 -0
- data/sig/header/compressor.rbs +23 -0
- data/sig/header/decompressor.rbs +22 -0
- data/sig/header/encoding_context.rbs +34 -0
- data/sig/header/huffman.rbs +9 -0
- data/sig/next.rbs +95 -0
- data/sig/server.rbs +12 -0
- data/sig/stream.rbs +77 -0
- metadata +26 -10
- data/lib/http/2/next/buffer.rb +0 -80
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d8116cb645b3a24de8f06bd6e1d6e14ba75c57e28f6a4daf9e999bab456ac5f
|
4
|
+
data.tar.gz: 9f97d8e2748411a121e1ca5e7b1de77298371638579829a5d2a5881d353c8ff3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61248cc2f85d2b60d0edf3a8a4b0643836a44c66a7ded2382c86010a08da519290dba36973599ed65fea11a5727e3b8a6576c5a82782c38188e5f83adf098c82
|
7
|
+
data.tar.gz: 8a61192c8c2f8c1dfbf830254eab786ebb0e59304da1e23f791911201cf08e8c93f1546831f06159e334888a05e72a0c42d3a003a998be357c05ee9f3f00e74a
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[](http://rubygems.org/gems/http-2-next)
|
4
4
|
[](https://gitlab.com/honeyryderchuck/http-2-next/commits/master)
|
5
|
-
[](https://honeyryderchuck.gitlab.io/http-2-next/coverage/#_AllFiles)
|
5
|
+
[](https://honeyryderchuck.gitlab.io/http-2-next/coverage/#_AllFiles)
|
6
6
|
|
7
7
|
**Attention!** This is a fork of the [http-2](https://github.com/igrigorik/http-2) gem.
|
8
8
|
|
data/lib/http/2/next.rb
CHANGED
@@ -4,11 +4,8 @@ require "http/2/next/version"
|
|
4
4
|
require "http/2/next/extensions"
|
5
5
|
require "http/2/next/error"
|
6
6
|
require "http/2/next/emitter"
|
7
|
-
require "http/2/next/buffer"
|
8
7
|
require "http/2/next/flow_buffer"
|
9
|
-
require "http/2/next/
|
10
|
-
require "http/2/next/huffman_statemachine"
|
11
|
-
require "http/2/next/compressor"
|
8
|
+
require "http/2/next/header"
|
12
9
|
require "http/2/next/framer"
|
13
10
|
require "http/2/next/connection"
|
14
11
|
require "http/2/next/client"
|
@@ -51,18 +51,19 @@ module HTTP2Next
|
|
51
51
|
include Emitter
|
52
52
|
include Error
|
53
53
|
|
54
|
+
using StringExtensions
|
55
|
+
|
54
56
|
# Connection state (:new, :closed).
|
55
57
|
attr_reader :state
|
56
58
|
|
57
59
|
# Size of current connection flow control window (by default, set to
|
58
60
|
# infinity, but is automatically updated on receipt of peer settings).
|
59
61
|
attr_reader :local_window
|
60
|
-
attr_reader :remote_window
|
62
|
+
attr_reader :remote_window, :remote_settings
|
61
63
|
alias window local_window
|
62
64
|
|
63
65
|
# Current settings value for local and peer
|
64
66
|
attr_reader :local_settings
|
65
|
-
attr_reader :remote_settings
|
66
67
|
|
67
68
|
# Pending settings value
|
68
69
|
# Sent but not ack'ed settings
|
@@ -72,6 +73,9 @@ module HTTP2Next
|
|
72
73
|
# are not counted towards the stream limit).
|
73
74
|
attr_reader :active_stream_count
|
74
75
|
|
76
|
+
# Max number of streams that can be in-transit in this connection.
|
77
|
+
attr_writer :max_streams
|
78
|
+
|
75
79
|
# Initializes new connection object.
|
76
80
|
#
|
77
81
|
def initialize(settings = {})
|
@@ -82,6 +86,7 @@ module HTTP2Next
|
|
82
86
|
@decompressor = Header::Decompressor.new(settings)
|
83
87
|
|
84
88
|
@active_stream_count = 0
|
89
|
+
@max_streams = nil
|
85
90
|
@last_activated_stream = 0
|
86
91
|
@last_stream_id = 0
|
87
92
|
@streams = {}
|
@@ -95,12 +100,13 @@ module HTTP2Next
|
|
95
100
|
@remote_window_limit = @remote_settings[:settings_initial_window_size]
|
96
101
|
@remote_window = @remote_window_limit
|
97
102
|
|
98
|
-
@recv_buffer =
|
103
|
+
@recv_buffer = "".b
|
99
104
|
@continuation = []
|
100
105
|
@error = nil
|
101
106
|
|
102
107
|
@h2c_upgrade = nil
|
103
108
|
@closed_since = nil
|
109
|
+
@received_frame = false
|
104
110
|
end
|
105
111
|
|
106
112
|
def closed?
|
@@ -114,7 +120,7 @@ module HTTP2Next
|
|
114
120
|
# @param parent [Stream]
|
115
121
|
def new_stream(**args)
|
116
122
|
raise ConnectionClosed if @state == :closed
|
117
|
-
raise StreamLimitExceeded if @active_stream_count >= @remote_settings[:settings_max_concurrent_streams]
|
123
|
+
raise StreamLimitExceeded if @active_stream_count >= (@max_streams || @remote_settings[:settings_max_concurrent_streams])
|
118
124
|
|
119
125
|
connection_error(:protocol_error, msg: "id is smaller than previous") if @stream_id < @last_activated_stream
|
120
126
|
|
@@ -155,7 +161,7 @@ module HTTP2Next
|
|
155
161
|
send(type: :goaway, last_stream: last_stream,
|
156
162
|
error: error, payload: payload)
|
157
163
|
@state = :closed
|
158
|
-
@closed_since =
|
164
|
+
@closed_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
159
165
|
end
|
160
166
|
|
161
167
|
# Sends a WINDOW_UPDATE frame to the peer.
|
@@ -172,7 +178,7 @@ module HTTP2Next
|
|
172
178
|
# @param settings [Array or Hash]
|
173
179
|
def settings(payload)
|
174
180
|
payload = payload.to_a
|
175
|
-
|
181
|
+
validate_settings(@local_role, payload)
|
176
182
|
@pending_settings << payload
|
177
183
|
send(type: :settings, stream: 0, payload: payload)
|
178
184
|
@pending_settings << payload
|
@@ -209,6 +215,11 @@ module HTTP2Next
|
|
209
215
|
end
|
210
216
|
|
211
217
|
while (frame = @framer.parse(@recv_buffer))
|
218
|
+
if is_a?(Client) && !@received_frame
|
219
|
+
connection_error(:protocol_error, msg: "didn't receive settings") if frame[:type] != :settings
|
220
|
+
@received_frame = true
|
221
|
+
end
|
222
|
+
|
212
223
|
# Implementations MUST discard frames
|
213
224
|
# that have unknown or unsupported types.
|
214
225
|
if frame[:type].nil?
|
@@ -236,7 +247,7 @@ module HTTP2Next
|
|
236
247
|
@continuation.clear
|
237
248
|
|
238
249
|
frame.delete(:length)
|
239
|
-
frame[:payload] =
|
250
|
+
frame[:payload] = payload
|
240
251
|
frame[:flags] << :end_headers
|
241
252
|
end
|
242
253
|
|
@@ -469,7 +480,7 @@ module HTTP2Next
|
|
469
480
|
# the connection, although a new connection can be established
|
470
481
|
# for new streams.
|
471
482
|
@state = :closed
|
472
|
-
@closed_since =
|
483
|
+
@closed_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
473
484
|
emit(:goaway, frame[:last_stream], frame[:error], frame[:payload])
|
474
485
|
when :altsvc
|
475
486
|
# 4. The ALTSVC HTTP/2 Frame
|
@@ -494,7 +505,7 @@ module HTTP2Next
|
|
494
505
|
when :ping
|
495
506
|
ping_management(frame)
|
496
507
|
else
|
497
|
-
connection_error if (
|
508
|
+
connection_error if (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @closed_since) > 15
|
498
509
|
end
|
499
510
|
else
|
500
511
|
connection_error
|
@@ -517,8 +528,6 @@ module HTTP2Next
|
|
517
528
|
def validate_settings(role, settings)
|
518
529
|
settings.each do |key, v|
|
519
530
|
case key
|
520
|
-
when :settings_header_table_size
|
521
|
-
# Any value is valid
|
522
531
|
when :settings_enable_push
|
523
532
|
case role
|
524
533
|
when :server
|
@@ -526,32 +535,41 @@ module HTTP2Next
|
|
526
535
|
# Clients MUST reject any attempt to change the
|
527
536
|
# SETTINGS_ENABLE_PUSH setting to a value other than 0 by treating the
|
528
537
|
# message as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
529
|
-
|
538
|
+
next if v.zero?
|
539
|
+
|
540
|
+
connection_error(:protocol_error, msg: "invalid #{key} value")
|
530
541
|
when :client
|
531
542
|
# Any value other than 0 or 1 MUST be treated as a
|
532
543
|
# connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
533
|
-
|
544
|
+
next if v.zero? || v == 1
|
545
|
+
|
546
|
+
connection_error(:protocol_error, msg: "invalid #{key} value")
|
534
547
|
end
|
535
|
-
when :settings_max_concurrent_streams
|
536
|
-
# Any value is valid
|
537
548
|
when :settings_initial_window_size
|
538
549
|
# Values above the maximum flow control window size of 2^31-1 MUST
|
539
550
|
# be treated as a connection error (Section 5.4.1) of type
|
540
551
|
# FLOW_CONTROL_ERROR.
|
541
|
-
|
552
|
+
next if v <= 0x7fffffff
|
553
|
+
|
554
|
+
connection_error(:flow_control_error, msg: "invalid #{key} value")
|
542
555
|
when :settings_max_frame_size
|
543
556
|
# The initial value is 2^14 (16,384) octets. The value advertised
|
544
557
|
# by an endpoint MUST be between this initial value and the maximum
|
545
558
|
# allowed frame size (2^24-1 or 16,777,215 octets), inclusive.
|
546
559
|
# Values outside this range MUST be treated as a connection error
|
547
560
|
# (Section 5.4.1) of type PROTOCOL_ERROR.
|
548
|
-
|
549
|
-
|
561
|
+
next if v >= 16_384 && v <= 16_777_215
|
562
|
+
|
563
|
+
connection_error(:protocol_error, msg: "invalid #{key} value")
|
564
|
+
# when :settings_max_concurrent_streams
|
565
|
+
# Any value is valid
|
566
|
+
# when :settings_header_table_size
|
567
|
+
# Any value is valid
|
568
|
+
# when :settings_max_header_list_size
|
550
569
|
# Any value is valid
|
551
570
|
# else # ignore unknown settings
|
552
571
|
end
|
553
572
|
end
|
554
|
-
nil
|
555
573
|
end
|
556
574
|
|
557
575
|
# Update connection settings based on parameters set by the peer.
|
@@ -568,8 +586,7 @@ module HTTP2Next
|
|
568
586
|
# Process pending settings we have sent.
|
569
587
|
[@pending_settings.shift, :local]
|
570
588
|
else
|
571
|
-
|
572
|
-
connection_error(check) if check
|
589
|
+
validate_settings(@remote_role, frame[:payload])
|
573
590
|
[frame[:payload], :remote]
|
574
591
|
end
|
575
592
|
|
@@ -656,7 +673,7 @@ module HTTP2Next
|
|
656
673
|
#
|
657
674
|
# @param frame [Hash]
|
658
675
|
def decode_headers(frame)
|
659
|
-
frame[:payload] = @decompressor.decode(frame[:payload], frame) if frame[:payload].is_a?
|
676
|
+
frame[:payload] = @decompressor.decode(frame[:payload], frame) if frame[:payload].is_a?(String)
|
660
677
|
rescue CompressionError => e
|
661
678
|
connection_error(:compression_error, e: e)
|
662
679
|
rescue ProtocolError => e
|
@@ -671,15 +688,16 @@ module HTTP2Next
|
|
671
688
|
# @return [Array of Frame]
|
672
689
|
def encode_headers(frame)
|
673
690
|
payload = frame[:payload]
|
674
|
-
payload = @compressor.encode(payload) unless payload.is_a?
|
691
|
+
payload = @compressor.encode(payload) unless payload.is_a?(String)
|
675
692
|
|
676
693
|
frames = []
|
677
694
|
|
678
|
-
while payload.bytesize > 0
|
695
|
+
while payload && payload.bytesize > 0
|
679
696
|
cont = frame.dup
|
680
697
|
cont[:type] = :continuation
|
681
698
|
cont[:flags] = []
|
682
|
-
cont[:payload] = payload.
|
699
|
+
cont[:payload] = payload.byteslice(0, @remote_settings[:settings_max_frame_size])
|
700
|
+
payload = payload.byteslice(@remote_settings[:settings_max_frame_size]..-1)
|
683
701
|
frames << cont
|
684
702
|
end
|
685
703
|
if frames.empty?
|
@@ -703,10 +721,10 @@ module HTTP2Next
|
|
703
721
|
# @param priority [Integer]
|
704
722
|
# @param window [Integer]
|
705
723
|
# @param parent [Stream]
|
706
|
-
def activate_stream(id
|
724
|
+
def activate_stream(id:, **args)
|
707
725
|
connection_error(msg: "Stream ID already exists") if @streams.key?(id)
|
708
726
|
|
709
|
-
raise StreamLimitExceeded if @active_stream_count >= @local_settings[:settings_max_concurrent_streams]
|
727
|
+
raise StreamLimitExceeded if @active_stream_count >= (@max_streams || @local_settings[:settings_max_concurrent_streams])
|
710
728
|
|
711
729
|
stream = Stream.new(connection: self, id: id, **args)
|
712
730
|
|
@@ -720,11 +738,11 @@ module HTTP2Next
|
|
720
738
|
# References to such streams will be purged whenever another stream
|
721
739
|
# is closed, with a minimum of 15s RTT time window.
|
722
740
|
@streams_recently_closed.reject! do |stream_id, v|
|
723
|
-
to_delete = (
|
741
|
+
to_delete = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - v) > 15
|
724
742
|
@streams.delete stream_id if to_delete
|
725
743
|
to_delete
|
726
744
|
end
|
727
|
-
@streams_recently_closed[id] =
|
745
|
+
@streams_recently_closed[id] = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
728
746
|
end
|
729
747
|
|
730
748
|
stream.on(:promise, &method(:promise)) if is_a? Server
|
@@ -742,7 +760,7 @@ module HTTP2Next
|
|
742
760
|
|
743
761
|
def verify_pseudo_headers(frame, mandatory_headers)
|
744
762
|
headers = frame[:payload]
|
745
|
-
return if headers.is_a?(
|
763
|
+
return if headers.is_a?(String)
|
746
764
|
|
747
765
|
pseudo_headers = headers.take_while do |field, value|
|
748
766
|
# use this loop to validate pseudo-headers
|
data/lib/http/2/next/emitter.rb
CHANGED
@@ -9,19 +9,18 @@ module HTTP2Next
|
|
9
9
|
#
|
10
10
|
# @param event [Symbol]
|
11
11
|
# @param block [Proc] callback function
|
12
|
-
def
|
12
|
+
def on(event, &block)
|
13
13
|
raise ArgumentError, "must provide callback" unless block_given?
|
14
14
|
|
15
15
|
listeners(event.to_sym).push block
|
16
16
|
end
|
17
|
-
alias on add_listener
|
18
17
|
|
19
18
|
# Subscribe to next event (at most once) for specified type.
|
20
19
|
#
|
21
20
|
# @param event [Symbol]
|
22
21
|
# @param block [Proc] callback function
|
23
22
|
def once(event, &block)
|
24
|
-
|
23
|
+
on(event) do |*args, &callback|
|
25
24
|
block.call(*args, &callback)
|
26
25
|
:delete
|
27
26
|
end
|
@@ -34,7 +33,7 @@ module HTTP2Next
|
|
34
33
|
# @param block [Proc] callback function
|
35
34
|
def emit(event, *args, &block)
|
36
35
|
listeners(event).delete_if do |cb|
|
37
|
-
cb.call(*args, &block)
|
36
|
+
:delete == cb.call(*args, &block) # rubocop:disable Style/YodaCondition
|
38
37
|
end
|
39
38
|
end
|
40
39
|
|
data/lib/http/2/next/error.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module HTTP2Next
|
4
|
-
module
|
4
|
+
module RegexpExtensions
|
5
5
|
unless Regexp.method_defined?(:match?)
|
6
6
|
refine Regexp do
|
7
7
|
def match?(*args)
|
@@ -10,4 +10,29 @@ module HTTP2Next
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
+
|
14
|
+
module StringExtensions
|
15
|
+
refine String do
|
16
|
+
def read(n)
|
17
|
+
chunk = byteslice(0..n - 1)
|
18
|
+
remaining = byteslice(n..-1)
|
19
|
+
remaining ? replace(remaining) : clear
|
20
|
+
chunk
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_uint32
|
24
|
+
read(4).unpack1("N")
|
25
|
+
end
|
26
|
+
|
27
|
+
def shift_byte
|
28
|
+
read(1).ord
|
29
|
+
end
|
30
|
+
|
31
|
+
unless String.method_defined?(:unpack1)
|
32
|
+
def unpack1(format)
|
33
|
+
unpack(format).first
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
13
38
|
end
|
@@ -73,6 +73,7 @@ module HTTP2Next
|
|
73
73
|
|
74
74
|
while (frame = send_buffer.retrieve(@remote_window))
|
75
75
|
|
76
|
+
# puts "#{self.class} -> #{@remote_window}"
|
76
77
|
sent = frame[:payload].bytesize
|
77
78
|
|
78
79
|
manage_state(frame) do
|
@@ -137,10 +138,13 @@ module HTTP2Next
|
|
137
138
|
|
138
139
|
# Split frame so that it fits in the window
|
139
140
|
# TODO: consider padding!
|
140
|
-
|
141
|
-
|
142
|
-
|
141
|
+
frame_bytes = payload.byteslice(0, window_size)
|
142
|
+
payload = payload.byteslice(window_size..-1)
|
143
|
+
|
144
|
+
frame[:payload] = frame_bytes
|
145
|
+
frame[:length] = frame_bytes.bytesize
|
143
146
|
chunk[:payload] = payload
|
147
|
+
chunk[:length] = payload.bytesize
|
144
148
|
|
145
149
|
# if no longer last frame in sequence...
|
146
150
|
frame[:flags] -= [:end_stream] if end_stream
|
data/lib/http/2/next/framer.rb
CHANGED
@@ -4,6 +4,8 @@ module HTTP2Next
|
|
4
4
|
# Performs encoding, decoding, and validation of binary HTTP/2 frames.
|
5
5
|
#
|
6
6
|
class Framer
|
7
|
+
using StringExtensions
|
8
|
+
|
7
9
|
include Error
|
8
10
|
|
9
11
|
# Default value of max frame size (16384 bytes)
|
@@ -154,9 +156,10 @@ module HTTP2Next
|
|
154
156
|
# Decodes common 9-byte header.
|
155
157
|
#
|
156
158
|
# @param buf [Buffer]
|
159
|
+
# @return [Hash] the corresponding frame
|
157
160
|
def read_common_header(buf)
|
158
161
|
frame = {}
|
159
|
-
len_hi, len_lo, type, flags, stream = buf.
|
162
|
+
len_hi, len_lo, type, flags, stream = buf.byteslice(0, 9).unpack(HEADERPACK)
|
160
163
|
|
161
164
|
frame[:length] = (len_hi << FRAME_LENGTH_HISHIFT) | len_lo
|
162
165
|
frame[:type], = FRAME_TYPES.find { |_t, pos| type == pos }
|
@@ -175,7 +178,7 @@ module HTTP2Next
|
|
175
178
|
#
|
176
179
|
# @param frame [Hash]
|
177
180
|
def generate(frame)
|
178
|
-
bytes =
|
181
|
+
bytes = "".b
|
179
182
|
length = 0
|
180
183
|
|
181
184
|
frame[:flags] ||= []
|
@@ -184,6 +187,7 @@ module HTTP2Next
|
|
184
187
|
case frame[:type]
|
185
188
|
when :data
|
186
189
|
bytes << frame[:payload]
|
190
|
+
bytes.force_encoding(Encoding::BINARY)
|
187
191
|
length += frame[:payload].bytesize
|
188
192
|
|
189
193
|
when :headers
|
@@ -221,7 +225,7 @@ module HTTP2Next
|
|
221
225
|
raise CompressionError, "Invalid stream ID (#{frame[:stream]})" if (frame[:stream]).nonzero?
|
222
226
|
|
223
227
|
frame[:payload].each do |(k, v)|
|
224
|
-
if k.is_a? Integer
|
228
|
+
if k.is_a? Integer # rubocop:disable Style/GuardClause
|
225
229
|
DEFINED_SETTINGS.value?(k) || next
|
226
230
|
else
|
227
231
|
k = DEFINED_SETTINGS[k]
|
@@ -333,10 +337,10 @@ module HTTP2Next
|
|
333
337
|
#
|
334
338
|
# @param buf [Buffer]
|
335
339
|
def parse(buf)
|
336
|
-
return
|
340
|
+
return if buf.size < 9
|
337
341
|
|
338
342
|
frame = read_common_header(buf)
|
339
|
-
return
|
343
|
+
return if buf.size < 9 + frame[:length]
|
340
344
|
|
341
345
|
raise ProtocolError, "payload too large" if frame[:length] > @local_max_frame_size
|
342
346
|
|
@@ -353,11 +357,11 @@ module HTTP2Next
|
|
353
357
|
if FRAME_TYPES_WITH_PADDING.include?(frame[:type])
|
354
358
|
padded = frame[:flags].include?(:padded)
|
355
359
|
if padded
|
356
|
-
padlen = payload.read(1).
|
360
|
+
padlen = payload.read(1).unpack1(UINT8)
|
357
361
|
frame[:padding] = padlen + 1
|
358
362
|
raise ProtocolError, "padding too long" if padlen > payload.bytesize
|
359
363
|
|
360
|
-
payload.
|
364
|
+
payload = payload.byteslice(0, payload.bytesize - padlen) if padlen > 0
|
361
365
|
frame[:length] -= frame[:padding]
|
362
366
|
frame[:flags].delete(:padded)
|
363
367
|
end
|
@@ -371,7 +375,9 @@ module HTTP2Next
|
|
371
375
|
e_sd = payload.read_uint32
|
372
376
|
frame[:dependency] = e_sd & RBIT
|
373
377
|
frame[:exclusive] = (e_sd & EBIT) != 0
|
374
|
-
|
378
|
+
weight = payload.byteslice(0, 1).ord + 1
|
379
|
+
frame[:weight] = weight
|
380
|
+
payload = payload.byteslice(1..-1)
|
375
381
|
end
|
376
382
|
frame[:payload] = payload.read(frame[:length])
|
377
383
|
when :priority
|
@@ -380,7 +386,9 @@ module HTTP2Next
|
|
380
386
|
e_sd = payload.read_uint32
|
381
387
|
frame[:dependency] = e_sd & RBIT
|
382
388
|
frame[:exclusive] = (e_sd & EBIT) != 0
|
383
|
-
|
389
|
+
weight = payload.byteslice(0, 1).ord + 1
|
390
|
+
frame[:weight] = weight
|
391
|
+
payload = payload.byteslice(1..-1)
|
384
392
|
when :rst_stream
|
385
393
|
raise FrameSizeError, "Invalid length for RST_STREAM (#{frame[:length]} != 4)" if frame[:length] != 4
|
386
394
|
|
@@ -395,7 +403,7 @@ module HTTP2Next
|
|
395
403
|
raise ProtocolError, "Invalid stream ID (#{frame[:stream]})" if (frame[:stream]).nonzero?
|
396
404
|
|
397
405
|
(frame[:length] / 6).times do
|
398
|
-
id = payload.read(2).
|
406
|
+
id = payload.read(2).unpack1(UINT16)
|
399
407
|
val = payload.read_uint32
|
400
408
|
|
401
409
|
# Unsupported or unrecognized settings MUST be ignored.
|
@@ -425,10 +433,12 @@ module HTTP2Next
|
|
425
433
|
when :altsvc
|
426
434
|
frame[:max_age], frame[:port] = payload.read(6).unpack(UINT32 + UINT16)
|
427
435
|
|
428
|
-
len = payload.
|
436
|
+
len = payload.byteslice(0, 1).ord
|
437
|
+
payload = payload.byteslice(1..-1)
|
429
438
|
frame[:proto] = payload.read(len) if len > 0
|
430
439
|
|
431
|
-
len = payload.
|
440
|
+
len = payload.byteslice(0, 1).ord
|
441
|
+
payload = payload.byteslice(1..-1)
|
432
442
|
frame[:host] = payload.read(len) if len > 0
|
433
443
|
|
434
444
|
frame[:origin] = payload.read(payload.size) unless payload.empty?
|
@@ -437,7 +447,7 @@ module HTTP2Next
|
|
437
447
|
origins = []
|
438
448
|
|
439
449
|
until payload.empty?
|
440
|
-
len = payload.read(2).
|
450
|
+
len = payload.read(2).unpack1(UINT16)
|
441
451
|
origins << payload.read(len)
|
442
452
|
end
|
443
453
|
|
@@ -452,17 +462,16 @@ module HTTP2Next
|
|
452
462
|
|
453
463
|
def pack_error(e)
|
454
464
|
unless e.is_a? Integer
|
455
|
-
raise CompressionError, "Unknown error ID for #{e}" if DEFINED_ERRORS[e].nil?
|
456
|
-
|
457
465
|
e = DEFINED_ERRORS[e]
|
466
|
+
|
467
|
+
raise CompressionError, "Unknown error ID for #{e}" unless e
|
458
468
|
end
|
459
469
|
|
460
470
|
[e].pack(UINT32)
|
461
471
|
end
|
462
472
|
|
463
473
|
def unpack_error(error)
|
464
|
-
|
465
|
-
name || error
|
474
|
+
DEFINED_ERRORS.key(error) || error
|
466
475
|
end
|
467
476
|
end
|
468
477
|
end
|