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

http3: support Http3Options for downstream #15753

Merged
merged 20 commits into from
Apr 6, 2021

Conversation

danzh2010
Copy link
Contributor

@danzh2010 danzh2010 commented Mar 30, 2021

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

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/envoy/.
API shepherd assignee is @htuch
CC @envoyproxy/api-watchers: FYI only for changes made to api/envoy/.

🐱

Caused by: #15753 was opened by danzh2010.

see: more, trace.

@danzh2010 danzh2010 changed the title quiche: support Http3Options for downstream http3: support Http3Options for downstream Mar 30, 2021
Copy link
Contributor

@alyssawilk alyssawilk left a 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) {
Copy link
Contributor

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.

Copy link
Contributor Author

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.

source/common/quic/envoy_quic_server_stream.h Show resolved Hide resolved
return HeaderValidationResult::ACCEPT;
}

HeaderValidationResult validateContentLength(absl::string_view header_value,
Copy link
Contributor

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

Copy link
Contributor Author

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];
Copy link
Contributor Author

@danzh2010 danzh2010 Mar 30, 2021

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.

Copy link
Member

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.

@alyssawilk
Copy link
Contributor

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.
Also please main merge to pick up the Matt moving-all-the-things PR

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #15753 (comment) was created by @danzh2010.

see: more, trace.

@alyssawilk alyssawilk self-assigned this Mar 31, 2021
Copy link
Member

@htuch htuch left a 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 <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Copy link
Contributor

@alyssawilk alyssawilk left a 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

source/common/http/header_utility.h Outdated Show resolved Hide resolved
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() &&
Copy link
Contributor

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?

Copy link
Contributor Author

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.

source/common/quic/quic_filter_manager_connection_impl.h Outdated Show resolved Hide resolved
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
alyssawilk
alyssawilk previously approved these changes Apr 1, 2021
@danzh2010
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #15753 (comment) was created by @danzh2010.

see: more, trace.

Copy link
Member

@mattklein123 mattklein123 left a 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";
Copy link
Member

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?

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -995,6 +995,11 @@ class ClusterInfo {
*/
virtual Http::Http2::CodecStats& http2CodecStats() const PURE;

/**
* @return the Http2 Codec Stats.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* @return the Http2 Codec Stats.
* @return the Http3 Codec Stats.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Comment on lines 47 to 49
ENVOY_CONN_LOG(error, "Attempt to create stream {} before HCM filter is initialized.", *this,
id);
return nullptr;
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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(
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Contributor

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 <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Contributor Author

I refactored the stream error handling a bit. PTAL

mattklein123
mattklein123 previously approved these changes Apr 4, 2021
Copy link
Member

@mattklein123 mattklein123 left a 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,
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

@repokitteh-read-only repokitteh-read-only bot removed the api label Apr 4, 2021
@danzh2010
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #15753 (comment) was created by @danzh2010.

see: more, trace.

Copy link
Contributor

@alyssawilk alyssawilk left a 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(
Copy link
Contributor

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());
Copy link
Contributor

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.

Copy link
Contributor Author

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 <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

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

update comment, please?

Copy link
Contributor Author

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 <danzh@google.com>
@alyssawilk
Copy link
Contributor

API hasn't changed since the LGTM so I'm going to go ahead and merge.

@alyssawilk alyssawilk merged commit c93d486 into envoyproxy:main Apr 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants