Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3b0cebf
HCM: guard Envoy from removal of cirical response headers.
mathetake Mar 25, 2021
16a9c78
Add test for checkRequired{Request,Response}Headers
mathetake Mar 25, 2021
0571faa
Fix typo
mathetake Mar 25, 2021
0fd4855
review
mathetake Mar 26, 2021
3e0b74a
Make codec return the status
mathetake Mar 26, 2021
928717c
Fix assertion
mathetake Mar 26, 2021
52f9319
Fix head request crash
mathetake Mar 26, 2021
9f4628d
Fix typo
mathetake Mar 26, 2021
f7d37b8
Merge remote-tracking branch 'origin/main' into status-header
mathetake Mar 26, 2021
7fca42d
Add maybeEndDecode test
mathetake Mar 26, 2021
0dafb70
Simplify
mathetake Mar 26, 2021
5c564ad
Add codec test
mathetake Mar 26, 2021
59cc65d
Fix comment
mathetake Mar 26, 2021
719c1be
Add http2 integration test
mathetake Mar 28, 2021
ce54947
Add http integration test
mathetake Mar 28, 2021
16d93ff
Add 101continue test
mathetake Mar 29, 2021
e4d8e9f
onFirstDownstreamTxByteSent after encoding
mathetake Mar 29, 2021
7f19036
Merge remote-tracking branch 'origin/main' into status-header
mathetake Mar 29, 2021
747211c
use RELEASE_ASSERT and add comments
mathetake Mar 30, 2021
017e9c7
fix typo
mathetake Mar 30, 2021
a979014
Moved tests to ProtocolIntegrationTest matrix
mathetake Mar 30, 2021
af9865a
tidy up
mathetake Mar 30, 2021
e25c790
checkRequiredResponseHeaders on quic server stream encoder
mathetake Mar 30, 2021
e6dd0ca
Merge remote-tracking branch 'origin/main' into status-header
mathetake Mar 31, 2021
4a4a181
Fix upstreamed test
mathetake Mar 31, 2021
7421efd
Revert the change for QUIC
mathetake Mar 31, 2021
e51dbc9
Merge remote-tracking branch 'origin/main' into status-header
mathetake Apr 1, 2021
8434064
Revert reverted change to QUIC
mathetake Apr 2, 2021
efdc243
Fix tests
mathetake Apr 2, 2021
7093416
Merge remote-tracking branch 'origin/main' into status-header
mathetake Apr 6, 2021
b91f23b
Revert bad merge
mathetake Apr 7, 2021
1034e00
Tidy up messages
mathetake Apr 7, 2021
a0b8b3a
Add @return comments
mathetake Apr 7, 2021
e8fd6d9
RELEASE_ASSERT -> ASSERT
mathetake Apr 7, 2021
174e51a
Fix ASSERT
mathetake Apr 7, 2021
0c8c649
Merge remote-tracking branch 'origin/main' into status-header
mathetake Apr 8, 2021
c7eda3c
Split FilterRemovedRequiredHeaders to reseponse/request
mathetake Apr 8, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ Below are the list of reasons the HttpConnectionManager or Router filter may sen
duration_timeout, The max connection duration was exceeded.
direct_response, A direct response was generated by the router filter.
filter_chain_not_found, The request was rejected due to no matching filter chain.
filter_removed_required_headers, The request was rejected in the filter manager because a configured filter removed required headers.
filter_removed_required_request_headers, The request was rejected in the filter manager because a configured filter removed required request headers.
filter_removed_required_response_headers, The response was rejected in the filter manager because a configured filter removed required response headers or these values were invalid (e.g. overflown).
internal_redirect, The original stream was replaced with an internal redirect.
low_version, The HTTP/1.0 or HTTP/0.9 request was rejected due to HTTP/1.0 support not being configured.
maintenance_mode, The request was rejected by the router filter because the cluster was in maintenance mode.
Expand Down
8 changes: 5 additions & 3 deletions include/envoy/http/codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,18 @@ class ResponseEncoder : public virtual StreamEncoder {
/**
* Encode 100-Continue headers.
* @param headers supplies the 100-Continue header map to encode.
* @return indicates the result of encoding and has Http::StatusCode::Ok for success.
*/
virtual void encode100ContinueHeaders(const ResponseHeaderMap& headers) PURE;
virtual Http::Status encode100ContinueHeaders(const ResponseHeaderMap& headers) PURE;

/**
* Encode headers, optionally indicating end of stream. Response headers must
* have a valid :status set.
* have a valid :status set
* @param headers supplies the header map to encode.
* @param end_stream supplies whether this is a header only response.
* @return indicates the result of encoding and has Http::StatusCode::Ok for success.
*/
virtual void encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) PURE;
virtual Http::Status encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) PURE;

