http-2-next 0.2.6 → 0.4.3
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 +42 -28
- 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 +28 -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: aba29aa46e044dc37656a40df1cce81dcdc185fcb166d456592e5e05b5a45295
|
|
4
|
+
data.tar.gz: 95ada3112561c105b5d2a9e9545aab8a29809c49bd5a70d7c64690ce80b47ccc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3e0e50d2c307de9733f7951f9abb1a67c111da2b2740f04b7d204343410258981d28917dd0c22e7b8f6e6be9dec4bfb73f20fa118183a54268d1f4d2db43ce85
|
|
7
|
+
data.tar.gz: 4c5b8b4a840853e6d785b9d7565753e7e011a5db6d0b5b59fe042cd09491c10c429761a929824af83378b318d3eff43e58949ab6967bf57f6d571a89738ba77e
|
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
|
|
@@ -99,12 +100,13 @@ module HTTP2Next
|
|
|
99
100
|
@remote_window_limit = @remote_settings[:settings_initial_window_size]
|
|
100
101
|
@remote_window = @remote_window_limit
|
|
101
102
|
|
|
102
|
-
@recv_buffer =
|
|
103
|
+
@recv_buffer = "".b
|
|
103
104
|
@continuation = []
|
|
104
105
|
@error = nil
|
|
105
106
|
|
|
106
107
|
@h2c_upgrade = nil
|
|
107
108
|
@closed_since = nil
|
|
109
|
+
@received_frame = false
|
|
108
110
|
end
|
|
109
111
|
|
|
110
112
|
def closed?
|
|
@@ -159,7 +161,7 @@ module HTTP2Next
|
|
|
159
161
|
send(type: :goaway, last_stream: last_stream,
|
|
160
162
|
error: error, payload: payload)
|
|
161
163
|
@state = :closed
|
|
162
|
-
@closed_since =
|
|
164
|
+
@closed_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
163
165
|
end
|
|
164
166
|
|
|
165
167
|
# Sends a WINDOW_UPDATE frame to the peer.
|
|
@@ -176,7 +178,7 @@ module HTTP2Next
|
|
|
176
178
|
# @param settings [Array or Hash]
|
|
177
179
|
def settings(payload)
|
|
178
180
|
payload = payload.to_a
|
|
179
|
-
|
|
181
|
+
validate_settings(@local_role, payload)
|
|
180
182
|
@pending_settings << payload
|
|
181
183
|
send(type: :settings, stream: 0, payload: payload)
|
|
182
184
|
@pending_settings << payload
|
|
@@ -213,6 +215,11 @@ module HTTP2Next
|
|
|
213
215
|
end
|
|
214
216
|
|
|
215
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
|
+
|
|
216
223
|
# Implementations MUST discard frames
|
|
217
224
|
# that have unknown or unsupported types.
|
|
218
225
|
if frame[:type].nil?
|
|
@@ -240,7 +247,7 @@ module HTTP2Next
|
|
|
240
247
|
@continuation.clear
|
|
241
248
|
|
|
242
249
|
frame.delete(:length)
|
|
243
|
-
frame[:payload] =
|
|
250
|
+
frame[:payload] = payload
|
|
244
251
|
frame[:flags] << :end_headers
|
|
245
252
|
end
|
|
246
253
|
|
|
@@ -473,7 +480,7 @@ module HTTP2Next
|
|
|
473
480
|
# the connection, although a new connection can be established
|
|
474
481
|
# for new streams.
|
|
475
482
|
@state = :closed
|
|
476
|
-
@closed_since =
|
|
483
|
+
@closed_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
477
484
|
emit(:goaway, frame[:last_stream], frame[:error], frame[:payload])
|
|
478
485
|
when :altsvc
|
|
479
486
|
# 4. The ALTSVC HTTP/2 Frame
|
|
@@ -498,7 +505,7 @@ module HTTP2Next
|
|
|
498
505
|
when :ping
|
|
499
506
|
ping_management(frame)
|
|
500
507
|
else
|
|
501
|
-
connection_error if (
|
|
508
|
+
connection_error if (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @closed_since) > 15
|
|
502
509
|
end
|
|
503
510
|
else
|
|
504
511
|
connection_error
|
|
@@ -521,8 +528,6 @@ module HTTP2Next
|
|
|
521
528
|
def validate_settings(role, settings)
|
|
522
529
|
settings.each do |key, v|
|
|
523
530
|
case key
|
|
524
|
-
when :settings_header_table_size
|
|
525
|
-
# Any value is valid
|
|
526
531
|
when :settings_enable_push
|
|
527
532
|
case role
|
|
528
533
|
when :server
|
|
@@ -530,32 +535,41 @@ module HTTP2Next
|
|
|
530
535
|
# Clients MUST reject any attempt to change the
|
|
531
536
|
# SETTINGS_ENABLE_PUSH setting to a value other than 0 by treating the
|
|
532
537
|
# message as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
|
533
|
-
|
|
538
|
+
next if v.zero?
|
|
539
|
+
|
|
540
|
+
connection_error(:protocol_error, msg: "invalid #{key} value")
|
|
534
541
|
when :client
|
|
535
542
|
# Any value other than 0 or 1 MUST be treated as a
|
|
536
543
|
# connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
|
537
|
-
|
|
544
|
+
next if v.zero? || v == 1
|
|
545
|
+
|
|
546
|
+
connection_error(:protocol_error, msg: "invalid #{key} value")
|
|
538
547
|
end
|
|
539
|
-
when :settings_max_concurrent_streams
|
|
540
|
-
# Any value is valid
|
|
541
548
|
when :settings_initial_window_size
|
|
542
549
|
# Values above the maximum flow control window size of 2^31-1 MUST
|
|
543
550
|
# be treated as a connection error (Section 5.4.1) of type
|
|
544
551
|
# FLOW_CONTROL_ERROR.
|
|
545
|
-
|
|
552
|
+
next if v <= 0x7fffffff
|
|
553
|
+
|
|
554
|
+
connection_error(:flow_control_error, msg: "invalid #{key} value")
|
|
546
555
|
when :settings_max_frame_size
|
|
547
556
|
# The initial value is 2^14 (16,384) octets. The value advertised
|
|
548
557
|
# by an endpoint MUST be between this initial value and the maximum
|
|
549
558
|
# allowed frame size (2^24-1 or 16,777,215 octets), inclusive.
|
|
550
559
|
# Values outside this range MUST be treated as a connection error
|
|
551
560
|
# (Section 5.4.1) of type PROTOCOL_ERROR.
|
|
552
|
-
|
|
553
|
-
|
|
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
|
|
554
569
|
# Any value is valid
|
|
555
570
|
# else # ignore unknown settings
|
|
556
571
|
end
|
|
557
572
|
end
|
|
558
|
-
nil
|
|
559
573
|
end
|
|
560
574
|
|
|
561
575
|
# Update connection settings based on parameters set by the peer.
|
|
@@ -572,8 +586,7 @@ module HTTP2Next
|
|
|
572
586
|
# Process pending settings we have sent.
|
|
573
587
|
[@pending_settings.shift, :local]
|
|
574
588
|
else
|
|
575
|
-
|
|
576
|
-
connection_error(check) if check
|
|
589
|
+
validate_settings(@remote_role, frame[:payload])
|
|
577
590
|
[frame[:payload], :remote]
|
|
578
591
|
end
|
|
579
592
|
|
|
@@ -660,7 +673,7 @@ module HTTP2Next
|
|
|
660
673
|
#
|
|
661
674
|
# @param frame [Hash]
|
|
662
675
|
def decode_headers(frame)
|
|
663
|
-
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)
|
|
664
677
|
rescue CompressionError => e
|
|
665
678
|
connection_error(:compression_error, e: e)
|
|
666
679
|
rescue ProtocolError => e
|
|
@@ -675,15 +688,16 @@ module HTTP2Next
|
|
|
675
688
|
# @return [Array of Frame]
|
|
676
689
|
def encode_headers(frame)
|
|
677
690
|
payload = frame[:payload]
|
|
678
|
-
payload = @compressor.encode(payload) unless payload.is_a?
|
|
691
|
+
payload = @compressor.encode(payload) unless payload.is_a?(String)
|
|
679
692
|
|
|
680
693
|
frames = []
|
|
681
694
|
|
|
682
|
-
while payload.bytesize > 0
|
|
695
|
+
while payload && payload.bytesize > 0
|
|
683
696
|
cont = frame.dup
|
|
684
697
|
cont[:type] = :continuation
|
|
685
698
|
cont[:flags] = []
|
|
686
|
-
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)
|
|
687
701
|
frames << cont
|
|
688
702
|
end
|
|
689
703
|
if frames.empty?
|
|
@@ -707,7 +721,7 @@ module HTTP2Next
|
|
|
707
721
|
# @param priority [Integer]
|
|
708
722
|
# @param window [Integer]
|
|
709
723
|
# @param parent [Stream]
|
|
710
|
-
def activate_stream(id
|
|
724
|
+
def activate_stream(id:, **args)
|
|
711
725
|
connection_error(msg: "Stream ID already exists") if @streams.key?(id)
|
|
712
726
|
|
|
713
727
|
raise StreamLimitExceeded if @active_stream_count >= (@max_streams || @local_settings[:settings_max_concurrent_streams])
|
|
@@ -724,11 +738,11 @@ module HTTP2Next
|
|
|
724
738
|
# References to such streams will be purged whenever another stream
|
|
725
739
|
# is closed, with a minimum of 15s RTT time window.
|
|
726
740
|
@streams_recently_closed.reject! do |stream_id, v|
|
|
727
|
-
to_delete = (
|
|
741
|
+
to_delete = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - v) > 15
|
|
728
742
|
@streams.delete stream_id if to_delete
|
|
729
743
|
to_delete
|
|
730
744
|
end
|
|
731
|
-
@streams_recently_closed[id] =
|
|
745
|
+
@streams_recently_closed[id] = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
732
746
|
end
|
|
733
747
|
|
|
734
748
|
stream.on(:promise, &method(:promise)) if is_a? Server
|
|
@@ -746,7 +760,7 @@ module HTTP2Next
|
|
|
746
760
|
|
|
747
761
|
def verify_pseudo_headers(frame, mandatory_headers)
|
|
748
762
|
headers = frame[:payload]
|
|
749
|
-
return if headers.is_a?(
|
|
763
|
+
return if headers.is_a?(String)
|
|
750
764
|
|
|
751
765
|
pseudo_headers = headers.take_while do |field, value|
|
|
752
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,31 @@ module HTTP2Next
|
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
module StringExtensions
|
|
15
|
+
refine String do
|
|
16
|
+
def read(n)
|
|
17
|
+
return "".b if n == 0
|
|
18
|
+
|
|
19
|
+
chunk = byteslice(0..n - 1)
|
|
20
|
+
remaining = byteslice(n..-1)
|
|
21
|
+
remaining ? replace(remaining) : clear
|
|
22
|
+
chunk
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def read_uint32
|
|
26
|
+
read(4).unpack1("N")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def shift_byte
|
|
30
|
+
read(1).ord
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
unless String.method_defined?(:unpack1)
|
|
34
|
+
def unpack1(format)
|
|
35
|
+
unpack(format).first
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
13
40
|
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
|