Skip to content

Commit

Permalink
http/1: fix sending overload crash when request is reset
Browse files Browse the repository at this point in the history
Signed-off-by: Boteng Yao <[email protected]>
Signed-off-by: Ryan Northey <[email protected]>
  • Loading branch information
botengyao authored and phlax committed Dec 18, 2024
1 parent e6c5f40 commit dc4cc8f
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 1 deletion.
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ minor_behavior_changes:

bug_fixes:
# *Changes expected to improve the state of the world and are unlikely to have negative effects*
- area: http/1
change: |
Fixes sending overload crashes when HTTP/1 request is reset.
removed_config_or_runtime:
# *Normally occurs at the end of the* :ref:`deprecation period <deprecated>`
Expand Down
4 changes: 4 additions & 0 deletions source/common/http/http1/codec_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,10 @@ Status ServerConnectionImpl::sendProtocolError(absl::string_view details) {
if (active_request_ == nullptr) {
RETURN_IF_ERROR(onMessageBeginImpl());
}

if (resetStreamCalled()) {
return okStatus();
}
ASSERT(active_request_);

active_request_->response_encoder_.setDetails(details);
Expand Down
1 change: 0 additions & 1 deletion source/common/http/http1/codec_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,6 @@ class ServerConnectionImpl : public ServerConnection, public ConnectionImpl {
return *absl::get<RequestHeaderMapPtr>(headers_or_trailers_);
}
void allocHeaders(StatefulHeaderKeyFormatterPtr&& formatter) override {
ASSERT(nullptr == absl::get<RequestHeaderMapPtr>(headers_or_trailers_));
ASSERT(!processing_trailers_);
auto headers = RequestHeaderMapImpl::create(max_headers_kb_, max_headers_count_);
headers->setFormatter(std::move(formatter));
Expand Down
33 changes: 33 additions & 0 deletions test/common/http/http1/codec_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2428,6 +2428,39 @@ TEST_P(Http1ServerConnectionImplTest, LoadShedPointCanCloseConnectionOnDispatchO
EXPECT_TRUE(isEnvoyOverloadError(status));
}

TEST_P(Http1ServerConnectionImplTest, LoadShedPointForAlreadyResetStream) {
InSequence sequence;

Server::MockLoadShedPoint mock_abort_dispatch;
EXPECT_CALL(overload_manager_, getLoadShedPoint(_)).WillOnce(Return(&mock_abort_dispatch));
initialize();

EXPECT_CALL(mock_abort_dispatch, shouldShedLoad()).WillOnce(Return(false));

NiceMock<MockRequestDecoder> decoder;
Http::ResponseEncoder* response_encoder = nullptr;
EXPECT_CALL(callbacks_, newStream(_, _))
.WillOnce(Invoke([&](ResponseEncoder& encoder, bool) -> RequestDecoder& {
response_encoder = &encoder;
return decoder;
}));

Buffer::OwnedImpl request_line_buffer("GET / HTTP/1.1\r\n");
auto status = codec_->dispatch(request_line_buffer);
EXPECT_EQ(0, request_line_buffer.length());

EXPECT_CALL(mock_abort_dispatch, shouldShedLoad()).WillRepeatedly(Return(true));
Buffer::OwnedImpl headers_buffer("final-header: value\r\n\r\n");

// The reset stream can be triggered in the middle of dispatching.
connection_.dispatcher_.post(
[&] { response_encoder->getStream().resetStream(StreamResetReason::LocalReset); });

status = codec_->dispatch(headers_buffer);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(isEnvoyOverloadError(status));
}

TEST_P(Http1ServerConnectionImplTest, LoadShedPointCanCloseConnectionOnDispatchOfContinuingStream) {
Server::MockLoadShedPoint mock_abort_dispatch;
EXPECT_CALL(overload_manager_, getLoadShedPoint(_)).WillOnce(Return(&mock_abort_dispatch));
Expand Down

0 comments on commit dc4cc8f

Please sign in to comment.