/**
* Encode trailers. This implicitly ends the stream.
Expand Down
6 changes: 4 additions & 2 deletions include/envoy/stream_info/stream_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,11 @@ struct ResponseCodeDetailValues {
// The original stream was replaced with an internal redirect.
const std::string InternalRedirect = "internal_redirect";
// The request was rejected because configured filters erroneously removed required headers.
const std::string FilterRemovedRequiredHeaders = "filter_removed_required_headers";
const std::string FilterRemovedRequiredRequestHeaders = "filter_removed_required_request_headers";
const std::string FilterRemovedRequiredResponseHeaders =
"filter_removed_required_response_headers";
// Changes or additions to details should be reflected in
// docs/root/configuration/http/http_conn_man/response_code_details_details.rst
// docs/root/configuration/http/http_conn_man/response_code_details.rst
};

using ResponseCodeDetails = ConstSingleton<ResponseCodeDetailValues>;
Expand Down
35 changes: 26 additions & 9 deletions source/common/http/conn_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -901,8 +901,11 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapPtr&& he
request_headers_->Expect()->value() == Headers::get().ExpectValues._100Continue.c_str()) {
// Note in the case Envoy is handling 100-Continue complexity, it skips the filter chain
// and sends the 100-Continue directly to the encoder.
chargeStats(continueHeader());
response_encoder_->encode100ContinueHeaders(continueHeader());
const auto& continue_headers = continueHeader();
const auto status = response_encoder_->encode100ContinueHeaders(continue_headers);
// We must make sure static `continue_headers` is valid in its content and encoding not fail.
ASSERT(status.ok());
chargeStats(continue_headers);
// Remove the Expect header so it won't be handled again upstream.
request_headers_->removeExpect();
}
Expand Down Expand Up @@ -1334,13 +1337,15 @@ void ConnectionManagerImpl::ActiveStream::encode100ContinueHeaders(
ConnectionManagerUtility::mutateResponseHeaders(response_headers, request_headers_.get(),
connection_manager_.config_, EMPTY_STRING);

// Count both the 1xx and follow-up response code in stats.
chargeStats(response_headers);

ENVOY_STREAM_LOG(debug, "encoding 100 continue headers via codec:\n{}", *this, response_headers);

// Now actually encode via the codec.
response_encoder_->encode100ContinueHeaders(response_headers);
const auto status = response_encoder_->encode100ContinueHeaders(response_headers);
// encode100ContinueHeaders is always called with valid headers soon after parsing so must be OK.
ASSERT(status.ok());

// Count both the 1xx and follow-up response code in stats.
chargeStats(response_headers);
}

void ConnectionManagerImpl::ActiveStream::encodeHeaders(ResponseHeaderMap& headers,
Expand Down Expand Up @@ -1456,14 +1461,26 @@ void ConnectionManagerImpl::ActiveStream::encodeHeaders(ResponseHeaderMap& heade
}
}

chargeStats(headers);

ENVOY_STREAM_LOG(debug, "encoding headers via codec (end_stream={}):\n{}", *this, end_stream,
headers);

// Now actually encode via the codec.
const auto status = response_encoder_->encodeHeaders(headers, end_stream);
if (!status.ok()) {
// This branch can happen when a misbehaving filter chain removed critical headers or set
// malformed header values.
// Also the bad http response status from upstream over HTTP2/3 (e.g. overflown status value)
// reaches here.
const auto request_headers = requestHeaders();
sendLocalReply(
request_headers.has_value() && Grpc::Common::isGrpcRequestHeaders(request_headers.ref()),
Http::Code::BadGateway, status.message(), nullptr, absl::nullopt,
absl::StrCat(StreamInfo::ResponseCodeDetails::get().FilterRemovedRequiredResponseHeaders,
"{", status.message(), "}"));
return;
}
filter_manager_.streamInfo().onFirstDownstreamTxByteSent();
response_encoder_->encodeHeaders(headers, end_stream);
chargeStats(headers);
}

void ConnectionManagerImpl::ActiveStream::encodeData(Buffer::Instance& data, bool end_stream) {
Expand Down
2 changes: 2 additions & 0 deletions source/common/http/conn_manager_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,14 @@ class ConnectionManagerImpl : Logger::Loggable<Logger::Id::http>,
}

void endStream() override {
// This assertion must satisfy and be guarded by callers with streamEnded().
ASSERT(!state_.codec_saw_local_complete_);
state_.codec_saw_local_complete_ = true;
filter_manager_.streamInfo().onLastDownstreamTxByteSent();
request_response_timespan_->complete();
connection_manager_.doEndStream(*this);
}
bool streamEnded() override { return state_.codec_saw_local_complete_; }
void onDecoderFilterBelowWriteBufferLowWatermark() override;
void onDecoderFilterAboveWriteBufferHighWatermark() override;
void upgradeFilterChainCreated() override {
Expand Down
13 changes: 9 additions & 4 deletions source/common/http/filter_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1011,8 +1011,10 @@ void FilterManager::maybeContinueEncoding(
void FilterManager::encodeHeaders(ActiveStreamEncoderFilter* filter, ResponseHeaderMap& headers,
bool end_stream) {
// See encodeHeaders() comments in include/envoy/http/filter.h for why the 1xx precondition holds.
ASSERT(!CodeUtility::is1xx(Utility::getResponseStatus(headers)) ||
Utility::getResponseStatus(headers) == enumToInt(Http::Code::SwitchingProtocols));
ASSERT(HeaderUtility::checkRequiredResponseHeaders(headers).ok() &&
(!CodeUtility::is1xx(Utility::getResponseStatus(headers)) ||
Utility::getResponseStatus(headers) == enumToInt(Http::Code::SwitchingProtocols)));

filter_manager_callbacks_.resetIdleTimer();
disarmRequestTimeout();

Expand Down Expand Up @@ -1065,8 +1067,8 @@ void FilterManager::encodeHeaders(ActiveStreamEncoderFilter* filter, ResponseHea
}

const bool modified_end_stream = (end_stream && continue_data_entry == encoder_filters_.end());
state_.non_100_response_headers_encoded_ = true;
filter_manager_callbacks_.encodeHeaders(headers, modified_end_stream);
state_.non_100_response_headers_encoded_ = true;
Copy link
Copy Markdown
Member Author

@mathetake mathetake Mar 26, 2021

Choose a reason for hiding this comment

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

this change is necessary since there's a check of non_100_response_headers_encoded_ != false in the local reply and it makes sense to keep that assertion.

maybeEndEncode(modified_end_stream);

if (!modified_end_stream) {
Expand Down Expand Up @@ -1247,7 +1249,10 @@ void FilterManager::encodeTrailers(ActiveStreamEncoderFilter* filter,
}

void FilterManager::maybeEndEncode(bool end_stream) {
if (end_stream) {
// filter_manager_callbacks_.streamEnded() returns True here when the codec failed to encode
// headers due to the lack of required response headers, and filter_manager_callbacks already sent
// the local reply and ended the stream by itself. So in that case this function must be no-op.
if (end_stream && !filter_manager_callbacks_.streamEnded()) {
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.

where are we now calling maybeEndEncode after the stream already ended?
I'm not sure but my concern is we may have a problem we should be solving before we reach this point.

Copy link
Copy Markdown
Member Author

@mathetake mathetake Apr 8, 2021

Choose a reason for hiding this comment

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

that is when the local reply is sent (due to the missing requires response headers) in the ConnectionManagerImpl::ActiveStream::encodeHeaders as filter_manager_callbacks.encodeHeaders, and the filter manager then reaches maybeEndEncode.

filter_manager_callbacks_.encodeHeaders(headers, modified_end_stream);
state_.non_100_response_headers_encoded_ = true;
maybeEndEncode(modified_end_stream);

But yeah I think this made the code a little bit more complex so maybe we should just return the status from filter_manager_callbacks and send the LocalReply just before maybeEndEncode in FilterManager..

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.

WDYT?

Copy link
Copy Markdown
Contributor

@alyssawilk alyssawilk Apr 8, 2021

Choose a reason for hiding this comment

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

Yeah, I think I'd rather have the HCM encodeHeaders return a status, so the filter manager knows something has gone awry.
I think it's useful to retain checks in maybeEndEncode happening once to catch other weird corner case bugs.
cc @snowp for a second opinion.

filter_manager_callbacks_.endStream();
}
}
Expand Down
5 changes: 5 additions & 0 deletions source/common/http/filter_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,11 @@ class FilterManagerCallbacks {
*/
virtual void endStream() PURE;

