diff --git a/lib/http/2/connection.rb b/lib/http/2/connection.rb index a7e81b01..435377ea 100644 --- a/lib/http/2/connection.rb +++ b/lib/http/2/connection.rb @@ -656,15 +656,18 @@ def activate_stream(id: nil, **args) # permitted to open. stream.once(:active) { @active_stream_count += 1 } stream.once(:close) do - @streams.delete id @active_stream_count -= 1 # Store a reference to the closed stream, such that we can respond # to any in-flight frames while close is registered on both sides. # References to such streams will be purged whenever another stream # is closed, with a minimum of 15s RTT time window. - @streams_recently_closed.delete_if { |_, v| (Time.now - v) > 15 } @streams_recently_closed[id] = Time.now + to_delete = @streams_recently_closed.select { |_, v| (Time.now - v) > 15 } + to_delete.each do |stream_id| + @streams.delete stream_id + @streams_recently_closed.delete stream_id + end end stream.on(:promise, &method(:promise)) if self.is_a? Server diff --git a/spec/connection_spec.rb b/spec/connection_spec.rb index 388aa8f1..24df95c6 100644 --- a/spec/connection_spec.rb +++ b/spec/connection_spec.rb @@ -543,6 +543,20 @@ end.to raise_error(ProtocolError) end + it 'should not raise an error on frame for a closed stream ID' do + srv = Server.new + srv << CONNECTION_PREFACE_MAGIC + + stream = srv.new_stream + stream.send HEADERS.dup + stream.send DATA.dup + stream.close + + expect do + srv << f.generate(RST_STREAM.dup.merge(stream: stream.id)) + end.to_not raise_error + end + it 'should send GOAWAY frame on connection error' do stream = @conn.new_stream