diff --git a/source/common/network/connection_impl_base.cc b/source/common/network/connection_impl_base.cc index 71a5fbb5e94ac..46bf98bcdf1fa 100644 --- a/source/common/network/connection_impl_base.cc +++ b/source/common/network/connection_impl_base.cc @@ -50,8 +50,14 @@ void ConnectionImplBase::initializeDelayedCloseTimer() { void ConnectionImplBase::raiseConnectionEvent(ConnectionEvent event) { for (ConnectionCallbacks* callback : callbacks_) { - // TODO(mattklein123): If we close while raising a connected event we should not raise further - // connected events. + // If a previous connected callback closed the connection, don't raise any further connected + // events. There was already recursion raising closed events. We still raise closed events + // to further callbacks because such events are typically used for cleanup. + if (event != ConnectionEvent::LocalClose && event != ConnectionEvent::RemoteClose && + state() != State::Open) { + return; + } + if (callback != nullptr) { callback->onEvent(event); } diff --git a/test/common/network/connection_impl_test.cc b/test/common/network/connection_impl_test.cc index 9ed110871c688..d362401c5881a 100644 --- a/test/common/network/connection_impl_test.cc +++ b/test/common/network/connection_impl_test.cc @@ -334,10 +334,15 @@ TEST_P(ConnectionImplTest, CloseDuringConnectCallback) { EXPECT_TRUE(client_connection_->connecting()); StrictMock added_and_removed_callbacks; - // Make sure removed connections don't get events. + // Make sure removed callbacks don't get events. client_connection_->addConnectionCallbacks(added_and_removed_callbacks); client_connection_->removeConnectionCallbacks(added_and_removed_callbacks); + // Make sure later callbacks don't receive a connected event if an earlier callback closed + // the connection during its callback. + StrictMock later_callbacks; + client_connection_->addConnectionCallbacks(later_callbacks); + std::shared_ptr add_and_remove_filter = std::make_shared>(); @@ -346,6 +351,7 @@ TEST_P(ConnectionImplTest, CloseDuringConnectCallback) { client_connection_->close(ConnectionCloseType::NoFlush); })); EXPECT_CALL(client_callbacks_, onEvent(ConnectionEvent::LocalClose)); + EXPECT_CALL(later_callbacks, onEvent(ConnectionEvent::LocalClose)); read_filter_ = std::make_shared>();