-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
UHV: Fix response status checks #27125
Conversation
Signed-off-by: Yan Avlasov <yavlasov@google.com>
// Non-informational headers are non-1xx OR 101-SwitchingProtocols, since 101 implies that | ||
// further proxying is on an upgrade path. | ||
received_noninformational_headers_ = | ||
!CodeUtility::is1xx(status) || status == enumToInt(Http::Code::SwitchingProtocols); |
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.
why don't we have he same problem for the other codecs?
would it makes more sense to have isSpecial1xx handle these cases?
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.
Good point. Both balsa and EnvoyQuicClientStream validate status, so it does not reach UHV. I will work on fixing this. Balsa fix will need to wait, since Bence is OOO.
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 have moved the :status
header checks for H/2 and H/3 codecs into UHV when it is enabled. For H/1 codec it is a lot more difficult to move status validation in the response line out of the low level parser (http-parser and Balsa), as it will require changing parser API and a few other spots where parser itself is using the code. This may become more tractable once http-parser is decommissioned.
I think keeping status validation in H/1 parser for now is ok, as it just reduces visibility into protocol errors if status is malformed. When the plumbing for the parser error codes into reset reason strings is finished it will reduce this shortcoming.
Signed-off-by: Yan Avlasov <yavlasov@google.com>
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 good. A couple of small comments.
} else { | ||
response_decoder_.decodeHeaders(std::move(headers), sendEndStream()); | ||
} | ||
} else { |
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.
nit: Let's use early return to save a level of nesting:
if (!status_opt.has_value()) {
// In case the status is invalid or missing, the response_decoder_.decodeHeaders() will fail the
// request
response_decoder_.decodeHeaders(std::move(headers), sendEndStream());
return;
}
const uint64_t status = status_opt.value();
...
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.
Done.
@@ -1879,13 +1879,6 @@ TEST_P(ProtocolIntegrationTest, 304WithBody) { | |||
} | |||
|
|||
TEST_P(ProtocolIntegrationTest, OverflowingResponseCode) { | |||
#ifdef ENVOY_ENABLE_UHV |
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.
Woo hoo!
@@ -547,6 +546,31 @@ void ConnectionImpl::ClientStreamImpl::decodeHeaders() { | |||
} else { | |||
response_decoder_.decodeHeaders(std::move(headers), sendEndStream()); | |||
} | |||
#else | |||
// in UHV mode the :status header at this point can be malformed, as it is validated |
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.
nit: "in" => "In"
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.
Done
// represented as their HTTP/1 forms, regardless of the HTTP version used. | ||
// Therefore, these need to be transformed into their HTTP/1 form. | ||
|
||
// in UHV mode the :status header at this point can be malformed, as it is validated |
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.
nit: "in" => "In"
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.
Done
if (optional_status.has_value()) { | ||
const uint64_t status = optional_status.value(); | ||
if (Http::CodeUtility::is1xx(status)) { | ||
// These are Informational 1xx headers, not the actual response headers. |
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.
Does this need to check enumToInt(Http::Code::SwitchingProtocols), too?
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.
101 Switching protocols
is invalid for H/2 and H/3, since they do not support upgrades, and have the extended CONNECT which uses 200 status.
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, agreed. But I'm wondering if we need to detect this code and explicitly error out, since it's forbidden. Do we have an integration test for 101 Switching protocols
over H3 (with and without UHV)?
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.
This is a good question. The standard does not say that it is malformed, only that it is not supported https://www.rfc-editor.org/rfc/rfc9113#name-the-upgrade-header-field . I'm unsure if it needs to be treated as a protocol error by Envoy. Also not sure what effect it will have on H/3 by calling set_headers_decompressed(false);
Thanks for pointing this out. I've filed #29071 (and left comment in code) since it is a bigger issue that needs separate look.
Signed-off-by: Yan Avlasov <yavlasov@google.com>
Signed-off-by: Yan Avlasov <yavlasov@google.com>
Commit Message:
Change the code in H/2 and H/3 codecs that needs valid
:status
value before the header map was validated by UHV to not expect the:status
to be valid. If:status
is invalid the response is rejected when it is checked by UHV in the CodecClient.For H/1 codec the status validation remains in the low level parser as it is a much larger change to move it to UHV. This reduces visibility into protocol errors due to malformed status (i.e. it is impossible to see the specific status value that caused the failure), however it will be mitigated once parser error reasons are plumbed into the reset reason strings that are logged in the access log.
Additional Description:
For H/1 codec it is a lot more difficult to move status validation in the response line out of the low level parser (http-parser and Balsa), as it will require changing parser API and a few other spots where parser itself is using the code. This may become more tractable once http-parser is decommissioned.
I think keeping status validation in H/1 parser for now is ok, as it just reduces visibility into protocol errors if status is malformed. When the plumbing for the parser error codes into reset reason strings is finished it will reduce this shortcoming.
Risk Level: Low. Build flag protected
Testing: Unit Tests
Docs Changes: N/A
Release Notes: N/A
Platform Specific Features: N/A