Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/common/http/conn_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ RequestDecoder& ConnectionManagerImpl::newStream(ResponseEncoder& response_encod
new_stream->state_.saw_connection_close_ = true;
// Prevent erroneous debug log of closing due to incoming connection close header.
drain_state_ = DrainState::Closing;
} else {
} else if (drain_state_ == DrainState::NotDraining) {
startDrainSequence();
}
ENVOY_CONN_LOG(debug, "max requests per connection reached", read_callbacks_->connection());
Expand Down
29 changes: 29 additions & 0 deletions test/common/http/conn_manager_impl_test_2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,35 @@ TEST_F(HttpConnectionManagerImplTest, ConnectionDurationNoCodec) {
EXPECT_EQ(1U, stats_.named_.downstream_cx_max_duration_reached_.value());
}

// Regression test for https://github.com/envoyproxy/envoy/issues/19045
TEST_F(HttpConnectionManagerImplTest, MaxRequests) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test! Just to make sure I'm clear, does this test fail without the changes to source/common/http/conn_manager_impl.cc? (I assume it does)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it would crash actually, because function startDrainSequence() will be called multiple times, ref: https://github.com/envoyproxy/envoy/blob/main/source/common/http/conn_manager_impl.cc#L1162

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

max_requests_per_connection_ = 1;
codec_->protocol_ = Protocol::Http2;
setup(false, "");

Event::MockTimer* drain_timer = setUpTimer();
EXPECT_CALL(*drain_timer, enableTimer(_, _));

EXPECT_CALL(*codec_, dispatch(_)).WillRepeatedly(Invoke([&](Buffer::Instance&) -> Http::Status {
conn_manager_->newStream(response_encoder_);
return Http::okStatus();
}));

EXPECT_CALL(*codec_, goAway());
EXPECT_CALL(*codec_, shutdownNotice());
EXPECT_CALL(*drain_timer, disableTimer());

// Kick off two requests.
Buffer::OwnedImpl fake_input("hello");
conn_manager_->onData(fake_input, false);
conn_manager_->onData(fake_input, false);
drain_timer->invokeCallback();

EXPECT_EQ(2U, stats_.named_.downstream_cx_max_requests_reached_.value());

conn_manager_->onEvent(Network::ConnectionEvent::RemoteClose);
}

TEST_F(HttpConnectionManagerImplTest, ConnectionDuration) {
max_connection_duration_ = (std::chrono::milliseconds(10));
Event::MockTimer* connection_duration_timer = setUpTimer();
Expand Down
3 changes: 2 additions & 1 deletion test/common/http/conn_manager_impl_test_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan
originalIpDetectionExtensions() const override {
return ip_detection_extensions_;
}
uint64_t maxRequestsPerConnection() const override { return 0; }
uint64_t maxRequestsPerConnection() const override { return max_requests_per_connection_; }

Envoy::Event::SimulatedTimeSystem test_time_;
NiceMock<Router::MockRouteConfigProvider> route_config_provider_;
Expand Down Expand Up @@ -184,6 +184,7 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan
absl::optional<std::string> user_agent_;
uint32_t max_request_headers_kb_{Http::DEFAULT_MAX_REQUEST_HEADERS_KB};
uint32_t max_request_headers_count_{Http::DEFAULT_MAX_HEADERS_COUNT};
uint64_t max_requests_per_connection_{};
absl::optional<std::chrono::milliseconds> idle_timeout_;
absl::optional<std::chrono::milliseconds> max_connection_duration_;
std::chrono::milliseconds stream_idle_timeout_{};
Expand Down