http-2-next 0.2.3 → 0.4.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.
@@ -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").unpack("B*").first[-l..-1] }.each(&:freeze).freeze
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
@@ -79,7 +79,8 @@ module HTTP2Next
79
79
  receive(CONNECTION_PREFACE_MAGIC)
80
80
 
81
81
  # Process received HTTP2-Settings payload
82
- buf = HTTP2Next::Buffer.new Base64.urlsafe_decode64(settings.to_s)
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] = [:end_stream]
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 args [Array]
142
+ # @param parent [Stream]
143
+ # @param headers [Enumerable[String, String]]
144
+ # @param flags [Array[Symbol]]
141
145
  # @param callback [Proc]
142
- def promise(*args)
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,
@@ -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
@@ -164,7 +163,7 @@ module HTTP2Next
164
163
  return unless @_trailers
165
164
 
166
165
  trailers = frame[:payload]
167
- return if trailers.is_a?(Buffer)
166
+ return unless trailers.respond_to?(:each)
168
167
 
169
168
  trailers.each do |field, _|
170
169
  @_trailers.delete(field)
@@ -174,7 +173,7 @@ module HTTP2Next
174
173
  end
175
174
 
176
175
  def calculate_content_length(data_length)
177
- return unless @_content_length
176
+ return unless @_content_length && data_length
178
177
 
179
178
  @_content_length -= data_length
180
179
  return if @_content_length >= 0
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTP2Next
4
- VERSION = "0.2.3"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -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
- attr_accessor :transitions
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
@@ -0,0 +1,9 @@
1
+ module HTTP2Next
2
+ class Client < Connection
3
+ def upgrade: () -> Stream
4
+
5
+ def send_connection_preface: () -> void
6
+
7
+ def self.settings_header: (settings_enum) -> String
8
+ end
9
+ end
@@ -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
@@ -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
@@ -0,0 +1,13 @@
1
+ module HTTP2Next
2
+ class FrameBuffer
3
+ attr_reader bytesize: Integer
4
+
5
+ @buffer: Array[String]
6
+
7
+ def <<: (frame) -> void
8
+
9
+ def empty?: () -> bool
10
+
11
+ def retrieve: (Integer) -> frame?
12
+ end
13
+ 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
@@ -0,0 +1,9 @@
1
+ module HTTP2Next
2
+ module Header
3
+ class Huffman
4
+ def encode: (String str) -> String
5
+
6
+ def decode: (String str) -> String
7
+ end
8
+ end
9
+ end
data/sig/next.rbs ADDED
@@ -0,0 +1,95 @@
1
+ module HTTP2Next
2
+ DEFAULT_FLOW_WINDOW: Integer
3
+
4
+ DEFAULT_HEADER_SIZE: Integer
5
+
6
+ DEFAULT_MAX_CONCURRENT_STREAMS: Integer
7
+
8
+ type settings_hash = Hash[Symbol, Integer]
9
+
10
+ type settings_enum = Enumerable[Symbol, Integer]
11
+
12
+ SPEC_DEFAULT_CONNECTION_SETTINGS: settings_hash
13
+
14
+ DEFAULT_CONNECTION_SETTINGS: settings_hash
15
+
16
+ DEFAULT_WEIGHT: Integer
17
+
18
+ CONNECTION_PREFACE_MAGIC: String
19
+
20
+ REQUEST_MANDATORY_HEADERS: Array[Symbol]
21
+
22
+ RESPONSE_MANDATORY_HEADERS: Array[Symbol]
23
+
24
+ type header_pair = [String, String]
25
+
26
+ # # FRAMES
27
+ # type frame_control_flags = Array[:end_headers | :end_stream]
28
+
29
+ # # HEADERS
30
+ # type headers_frame = {
31
+ # type: :headers, flags: frame_control_flags, stream: Integer, payload: Enumerable[header_pair],
32
+ # ?method: Symbol, ?trailer: Array[String], ?content_length: Integer, ?padding: Integer
33
+ # }
34
+
35
+ # # DATA
36
+ # type data_frame = { type: :data, flags: frame_control_flags, stream: Integer, length: Integer, payload: String, ?padding: Integer }
37
+
38
+ # # PUSH_PROMISE
39
+ # type push_promise_frame = { type: :push_promise, promise_stream: Integer, flags: frame_control_flags, stream: Integer, ?method: Symbol, ?trailer: Array[String], ?content_length: Integer, payload: Enumerable[header_pair], ?padding: Integer }
40
+
41
+ # # SETTINGS
42
+ # type settings_frame = { type: :settings, stream: 0, payload: Array[[Symbol | Integer, Integer]] }
43
+
44
+ # # WINDOW_UPDATE
45
+ # type window_update_frame = { type: :window_update, stream: Integer, increment: Integer }
46
+
47
+ # # PRIORITY
48
+ # type priority_frame = { type: :priority, stream: Integer, dependency: Integer, exclusive: bool, weight: Integer }
49
+
50
+ # # ALTSVC
51
+ # type altsvc_frame = { type: :altsvc, stream: 0, max_age: Integer, port: Integer, proto: "String", host: String }
52
+
53
+ # # ORIGIN
54
+ # type origin_frame = { type: :origin, stream: 0, origin: Array[String] }
55
+
56
+ # # PING
57
+ # type ping_frame = { type: :ping, payload: String, length: Integer }
58
+
59
+ # # GOAWAY
60
+ # type goaway_frame = { type: :goaway, stream: 0, last_stream: Integer, error: Symbol? }
61
+
62
+ # type frame = headers_frame | data_frame | push_promise_frame |
63
+ # settings_frame | window_update_frame | priority_frame | altsvc_frame |
64
+ # origin_frame | ping_frame | goaway_frame
65
+
66
+ type frame_key = :type | :flags | :stream | :padding | :ignore |
67
+ # headers
68
+ :method | :trailer | :content_length |
69
+ # data, settings, ping
70
+ :payload | :length |
71
+ # promise
72
+ :promise_stream |
73
+ # window_update
74
+ :increment |
75
+ # priority
76
+ :dependency | :exclusive | :weight |
77
+ # altsvc
78
+ :max_age | :port | :proto | :host |
79
+ # origin
80
+ :origin |
81
+ # goaway
82
+ :last_stream | :error
83
+
84
+ type frame_value = Integer |
85
+ Symbol | # type (:data, :headers)
86
+ Array[Symbol] |
87
+ String |
88
+ bool |
89
+ Array[String] |
90
+ Array[[Symbol | Integer, Integer]] |
91
+ Enumerable[header_pair] |
92
+ nil
93
+
94
+ type frame = Hash[frame_key, frame_value]
95
+ end