Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: split strict_1xx_and_204_response_headers into two settings #15880

Merged
merged 5 commits into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 6 additions & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Minor Behavior Changes
----------------------
*Changes that may cause incompatibilities for some users, but should not for most*

* http: replaced setting `envoy.reloadable_features.strict_1xx_and_204_response_headers` with settings
`envoy.reloadable_features.require_strict_1xx_and_204_response_headers`
(require upstream 1xx or 204 responses to not have Transfer-Encoding or non-zero Content-Length headers) and
`envoy.reloadable_features.send_strict_1xx_and_204_response_headers`
(do not send 1xx or 204 responses with these headers). Both are true by default.

Bug Fixes
---------
*Changes expected to improve the state of the world and are unlikely to have negative effects*
Expand Down
18 changes: 11 additions & 7 deletions source/common/http/http1/codec_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,10 @@ void StreamEncoderImpl::encodeHeadersBase(const RequestOrResponseHeaderMap& head
} else if (connection_.protocol() == Protocol::Http10) {
chunk_encoding_ = false;
} else if (status && (*status < 200 || *status == 204) &&
connection_.strict1xxAnd204Headers()) {
// TODO(zuercher): when the "envoy.reloadable_features.strict_1xx_and_204_response_headers"
// feature flag is removed, this block can be coalesced with the 100 Continue logic above.
connection_.sendStrict1xxAnd204Headers()) {
// TODO(zuercher): when the
// "envoy.reloadable_features.send_strict_1xx_and_204_response_headers" feature flag is
// removed, this block can be coalesced with the 100 Continue logic above.

// For 1xx and 204 responses, do not send the chunked encoding header or enable chunked
// encoding: https://tools.ietf.org/html/rfc7230#section-3.3.1
Expand Down Expand Up @@ -458,8 +459,10 @@ ConnectionImpl::ConnectionImpl(Network::Connection& connection, CodecStats& stat
encode_only_header_key_formatter_(encodeOnlyFormatterFromSettings(settings)),
processing_trailers_(false), handling_upgrade_(false), reset_stream_called_(false),
deferred_end_stream_headers_(false),
strict_1xx_and_204_headers_(Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.strict_1xx_and_204_response_headers")),
require_strict_1xx_and_204_headers_(Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.require_strict_1xx_and_204_response_headers")),
send_strict_1xx_and_204_headers_(Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.send_strict_1xx_and_204_response_headers")),
dispatching_(false), output_buffer_(connection.dispatcher().getWatermarkFactory().create(
[&]() -> void { this->onBelowLowWatermark(); },
[&]() -> void { this->onAboveHighWatermark(); },
Expand Down Expand Up @@ -853,7 +856,8 @@ void ConnectionImpl::dumpState(std::ostream& os, int indent_level) const {
os << spaces << "Http1::ConnectionImpl " << this << DUMP_MEMBER(dispatching_)
<< DUMP_MEMBER(dispatching_slice_already_drained_) << DUMP_MEMBER(reset_stream_called_)
<< DUMP_MEMBER(handling_upgrade_) << DUMP_MEMBER(deferred_end_stream_headers_)
<< DUMP_MEMBER(strict_1xx_and_204_headers_) << DUMP_MEMBER(processing_trailers_)
<< DUMP_MEMBER(require_strict_1xx_and_204_headers_)
<< DUMP_MEMBER(send_strict_1xx_and_204_headers_) << DUMP_MEMBER(processing_trailers_)
<< DUMP_MEMBER(buffered_body_.length());

// Dump header parsing state, and any progress on headers.
Expand Down Expand Up @@ -1279,7 +1283,7 @@ Envoy::StatusOr<ParserStatus> ClientConnectionImpl::onHeadersCompleteBase() {
handling_upgrade_ = true;
}

if (strict_1xx_and_204_headers_ &&
if (require_strict_1xx_and_204_headers_ &&
(parser_->statusCode() < 200 || parser_->statusCode() == 204)) {
if (headers->TransferEncoding()) {
RETURN_IF_ERROR(
Expand Down
5 changes: 3 additions & 2 deletions source/common/http/http1/codec_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class ConnectionImpl : public virtual Connection,
void onUnderlyingConnectionAboveWriteBufferHighWatermark() override { onAboveHighWatermark(); }
void onUnderlyingConnectionBelowWriteBufferLowWatermark() override { onBelowLowWatermark(); }

bool strict1xxAnd204Headers() { return strict_1xx_and_204_headers_; }
bool sendStrict1xxAnd204Headers() { return send_strict_1xx_and_204_headers_; }

// Codec errors found in callbacks are overridden within the http_parser library. This holds those
// errors to propagate them through to dispatch() where we can handle the error.
Expand Down Expand Up @@ -280,7 +280,8 @@ class ConnectionImpl : public virtual Connection,
// HTTP/1 message has been flushed from the parser. This allows raising an HTTP/2 style headers
// block with end stream set to true with no further protocol data remaining.
bool deferred_end_stream_headers_ : 1;
const bool strict_1xx_and_204_headers_ : 1;
const bool require_strict_1xx_and_204_headers_ : 1;
const bool send_strict_1xx_and_204_headers_ : 1;
bool dispatching_ : 1;
bool dispatching_slice_already_drained_ : 1;

Expand Down
3 changes: 2 additions & 1 deletion source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ constexpr const char* runtime_features[] = {
"envoy.reloadable_features.preserve_downstream_scheme",
"envoy.reloadable_features.remove_forked_chromium_url",
"envoy.reloadable_features.require_ocsp_response_for_must_staple_certs",
"envoy.reloadable_features.require_strict_1xx_and_204_response_headers",
"envoy.reloadable_features.return_502_for_upstream_protocol_errors",
"envoy.reloadable_features.strict_1xx_and_204_response_headers",
"envoy.reloadable_features.send_strict_1xx_and_204_response_headers",
"envoy.reloadable_features.tls_use_io_handle_bio",
"envoy.reloadable_features.treat_host_like_authority",
"envoy.reloadable_features.treat_upstream_connect_timeout_as_connect_failure",
Expand Down
8 changes: 4 additions & 4 deletions test/common/http/http1/codec_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2295,7 +2295,7 @@ TEST_F(Http1ClientConnectionImplTest, 204ResponseContentLengthNotAllowed) {
{
TestScopedRuntime scoped_runtime;
Runtime::LoaderSingleton::getExisting()->mergeValues(
{{"envoy.reloadable_features.strict_1xx_and_204_response_headers", "false"}});
{{"envoy.reloadable_features.require_strict_1xx_and_204_response_headers", "false"}});

initialize();

Expand Down Expand Up @@ -2331,7 +2331,7 @@ TEST_F(Http1ClientConnectionImplTest, 204ResponseWithContentLength0) {
{
TestScopedRuntime scoped_runtime;
Runtime::LoaderSingleton::getExisting()->mergeValues(
{{"envoy.reloadable_features.strict_1xx_and_204_response_headers", "false"}});
{{"envoy.reloadable_features.require_strict_1xx_and_204_response_headers", "false"}});

NiceMock<MockResponseDecoder> response_decoder;
Http::RequestEncoder& request_encoder = codec_->newStream(response_decoder);
Expand Down Expand Up @@ -2365,7 +2365,7 @@ TEST_F(Http1ClientConnectionImplTest, 204ResponseTransferEncodingNotAllowed) {
{
TestScopedRuntime scoped_runtime;
Runtime::LoaderSingleton::getExisting()->mergeValues(
{{"envoy.reloadable_features.strict_1xx_and_204_response_headers", "false"}});
{{"envoy.reloadable_features.require_strict_1xx_and_204_response_headers", "false"}});

initialize();

Expand Down Expand Up @@ -2467,7 +2467,7 @@ TEST_F(Http1ClientConnectionImplTest, 101ResponseTransferEncodingNotAllowed) {
{
TestScopedRuntime scoped_runtime;
Runtime::LoaderSingleton::getExisting()->mergeValues(
{{"envoy.reloadable_features.strict_1xx_and_204_response_headers", "false"}});
{{"envoy.reloadable_features.require_strict_1xx_and_204_response_headers", "false"}});

initialize();

Expand Down