http-2-next 0.1.0 → 0.1.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/lib/http/2/next/client.rb +6 -0
- data/lib/http/2/next/connection.rb +21 -0
- data/lib/http/2/next/server.rb +4 -0
- data/lib/http/2/next/stream.rb +9 -24
- data/lib/http/2/next/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1a2260b9fc7284c07a10b356a5008632319f6511848b8bfe923d908df84b92e
|
4
|
+
data.tar.gz: c733242b644fcb16685df75cbac2934ad43fe2d284ea90ad28fb9af89210588e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 616823541f91bcd9b13ab0b040c837fafd69f3dc8e0be7fc9a1a04e461f6cd129a5a64be09e6412fdacadcf04d3433039cbf5da56cb6604d9baea28abd7ee5d3
|
7
|
+
data.tar.gz: fe807a6f0318f6ed00fb2a7922d5e78202dd9165345df312f668baaa08af926d3e4d641da48899f7d6b830f9b7375096ad61f0bbd70bf2c00cbf8f12ce5bbb50
|
data/lib/http/2/next/client.rb
CHANGED
@@ -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
|
#
|
data/lib/http/2/next/server.rb
CHANGED
@@ -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]
|
data/lib/http/2/next/stream.rb
CHANGED
@@ -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
|
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
|
-
|
134
|
-
|
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
|
|
data/lib/http/2/next/version.rb
CHANGED
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.
|
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
|
+
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:
|