Skip to content

Commit ddab283

Browse files
committed
http/h1_stream: handle EOF when body_read_type==length
If a client closes the connection before sending the expected number of bytes then return `EPIPE`. This fixes a potential infinite draining loop when trying to trying to `:shutdown()` a stream.
1 parent f33b186 commit ddab283

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

http/h1_stream.lua

+2
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,8 @@ function stream_methods:read_next_chunk(timeout)
861861
if chunk ~= nil then
862862
self.body_read_left = length_n - #chunk
863863
end_stream = (self.body_read_left == 0)
864+
elseif err == nil then
865+
return nil, ce.strerror(ce.EPIPE), ce.EPIPE
864866
end
865867
elseif length_n == 0 then
866868
chunk = ""

spec/h1_stream_spec.lua

+27
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,33 @@ describe("http1 stream", function()
295295
server:close()
296296
client:close()
297297
end)
298+
it("Doesn't hang when a content-length delimited stream is closed", function()
299+
local server, client = new_pair(1.1)
300+
local cq = cqueues.new()
301+
cq:wrap(function()
302+
local stream = client:new_stream()
303+
local headers = new_headers()
304+
headers:append(":method", "GET")
305+
headers:append(":scheme", "http")
306+
headers:append(":authority", "myauthority")
307+
headers:append(":path", "/a")
308+
assert(stream:write_headers(headers, true))
309+
end)
310+
cq:wrap(function()
311+
local stream = server:get_next_incoming_stream()
312+
assert(stream:get_headers())
313+
local res_headers = new_headers()
314+
res_headers:append(":status", "200")
315+
res_headers:append("content-length", "100")
316+
assert(stream:write_headers(res_headers, false))
317+
assert(stream:write_chunk("foo", false))
318+
assert(stream:shutdown())
319+
end)
320+
assert_loop(cq, TEST_TIMEOUT)
321+
assert.truthy(cq:empty())
322+
server:close()
323+
client:close()
324+
end)
298325
it("allows pipelining", function()
299326
local server, client = new_pair(1.1)
300327
local cq = cqueues.new()

0 commit comments

Comments
 (0)