http-2-next 0.2.4 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/http/2/next.rb +1 -4
- data/lib/http/2/next/connection.rb +49 -31
- 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 +25 -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: 8fa01852fa00c35563fb999f007c1894c4b46a18a40d311d21908c42fc1b17f1
|
4
|
+
data.tar.gz: 7366509fdd22062f761abc7c4c6c46fa2e707ba953c17e3e86f449a67b5c38f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8e6170d679b518d9de1fb1222d8a4c4996906e4a015a67d7418bb5c56af7c60e7551206303518612b16f19eddaaf1d50af96eb75d2611c7e4709a3f4401212c
|
7
|
+
data.tar.gz: 75c0652bc0b55feb14883841aa1119f4c0751ad5b435bd7e2de3443f8c6a354eaae25777c71c6fb1d9e35e90760af34c7a3319e418c5ccf5f44909f0741910c1
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/http-2-next.svg)](http://rubygems.org/gems/http-2-next)
|
4
4
|
[![Build status](https://gitlab.com/honeyryderchuck/http-2-next/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/http-2-next/commits/master)
|
5
|
-
[![coverage report](https://gitlab.com/honeyryderchuck/http-2-next/badges/master/coverage.svg)](https://honeyryderchuck.gitlab.io/http-2-next/coverage/#_AllFiles)
|
5
|
+
[![coverage report](https://gitlab.com/honeyryderchuck/http-2-next/badges/master/coverage.svg?job=coverage)](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
|
|
@@ -719,12 +737,12 @@ module HTTP2Next
|
|
719
737
|
# to any in-flight frames while close is registered on both sides.
|
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
|
-
@streams_recently_closed.reject do |
|
723
|
-
to_delete = (
|
740
|
+
@streams_recently_closed.reject! do |stream_id, v|
|
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] ||= []
|
@@ -221,7 +224,7 @@ module HTTP2Next
|
|
221
224
|
raise CompressionError, "Invalid stream ID (#{frame[:stream]})" if (frame[:stream]).nonzero?
|
222
225
|
|
223
226
|
frame[:payload].each do |(k, v)|
|
224
|
-
if k.is_a? Integer
|
227
|
+
if k.is_a? Integer # rubocop:disable Style/GuardClause
|
225
228
|
DEFINED_SETTINGS.value?(k) || next
|
226
229
|
else
|
227
230
|
k = DEFINED_SETTINGS[k]
|
@@ -333,10 +336,10 @@ module HTTP2Next
|
|
333
336
|
#
|
334
337
|
# @param buf [Buffer]
|
335
338
|
def parse(buf)
|
336
|
-
return
|
339
|
+
return if buf.size < 9
|
337
340
|
|
338
341
|
frame = read_common_header(buf)
|
339
|
-
return
|
342
|
+
return if buf.size < 9 + frame[:length]
|
340
343
|
|
341
344
|
raise ProtocolError, "payload too large" if frame[:length] > @local_max_frame_size
|
342
345
|
|
@@ -353,11 +356,11 @@ module HTTP2Next
|
|
353
356
|
if FRAME_TYPES_WITH_PADDING.include?(frame[:type])
|
354
357
|
padded = frame[:flags].include?(:padded)
|
355
358
|
if padded
|
356
|
-
padlen = payload.read(1).
|
359
|
+
padlen = payload.read(1).unpack1(UINT8)
|
357
360
|
frame[:padding] = padlen + 1
|
358
361
|
raise ProtocolError, "padding too long" if padlen > payload.bytesize
|
359
362
|
|
360
|
-
payload.
|
363
|
+
payload = payload.byteslice(0, payload.bytesize - padlen) if padlen > 0
|
361
364
|
frame[:length] -= frame[:padding]
|
362
365
|
frame[:flags].delete(:padded)
|
363
366
|
end
|
@@ -371,7 +374,9 @@ module HTTP2Next
|
|
371
374
|
e_sd = payload.read_uint32
|
372
375
|
frame[:dependency] = e_sd & RBIT
|
373
376
|
frame[:exclusive] = (e_sd & EBIT) != 0
|
374
|
-
|
377
|
+
weight = payload.byteslice(0, 1).ord + 1
|
378
|
+
frame[:weight] = weight
|
379
|
+
payload = payload.byteslice(1..-1)
|
375
380
|
end
|
376
381
|
frame[:payload] = payload.read(frame[:length])
|
377
382
|
when :priority
|
@@ -380,7 +385,9 @@ module HTTP2Next
|
|
380
385
|
e_sd = payload.read_uint32
|
381
386
|
frame[:dependency] = e_sd & RBIT
|
382
387
|
frame[:exclusive] = (e_sd & EBIT) != 0
|
383
|
-
|
388
|
+
weight = payload.byteslice(0, 1).ord + 1
|
389
|
+
frame[:weight] = weight
|
390
|
+
payload = payload.byteslice(1..-1)
|
384
391
|
when :rst_stream
|
385
392
|
raise FrameSizeError, "Invalid length for RST_STREAM (#{frame[:length]} != 4)" if frame[:length] != 4
|
386
393
|
|
@@ -395,7 +402,7 @@ module HTTP2Next
|
|
395
402
|
raise ProtocolError, "Invalid stream ID (#{frame[:stream]})" if (frame[:stream]).nonzero?
|
396
403
|
|
397
404
|
(frame[:length] / 6).times do
|
398
|
-
id = payload.read(2).
|
405
|
+
id = payload.read(2).unpack1(UINT16)
|
399
406
|
val = payload.read_uint32
|
400
407
|
|
401
408
|
# Unsupported or unrecognized settings MUST be ignored.
|
@@ -425,10 +432,12 @@ module HTTP2Next
|
|
425
432
|
when :altsvc
|
426
433
|
frame[:max_age], frame[:port] = payload.read(6).unpack(UINT32 + UINT16)
|
427
434
|
|
428
|
-
len = payload.
|
435
|
+
len = payload.byteslice(0, 1).ord
|
436
|
+
payload = payload.byteslice(1..-1)
|
429
437
|
frame[:proto] = payload.read(len) if len > 0
|
430
438
|
|
431
|
-
len = payload.
|
439
|
+
len = payload.byteslice(0, 1).ord
|
440
|
+
payload = payload.byteslice(1..-1)
|
432
441
|
frame[:host] = payload.read(len) if len > 0
|
433
442
|
|
434
443
|
frame[:origin] = payload.read(payload.size) unless payload.empty?
|
@@ -437,7 +446,7 @@ module HTTP2Next
|
|
437
446
|
origins = []
|
438
447
|
|
439
448
|
until payload.empty?
|
440
|
-
len = payload.read(2).
|
449
|
+
len = payload.read(2).unpack1(UINT16)
|
441
450
|
origins << payload.read(len)
|
442
451
|
end
|
443
452
|
|
@@ -452,17 +461,16 @@ module HTTP2Next
|
|
452
461
|
|
453
462
|
def pack_error(e)
|
454
463
|
unless e.is_a? Integer
|
455
|
-
raise CompressionError, "Unknown error ID for #{e}" if DEFINED_ERRORS[e].nil?
|
456
|
-
|
457
464
|
e = DEFINED_ERRORS[e]
|
465
|
+
|
466
|
+
raise CompressionError, "Unknown error ID for #{e}" unless e
|
458
467
|
end
|
459
468
|
|
460
469
|
[e].pack(UINT32)
|
461
470
|
end
|
462
471
|
|
463
472
|
def unpack_error(error)
|
464
|
-
|
465
|
-
name || error
|
473
|
+
DEFINED_ERRORS.key(error) || error
|
466
474
|
end
|
467
475
|
end
|
468
476
|
end
|