http-2-next 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b8760a4af91eae4da3ae631c99b68cef2130cc0758ac7c91420bffe53582e55
4
- data.tar.gz: ced41c1e91b125dd4ea957d026b27ccec5cd2aa79ca6376883f829c52199e758
3
+ metadata.gz: e1a2260b9fc7284c07a10b356a5008632319f6511848b8bfe923d908df84b92e
4
+ data.tar.gz: c733242b644fcb16685df75cbac2934ad43fe2d284ea90ad28fb9af89210588e
5
5
  SHA512:
6
- metadata.gz: a3f421c1e495cb9bed15a3635dfdae9996074a77e221f1a3e5ebd75be0df0e154ab395ffc3caf3e333749b2fd4350ec226941f84c55c9c99ef023f18fe1da002
7
- data.tar.gz: 4f0af698fbd7ac5a94b03fba9b93f47c6d8c34d0e44469a63dcec27609932a45e2b59f6ed08a8e55441d14756a238a8f0bea08ae795e3494e061f82d0a4668cf
6
+ metadata.gz: 616823541f91bcd9b13ab0b040c837fafd69f3dc8e0be7fc9a1a04e461f6cd129a5a64be09e6412fdacadcf04d3433039cbf5da56cb6604d9baea28abd7ee5d3
7
+ data.tar.gz: fe807a6f0318f6ed00fb2a7922d5e78202dd9165345df312f668baaa08af926d3e4d641da48899f7d6b830f9b7375096ad61f0bbd70bf2c00cbf8f12ce5bbb50
@@ -68,5 +68,11 @@ module HTTP2Next
68
68
  frame = Framer.new.generate(type: :settings, stream: 0, payload: settings)
69
69
  Base64.urlsafe_encode64(frame[9..-1])
70
70
  end
71
+
72
+ private
73
+
74
+ def verify_pseudo_headers(frame, mandatory_headers = RESPONSE_MANDATORY_HEADERS)
75
+ super(frame, mandatory_headers)
76
+ end
71
77
  end
72
78
  end
@@ -35,6 +35,9 @@ module HTTP2Next
35
35
  # Default connection "fast-fail" preamble string as defined by the spec.
36
36
  CONNECTION_PREFACE_MAGIC = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
37
37
 
38
+ REQUEST_MANDATORY_HEADERS = %w[:scheme :method :authority :path].freeze
39
+ RESPONSE_MANDATORY_HEADERS = %w[:status].freeze
40
+
38
41
  # Connection encapsulates all of the connection, stream, flow-control,
39
42
  # error management, and other processing logic required for a well-behaved
40
43
  # HTTP 2.0 endpoint.
@@ -270,6 +273,8 @@ module HTTP2Next
270
273
 
271
274
  stream = @streams[frame[:stream]]
272
275
  if stream.nil?
