Skip to content

Commit 789983a

Browse files
authored
Ignore non-final responses. (#137)
1 parent a6f0617 commit 789983a

File tree

8 files changed

+59
-16
lines changed

8 files changed

+59
-16
lines changed

async-http.gemspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ Gem::Specification.new do |spec|
2222
spec.add_dependency "async", ">= 1.25"
2323
spec.add_dependency "async-io", ">= 1.28"
2424
spec.add_dependency "async-pool", ">= 0.2"
25-
spec.add_dependency "protocol-http", "~> 0.24.0"
26-
spec.add_dependency "protocol-http1", "~> 0.15.0"
25+
spec.add_dependency "protocol-http", "~> 0.25.0"
26+
spec.add_dependency "protocol-http1", "~> 0.16.0"
2727
spec.add_dependency "protocol-http2", "~> 0.15.0"
2828
spec.add_dependency "traces", ">= 0.10.0"
2929
end

fixtures/async/http/a_protocol.rb

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,26 @@ module HTTP
4141
end
4242
end
4343

44-
with "huge body", timeout: 600 do
45-
let(:body) {::Protocol::HTTP::Body::File.open("/dev/zero", size: 512*1024**2)}
44+
with "interim response" do
45+
let(:app) do
46+
::Protocol::HTTP::Middleware.for do |request|
47+
request.write_interim_response(
48+
::Protocol::HTTP::Response[103, [["link", "</style.css>; rel=preload; as=style"]]]
49+
)
50+
51+
::Protocol::HTTP::Response[200, {}, ["Hello World"]]
52+
end
53+
end
54+
55+
it "can read informational response" do
56+
response = client.get("/")
57+
expect(response).to be(:success?)
58+
expect(response.read).to be == "Hello World"
59+
end
60+
end
61+
62+
with "huge body" do
63+
let(:body) {::Protocol::HTTP::Body::File.open("/dev/zero", size: 8*1024**2)}
4664

4765
let(:app) do
4866
::Protocol::HTTP::Middleware.for do |request|

lib/async/http/protocol/http1/request.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ def hijack?
3838
def hijack!
3939
@connection.hijack!
4040
end
41+
42+
def write_interim_response(response)
43+
@connection.write_interim_response(response.version, response.status, response.headers)
44+
end
4145
end
4246
end
4347
end

lib/async/http/protocol/http1/response.rb

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,21 @@ module Protocol
1111
module HTTP1
1212
class Response < Protocol::Response
1313
def self.read(connection, request)
14-
if parts = connection.read_response(request.method)
15-
self.new(connection, *parts)
14+
while parts = connection.read_response(request.method)
15+
response = self.new(connection, *parts)
16+
17+
if response.final?
18+
return response
19+
end
1620
end
1721
end
1822

1923
UPGRADE = 'upgrade'
20-
21-
# @attribute [String] The HTTP response line reason.
24+
25+
# @attribute [String] The HTTP response line reason.
2226
attr :reason
23-
24-
# @parameter reason [String] HTTP response line reason phrase
27+
28+
# @parameter reason [String] HTTP response line reason phrase.
2529
def initialize(connection, version, status, reason, headers, body)
2630
@connection = connection
2731
@reason = reason
@@ -34,7 +38,7 @@ def initialize(connection, version, status, reason, headers, body)
3438
def connection
3539
@connection
3640
end
37-
41+
3842
def hijack?
3943
@body.nil?
4044
end

lib/async/http/protocol/http2/request.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ def send_response(response)
141141
@stream.send_headers(nil, headers, ::Protocol::HTTP2::END_STREAM)
142142
end
143143
end
144+
145+
def write_interim_response(response)
146+
protocol_headers = [
147+
[STATUS, response.status]
148+
]
149+
150+
headers = ::Protocol::HTTP::Headers::Merged.new(protocol_headers, response.headers)
151+
152+
@stream.send_headers(nil, headers)
153+
end
144154
end
145155
end
146156
end

lib/async/http/protocol/http2/response.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ def accept_push_promise_stream(promised_stream_id, headers)
3939
# This should be invoked from the background reader, and notifies the task waiting for the headers that we are done.
4040
def receive_initial_headers(headers, end_stream)
4141
headers.each do |key, value|
42+
# It's guaranteed that this should be the first header:
4243
if key == STATUS
44+
status = Integer(value)
45+
46+
# Ignore informational headers:
47+
return if status >= 100 && status < 200
48+
4349
@response.status = Integer(value)
4450
elsif key == PROTOCOL
4551
@response.protocol = value

lib/async/http/protocol/http2/stream.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ def receive_trailing_headers(headers, end_stream)
5050
end
5151

5252
def process_headers(frame)
53-
if @headers.nil?
54-
@headers = ::Protocol::HTTP::Headers.new
55-
self.receive_initial_headers(super, frame.end_stream?)
56-
elsif frame.end_stream?
53+
if frame.end_stream? && @headers
5754
self.receive_trailing_headers(super, frame.end_stream?)
5855
else
59-
raise ::Protocol::HTTP2::HeaderError, "Unable to process headers!"
56+
@headers ||= ::Protocol::HTTP::Headers.new
57+
self.receive_initial_headers(super, frame.end_stream?)
6058
end
6159

6260
# TODO this might need to be in an ensure block:

lib/async/http/protocol/request.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ def hijack?
2525
false
2626
end
2727

28+
def write_interim_response(response)
29+
end
30+
2831
def peer
2932
if connection = self.connection
3033
connection.peer

0 commit comments

Comments
 (0)