Skip to content

Commit b57dc02

Browse files
committed
Allow HTTP/2 frames to be written from a fiber which is not a task.
1 parent b6bf5b6 commit b57dc02

2 files changed

Lines changed: 38 additions & 2 deletions

File tree

‎lib/async/http/protocol/http2/connection.rb‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,21 @@ def synchronize(&block)
4747

4848
# Write a single frame, deferring stop until the frame is written.
4949
def write_frame(frame)
50-
Task.current.defer_stop{super}
50+
defer_stop {super}
5151
end
5252

5353
# Write multiple frames, deferring stop until the frames are written.
5454
def write_frames
55-
Task.current.defer_stop{super}
55+
defer_stop {super}
56+
end
57+
58+
# A fiber may be running under the scheduler without being an Async task, e.g. an `Enumerator` reading a response body, in which case there is no task to defer stopping.
59+
private def defer_stop(&block)
60+
if task = Task.current?
61+
task.defer_stop(&block)
62+
else
63+
yield
64+
end
5665
end
5766

5867
# @returns [String] A string representation of this connection.

‎test/async/http/protocol/http2.rb‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,33 @@ def make_client(endpoint, **options)
149149
end
150150
end
151151

152+
with "a fiber which is not an Async task" do
153+
let(:app) do
154+
Protocol::HTTP::Middleware.for do |request|
155+
Protocol::HTTP::Response[200, {}, ["x" * 1_000_000] * 10]
156+
end
157+
end
158+
159+
it "can read a response body larger than the window" do
160+
response = client.get("/")
161+
162+
# An Enumerator iterates in its own fiber, which has the scheduler but no task, e.g. Falcon reading a Rack body:
163+
chunks = Enumerator.new do |yielder|
164+
response.body.each{|chunk| yielder << chunk}
165+
end
166+
167+
size = 0
168+
169+
loop do
170+
size += chunks.next.bytesize
171+
end
172+
173+
expect(size).to be == 10_000_000
174+
ensure
175+
response&.close
176+
end
177+
end
178+
152179
with "stopping requests" do
153180
let(:finished) {Async::Promise.new}
154181

0 commit comments

Comments
 (0)