276
+ verify_pseudo_headers(frame)
277
+
273
278
  stream = activate_stream(
274
279
  id: frame[:stream],
275
280
  weight: frame[:weight] || DEFAULT_WEIGHT,
@@ -329,6 +334,7 @@ module HTTP2Next
329
334
  end
330
335
  end
331
336
 
337
+ verify_pseudo_headers(frame, REQUEST_MANDATORY_HEADERS)
332
338
  stream = activate_stream(id: pid, parent: parent)
333
339
  verify_stream_order(stream.id)
334
340
  emit(:promise, stream)
@@ -727,6 +733,21 @@ module HTTP2Next
727
733
  @last_stream_id = id
728
734
  end
729
735
 
736
+ def verify_pseudo_headers(frame, mandatory_headers)
737
+ headers = frame[:payload]
738
+ return if headers.is_a?(Buffer)
739
+
740
+ pseudo_headers = headers.take_while do |field, value|
741
+ # use this loop to validate pseudo-headers
742
+ connection_error(:protocol_error, msg: "path is empty") if field == ":path" && value.empty?
743
+ field.start_with?(":")
744
+ end.map(&:first)
745
+ return if mandatory_headers.size == pseudo_headers.size &&
746
+ (mandatory_headers - pseudo_headers).empty?
747
+
748
+ connection_error(:protocol_error, msg: "invalid pseudo-headers")
749
+ end
750
+
730
751
  # Emit GOAWAY error indicating to peer that the connection is being
731
752
  # aborted, and once sent, raise a local exception.
732
753
  #
@@ -114,6 +114,10 @@ module HTTP2Next
114
114
 
115
115
  private
116
116
 
117
+ def verify_pseudo_headers(frame, mandatory_headers = REQUEST_MANDATORY_HEADERS)
118
+ super(frame, mandatory_headers)
119
+ end
120
+
117
121
  # Handle locally initiated server-push event emitted by the stream.
118
122
  #
119
123
  # @param args [Array]
@@ -116,7 +116,8 @@ module HTTP2Next
116
116
  # stream error (Section 5.4.2) of type STREAM_CLOSED.
117
117
  stream_error(:stream_closed) unless @state == :open ||
118
118
  @state == :half_closed_local ||
119
- @state == :half_closing || @state == :closing
119
+ @state == :half_closing || @state == :closing ||
120
+ (@state == :closed && @closed == :local_rst)
120
121
  @received_data = true
121
122
  calculate_content_length(frame[:length])
122
123
  update_local_window(frame)
@@ -124,21 +125,22 @@ module HTTP2Next
124
125
  emit(:data, frame[:payload]) unless frame[:ignore]
125
126
  calculate_window_update(@local_window_max_size)
126
127
  when :headers
127
- stream_error(:stream_closed) if @state == :closed || @state == :remote_closed
128
+ stream_error(:stream_closed) if (@state == :closed && @closed != :local_rst) ||
129
+ @state == :remote_closed
128
130
  @_method ||= frame[:method]
129
131
  @_content_length ||= frame[:content_length]
130
132
  @_trailers ||= frame[:trailer]
131
133
  if @_waiting_on_trailers
132
134
  verify_trailers(frame)
133
- else
134
- verify_pseudo_headers(frame)
135
+ elsif @received_data
136
+ stream_error(:protocol_error, msg: "already received data")
135
137
  end
136
138
  emit(:headers, frame[:payload]) unless frame[:ignore]
137
139
  @_waiting_on_trailers = !@_trailers.nil?
138
140
  when :push_promise
139
141
  emit(:promise_headers, frame[:payload]) unless frame[:ignore]
140
142
  when :continuation
141
- stream_error(:stream_closed) if @state == :closed || @state == :remote_closed
143
+ stream_error(:stream_closed) if (@state == :closed && @closed != :local_rst) || @state == :remote_closed
142
144
  stream_error(:protocol_error) if @received_data
143
145
  when :priority
144
146
  process_priority(frame)
@@ -158,25 +160,6 @@ module HTTP2Next
158
160
  end
159
161
  alias << receive
160
162
 
161
- REQUEST_MANDATORY_HEADERS = %w[:scheme :method :authority :path].freeze
162
- RESPONSE_MANDATORY_HEADERS = %w[:status].freeze
163
-
164
- def verify_pseudo_headers(frame)
165
- headers = frame[:payload]
166
- return if headers.is_a?(Buffer)
167
-
168
- mandatory_headers = @id.odd? ? REQUEST_MANDATORY_HEADERS : RESPONSE_MANDATORY_HEADERS
169
- pseudo_headers = headers.take_while do |field, value|
170
- # use this loop to validate pseudo-headers
171
- stream_error(:protocol_error, msg: "path is empty") if field == ":path" && value.empty?
172
- field.start_with?(":")
173
- end.map(&:first)
174
- return if mandatory_headers.size == pseudo_headers.size &&
175
- (mandatory_headers - pseudo_headers).empty?
176
-
177
- stream_error(:protocol_error, msg: "invalid pseudo-headers")
178
- end
179
-
180
163
  def verify_trailers(frame)
181
164
  stream_error(:protocol_error, msg: "trailer headers frame must close the stream") unless end_stream?(frame)
182
165
  return unless @_trailers
@@ -675,6 +658,8 @@ module HTTP2Next
675
658
  end
676
659
 
677
660
  def stream_error(error = :internal_error, msg: nil)
661
+ # if the stream already broke with an error, ignore subsequent
662
+
678
663
  @error = error
679
664
  close(error) if @state != :closed
680
665
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTP2Next
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
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.1.0
4
+ version: 0.1.1
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: 2019-11-13 00:00:00.000000000 Z
13
+ date: 2019-11-17 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: Pure-ruby HTTP 2.0 protocol implementation
16
16
  email: