http-2-next 0.2.2 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2be1f3b17829c7575759ab9ea216d5a63af21ae5ab9a0119954225995fcae57
4
- data.tar.gz: e380996bda5b61c61d1431ddf8fe215e06b70a48dd57e23195c4150a6b299d6f
3
+ metadata.gz: 57b5112f768b60bc8cba8e6f82925eafc0de71a947fc5282bcc0f4b10dd42b49
4
+ data.tar.gz: 9e8470275022f7d9742232cb1cc2ffab1644a77268a21a656a702db219a3fb93
5
5
  SHA512:
6
- metadata.gz: 285d28b22bb98043f21b1d234097e16e68d2c4b66a9d92137330ea63775ab2ea714eb93e2180a236ee4f950ac3fcada06105a0e4060fd80b1f632d52cc3c037b
7
- data.tar.gz: 1a6d3610f31c771e6cfda9e6871c63ff3d0beefb4574a7622545f70d7c6b0ff6ee0f5f186a60b54648c33acbf75b3934da9a155068556cc19b83cd69f5b960c4
6
+ metadata.gz: a466e82b5a77065453b531602daf30fc5c44bb4918e46f3bc0b48e80268b5496ae23b2bc3ee6f40c8fcf6920dc5ea1a0490c861ace6776f2f522aba090c0309f
7
+ data.tar.gz: b469ea645f4a74fbf5e045a6205ecccf3104d93f190c93cdcfc2faf1f0046623596af728278d3839cddcba235fb1382a830899b5d1f0d7f1ba89734e1cdafc29
data/lib/http/2/next.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "http/2/next/version"
4
+ require "http/2/next/extensions"
4
5
  require "http/2/next/error"
5
6
  require "http/2/next/emitter"
6
7
  require "http/2/next/buffer"
@@ -67,12 +67,14 @@ module HTTP2Next
67
67
  # Ensures that data that is added is binary encoded as well,
68
68
  # otherwise this could lead to the Buffer instance changing its encoding.
69
69
  %i[<< prepend].each do |mutating_method|
70
- define_method(mutating_method) do |string|
70
+ class_eval(<<-METH, __FILE__, __LINE__ + 1)
71
+ def #{mutating_method}(string)
71
72
  string = string.dup if string.frozen?
72
- @buffer.send mutating_method, string.force_encoding(Encoding::BINARY)
73
+ @buffer.send __method__, string.force_encoding(Encoding::BINARY)
73
74
 
74
75
  self
75
76
  end
77
+ METH
76
78
  end
77
79
  end
78
80
  end
@@ -12,6 +12,10 @@ module HTTP2Next
12
12
  class EncodingContext
13
13
  include Error
14
14
 
15
+ using Extensions
16
+
17
+ UPPER = /[[:upper:]]/.freeze
18
+
15
19
  # @private
16
20
  # Static table
17
21
  # - http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-10#appendix-A
@@ -188,7 +192,7 @@ module HTTP2Next
188
192
  cmd[:index] ||= cmd[:name]
189
193
  cmd[:value] ||= v
190
194
  cmd[:name] = k
191
- elsif cmd[:name] != cmd[:name].downcase
195
+ elsif UPPER.match?(cmd[:name])
192
196
  raise ProtocolError, "Invalid uppercase key: #{cmd[:name]}"
193
197
  end
194
198
 
@@ -217,7 +221,7 @@ module HTTP2Next
217
221
  headers.each do |field, value|
218
222
  # Literal header names MUST be translated to lowercase before
219
223
  # encoding and transmission.
220
- field = field.downcase
224
+ field = field.downcase if UPPER.match?(field)
221
225
  value = "/" if field == ":path" && value.empty?
222
226
  cmd = addcmd(field, value)
223
227
  cmd[:type] = :noindex if noindex && cmd[:type] == :incremental
@@ -96,7 +96,6 @@ module HTTP2Next
96
96
  @remote_window = @remote_window_limit
97
97
 
98
98
  @recv_buffer = Buffer.new
99
- @send_buffer = []
100
99
  @continuation = []
101
100
  @error = nil
102
101
 
@@ -720,12 +719,12 @@ module HTTP2Next
720
719
  # to any in-flight frames while close is registered on both sides.
721
720
  # References to such streams will be purged whenever another stream
722
721
  # is closed, with a minimum of 15s RTT time window.
723
- @streams_recently_closed[id] = Time.now
724
- to_delete = @streams_recently_closed.select { |_, v| (Time.now - v) > 15 }
725
- to_delete.each do |stream_id|
726
- @streams.delete stream_id
727
- @streams_recently_closed.delete stream_id
722
+ @streams_recently_closed.reject do |_, v|
723
+ to_delete = (Time.now - v) > 15
724
+ @streams.delete stream_id if to_delete
725
+ to_delete
728
726
  end
727
+ @streams_recently_closed[id] = Time.now
729
728
  end
730
729
 
731
730
  stream.on(:promise, &method(:promise)) if is_a? Server
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTP2Next
4
+ module Extensions
5
+ unless Regexp.method_defined?(:match?)
6
+ refine Regexp do
7
+ def match?(*args)
8
+ !match(*args).nil?
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -14,7 +14,7 @@ module HTTP2Next
14
14
  #
15
15
  # @return [Integer]
16
16
  def buffered_amount
