-
Notifications
You must be signed in to change notification settings - Fork 5.5k
http3: adding connect support #17877
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
Changes from 2 commits
64cb5a6
3924a76
3679898
fa2c3a8
e40d6b4
65e8a4f
9297851
5988a7e
ec4bfa4
8c06cdd
49ad7fa
3f4ee6c
6b3bb58
ed3cbff
fe54c45
ba1234c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -339,6 +339,12 @@ Http::Status HeaderUtility::checkRequiredRequestHeaders(const Http::RequestHeade | |
| return absl::InvalidArgumentError( | ||
| absl::StrCat("missing required header: ", Envoy::Http::Headers::get().Host.get())); | ||
| } | ||
| if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.validate_connect") && | ||
| headers.Path() && !headers.Protocol()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like scheme is also required, interestingly. Should we check for that too? o On requests that contain the :protocol pseudo-header field, the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From this code it looks like we allow CONNECT here without protocol (and hence without path). Is that right? If so, my earlier assumption that we only supported 8841 is definitely wrong :)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. scheme is default required for all HTTP/3 so I believe is validated elsewhere.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The :scheme header is prohibited from vanilla CONNECT requests in HTTP/3: Is something validating that :scheme is present for CONNECT requests elsewhere? If so, is that perhaps incorrect?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Protocol and path MUST both be sent for extended CONNECT. So if one is sent but not the other, yes, I think that's invalid,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed and tested. |
||
| // Path header should only be present for CONNECT for upgrade style CONECT. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo, should be CONNECT
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| return absl::InvalidArgumentError( | ||
| absl::StrCat("missing required header: ", Envoy::Http::Headers::get().Host.get())); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, nice catch. |
||
| } | ||
| } else { | ||
| if (!headers.Path()) { | ||
| // :path header must be present for non-CONNECT requests. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -155,7 +155,9 @@ void EnvoyQuicServerStream::OnInitialHeadersComplete(bool fin, size_t frame_len, | |
| onStreamError(close_connection_upon_invalid_header_); | ||
| return; | ||
| } | ||
| if (Http::HeaderUtility::requestHeadersValid(*headers) != absl::nullopt) { | ||
| if (Http::HeaderUtility::requestHeadersValid(*headers) != absl::nullopt || | ||
| Http::HeaderUtility::checkRequiredRequestHeaders(*headers) != Http::okStatus() || | ||
| (headers->Protocol() && !http3_options_.allow_upgrade_connect())) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could be reading this wrong, but it looks like if the request method is CONNECT but it doesn't have the :protocol header, we will consider the request valid. Is that right?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah CONNECT either has to have no path, or path + protocol. https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/upgrades |
||
| details_ = Http3ResponseCodeDetailValues::invalid_http_header; | ||
| onStreamError(absl::nullopt); | ||
| return; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,6 +94,7 @@ constexpr const char* runtime_features[] = { | |
| "envoy.reloadable_features.unquote_log_string_values", | ||
| "envoy.reloadable_features.upstream_host_weight_change_causes_rebuild", | ||
| "envoy.reloadable_features.use_observable_cluster_name", | ||
| "envoy.reloadable_features.validate_connect", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be documented somewhere? |
||
| "envoy.reloadable_features.vhds_heartbeats", | ||
| "envoy.reloadable_features.wasm_cluster_name_envoy_grpc", | ||
| "envoy.reloadable_features.upstream_http2_flood_checks", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -643,7 +643,7 @@ void ConfigHelper::addClusterFilterMetadata(absl::string_view metadata_yaml, | |
|
|
||
| void ConfigHelper::setConnectConfig( | ||
| envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& hcm, | ||
| bool terminate_connect, bool allow_post) { | ||
| bool terminate_connect, bool allow_post, bool http3) { | ||
| auto* route_config = hcm.mutable_route_config(); | ||
| ASSERT_EQ(1, route_config->virtual_hosts_size()); | ||
| auto* route = route_config->mutable_virtual_hosts(0)->mutable_routes(0); | ||
|
|
@@ -671,6 +671,9 @@ void ConfigHelper::setConnectConfig( | |
|
|
||
| hcm.add_upgrade_configs()->set_upgrade_type("CONNECT"); | ||
| hcm.mutable_http2_protocol_options()->set_allow_connect(true); | ||
| if (http3) { | ||
| hcm.mutable_http3_protocol_options()->set_allow_upgrade_connect(true); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like the h2 and h3 option are named differently: Would it make sense to use the same name in both places?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the H2 option is (sadly) misnamed because HTTP/2 allows standard connect without a special knob, and just disallows the upgrade style connect. |
||
| } | ||
| } | ||
|
|
||
| void ConfigHelper::applyConfigModifiers() { | ||
|
|
||
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.
To confirm my interpretation of this config this only allows RFC 8441 style CONNECT which requires both :path and :protocol. It does not enable RFC 7540 style CONNECT (without :path or :protocol). RFC 8441 requires SETTINGS_ENABLE_CONNECT_PROTOCOL be received by the client before sending the extended CONNECT. Presumably Envoy sends this setting? I wonder if we should call out the RFCs here (and possibly in the corresponding HTTP/2 config). What do you think?
All of this being said, RFC 8841 is an extension to HTTP/2 not an extension to HTTP/3. HTTP/2 settings are not automatically valid for HTTP/3.
I think we need to write a doc describing how to do port RFC 8841 to HTTP/2. (Similar docs need to be written for the ORIGIN and ALT_SVC frames, fwiw. https://www.ietf.org/archive/id/draft-bishop-httpbis-altsvc-quic-01.html ) In particular we need to define a value for SETTINGS_ENABLE_CONNECT_PROTOCOL in HTTP/3. I've started that process here:
https://github.com/RyanTheOptimist/httpbis-h3-websockets/blob/main/draft-hamilton-httpbis-h3-websockets.md
and will work with httpbis folks to push this forward.
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 we could just land standard CONNECT support but I think folks are going to want websocket over h3 if they have it for H2.
I'll link to the H2 spec and your draft and tag it alpha. Alternately I can just add support for standard connect (block anything with path, regardless of protocol) and wait on the RFC. thoughts?
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 either approach is fine, but I share your intuition that folks will want H3 websockets if they have H2 websockets. I think linking to the draft and tagging it as alpha is fine. BTW, here's the IETF url for the draft https://datatracker.ietf.org/doc/html/draft-hamilton-httpbis-h3-websockets if you want to link to it.