-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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: stream error on invalid HTTP messaging for HTTP/1 #11884
http: stream error on invalid HTTP messaging for HTTP/1 #11884
Conversation
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, good start! Next you'll want to make your new function available from the Http Connection Manager, since it only has the abstract APIs. You could also start on the codec tests paralleling mine for HTTP/2 for which value takes precedence. right now you can obviously only test yours being on and off, but once my PR lands we can do the full 4x combinations.
api/envoy/api/v2/core/protocol.proto
Outdated
@@ -142,6 +142,10 @@ message Http1ProtocolOptions { | |||
// - Not a response to a HEAD request. | |||
// - The content length header is not present. | |||
bool enable_trailers = 5; | |||
|
|||
// [#not-implemented-hide:] | |||
// Overrides envoy's behavior on invalid HTTP messaging configured in the hcm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you'll want to ref link to the actual hcm field - you can crib that notation from my PR as well :-)
@@ -128,8 +131,13 @@ class ResponseEncoderImpl : public StreamEncoderImpl, public ResponseEncoder { | |||
void encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) override; | |||
void encodeTrailers(const ResponseTrailerMap& trailers) override { encodeTrailersBase(trailers); } | |||
|
|||
absl::optional<bool> streamErrorOnInvalidHTTPMessage() override { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HTTP -> Http ?
…o, extend codec interface so that hcm can pull this new option from the codec. Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
…ng for HTTP/1.1 Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
26b7a81
to
2d6cac8
Compare
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
@alyssawilk I think this is ready for another look. One question though: do we want to update the old code path for sending errors from the codec as well ( envoy/source/common/http/http1/codec_impl.cc Line 969 in bfab9ed
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good!
I think your PR needs a format check, and it'd be good to have an integration test Luckily I think Piotr wrote most of one for you
DownstreamProtocolIntegrationTest,.InvalidContentLengthAllowed
tests that for http/2 the config override results in stream reset, for HTTP/1 it results in disconnect.
You will need to change it to set the HTTP/1.1 override as well, and perhaps change the invalid message from one with invalid content length (which will trigger before the headers are complete) to some other messaging error - maybe remove the host?
@@ -157,6 +157,11 @@ message Http1ProtocolOptions { | |||
// - Not a response to a HEAD request. | |||
// - The content length header is not present. | |||
bool enable_trailers = 5; | |||
|
|||
// Allows invalid HTTP messaging. When this option is disabled (default), then Envoy will terminate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, when this option is disabled, Envoy will terminate the connection, but I think you should remove reference to default behavior, since the default behavior is actually to ignore this field and use the HCM value.
!connection_manager_.config_.streamErrorOnInvalidHttpMessaging() && | ||
code == Http::Code::BadRequest && connection_manager_.codec_->protocol() < Protocol::Http2) { | ||
code == Http::Code::BadRequest && connection_manager_.codec_->protocol() < Protocol::Http2 && | ||
!Utility::streamErrorOnInvalidHttpMessage( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this function is only used in one place, I'd be mildly inclined to make this utility in an unnamed namespace in the cc file, and unit test the HCM by setting explicit configs. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping?
absl::optional<bool> stream_error_on_invalid_http_message_; | ||
|
||
absl::optional<bool> streamErrorOnInvalidHttpMessage() const override { | ||
return stream_error_on_invalid_http_message_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to latch this, or can we just return parent_.stream_error_on_invalid_http_messaging_ here?
Also let's make sure this and the HTTP/1.1 function have unit tests, even if they're pretty trivial.
Signed-off-by: Erica Manno <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks this LGTM modulo the comment about clarifying what is supported downstream and upstream. @alyssawilk is back from vacation so I will defer to her for final review. Thank you!
include/envoy/http/codec.h
Outdated
// Behaviour on invalid HTTP messaging: | ||
// - if set and true, the HTTP/1.1 connection is left open (where possible) | ||
// - if set and false, the HTTP/1.1 connection is terminated | ||
// - if not set, fall back to the HCM behaviour on invalid HTTP messaging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think it would be good to call this out more in the comments and the proto documentation. The proto is a generic message that is used for both upstream and downstream, so I think it would be good to clarify that it only applies right now for downstream?
Signed-off-by: Erica Manno <[email protected]>
@alyssawilk ping: any further feedback beside what Matt said? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh ugh I'm so sorry, I thought I sent these comments out last week! thanks for the ping and sorry for the lag and late cross-codec-behavior comment
// open where possible. | ||
// If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging | ||
// <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.stream_error_on_invalid_http_message>`; | ||
// if not set, this is overridden by any HCM :ref:`stream_error_on_invalid_http_messaging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can leave out the "if not set" because the sentence above makes it clear that otherwise the HCM value is used.
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
@alyssawilk no worries! I have reworked the code a bit to take into account your cross-codec-behavior comment. Please take another look when you get a chance :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks for your patience with the last minute thought! sending a few more ideas your way
@@ -164,7 +164,7 @@ message Http1ProtocolOptions { | |||
// open where possible. | |||
// If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging | |||
// <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.stream_error_on_invalid_http_message>`; | |||
// if not set, this is overridden by any HCM :ref:`stream_error_on_invalid_http_messaging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, for any ocnfusion, I was suggesting taking out this line and following.
include/envoy/http/codec.h
Outdated
@@ -147,7 +147,7 @@ class ResponseEncoder : public virtual StreamEncoder { | |||
* Indicates whether invalid HTTP messaging should be handled with a stream error or a connection | |||
* error; if value is missing, then HCM drives behaviour on invalid HTTP messaging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update comment to remove "if value is missing, then HCM drives behaviour on invalid HTTP messaging."
Utility::parseHttp1Settings(const envoy::config::core::v3::Http1ProtocolOptions& config, | ||
bool hcm_stream_error_set, | ||
const Protobuf::BoolValue& hcm_stream_error) { | ||
Http1Settings ret = parseHttp1Settings(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this function just return the override_stream_error if set, and if not returns the HCM value no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, isn't it the case that when this function is called the HCM value hasn't been initialised to its default value yet (in case of no explicit configuration)? See
envoy/source/extensions/filters/network/http_connection_manager/config.cc
Lines 233 to 234 in c555587
stream_error_on_invalid_http_messaging_( | |
PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, stream_error_on_invalid_http_message, false)), |
I guess we could move that initialisation so that it happens earlier, and then simplify this function as per your comment. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I see what your concern is, but I believe (and you can unit test) that the default value for BoolValue is false, and the default for stream_error_on_invalid_http_messaging_ is false, so you should just be able to set the default to config.override_stream_error_on_invalid_http_message().value() even if it's not set.
Signed-off-by: Erica Manno <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great - just a few final comments :-)
Utility::parseHttp1Settings(const envoy::config::core::v3::Http1ProtocolOptions& config, | ||
bool hcm_stream_error_set, | ||
const Protobuf::BoolValue& hcm_stream_error) { | ||
Http1Settings ret = parseHttp1Settings(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I see what your concern is, but I believe (and you can unit test) that the default value for BoolValue is false, and the default for stream_error_on_invalid_http_messaging_ is false, so you should just be able to set the default to config.override_stream_error_on_invalid_http_message().value() even if it's not set.
@@ -2131,6 +2131,63 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithInvalidRequest) { | |||
conn_manager_->onData(fake_input, false); | |||
} | |||
|
|||
class StreamErrorOnInvalidHttpMessageTest : public HttpConnectionManagerImplTest { | |||
public: | |||
void sendInvalidRequestAndVerifyConnectionState(bool codec_stream_error, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these are always opposite I think you can just have one boolean, stream_error_in_invalid_messaging and make sure that the connection is terminated if !stream_error
// HTTP message (missing :host header) | ||
TEST_P(DownstreamProtocolIntegrationTest, | ||
Http1ConnectionIsLeftOpenIfHCMStreamErrorIsFalseAndOverrideIsTrue) { | ||
if (downstreamProtocol() == Http::CodecClient::Type::HTTP2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can move these to
TEST_P(IntegrationTest,...)
and then it won't kick off a test run for downstream HTTP/2
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
Signed-off-by: Erica Manno <[email protected]>
@alyssawilk ping: any further comments or feedback? Would love to wrap this up this week if possible :-) |
over to Matt for API sign off. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, especially for the lengthy review cycle. This stuff is tricky to get right!
In this PR:
Helps with http: require stream_error_on_invalid_http_messaging to be set for every HCM #9846.
Risk Level: high (HCM changes)
Testing: new unit tests and integration tests
Docs Changes: n/a
Release Notes: updated
Runtime guard: envoy.reloadable_features.hcm_stream_error_on_invalid_message (already introduced by #11748)