Skip to content

Commit 7e60c1b

Browse files
Default error when closing active streams.
Possible fix for <socketry/async-http#201>.
1 parent 6ed67a2 commit 7e60c1b

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

lib/protocol/http2/connection.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ def delete(id)
109109
# Close the underlying framer and all streams.
110110
def close(error = nil)
111111
# The underlying socket may already be closed by this point.
112+
113+
# If there are active streams when the connection closes, it's an error for those streams, even if the connection itself closed cleanly:
114+
if @streams.any? and error.nil?
115+
error = EOFError.new("Connection closed with #{@streams.size} active stream(s)!")
116+
end
117+
112118
@streams.each_value{|stream| stream.close(error)}
113119
@streams.clear
114120

test/protocol/http2/connection.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,68 @@
9797
end
9898
end.to raise_exception(EOFError, message: be =~ /Connection closed/)
9999
end
100+
101+
with "#close" do
102+
it "closes the connection without active streams" do
103+
# No active streams
104+
expect(connection.streams).to be(:empty?)
105+
106+
# Close the connection - should not raise:
107+
connection.close(nil)
108+
109+
expect(connection).to be(:closed?)
110+
end
111+
112+
it "generates an error when closing with active streams" do
113+
# Create an active stream:
114+
stream = Protocol::HTTP2::Stream.new(connection, 1)
115+
connection.streams[1] = stream
116+
117+
expect(stream).to receive(:close) do |error|
118+
expect(error).to be_a(EOFError)
119+
expect(error.message).to be =~ /Connection closed with 1 active stream/
120+
end
121+
122+
# Close the connection without an error:
123+
connection.close(nil)
124+
end
125+
126+
it "passes through the error when closing with active streams and an explicit error" do
127+
# Create an active stream:
128+
stream = Protocol::HTTP2::Stream.new(connection, 1)
129+
connection.streams[1] = stream
130+
131+
custom_error = RuntimeError.new("Connection failed!")
132+
133+
expect(stream).to receive(:close) do |error|
134+
expect(error).to be === custom_error
135+
end
136+
137+
# Close the connection with an explicit error:
138+
connection.close(custom_error)
139+
end
140+
141+
it "generates an error for multiple active streams" do
142+
# Create multiple active streams:
143+
stream1 = Protocol::HTTP2::Stream.new(connection, 1)
144+
stream2 = Protocol::HTTP2::Stream.new(connection, 3)
145+
connection.streams[1] = stream1
146+
connection.streams[3] = stream2
147+
148+
expect(stream1).to receive(:close) do |error|
149+
expect(error).to be_a(EOFError)
150+
expect(error.message).to be =~ /Connection closed with 2 active stream/
151+
end
152+
153+
expect(stream2).to receive(:close) do |error|
154+
expect(error).to be_a(EOFError)
155+
expect(error.message).to be =~ /Connection closed with 2 active stream/
156+
end
157+
158+
# Close the connection without an error:
159+
connection.close(nil)
160+
end
161+
end
100162
end
101163

102164
with "client and server" do

0 commit comments

Comments
 (0)