17
- @send_buffer.map { |f| f[:length] }.reduce(0, :+)
17
+ send_buffer.bytesize
18
18
  end
19
19
 
20
20
  def flush
@@ -23,6 +23,10 @@ module HTTP2Next
23
23
 
24
24
  private
25
25
 
26
+ def send_buffer
27
+ @send_buffer ||= FrameBuffer.new
28
+ end
29
+
26
30
  def update_local_window(frame)
27
31
  frame_size = frame[:payload].bytesize
28
32
  frame_size += frame[:padding] || 0
@@ -63,42 +67,20 @@ module HTTP2Next
63
67
  # Buffered DATA frames are emitted in FIFO order.
64
68
  #
65
69
  # @param frame [Hash]
66
- # @param encode [Boolean] set to true by co
70
+ # @param encode [Boolean] set to true by connection
67
71
  def send_data(frame = nil, encode = false)
68
- @send_buffer.push frame unless frame.nil?
72
+ send_buffer << frame unless frame.nil?
69
73
 
70
- # FIXME: Frames with zero length with the END_STREAM flag set (that
71
- # is, an empty DATA frame) MAY be sent if there is no available space
72
- # in either flow control window.
73
- while @remote_window > 0 && !@send_buffer.empty?
74
- frame = @send_buffer.shift
75
-
76
- sent = 0
77
- frame_size = frame[:payload].bytesize
78
-
79
- if frame_size > @remote_window
80
- payload = frame.delete(:payload)
81
- chunk = frame.dup
82
-
83
- # Split frame so that it fits in the window
84
- # TODO: consider padding!
85
- frame[:payload] = payload.slice!(0, @remote_window)
86
- frame[:length] = frame[:payload].bytesize
87
- chunk[:length] = payload.bytesize
88
- chunk[:payload] = payload
89
-
90
- # if no longer last frame in sequence...
91
- frame[:flags] -= [:end_stream] if frame[:flags].include? :end_stream
92
-
93
- @send_buffer.unshift chunk
94
- sent = @remote_window
95
- else
96
- sent = frame_size
97
- end
74
+ while (frame = send_buffer.retrieve(@remote_window))
75
+
76
+ sent = frame[:payload].bytesize
98
77
 
99
78
  manage_state(frame) do
100
- frames = encode ? encode(frame) : [frame]
101
- frames.each { |f| emit(:frame, f) }
79
+ if encode
80
+ encode(frame).each { |f| emit(:frame, f) }
81
+ else
82
+ emit(:frame, frame)
83
+ end
102
84
  @remote_window -= sent
103
85
  end
104
86
  end
@@ -116,4 +98,59 @@ module HTTP2Next
116
98
  send_data(nil, encode)
117
99
  end
118
100
  end
101
+
102
+ class FrameBuffer
103
+ attr_reader :bytesize
104
+
105
+ def initialize
106
+ @buffer = []
107
+ @bytesize = 0
108
+ end
109
+
110
+ def <<(frame)
111
+ @buffer << frame
112
+ @bytesize += frame[:payload].bytesize
113
+ end
114
+
115
+ def empty?
116
+ @bytesize == 0
117
+ end
118
+
119
+ def retrieve(window_size)
120
+ return if @buffer.empty?
121
+
122
+ frame = @buffer.first
123
+
124
+ frame_size = frame[:payload].bytesize
125
+ end_stream = frame[:flags].include? :end_stream
126
+
127
+ # Frames with zero length with the END_STREAM flag set (that
128
+ # is, an empty DATA frame) MAY be sent if there is no available space
129
+ # in either flow control window.
130
+ return if window_size == 0 && !(frame_size == 0 && end_stream)
131
+
132
+ @buffer.shift
133
+
134
+ if frame_size > window_size
135
+ payload = frame.delete(:payload)
136
+ chunk = frame.dup
137
+
138
+ # Split frame so that it fits in the window
139
+ # TODO: consider padding!
140
+ frame[:payload] = payload.slice!(0, window_size)
141
+ frame[:length] = frame[:payload].bytesize
142
+ chunk[:length] = payload.bytesize
143
+ chunk[:payload] = payload
144
+
145
+ # if no longer last frame in sequence...
146
+ frame[:flags] -= [:end_stream] if end_stream
147
+
148
+ @buffer.unshift(chunk)
149
+ @bytesize -= window_size
150
+ else
151
+ @bytesize -= frame_size
152
+ end
153
+ frame
154
+ end
155
+ end
119
156
  end
@@ -89,7 +89,6 @@ module HTTP2Next
89
89
  @state = state
90
90
  @error = false
91
91
  @closed = false
92
- @send_buffer = []
93
92
  @_method = @_content_length = nil
94
93
  @_waiting_on_trailers = false
95
94
  @received_data = false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTP2Next
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http-2-next
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-02-21 00:00:00.000000000 Z
13
+ date: 2020-02-29 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: Pure-ruby HTTP 2.0 protocol implementation
16
16
  email:
@@ -27,6 +27,7 @@ files:
27
27
  - lib/http/2/next/connection.rb
28
28
  - lib/http/2/next/emitter.rb
29
29
  - lib/http/2/next/error.rb
30
+ - lib/http/2/next/extensions.rb
30
31
  - lib/http/2/next/flow_buffer.rb
31
32
  - lib/http/2/next/framer.rb
32
33
  - lib/http/2/next/huffman.rb