diff --git a/quic/api/QuicSocket.h b/quic/api/QuicSocket.h index 1e717f265..3a820d032 100644 --- a/quic/api/QuicSocket.h +++ b/quic/api/QuicSocket.h @@ -131,6 +131,12 @@ class QuicSocket { StreamId, StreamGroupId) noexcept {} + /** + * Invoked when a given stream has been closed and its state reaped by + * the transport. After this point no operations can be done on the stream. + */ + virtual void onStreamStateReaped(StreamId) noexcept {} + /** * Invoked when a stream receives a StopSending frame from a peer. * The application should reset the stream as part of this callback. diff --git a/quic/api/QuicTransportBase.cpp b/quic/api/QuicTransportBase.cpp index 523c06f91..ef2d195b5 100644 --- a/quic/api/QuicTransportBase.cpp +++ b/quic/api/QuicTransportBase.cpp @@ -2611,6 +2611,9 @@ void QuicTransportBase::checkForClosedStream() { getClosingStream(folly::to(*itr))); } conn_->streamManager->removeClosedStream(*itr); + if (connCallback_) { + connCallback_->onStreamStateReaped(*itr); + } maybeSendStreamLimitUpdates(*conn_); if (readCbIt != readCallbacks_.end()) { readCallbacks_.erase(readCbIt); diff --git a/quic/api/test/Mocks.h b/quic/api/test/Mocks.h index 46f663a1f..2647e7f83 100644 --- a/quic/api/test/Mocks.h +++ b/quic/api/test/Mocks.h @@ -123,6 +123,7 @@ class MockConnectionCallback : public QuicSocket::ConnectionCallback { onNewUnidirectionalStreamInGroup, (StreamId, StreamGroupId), (noexcept)); + MOCK_METHOD((void), onStreamStateReaped, (StreamId), (noexcept)); MOCK_METHOD( (void), onStopSending, diff --git a/quic/api/test/QuicTransportBaseTest.cpp b/quic/api/test/QuicTransportBaseTest.cpp index 917860863..3579d7391 100644 --- a/quic/api/test/QuicTransportBaseTest.cpp +++ b/quic/api/test/QuicTransportBaseTest.cpp @@ -1743,6 +1743,7 @@ TEST_P(QuicTransportImplTestBase, CloseStreamAfterReadError) { transport->closeStream(stream1); EXPECT_CALL(readCb1, readError(stream1, IsError(LocalErrorCode::NO_ERROR))); + EXPECT_CALL(connCallback, onStreamStateReaped(stream1)); transport->driveReadCallbacks(); EXPECT_FALSE(transport->transportConn->streamManager->streamExists(stream1));