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 +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:
|