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: respecting header number limits #15970

Merged
merged 17 commits into from
May 3, 2021

Conversation

alyssawilk
Copy link
Contributor

Respecting upstream and downstream caps on number of headers for HTTP/3

Risk Level: n/a (http/3)
Testing: turned up integration tests
Docs Changes: n/a
Release Notes: n/a
#14829 among others.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Copy link
Contributor

@danzh2010 danzh2010 left a comment

Choose a reason for hiding this comment

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

Thanks for fixing more tests! A few thoughts on the details.

@@ -1600,7 +1600,6 @@ TEST_P(DownstreamProtocolIntegrationTest, ManyRequestHeadersAccepted) {
TEST_P(DownstreamProtocolIntegrationTest, ManyRequestTrailersRejected) {
// QUICHE doesn't limit number of headers.
EXCLUDE_DOWNSTREAM_HTTP3
Copy link
Contributor

Choose a reason for hiding this comment

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

The upstream http3 test failure is irrelevant to this fix right? I doubt current fix works for trailers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah, I should fix that.

@@ -47,12 +47,10 @@ TEST_P(Http2UpstreamIntegrationTest, RouterHeaderOnlyRequestAndResponseNoBuffer)
}

TEST_P(Http2UpstreamIntegrationTest, RouterUpstreamDisconnectBeforeRequestcomplete) {
EXCLUDE_UPSTREAM_HTTP3; // Close loop.
Copy link
Contributor

Choose a reason for hiding this comment

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

How are these tests related to max headers count?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They're not, I was just enabling excluded tests until I found ones that didn't work =P

Comment on lines 48 to 49
static constexpr absl::string_view invalid_underscore = "http3.unexpected_underscore";
static constexpr absl::string_view too_many_http_headers = "http3.too_many_http_headers";
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add/reuse those already defined in Http3ResponseCodeDetailValues? You may need to move it around.

Http::HeaderUtility::HeaderValidationResult result =
validator.validateHeader(entry.first, entry.second);
switch (result) {
case Http::HeaderUtility::HeaderValidationResult::REJECT:
details = invalid_underscore;
Copy link
Contributor

@danzh2010 danzh2010 Apr 14, 2021

Choose a reason for hiding this comment

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

This details is already assigned in server stream's validateHeader().

HeaderValidator& validator) {
std::unique_ptr<T>
quicHeadersToEnvoyHeaders(const quic::QuicHeaderList& header_list, HeaderValidator& validator,
uint32_t max_headers_allowed, absl::string_view& details) {
Copy link
Contributor

@danzh2010 danzh2010 Apr 14, 2021

Choose a reason for hiding this comment

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

Is it because QuicHeaderList doesn't expose size() interface that we need max_headers_allowed to be passed into this function?

I slightly prefer checking it in QUICHE and have something like OnHeadersTooLarge() or simply add QuicHeaderList::size() instead of iterating over the header list again.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

100% prefer checking in QUICHE and rejecting early, vs rejecting late in the game, but I think this is still better than nothing because it protects Envoy filters against too many headers. What do you think about landing this as-is and moving where we enforce once someone on quic-dev adds the knob we'd need?

Copy link
Contributor

Choose a reason for hiding this comment

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

SGTM.

if (headers == nullptr) {
onStreamError(close_connection_upon_invalid_header_);
onStreamError(close_connection_upon_invalid_header_, quic::QUIC_STREAM_INTERNAL_ERROR);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not negotiated in initial SETTINGS. I think it should be QUIC_BAD_APPLICATION_PAYLOAD or at least something else other than QUIC_STREAM_INTERNAL_ERROR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, so the quiche code maps bad application payload to Http::StreamResetReason::ProtocolError which is only for spec violations. We differentiate between envoy rejecting something which it is configured to reject from actual standards violantion by response code (503/502) so we need to have a different code for header limit checks. I don't care which but it has to translate to something which isn't an Envoy ProtocolError

Copy link
Contributor

Choose a reason for hiding this comment

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

How about QUIC_STREAM_EXCESSIVE_LOAD ?

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
HeaderValidator& validator) {
std::unique_ptr<T>
quicHeadersToEnvoyHeaders(const quic::QuicHeaderList& header_list, HeaderValidator& validator,
uint32_t max_headers_allowed, absl::string_view& details) {
Copy link
Contributor

Choose a reason for hiding this comment

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

SGTM.

if (headers == nullptr) {
onStreamError(close_connection_upon_invalid_header_);
onStreamError(close_connection_upon_invalid_header_, quic::QUIC_STREAM_INTERNAL_ERROR);
Copy link
Contributor

Choose a reason for hiding this comment

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

How about QUIC_STREAM_EXCESSIVE_LOAD ?

Comment on lines +253 to +257
if (received_trailers().size() > filterManagerConnection()->maxIncomingHeadersCount()) {
details_ = Http3ResponseCodeDetailValues::too_many_trailers;
onStreamError(close_connection_upon_invalid_header_);
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Same for client stream?

@@ -1622,13 +1617,12 @@ TEST_P(DownstreamProtocolIntegrationTest, ManyRequestTrailersRejected) {
EXPECT_TRUE(response->complete());
EXPECT_EQ("431", response->headers().getStatusValue());
} else {
ASSERT_TRUE(response->waitForReset());
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be reverted?

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Copy link
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

Seems right to me, just one tiny nit

static constexpr absl::string_view remote_refused = "http3.remote_refuse";
// The peer reset the stream.
static constexpr absl::string_view remote_reset = "http3.remote_reset";
// Too many trailers were sent
Copy link
Contributor

Choose a reason for hiding this comment

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

period

.
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
@alyssawilk
Copy link
Contributor Author

Looks like an asan flake in a new test
/wait

danzh2010
danzh2010 previously approved these changes Apr 28, 2021
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
@alyssawilk
Copy link
Contributor Author

woot! period added, merge conflicts sorted, test flake fixed :-)

Copy link
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

Thanks!

@alyssawilk alyssawilk merged commit 6a2e112 into envoyproxy:main May 3, 2021
gokulnair pushed a commit to gokulnair/envoy that referenced this pull request May 5, 2021
Respecting upstream and downstream caps on number of headers for HTTP/3

Risk Level: n/a (http/3)
Testing: turned up integration tests
Docs Changes: n/a
Release Notes: n/a
envoyproxy#14829 among others.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Gokul Nair <gnair@twitter.com>
gokulnair pushed a commit to gokulnair/envoy that referenced this pull request May 6, 2021
Respecting upstream and downstream caps on number of headers for HTTP/3

Risk Level: n/a (http/3)
Testing: turned up integration tests
Docs Changes: n/a
Release Notes: n/a
envoyproxy#14829 among others.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Gokul Nair <gnair@twitter.com>
gokulnair pushed a commit to gokulnair/envoy that referenced this pull request May 6, 2021
Respecting upstream and downstream caps on number of headers for HTTP/3

Risk Level: n/a (http/3)
Testing: turned up integration tests
Docs Changes: n/a
Release Notes: n/a
envoyproxy#14829 among others.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Gokul Nair <gnair@twitter.com>
@alyssawilk alyssawilk deleted the header_limits branch August 18, 2021 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants