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

upsteam protocol: add the ability to decide what protocol to use for upstream requests #697

Merged
merged 16 commits into from
Feb 21, 2020

Conversation

junr03
Copy link
Member

@junr03 junr03 commented Feb 20, 2020

Description: this PR adds the ability to decide what protocol to use for upstream requests. Note that this will be unnecessary once ALPN works for upstream requests (#502)
Risk Level: low
Testing: updated unit tests
Docs Changes: updated docs

Fixes #679

Signed-off-by: Jose Nino [email protected]

Jose Nino added 3 commits February 19, 2020 22:11
Signed-off-by: Jose Nino <[email protected]>
Signed-off-by: Jose Nino <[email protected]>
docs/root/api/http.rst Outdated Show resolved Hide resolved
@@ -477,19 +477,38 @@ const LowerCaseString ClusterHeader{"x-envoy-mobile-cluster"};
const std::string BaseCluster = "base";
const std::string BaseWlanCluster = "base_wlan";
const std::string BaseWwanCluster = "base_wwan";
const LowerCaseString H2UpstreamHeader{"x-envoy-mobile-upstream-protocol"};
Copy link
Contributor

Choose a reason for hiding this comment

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

I propose simplifying this with a x-envoy-mobile-force-h2 header. If a header with this name is present assume inferred h2 support, if not, default to h1.

Signed-off-by: Jose Nino <[email protected]>
enum class UpstreamHttpProtocol(internal val stringValue: String) {
HTTP1("http1"),
HTTP2("http2"),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can drop this enum if we just use a single header to force h2 (which is sort of non-standard anyways and only works with known destinations).

Copy link
Contributor

@goaway goaway left a comment

Choose a reason for hiding this comment

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

Nice work! Some suggestions to simplify this a bit.

@goaway
Copy link
Contributor

goaway commented Feb 20, 2020

Another approach would be to have an engine-level configuration option that allows you to specify authorities for which you know you can force h2. In some ways I like that better than a per-request approach, since support for this functionality is non-standard and relatively uncommon, and it avoids inadvertently dispatching requests to destinations that don't support it. It's more a property of the destination (:authority) than it is of the request.

That said, I'm okay with the per-request approach as well (it just means the application will have to implement its own whitelist).

@junr03
Copy link
Member Author

junr03 commented Feb 20, 2020

@goaway thanks for all the comments. I am answering to all of them in aggregate because I think they are all related.

I had originally written this PR with that approach, and actually with something similar to what you suggest below re: central configuration.

However, I moved to this approach for a few reasons:

  1. The enum allows us to express potential expansion of future options: h3, auto (when alpn support lands on upstream connections).
  2. The enum allows us to more easily migrate existing code to those future options without breaking the API if we find ourselves in a future where we care more strictly about API breakage as, hopefully, we see more adopters.
  3. IMO the protocol support of your destination is an application level concern (if the library can't do protocol negotiation for you), and the application developer should tell us that prior knowledge. I am also not a big fan of centralized configuration given at boot time, as you know :)

Right now absence of the header defaults us to http1 per the implementation in the Http::Dispatcher::setDestinationCluster. I can do:

I'd suggest moving this out of the constructor, and adding it via a builder method.

per your suggestion make this setting a less strong requirement. I think this brings us closer to the sentiment of making this engine-level configuration without having to wire more configuration through.

lmk what you think.

Jose Nino added 2 commits February 20, 2020 09:30
fix
Signed-off-by: Jose Nino <[email protected]>
@rebello95
Copy link
Contributor

A couple comments based on the discussions above:

1 (enum vs bool): If http2 were to be the only protocol we need to differentiate going forward, I think a boolean would be fine. However, since http3 is coming in the near future and we probably don't want to make protocol negotiation a hard blocker or to make breaking changes to the interfaces being introduced here, an enum seems like it'd probably make sense.

2 (engine versus request): Adding this information on a per-request basis is a bit more in line with how other configurations are set up now in Envoy Mobile. We moved to the dynamic forward proxy so that we no longer have to specify a fixed set of domains when starting the library, and requiring an http2 whitelist up front when starting up seems like a step backwards as it doesn't allow for new http2 domains to be discovered without restarting the library (not currently supported). Allowing this information to be specified per-request as a builder seems reasonable, especially considering @junr03 is stripping all x-envoy-mobile* headers (keeping the header implementation internal to the library)

Jose Nino added 3 commits February 20, 2020 13:04
Signed-off-by: Jose Nino <[email protected]>
fmt
Signed-off-by: Jose Nino <[email protected]>
Signed-off-by: Jose Nino <[email protected]>
Jose Nino added 2 commits February 20, 2020 13:29
Signed-off-by: Jose Nino <[email protected]>
fix
Signed-off-by: Jose Nino <[email protected]>
Signed-off-by: Jose Nino <[email protected]>
@junr03
Copy link
Member Author

junr03 commented Feb 20, 2020

@rebello95 sorry wasn't ready for a pass. I think I hit all your comments. Let me take a look

Jose Nino added 2 commits February 20, 2020 15:15
fmt
Signed-off-by: Jose Nino <[email protected]>
Signed-off-by: Jose Nino <[email protected]>
rebello95
rebello95 previously approved these changes Feb 20, 2020
@@ -4,13 +4,17 @@ internal fun Request.outboundHeaders(): Map<String, List<String>> {
val retryPolicyHeaders = retryPolicy?.outboundHeaders() ?: emptyMap()

val result = mutableMapOf<String, List<String>>()
result.putAll(headers.filter { entry -> !entry.key.startsWith(":") })
result.putAll(headers.filter { entry -> !(entry.key.startsWith(":") || entry.key.startsWith("x-envoy-mobile"))})
Copy link
Contributor

Choose a reason for hiding this comment

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

Up to you but using this might be more readable: !entry.key.startsWith(":") && !entry.key.startsWith("x-envoy-mobile")

Copy link
Member Author

Choose a reason for hiding this comment

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

I am always ambivalent about which one is more readable. I'll change to kick CI... 💩

Copy link
Contributor

Choose a reason for hiding this comment

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

😭

Signed-off-by: Jose Nino <[email protected]>
Signed-off-by: Michael Rebello <[email protected]>
@junr03 junr03 merged commit 92f9bf2 into master Feb 21, 2020
@junr03 junr03 deleted the h2 branch February 21, 2020 18:13
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.

configuration: option to use h2/http1.1 based on header information
3 participants