-
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
http3: support Http3Options for downstream #15753
Conversation
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[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.
Nice change!
Once you sort out docs CI, let's check coverage on this one and make sure we've got corner cases tested.
} | ||
|
||
HeaderValidationResult | ||
EnvoyQuicServerStream::checkHeaderNameForUnderscores(const std::string& header_name) { |
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.
can we factor the Http2 code into HeaderUtility or not enough overlap? or maybe at least stick it in the utility directory, unit terst, and we can use when we switch codec libraries.
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 moved this method to HeaderUtility, but using it in h2 codec doesn't save many lines, so I didn't use it there.
return HeaderValidationResult::ACCEPT; | ||
} | ||
|
||
HeaderValidationResult validateContentLength(absl::string_view header_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.
Ditto, consider moving to utility
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
@@ -325,6 +325,10 @@ message HttpConnectionManager { | |||
config.core.v3.Http2ProtocolOptions http2_protocol_options = 9 | |||
[(udpa.annotations.security).configure_for_untrusted_downstream = true]; | |||
|
|||
// Additional HTTP/3 settings that are passed directly to the HTTP/3 codec. | |||
config.core.v3.Http3ProtocolOptions http3_protocol_options = 44 | |||
[(udpa.annotations.security).configure_for_untrusted_downstream = true]; |
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.
@htuch The doc CI fails because this field is annotated with udpa.annotations.security, but doesn't have description in docs/protodoc_manifest.yaml. Do I need to document override_stream_error_on_invalid_http_message, the only field of Http3ProtocolOptions, there? http2_protocol_options doesn't have documentation about its similar fields in protodoc_manifest.yaml.
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 there is anything security related, e.g. buffering, update the example manifest YAML as per offline discussion. If not, feel free to drop the security annotation.
Try hiding the field and see if that fixes docs build - it's probably trying to generate docs for the (not hidden) field refering to the (hidden) proto and having problems. |
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
/retest |
Retrying Azure Pipelines: |
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.
/lgtm api
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[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.
Cool, just a few more nits and I think this one's good to go
Http::HeaderUtility::HeaderValidationResult | ||
validateHeader(const std::string& header_name, absl::string_view header_value) override { | ||
bool override_stream_error_on_invalid_http_message = | ||
http3_options_.has_override_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.
Given we're cloning this, what do you think of just always setting it in initializeAndValidate?
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.
Makes sense, then we don't need to check http3_options_.has_override_stream_error_on_invalid_http_message() here.
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
/retest |
Retrying Azure Pipelines: |
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 really awesome to see this all coming together. A few comments from a quick pass.
/wait
// closed. | ||
static constexpr absl::string_view invalid_http_header = "http3.invalid_header_field"; | ||
// The size of headers (or trailers) exceeded the configured limits. | ||
static constexpr absl::string_view headers_too_large = "http3.headers.too.large"; |
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: it's kind of strange that this one is uses dot separation and the others are using underscores? Can we be consistent? Is this copied from elsewhere?
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 saw http2.invalid.header.field
and thought any error from external library should use .
, 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.
I think this is probably just a typo. IMO I would make it consistent with the others.
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
include/envoy/upstream/upstream.h
Outdated
@@ -995,6 +995,11 @@ class ClusterInfo { | |||
*/ | |||
virtual Http::Http2::CodecStats& http2CodecStats() const PURE; | |||
|
|||
/** | |||
* @return the Http2 Codec Stats. |
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.
* @return the Http2 Codec Stats. | |
* @return the Http3 Codec Stats. |
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.
fixed
ENVOY_CONN_LOG(error, "Attempt to create stream {} before HCM filter is initialized.", *this, | ||
id); | ||
return nullptr; |
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.
Can this actually happen? If it can, can this log spam?
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.
It will be an implementation error if this happens.
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.
OK then please use either ASSERT or ENVOY_BUG depending on what you want to do in terms of providing testing. I don't think kind of error handling makes sense.
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
@@ -333,5 +333,57 @@ bool HeaderUtility::isModifiableHeader(absl::string_view header) { | |||
!absl::EqualsIgnoreCase(header, Headers::get().HostLegacy.get())); | |||
} | |||
|
|||
HeaderUtility::HeaderValidationResult HeaderUtility::checkHeaderNameForUnderscores( |
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.
It kills me that this code is now copied into a third place when we already effectively have it in both the H1 and H2 codec. This is really scary and security sensitive stuff and I feel we shouldn't be making the problem worse (it's in the opposite direction of #10646). Is there any work we can do to share some of this code now? Maybe we can do a different PR to add this helper and call it somehow from both other codecs?
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 don't want to touch any code in production in this PR because that needs feature protection. Once this PR lands, the other two codec can switch to this utility function.
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.
OK fair enough. Can you at least add comments and put TODOs in the other codec places which reference this code and the tracking issue for merging?
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
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.
cc @yanavlasov might be a good starter project for one of the envoy-sec folks
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
I refactored the stream error handling a bit. PTAL |
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 LGTM, will defer to @alyssawilk to review the most recent set of changes and merge. Thank you!
@@ -44,8 +44,10 @@ quic::QuicSpdyStream* EnvoyQuicServerSession::CreateIncomingStream(quic::QuicStr | |||
return nullptr; | |||
} | |||
if (!codec_stats_.has_value() || !http3_options_.has_value()) { | |||
ENVOY_CONN_LOG(error, "Attempt to create stream {} before HCM filter is initialized.", *this, | |||
id); | |||
ENVOY_BUG(false, |
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 you have a test for this ENVOY_BUG? If not just make it an assert.
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.
As long as our implementation is correct, it shouldn't be reached. So I don't know how to trigger it in a meaningful test right now. But I'd like to keep it in production, in case we miss some QUICHE behavior change that could occassionally lead to this in the future.
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.
But how will you know the error checking will work if we reach it in production? :) In general we require testing for ENVOY_BUG type logic, so I would still prefer that you switch this to assert if you can't reasonably test it.
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.
Okay, I added a unit test in envoy_quic_server_session_test to hit this ENVOY_BUG just to check the ENVOY_BUG works as intended in debug and release build.
/retest |
Retrying Azure Pipelines: |
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.
Nice! just one more nit and good to go.
@@ -333,5 +333,57 @@ bool HeaderUtility::isModifiableHeader(absl::string_view header) { | |||
!absl::EqualsIgnoreCase(header, Headers::get().HostLegacy.get())); | |||
} | |||
|
|||
HeaderUtility::HeaderValidationResult HeaderUtility::checkHeaderNameForUnderscores( |
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.
cc @yanavlasov might be a good starter project for one of the envoy-sec folks
if (Http::HeaderUtility::requestHeadersValid(*headers) != absl::nullopt) { | ||
stream_delegate()->OnStreamError(quic::QUIC_HTTP_FRAME_ERROR, "Invalid headers"); | ||
details_ = Http3ResponseCodeDetailValues::invalid_http_header; | ||
onStreamError(!http3_options_.override_stream_error_on_invalid_http_message().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.
what do you think of making this a default argument? If you'd prefer to be explicit I'd mildly prefer a helper function for brevity.
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'd prefer having explicit argument. I changed the function to take an optional bool which if absent means checking override_stream_error_on_invalid_http_message from h3 options.
Signed-off-by: Dan Zhang <[email protected]>
Signed-off-by: Dan Zhang <[email protected]>
@@ -91,7 +91,7 @@ class EnvoyQuicServerStream : public quic::QuicSpdyServerStreamBase, | |||
|
|||
// Either reset the stream or close the connection according to | |||
// close_connection_upon_invalid_header. | |||
void onStreamError(bool close_connection_upon_invalid_header); | |||
void onStreamError(absl::optional<bool> should_close_connection); |
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, please?
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
Signed-off-by: Dan Zhang <[email protected]>
API hasn't changed since the LGTM so I'm going to go ahead and merge. |
Commit Message: allow HCM to config Http3Options and use it with other HCM configs, i.e. max_request_headers_kb and headers_with_underscores_action, to setup QuicHttpServerConnectionImpl. And support these configurations in QUIC. Currently the only Http3Options configuration is override_stream_error_on_invalid_http_message.
Additional Description: added Http3 codec stats. Pass it along with Http3Options and other HCM configs.
Risk Level: low
Testing: enable related tests in quic_protocol_integration_test
Docs Changes: updated docs/root/configuration/http/http_conn_man/response_code_details.rst
Part of #12930 #2557