http-2-next 0.2.4 → 0.4.1
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 +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
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "error"
|
3
|
+
require_relative "../error"
|
4
|
+
require_relative "../extensions"
|
4
5
|
|
5
6
|
module HTTP2Next
|
6
7
|
# Implementation of huffman encoding for HPACK
|
@@ -9,6 +10,8 @@ module HTTP2Next
|
|
9
10
|
module Header
|
10
11
|
# Huffman encoder/decoder
|
11
12
|
class Huffman
|
13
|
+
using StringExtensions
|
14
|
+
|
12
15
|
include Error
|
13
16
|
|
14
17
|
BITS_AT_ONCE = 4
|
@@ -319,7 +322,7 @@ module HTTP2Next
|
|
319
322
|
[0x3fffffff, 30]
|
320
323
|
].each(&:freeze).freeze
|
321
324
|
|
322
|
-
ENCODE_TABLE = CODES.map { |c, l| [c].pack("N").
|
325
|
+
ENCODE_TABLE = CODES.map { |c, l| [c].pack("N").unpack1("B*")[-l..-1] }.each(&:freeze).freeze
|
323
326
|
end
|
324
327
|
end
|
325
328
|
end
|
File without changes
|
data/lib/http/2/next/server.rb
CHANGED
@@ -79,7 +79,8 @@ module HTTP2Next
|
|
79
79
|
receive(CONNECTION_PREFACE_MAGIC)
|
80
80
|
|
81
81
|
# Process received HTTP2-Settings payload
|
82
|
-
buf =
|
82
|
+
buf = "".b
|
83
|
+
buf << Base64.urlsafe_decode64(settings.to_s)
|
83
84
|
header = @framer.common_header(
|
84
85
|
length: buf.bytesize,
|
85
86
|
type: :settings,
|
@@ -95,6 +96,7 @@ module HTTP2Next
|
|
95
96
|
|
96
97
|
headers_frame = {
|
97
98
|
type: :headers,
|
99
|
+
flags: [:end_headers],
|
98
100
|
stream: 1,
|
99
101
|
weight: DEFAULT_WEIGHT,
|
100
102
|
dependency: 0,
|
@@ -103,7 +105,7 @@ module HTTP2Next
|
|
103
105
|
}
|
104
106
|
|
105
107
|
if body.empty?
|
106
|
-
headers_frame[:flags]
|
108
|
+
headers_frame[:flags] << [:end_stream]
|
107
109
|
stream << headers_frame
|
108
110
|
else
|
109
111
|
stream << headers_frame
|
@@ -137,10 +139,11 @@ module HTTP2Next
|
|
137
139
|
|
138
140
|
# Handle locally initiated server-push event emitted by the stream.
|
139
141
|
#
|
140
|
-
# @param
|
142
|
+
# @param parent [Stream]
|
143
|
+
# @param headers [Enumerable[String, String]]
|
144
|
+
# @param flags [Array[Symbol]]
|
141
145
|
# @param callback [Proc]
|
142
|
-
def promise(
|
143
|
-
parent, headers, flags = *args
|
146
|
+
def promise(parent, headers, flags)
|
144
147
|
promise = new_stream(parent: parent)
|
145
148
|
promise.send(
|
146
149
|
type: :push_promise,
|
data/lib/http/2/next/stream.rb
CHANGED
@@ -51,11 +51,10 @@ module HTTP2Next
|
|
51
51
|
|
52
52
|
# Stream priority as set by initiator.
|
53
53
|
attr_reader :weight
|
54
|
-
attr_reader :dependency
|
54
|
+
attr_reader :dependency, :remote_window
|
55
55
|
|
56
56
|
# Size of current stream flow control window.
|
57
57
|
attr_reader :local_window
|
58
|
-
attr_reader :remote_window
|
59
58
|
alias window local_window
|
60
59
|
|
61
60
|
# Reason why connection was closed.
|
@@ -75,7 +74,7 @@ module HTTP2Next
|
|
75
74
|
# @param parent [Stream]
|
76
75
|
# @param state [Symbol]
|
77
76
|
def initialize(connection:, id:, weight: 16, dependency: 0, exclusive: false, parent: nil, state: :idle)
|
78
|
-
stream_error(:protocol_error, "stream can't depend on itself") if id == dependency
|
77
|
+
stream_error(:protocol_error, msg: "stream can't depend on itself") if id == dependency
|
79
78
|
|
80
79
|
@connection = connection
|
81
80
|
@id = id
|
@@ -89,7 +88,7 @@ module HTTP2Next
|
|
89
88
|
@state = state
|
90
89
|
@error = false
|
91
90
|
@closed = false
|
92
|
-
@_method = @_content_length = nil
|
91
|
+
@_method = @_content_length = @_status_code = nil
|
93
92
|
@_waiting_on_trailers = false
|
94
93
|
@received_data = false
|
95
94
|
|
@@ -127,12 +126,17 @@ module HTTP2Next
|
|
127
126
|
stream_error(:stream_closed) if (@state == :closed && @closed != :local_rst) ||
|
128
127
|
@state == :remote_closed
|
129
128
|
@_method ||= frame[:method]
|
129
|
+
@_status_code ||= frame[:status]
|
130
130
|
@_content_length ||= frame[:content_length]
|
131
131
|
@_trailers ||= frame[:trailer]
|
132
132
|
if @_waiting_on_trailers
|
133
133
|
verify_trailers(frame)
|
134
|
-
elsif @received_data
|
135
|
-
|
134
|
+
elsif @received_data &&
|
135
|
+
(!@_status_code || @_status_code >= 200)
|
136
|
+
|
137
|
+
# An endpoint that receives a HEADERS frame without the END_STREAM flag set after receiving a final
|
138
|
+
# (non-informational) status code MUST treat the corresponding request or response as malformed.
|
139
|
+
verify_trailers(frame)
|
136
140
|
end
|
137
141
|
emit(:headers, frame[:payload]) unless frame[:ignore]
|
138
142
|
@_waiting_on_trailers = !@_trailers.nil?
|
@@ -164,7 +168,7 @@ module HTTP2Next
|
|
164
168
|
return unless @_trailers
|
165
169
|
|
166
170
|
trailers = frame[:payload]
|
167
|
-
return
|
171
|
+
return unless trailers.respond_to?(:each)
|
168
172
|
|
169
173
|
trailers.each do |field, _|
|
170
174
|
@_trailers.delete(field)
|
@@ -174,7 +178,7 @@ module HTTP2Next
|
|
174
178
|
end
|
175
179
|
|
176
180
|
def calculate_content_length(data_length)
|
177
|
-
return unless @_content_length
|
181
|
+
return unless @_content_length && data_length
|
178
182
|
|
179
183
|
@_content_length -= data_length
|
180
184
|
return if @_content_length >= 0
|
data/lib/http/2/next/version.rb
CHANGED
@@ -5,7 +5,7 @@ task :generate_table do
|
|
5
5
|
HuffmanTable::Node.generate_state_table
|
6
6
|
end
|
7
7
|
|
8
|
-
require_relative "../http/2/next/huffman"
|
8
|
+
require_relative "../http/2/next/header/huffman"
|
9
9
|
|
10
10
|
# @private
|
11
11
|
module HuffmanTable
|
@@ -13,9 +13,8 @@ module HuffmanTable
|
|
13
13
|
EOS = 256
|
14
14
|
|
15
15
|
class Node
|
16
|
-
attr_accessor :next, :emit, :final, :depth
|
17
|
-
|
18
|
-
attr_accessor :id
|
16
|
+
attr_accessor :next, :emit, :final, :depth, :transitions, :id
|
17
|
+
|
19
18
|
@@id = 0 # rubocop:disable Style/ClassVars
|
20
19
|
def initialize(depth)
|
21
20
|
@next = [nil, nil]
|
@@ -38,6 +37,7 @@ module HuffmanTable
|
|
38
37
|
|
39
38
|
class Transition
|
40
39
|
attr_accessor :emit, :node
|
40
|
+
|
41
41
|
def initialize(emit, node)
|
42
42
|
@emit = emit
|
43
43
|
@node = node
|
data/sig/client.rbs
ADDED
data/sig/connection.rbs
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
class Connection
|
3
|
+
include FlowBuffer
|
4
|
+
include Emitter
|
5
|
+
|
6
|
+
attr_reader state: Symbol
|
7
|
+
|
8
|
+
attr_reader local_window: Integer
|
9
|
+
attr_reader remote_window: Integer
|
10
|
+
|
11
|
+
alias window local_window
|
12
|
+
|
13
|
+
attr_reader remote_settings: settings_hash
|
14
|
+
attr_reader local_settings: settings_hash
|
15
|
+
attr_reader pending_settings: settings_hash
|
16
|
+
|
17
|
+
attr_reader active_stream_count: Integer
|
18
|
+
|
19
|
+
attr_writer max_streams: Integer
|
20
|
+
|
21
|
+
def closed?: () -> bool
|
22
|
+
|
23
|
+
def new_stream: (
|
24
|
+
?weight: Integer,
|
25
|
+
?dependency: Integer,
|
26
|
+
?exclusive: bool,
|
27
|
+
?parent: Stream?,
|
28
|
+
?state: Symbol
|
29
|
+
) -> Stream
|
30
|
+
|
31
|
+
def ping: (String) -> void
|
32
|
+
| (String) { () -> void } -> void
|
33
|
+
|
34
|
+
def goaway: (Symbol, String?) -> void
|
35
|
+
| (Symbol) -> void
|
36
|
+
| () -> void
|
37
|
+
|
38
|
+
def window_update: (Integer increment) -> void
|
39
|
+
|
40
|
+
def settings: (settings_enum) -> void
|
41
|
+
|
42
|
+
def receive: (string data) -> void
|
43
|
+
alias << receive
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def initialize: (settings_hash) -> untyped
|
48
|
+
|
49
|
+
def send: (frame) -> void
|
50
|
+
|
51
|
+
def encode: (frame) -> Array[String]
|
52
|
+
|
53
|
+
def connection_frame?: (frame) -> bool
|
54
|
+
|
55
|
+
def connection_management: (frame) -> void
|
56
|
+
|
57
|
+
def ping_management: (frame) -> void
|
58
|
+
|
59
|
+
def validate_settings: (:client | :server, settings_enum) -> void
|
60
|
+
|
61
|
+
def connection_settings: (frame) -> void
|
62
|
+
|
63
|
+
def decode_headers: (frame) -> void
|
64
|
+
|
65
|
+
def encode_headers: (frame) -> Array[frame]
|
66
|
+
|
67
|
+
def activate_stream: (id: Integer, **untyped) -> void
|
68
|
+
|
69
|
+
def verify_stream_order: (Integer id) -> void
|
70
|
+
|
71
|
+
def verify_pseudo_headers: (frame, Array[String]) -> void
|
72
|
+
end
|
73
|
+
end
|
data/sig/emitter.rbs
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
module Emitter
|
3
|
+
def on: (Symbol event) { (*untyped) -> void } -> void
|
4
|
+
|
5
|
+
def once: (Symbol event) { (*untyped) -> void } -> void
|
6
|
+
|
7
|
+
def emit: (Symbol event, *untyped args) ?{ (*untyped) -> void } -> void
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def listeners: (Symbol event) -> Array[Proc]
|
12
|
+
end
|
13
|
+
end
|
data/sig/flow_buffer.rbs
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
module FlowBuffer
|
3
|
+
MAX_WINDOW_SIZE: Integer
|
4
|
+
|
5
|
+
def buffered_amount: () -> Integer
|
6
|
+
|
7
|
+
def flush: () -> void
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def send_buffer: () -> FrameBuffer
|
12
|
+
|
13
|
+
def update_local_window: (frame) -> void
|
14
|
+
|
15
|
+
def calculate_window_update: (Integer) -> void
|
16
|
+
|
17
|
+
def send_data: () -> void
|
18
|
+
| (frame?) -> void
|
19
|
+
| (frame?, bool) -> void
|
20
|
+
|
21
|
+
def process_window_update: (frame: frame, ?encode: bool) -> void
|
22
|
+
end
|
23
|
+
end
|
data/sig/framer.rbs
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
class Framer
|
3
|
+
attr_accessor local_max_frame_size: Integer
|
4
|
+
|
5
|
+
attr_accessor remote_max_frame_size: Integer
|
6
|
+
|
7
|
+
def common_header: (frame) -> String
|
8
|
+
|
9
|
+
def read_common_frame: (String) -> frame
|
10
|
+
|
11
|
+
def generate: (frame) -> String
|
12
|
+
|
13
|
+
def parse: (String) -> frame?
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def initialize: (Integer, Integer) -> untyped
|
18
|
+
| (Integer) -> untyped
|
19
|
+
| () -> untyped
|
20
|
+
|
21
|
+
def pack_error: (Integer | Symbol e) -> String
|
22
|
+
|
23
|
+
def unpack_error: (Integer) -> (Symbol | Integer)
|
24
|
+
end
|
25
|
+
end
|
data/sig/header.rbs
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
module Header
|
3
|
+
type header_key = :type | :name | :value | :index
|
4
|
+
type header_value = Integer | String | :indexed | :changetablesize | :incremental | :noindex | :neverindexed
|
5
|
+
|
6
|
+
#type context_hash = {
|
7
|
+
# huffman?: (:always | :never | :shorter),
|
8
|
+
# index?: (:all | :static | :never),
|
9
|
+
# table_size?: Integer
|
10
|
+
#}
|
11
|
+
type context_hash = Hash[Symbol, Symbol | Integer]
|
12
|
+
|
13
|
+
type header_command = Hash[header_key, header_value]
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
module Header
|
3
|
+
class Compressor
|
4
|
+
@cc: EncodingContext
|
5
|
+
|
6
|
+
def table_size=: (Integer) -> void
|
7
|
+
|
8
|
+
def integer: (Integer, Integer) -> String
|
9
|
+
|
10
|
+
def string: (String) -> String
|
11
|
+
|
12
|
+
def header: (header_command, String) -> String
|
13
|
+
| (header_command) -> String
|
14
|
+
|
15
|
+
def encode: (Enumerable[header_pair]) -> String
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def initialize: (context_hash options) -> untyped
|
20
|
+
| () -> untyped
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
module Header
|
3
|
+
class Decompressor
|
4
|
+
@cc: EncodingContext
|
5
|
+
|
6
|
+
def table_size=: (Integer) -> void
|
7
|
+
|
8
|
+
def integer: (String, Integer) -> Integer
|
9
|
+
|
10
|
+
def string: (String) -> String
|
11
|
+
|
12
|
+
def header: (String) -> header_command
|
13
|
+
|
14
|
+
def decode: (String, frame?) -> Array[header_pair]
|
15
|
+
| (String) -> Array[header_pair]
|
16
|
+
private
|
17
|
+
|
18
|
+
def initialize: (context_hash options) -> untyped
|
19
|
+
| () -> untyped
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module HTTP2Next
|
2
|
+
module Header
|
3
|
+
class EncodingContext
|
4
|
+
STATIC_TABLE: Array[header_pair]
|
5
|
+
|
6
|
+
attr_reader table: Array[header_pair]
|
7
|
+
|
8
|
+
attr_reader options: context_hash
|
9
|
+
|
10
|
+
def dup: () -> EncodingContext
|
11
|
+
|
12
|
+
def dereference: (Integer) -> header_pair
|
13
|
+
|
14
|
+
def process: (header_command cmd) -> header_pair?
|
15
|
+
|
16
|
+
def encode: (_Each[header_pair]) -> Array[header_command]
|
17
|
+
|
18
|
+
def addcmd: (String name, String value) -> header_command
|
19
|
+
|
20
|
+
def table_size=: (Integer) -> void
|
21
|
+
|
22
|
+
def current_table_size: () -> Integer
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def initialize: (context_hash options) -> untyped
|
27
|
+
| () -> untyped
|
28
|
+
|
29
|
+
def add_to_table: (header_pair) -> void
|
30
|
+
|
31
|
+
def size_check: (header_pair?) -> bool
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|