/**
* Called to check if endStream() is called by filter manager.
*/
virtual bool streamEnded() PURE;

/**
* Called when the stream write buffer is no longer above the low watermark.
*/
Expand Down
12 changes: 11 additions & 1 deletion source/common/http/header_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ bool HeaderUtility::shouldCloseConnection(Http::Protocol protocol,
return false;
}

Http::Status HeaderUtility::checkRequiredHeaders(const Http::RequestHeaderMap& headers) {
Http::Status HeaderUtility::checkRequiredRequestHeaders(const Http::RequestHeaderMap& headers) {
if (!headers.Method()) {
return absl::InvalidArgumentError(
absl::StrCat("missing required header: ", Envoy::Http::Headers::get().Method.get()));
Expand All @@ -322,6 +322,16 @@ Http::Status HeaderUtility::checkRequiredHeaders(const Http::RequestHeaderMap& h
return Http::okStatus();
}

Http::Status HeaderUtility::checkRequiredResponseHeaders(const Http::ResponseHeaderMap& headers) {
const HeaderEntry* header = headers.Status();
uint64_t response_code;
if (!header || !absl::SimpleAtoi(headers.getStatusValue(), &response_code)) {
return absl::InvalidArgumentError(
absl::StrCat("missing required header: ", Envoy::Http::Headers::get().Status.get()));
}
return Http::okStatus();
}

bool HeaderUtility::isRemovableHeader(absl::string_view header) {
return (header.empty() || header[0] != ':') &&
!absl::EqualsIgnoreCase(header, Headers::get().HostLegacy.get());
Expand Down
11 changes: 9 additions & 2 deletions source/common/http/header_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,20 @@ class HeaderUtility {
*/
static void stripPortFromHost(RequestHeaderMap& headers, absl::optional<uint32_t> listener_port);

/* Does a common header check ensuring required headers are present.
/* Does a common header check ensuring required request headers are present.
* Required request headers include :method header, :path for non-CONNECT requests, and
* host/authority for HTTP/1.1 or CONNECT requests.
* @return Status containing the result. If failed, message includes details on which header was
* missing.
*/
static Http::Status checkRequiredHeaders(const Http::RequestHeaderMap& headers);
static Http::Status checkRequiredRequestHeaders(const Http::RequestHeaderMap& headers);

/* Does a common header check ensuring required response headers are present.
* Current required request headers only includes :status.
* @return Status containing the result. If failed, message includes details on which header was
* missing.
*/
static Http::Status checkRequiredResponseHeaders(const Http::ResponseHeaderMap& headers);

/**
* Returns true if a header may be safely removed without causing additional
Expand Down
14 changes: 8 additions & 6 deletions source/common/http/http1/codec_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ void StreamEncoderImpl::encodeFormattedHeader(absl::string_view key, absl::strin
}
}

void ResponseEncoderImpl::encode100ContinueHeaders(const ResponseHeaderMap& headers) {
Http::Status ResponseEncoderImpl::encode100ContinueHeaders(const ResponseHeaderMap& headers) {
ASSERT(headers.Status()->value() == "100");
encodeHeaders(headers, false);
return encodeHeaders(headers, false);
}

void StreamEncoderImpl::encodeHeadersBase(const RequestOrResponseHeaderMap& headers,
Expand Down Expand Up @@ -366,11 +366,12 @@ const Network::Address::InstanceConstSharedPtr& StreamEncoderImpl::connectionLoc
static const char RESPONSE_PREFIX[] = "HTTP/1.1 ";
static const char HTTP_10_RESPONSE_PREFIX[] = "HTTP/1.0 ";

void ResponseEncoderImpl::encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) {
Http::Status ResponseEncoderImpl::encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) {
started_response_ = true;

// The contract is that client codecs must ensure that :status is present.
ASSERT(headers.Status() != nullptr);
// The contract is that client codecs must ensure that required headers are present.
RETURN_IF_ERROR(HeaderUtility::checkRequiredResponseHeaders(headers));

uint64_t numeric_status = Utility::getResponseStatus(headers);

if (connection_.protocol() == Protocol::Http10 && connection_.supportsHttp10()) {
Expand All @@ -394,14 +395,15 @@ void ResponseEncoderImpl::encodeHeaders(const ResponseHeaderMap& headers, bool e
}

encodeHeadersBase(headers, absl::make_optional<uint64_t>(numeric_status), end_stream, false);
return Http::okStatus();
}

static const char REQUEST_POSTFIX[] = " HTTP/1.1\r\n";

Status RequestEncoderImpl::encodeHeaders(const RequestHeaderMap& headers, bool end_stream) {
// Required headers must be present. This can only happen by some erroneous processing after the
// downstream codecs decode.
RETURN_IF_ERROR(HeaderUtility::checkRequiredHeaders(headers));
RETURN_IF_ERROR(HeaderUtility::checkRequiredRequestHeaders(headers));

const HeaderEntry* method = headers.Method();
const HeaderEntry* path = headers.Path();
Expand Down
4 changes: 2 additions & 2 deletions source/common/http/http1/codec_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ class ResponseEncoderImpl : public StreamEncoderImpl, public ResponseEncoder {
bool startedResponse() { return started_response_; }

// Http::ResponseEncoder
void encode100ContinueHeaders(const ResponseHeaderMap& headers) override;
void encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) override;
Http::Status encode100ContinueHeaders(const ResponseHeaderMap& headers) override;
Http::Status encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) override;
void encodeTrailers(const ResponseTrailerMap& trailers) override { encodeTrailersBase(trailers); }

bool streamErrorOnInvalidHttpMessage() const override {
Expand Down
18 changes: 11 additions & 7 deletions source/common/http/http2/codec_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "common/http/header_utility.h"
#include "common/http/headers.h"
#include "common/http/http2/codec_stats.h"
#include "common/http/status.h"
#include "common/http/utility.h"
#include "common/runtime/runtime_features.h"

Expand Down Expand Up @@ -172,9 +173,10 @@ void ConnectionImpl::StreamImpl::buildHeaders(std::vector<nghttp2_nv>& final_hea
});
}

void ConnectionImpl::ServerStreamImpl::encode100ContinueHeaders(const ResponseHeaderMap& headers) {
Http::Status
ConnectionImpl::ServerStreamImpl::encode100ContinueHeaders(const ResponseHeaderMap& headers) {
ASSERT(headers.Status()->value() == "100");
encodeHeaders(headers, false);
return encodeHeaders(headers, false);
}

void ConnectionImpl::StreamImpl::encodeHeadersBase(const std::vector<nghttp2_nv>& final_headers,
Expand All @@ -201,7 +203,7 @@ Status ConnectionImpl::ClientStreamImpl::encodeHeaders(const RequestHeaderMap& h
bool end_stream) {
// Required headers must be present. This can only happen by some erroneous processing after the
// downstream codecs decode.
RETURN_IF_ERROR(HeaderUtility::checkRequiredHeaders(headers));
RETURN_IF_ERROR(HeaderUtility::checkRequiredRequestHeaders(headers));
// This must exist outside of the scope of isUpgrade as the underlying memory is
// needed until encodeHeadersBase has been called.
std::vector<nghttp2_nv> final_headers;
Expand Down Expand Up @@ -231,10 +233,10 @@ Status ConnectionImpl::ClientStreamImpl::encodeHeaders(const RequestHeaderMap& h
return okStatus();
}

void ConnectionImpl::ServerStreamImpl::encodeHeaders(const ResponseHeaderMap& headers,
bool end_stream) {
// The contract is that client codecs must ensure that :status is present.
ASSERT(headers.Status() != nullptr);
Http::Status ConnectionImpl::ServerStreamImpl::encodeHeaders(const ResponseHeaderMap& headers,
bool end_stream) {
// The contract is that client codecs must ensure that required headers are present.
RETURN_IF_ERROR(HeaderUtility::checkRequiredResponseHeaders(headers));

// This must exist outside of the scope of isUpgrade as the underlying memory is
// needed until encodeHeadersBase has been called.
Expand All @@ -248,6 +250,8 @@ void ConnectionImpl::ServerStreamImpl::encodeHeaders(const ResponseHeaderMap& he
buildHeaders(final_headers, headers);
}
encodeHeadersBase(final_headers, end_stream);

return Http::okStatus();
}

void ConnectionImpl::StreamImpl::encodeTrailersBase(const HeaderMap& trailers) {
Expand Down
4 changes: 2 additions & 2 deletions source/common/http/http2/codec_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,8 @@ class ConnectionImpl : public virtual Connection,
void createPendingFlushTimer() override;

// ResponseEncoder
void encode100ContinueHeaders(const ResponseHeaderMap& headers) override;
void encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) override;
Http::Status encode100ContinueHeaders(const ResponseHeaderMap& headers) override;
Http::Status encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) override;
void encodeTrailers(const ResponseTrailerMap& trailers) override {
encodeTrailersBase(trailers);
}
Expand Down
2 changes: 1 addition & 1 deletion source/common/quic/envoy_quic_client_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Http::Status EnvoyQuicClientStream::encodeHeaders(const Http::RequestHeaderMap&
bool end_stream) {
// Required headers must be present. This can only happen by some erroneous processing after the
// downstream codecs decode.
RETURN_IF_ERROR(Http::HeaderUtility::checkRequiredHeaders(headers));
RETURN_IF_ERROR(Http::HeaderUtility::checkRequiredRequestHeaders(headers));

ENVOY_STREAM_LOG(debug, "encodeHeaders: (end_stream={}) {}.", *this, end_stream, headers);
local_end_stream_ = end_stream;
Expand Down
12 changes: 9 additions & 3 deletions source/common/quic/envoy_quic_server_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#include <memory>

#include "common/http/status.h"

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
Expand Down Expand Up @@ -64,12 +66,15 @@ EnvoyQuicServerStream::EnvoyQuicServerStream(
stats, http3_options),
headers_with_underscores_action_(headers_with_underscores_action) {}

void EnvoyQuicServerStream::encode100ContinueHeaders(const Http::ResponseHeaderMap& headers) {
Http::Status
EnvoyQuicServerStream::encode100ContinueHeaders(const Http::ResponseHeaderMap& headers) {
ASSERT(headers.Status()->value() == "100");
encodeHeaders(headers, false);
return encodeHeaders(headers, false);
}

void EnvoyQuicServerStream::encodeHeaders(const Http::ResponseHeaderMap& headers, bool end_stream) {
Http::Status EnvoyQuicServerStream::encodeHeaders(const Http::ResponseHeaderMap& headers,
bool end_stream) {
RETURN_IF_ERROR(Http::HeaderUtility::checkRequiredResponseHeaders(headers));
ENVOY_STREAM_LOG(debug, "encodeHeaders (end_stream={}) {}.", *this, end_stream, headers);
// QUICHE guarantees to take all the headers. This could cause infinite data to
// be buffered on headers stream in Google QUIC implementation because
Expand All @@ -83,6 +88,7 @@ void EnvoyQuicServerStream::encodeHeaders(const Http::ResponseHeaderMap& headers
local_end_stream_ = end_stream;
SendBufferMonitor::ScopedWatermarkBufferUpdater updater(this, this);
WriteHeaders(envoyHeadersToSpdyHeaderBlock(headers), end_stream, nullptr);
return Http::okStatus();
}

void EnvoyQuicServerStream::encodeData(Buffer::Instance& data, bool end_stream) {
Expand Down
Loading