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

Add incoming and outgoing handlers for HTTP/2 #129

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tschneidereit
Copy link
Member

This PR adds the interfaces http2-incoming-handler and http2-outgoing-handler and the world http2-proxy, which exports and imports those interfaces, respectively.

Additionally, it adds the variant types.http-version and a method http-version()-> http-version to both types.incoming-request and types.incoming-response.

The motivation for these additions is that there are use cases that require specifically HTTP/2 to be used for both incoming and outgoing connections, so wasi-http should provide a way to enforce this requirement.

Most notably, gRPC is specified as layered on top of HTTP/2, not HTTP more generally, so attempting to transport it over HTTP/1.1 or HTTP/3 would fail.

An alternative API design would be to add a method each to types.{ outgoing-request, outgoing-response } to opt in to HTTP/2. I think the design proposed here is better in two regards:

  1. It makes static analysis of an application's intent much easier: instead of having to check for use of a set-http-version method on outgoing requests/responses and then making assumptions about which version that might opt in to, the normal validations for targeted worlds is sufficient.
  2. It matches what other APIs are doing and should make it easier to implement them in terms of wasi-http.

As an example of the latter point, Go's standard library uses the same approach: Go's net/http package transparently supports multiple HTTP versions, and explicitly opting in to HTTP/2 is possible using the x/net/http2 package.

Similarly, the Rust ecosystem's Hyper crate supports automatically choosing an HTTP version, or using http1 or http2 modules specifically.

In both cases, the other types in the HTTP APIs remain the same, as in this proposal.

This PR adds the interfaces `http2-incoming-handler` and `http2-outgoing-handler` and the world `http2-proxy`, which exports and imports those interfaces, respectively.

Additionally, it adds the variant `types.http-version` and a method `http-version()-> http-version` to both `types.incoming-request` and `types.incoming-response`.

The motivation for these additions is that there are use cases that require specifically HTTP/2 to be used for both incoming and outgoing connections, so wasi-http should provide a way to enforce this requirement.

Most notably, gRPC is specified as layered on top of HTTP/2, not HTTP more generally, so attempting to transport it over HTTP/1.1 or HTTP/3 would fail.

An alternative API design would be to add a method  each to `types.{ outgoing-request, outgoing-response }` to opt in to HTTP/2. I think the design proposed here is better in two regards:

1. It makes static analysis of an application's intent much easier: instead of having to check for use of a `set-http-version` method on outgoing requests/responses and then making assumptions about which version that might opt in to, the normal validations for targeted worlds is sufficient.
2. It matches what other APIs are doing and should make it easier to implement them in terms of wasi-http.

As an example of the latter point, Go's standard library uses the same approach: Go's [`net/http` package](https://pkg.go.dev/net/http@go1.23.0#hdr-HTTP_2) transparently supports multiple HTTP versions, and explicitly opting in to HTTP/2 is possible using the [`x/net/http2` package](https://pkg.go.dev/golang.org/x/net/http2).

Similarly, the Rust ecosystem's Hyper crate supports [automatically choosing](https://docs.rs/hyper/latest/hyper/server/conn/index.html) an HTTP version, or using `http1` or `http2` modules specifically.

In both cases, the other types in the HTTP APIs remain the same, as in this proposal.

Signed-off-by: Till Schneidereit <till@tillschneidereit.net>
@tschneidereit
Copy link
Member Author

I'd be very surprised if nobody had any good arguments for any tweaks to the API at all, so I'll hold off on updating the ABI files until the API is more final

HTTP11,
HTTP2,
HTTP3
other(string)
Copy link

@pavelsavara pavelsavara Sep 6, 2024

Choose a reason for hiding this comment

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

Adding HTTP4 to the enum would be API breaking change.

There is similar discussion about TSL version, with regards to future compatibility.
WebAssembly/wasi-sockets#104 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I saw that. My intuition is that HTTP versions are introduced rarely enough that we'll have solved this by the time HTTP/4 comes around, but I'm happy to change it if people feel that that's not right.

@pavelsavara
Copy link

pavelsavara commented Sep 6, 2024

An alternative API design would be to add a method each to types.{ outgoing-request, outgoing-response } to opt in to HTTP/2. I think the design proposed here is better in two regards:

C# could opt in into HTTP version dynamically via HttpRequestMessage.Version

Does this proposal mean we would have to import both interfaces for all dotnet apps ?
We are not able to prove that app uses only HTTP2 at compile time.

@tschneidereit
Copy link
Member Author

Does this proposal mean we would have to import both interfaces for all dotnet apps ?
We are not able to prove that app uses only HTTP2 at compile time.

That's a very good question. I don't know enough about .Net's configuration options, but maybe it'd be possible to make the inclusion optional by configuring things such that the requisite package isn't linked in?

@tschneidereit
Copy link
Member Author

We are not able to prove that app uses only HTTP2 at compile time.

And I assume you're also not able to prove that an app doesn't use HTTP/2? Because That seems strictly more important, as every host that can support the http2-* interfaces can also support the current interfaces, and the overhead involved in providing both should be trivial.

@pavelsavara
Copy link

The value of the Version could be " application configuration data" per endpoint, so that kills the static analysis benefit. For us and also any interpreted language I think.

The new interface/methods is breaking change, because we will need new version of the host.
The new method set-http-version is also breaking change, so no difference there.

But I think new-interface-per-feature approach is fragmenting the otherwise nice API surface.

Because we are going to break API compat again in p3 for promises, we could reconcile it back to one interface then.
There we would maybe have unification of outgoing vs incoming too.

@pavelsavara
Copy link

pavelsavara commented Sep 6, 2024

I realized that it's more complex. There is also HttpRequestMessage.VersionPolicy which defines what Version means.
RequestVersionExact, RequestVersionOrHigher, RequestVersionOrLower
dotnet default seems to be HTTP2+RequestVersionOrLower

Do I understand correctly that for HTTP2+RequestVersionExact and HTTP2+RequestVersionOrHigher I would call the new interface ?
And that for HTTP11+RequestVersionExact or HTTP11+RequestVersionOrLower I would call the old API ?

Essentially the new interface partially expressing the policy ?

Could I use the new interface to talk to HTTP11 only server ?

@tschneidereit
Copy link
Member Author

But I think new-interface-per-feature approach is fragmenting the otherwise nice API surface.

My thinking is that explicitly separating the interface is actively desirable in some, though unfortunately not all cases. Specifically for APIs that express the same kind of separation, as Go's standard library and Hyper do, the separation allows us to provide implementations of these APIs that only pull in wasi:http/http2-* if the HTTP/2-specific functionality is used.

It's unfortunate that this doesn't work for all languages, including C#, but I don't think that's a reason to go with a design that doesn't make it work for any languages.

Because we are going to break API compat again in p3 for promises, we could reconcile it back to one interface then. There we would maybe have unification of outgoing vs incoming too.

As described above, I think there is value in having multiple interfaces. If we get to a consensus that this assumption is wrong, then I think we should indeed go with something more like Joel's proposal and not have the API proposed here to begin with.

@tschneidereit
Copy link
Member Author

I realized that it's more complex. There is also HttpRequestMessage.VersionPolicy which defines what Version means. RequestVersionExact, RequestVersionOrHigher, RequestVersionOrLower dotnet default seems to be HTTP2+RequestVersionOrLower

That is more complex indeed :(

Do I understand correctly that for HTTP2+RequestVersionExact and HTTP2+RequestVersionOrHigher I would call the new interface ? And that for HTTP11+RequestVersionExact or HTTP11+RequestVersionOrLower I would call the old API ?

I think the best fit for the currently existing wasi-http interface is dotnet's HTTP11+RequestVersionOrHigher, and my proposal would add a way to support exactly dotnet's HTTP2+RequestVersionExact, but not HTTP2+RequestVersionOrHigher.

I think we could add support for both HTTP11+RequestVersionExact and HTTP2+RequestVersionOrHigher by making two changes to the proposal:

  1. change the expected semantics of the http2-* interfaces to by default match HTTP2+RequestVersionOrHigher
  2. add a prevent-http-version-upgrade method to types.{outgoing-request, outgoing-response} that changes the behavior to HTTP*+RequestVersionExact

Basically, one would express a requirement for a minimum http version by choosing the right interface (and I'd be happy to add http3-* versions to the proposal to fill in the API), and would express a requirement to use exactly that http version instead of potentially upgrading by calling prevent-http-version-upgrade.

This would allow components to continue targeting environments that can't provide HTTP/2 semantics (such as fetch in the browser) while also ensuring pre-deployment errors for components that couldn't work in an environment because they really do need HTTP/2 support. (All this of course only assuming the toolchain is able to produce components that can target the http2-* interfaces when needed, and not target them otherwise.)

Essentially the new interface partially expressing the policy ?

I think that's correct, with slight differences as described above.

Could I use the new interface to talk to HTTP11 only server ?

With the suggested changes above, it would be possible to use the non-http2 interface this way.

@yoshuawuyts
Copy link
Member

yoshuawuyts commented Sep 6, 2024

Heh, yeah I have to say I was also a little surprised to see this PR. I feel like this raises a question about what the scope should be for wasi:http. At least conceptually I would expect it to be a Component-native translation of IETF RFC 9110 with maybe some additional features like IETF RFC 9111.

What this PR seems to be adding is a version of the wasi:http which moves away from a single, shared, generic interface to also include protocol-specific HTTP interfaces. More specifically IETF RFC 9113, but this would probably also open the door for interfaces for IETF RFC 9112 and IETF RFC 9114. Following my gut feeling here: creating protocol-specific interfaces doesn't feel like it fits the scope of what I expect wasi:http to be?

But I realize there are also practical limitations in the component model. And so if this PR is intended to be a stepping stone to eventually consolidate on that more general interface, I definitely see the value in that. I don't want perfect to be the enemy of good - but I also want to make sure that we don't end up with various incompatible, protocol-specific, diverging interfaces. So I guess I'm also curious about what we want the eventual end-state to be for wasi:http?

edit: Intuitively, I feel like asking a question like: "Does this HTTP server make exclusive use of HTTP/2?" feels like an instance of a more general "feature detection" feature or pattern. When targeting the web, I can see us asking similar questions. For example: "Does this HTTP client persist cookies?" is another thing people will probably want to ask. Idk, maybe there's something along those lines we might be able to improve instead?

/// The implementor of this function must write a response to the
/// `response-outparam` before returning, or else the caller will respond
/// with an error on its behalf.
@since(version = 0.2.2)
Copy link
Member

@yoshuawuyts yoshuawuyts Sep 6, 2024

Choose a reason for hiding this comment

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

This PR implements an interface which has not yet gone through a WASI SG vote, and until it has it can't be included as part of a WASI release. Can you please change the @since gates to @unstable gates instead?:

Suggested change
@since(version = 0.2.2)
@unstable(feature = "http-http2")

Once this PR lands, please also file a PR on the WASI proposal tracker so we can track this extension as part of the WASI phase process. Full details on the process for adding interfaces to existing WASI proposals can be found here. Thanks!

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh of course yes: I'll make sure to change this before this lands—if it ever does. Thank you!

@Mossaka
Copy link
Collaborator

Mossaka commented Sep 9, 2024

I agree with @yoshuawuyts that we should keep wasi-http a generic and protocol-agnostic interface, as stated in the Goals section of readme

"The proposal intends to abstract over HTTP version and transport protocol choices (such as HTTP/1.1, HTTP/2 or HTTP/3)"

With that said, I do see values to a static representation of http/2 for gRPC. What if we make a separate wasi-http2 proposal and it is intended to be used as a low level interface and can be consumed by the hypothetical wasi-grpc interfaces. The description in the PR pointed out Go's http2 package and I read the description which stated:

"This package is low-level and intended to be used directly by very few people. Most users will use it indirectly through the automatic use by the net/http package (from Go 1.6 and later)"

Essentially, I am proposing to move http/2 to a separate proposal, outside of wasi-http. Will wasi-http supports http/2? Yes. but it's scope should remain to be the semantics of http.

@tschneidereit
Copy link
Member Author

@yoshuawuyts and @Mossaka thank you for much for the thoughtful feedback here!

I'll lay out my reasoning and how I see various constraints and design goals in a bit more detail below, but before I do: I think @Mossaka's proposal is right, and that this really should be a separate wasi:http2 proposal. And in hindsight I think this follows from my own arguments in the original PR description :)

Now for the constraints and design goals.

Assumed constraints

  1. There is at least one use case, gRPC, that has a hard requirement to ensure that incoming and outgoing requests are HTTP/2 specifically.
  2. There are some environments, notably including web browsers with the fetch API, that are incapable of implementing that requirement.
  3. [This is a new realization I had] There is at least one other use case, applications that can choose whether to use gRCP or gRPC-web, that wants to dynamically detect whether HTTP/2 is available and adjust behavior based on that.
  4. Most abstractly, "HTTP is special". By that I mean that we don't really get to design an API that feels like the ideal fit for WASI or the component model. Instead, we have to design an API that reflects the reality of both how the internet works and of how HTTP is used in language ecosystems. @pavelsavara's explanations of how dotnet presents protocol choices is a good example of this.

Assumed design goals

  1. We want to enable developers (of applications, but in this case more likely libraries and frameworks) to express the first requirement above directly instead of deriving it from the presence of some kind of indirect signal and hope that we get it right.
  2. We want environments that'll be unable to successfully run the application to fail as early as possible, instead of dynamically at some arbitrary point.

My conclusions from these constraints and goals

Based on this, I think we should have a strong signal to use exactly HTTP/2, and that signal should be statically analyzable, not dynamic. But we should also have a way to dynamically detect whether HTTP/2 can be used.

For the former, I had shied away from making an entire new proposal because it seemed like that proposal would be too small to be worth it. But I now realize that @Mossaka is right and that yes, it makes sense for this to be wasi:http2. This can then be used directly in language ecosystems that enable it, allowing for good static analyzability of the resulting components.

For the latter, I think it does make sense to add support for expressing preferred protocol choices and being able to check them dynamically as part of wasi:http.

Crucially though, I think an application making use of gRPC without being able to fall back to gRPC-web should wherever possible make use of wasi:http2 instead of this dynamic facility, because it'll never successfully run in environments that can't implement wasi:http2.

edit: Intuitively, I feel like asking a question like: "Does this HTTP server make exclusive use of HTTP/2?" feels like an instance of a more general "feature detection" feature or pattern. When targeting the web, I can see us asking similar questions. For example: "Does this HTTP client persist cookies?" is another thing people will probably want to ask. Idk, maybe there's something along those lines we might be able to improve instead?

@yoshuawuyts on this particular, as described above I think we're dealing with a much more fundamental feature here. The cookies example you give seems useful to query, but won't make a binary difference on whether the entire way the component is communicating is implementable in the host environment or not.

But I realize there are also practical limitations in the component model. And so if this PR is intended to be a stepping stone to eventually consolidate on that more general interface, I definitely see the value in that. I don't want perfect to be the enemy of good - but I also want to make sure that we don't end up with various incompatible, protocol-specific, diverging interfaces. So I guess I'm also curious about what we want the eventual end-state to be for wasi:http?

I hope based on the above it's clear that I don't think what I'm proposing is a stepping stone. Nor do I think it's working around any limitations of the component model. I don't love the proposed solution here in the least, and would love for someone to come up with a better one, but given the constraints above I can't see how that would involve a single wasi:http as an unbroken abstraction over all HTTP protocol versions.

@lukewagner
Copy link
Member

It seems pretty useful to have a single portable interface that a component can import to do gRPC that is implemented in terms of either H2 outside the browser or gRPC-Web inside the browser (or, before too long gRPC-over-HTTP/3, and also one day, when browsers eventually support trailers, gRPC-in-browser).

Instead of creating a whole new wasi:http2 which is both a lot of work and doesn't unlock this above portability value, should we instead consider a wasi:grpc?

Other reasons in favor of a wasi:grpc include:

  • While gRPC does care about some HTTP/2 details, I expect there are many details of HTTP/2 that gRPC is agnostic of. However, if we have an explicitly-HTTP/2 interface, we'll probably end up needing to add all these HTTP/2 details for other non-gRPC HTTP/2 use cases. Scoping the proposal to "gRPC" helps avoid this scope creep.
  • Talking to an engineer who added gRPC support recently, they pointed out that there are some subtle details involving framing in the gRPC protocol that break if you do generic optimizations that HTTP/2 would otherwise seem to allow and thus knowing "I'm doing gRPC" may be practically necessary.
  • HTTP proxies often don't want to expose the transport protocol because it breaks a bunch of use cases that depend on it being selected independently, and thus while many/all HTTP proxies should be able to support wasi:http, many will not support wasi:http2 but do want to support gRPC. By staying transport-agnostic, wasi:grpc should be supportable by most HTTP proxies. Case and point, proxy-wasm includes explicit gRPC functions.

That being said, I'm not sure what exactly wasi:grpc looks like. In the simplest case, wasi:grpc could be tiny and just define incoming-handler/outgoing-handler interfaces that use wasi:http/types.{incoming-request, ...}. But I'm not sure if that provides enough abstraction to allow a host implementation to swap in gRPC-Web (mostly because I don't know enough about gRPC-Web).

@tschneidereit
Copy link
Member Author

It seems pretty useful to have a single portable interface that a component can import to do gRPC that is implemented in terms of either H2 outside the browser or gRPC-Web inside the browser (or, before too long gRPC-over-HTTP/3, and also one day, when browsers eventually support trailers, gRPC-in-browser).

I agree that that seems useful, in the abstract. I'm less sure it's useful in the real world, though: I'm fairly certain that introducing wasi:grpc and making it the only reliable way to do gRPC with components would impose significant additional hurdles for adoption, as it would have to be integrated with each language's gRPC implementation(s) instead of the HTTP abstraction.

We're already asking language ecosystems to integrate wasi:http support into their HTTP abstractions. What you're asking them to do is to now also integrate wasi:grpc, but in a different place altogether, most likely with a different maintainer group.

Instead of creating a whole new wasi:http2 which is both a lot of work

Is it? What I'm thinking of boils down to moving the API proposed here into it's own wasi:http2 package, nothing really more. That is strictly (and substantially) less work on all sides: the specification, host implementation, and language ecosystems.

and doesn't unlock this above portability value, should we instead consider a wasi:grpc?

Do we have any evidence that this portability is something people would actually want? My understanding is that people explicitly decide on whether to use gRPC or gRPC-Web, and would not want the host to make any implicit decisions for them.

And to the extent that servers and clients support both protocol versions, they already have implementations of both, which we can readily support if we provide wasi:http and wasi:http2, whereas wasi:grpc would have the adoption problem I mentioned earlier.

Other reasons in favor of a wasi:grpc include:

* While gRPC does care about _some_ HTTP/2 details, I expect there are many details of HTTP/2 that gRPC is agnostic of.  However, if we have an explicitly-HTTP/2 interface, we'll probably end up needing to add all these HTTP/2 details for other non-gRPC HTTP/2 use cases.  Scoping the proposal to "gRPC" helps avoid this scope creep.

Can you say more about what would force us to add "all these HTTP/2 details"? I'm not sure why providing a way to explicitly choose HTTP/2 as the protocol version would somehow require us to also provide a way to tweak all possible knobs that can be tweaked for HTTP/2.

* Talking to an engineer who added gRPC support recently, they pointed out that there are some [subtle details involving framing](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md?plain=1&rgh-link-date=2024-09-10T17%3A32%3A18Z#L118) in the gRPC protocol that break if you do generic optimizations that HTTP/2 would otherwise seem to allow and thus knowing "I'm doing _gRPC_" may be practically necessary.

Are there more examples of subtle details than this one? And do we have any evidence that this is a practical concern? At a cursory glance at the canonical gRPC implementations for Rust and Go I couldn't find where those would have code to ensure that HTTP/2 is configured exactly right, leading me to the hunch that maybe this requirement is met by default in practice?

And if that's the case, could we address this issue by adding a requirement to keep to this particular headers/trailers framing?

* HTTP proxies often don't want to expose the transport protocol because it breaks a bunch of use cases that depend on it being selected independently, and thus while many/all HTTP proxies should be able to support `wasi:http`, many will _not_ support `wasi:http2` but _do_ want to support gRPC.  By staying transport-agnostic, `wasi:grpc` should be supportable by most HTTP proxies.  Case and point, [proxy-wasm](https://github.com/proxy-wasm/spec) includes explicit gRPC functions.

I think it's totally fine to add wasi:grpc for those use cases that really do need to be agnostic in this way. I don't think we should make that the only possible way to do gRPC in components at all.

That being said, I'm not sure what exactly wasi:grpc looks like. In the simplest case, wasi:grpc could be tiny and just define incoming-handler/outgoing-handler interfaces that use wasi:http/types.{incoming-request, ...}. But I'm not sure if that provides enough abstraction to allow a host implementation to swap in gRPC-Web (mostly because I don't know enough about gRPC-Web).

Which gets me back to my proposal of doing pretty much exactly this with wasi:http2 as an MVP, which we could get set up as a proposal quickly and add support for in various standard libraries equally quickly. For wasi:grpc we would, as you point out, have to do substantially more due diligence to find out what the right design is, which use cases we really do want/need to support, how an API could be integrated into ecosystems, etc.

@dicej
Copy link
Collaborator

dicej commented Sep 11, 2024

I agree with Till that wasi:grpc would involve a lot more work for the various language ecosystems we'd want to support. In .NET, Grpc.Net.Client is built on top of System.Net.Http.HttpClient (or System.Net.Sockets, if desired). In Rust, tonic is built on top of hyper for the HTTP part. I imagine other gRPC client implementations are similar. Porting them all to use a new high-level API would be a pretty huge task.

We've already demonstrated that Grpc.Net.Client can be made to work unchanged when we make minor hacks to wasmtime-wasi-http to force it to use HTTP/2, so the wasi:http2 approach makes the most sense from what I've seen so far.

@pavelsavara
Copy link

Could we just add set-minimal-version and set-maximal-version to existing WIT ?

I think that specific wasi:grpc would be extra work for Grpc.Net.Client if they can't just use dotnet System.Net.Http.HttpClient for H2

@lukewagner
Copy link
Member

Can you say more about what would force us to add "all these HTTP/2 details"? I'm not sure why providing a way to explicitly choose HTTP/2 as the protocol version would somehow require us to also provide a way to tweak all possible knobs that can be tweaked for HTTP/2.

If we have a whole interface focused on wasi:http2, as opposed to the more modest extensions to wasi:http, then I don't see how we'd be able to say "no" to exposing all the HTTP/2 details, because wasi:http2 would be the right place and level of abstraction to talk about HTTP/2-specific details. If we want to hide these details, it seems like we should go with the more-minimal additions to wasi:http, just enough to allow gRPC to work.

Do we have any evidence that this portability is something people would actually want?

I was basing this on your own comment above, where you mention applications probing for HTTP/2 and falling back to gRPC-Web. Googling around shows a number of places doing this. That suggests that there is an abstraction presented to the developer that allows this sort of transparent fallback. Instead of having N libraries/frameworks/languages implement this N times, it seems valuable to move this virtualization on the other side of the interface. But I agree this isn't a hard requirement.

And do we have any evidence that this is a practical concern?

It was an actual observed bug that required changing a real HTTP server's implementation based on a "this is for gRPC" flag set on the backend to disable an optimization that otherwise seems allowed by HTTP semantics. It's possible most implementations don't do this optimization, however, so maybe it's not enough of a problem in practice though.

Overall, I do appreciate the argument that the most expedient "cut point" is in the standard library HTTP implementation, where the context that we're doing gRPC has been lost. But then it seems like the next-best option is to do the minimal addition to wasi:http, perhaps what @pavelsavara is suggesting.

@tschneidereit
Copy link
Member Author

If we have a whole interface focused on wasi:http2, as opposed to the more modest extensions to wasi:http, then I don't see how we'd be able to say "no" to exposing all the HTTP/2 details, because wasi:http2 would be the right place and level of abstraction to talk about HTTP/2-specific details.

I don't know how to say this without it sounding facetious: I'd be happy to say "yes" to more things in this package as long as someone else steps up to do the work. In lieu of that, I find it pretty easy to say "no" 🤷🏻

It was an actual observed bug that required changing a real HTTP server's implementation based on a "this is for gRPC" flag set on the backend to disable an optimization that otherwise seems allowed by HTTP semantics. It's possible most implementations don't do this optimization, however, so maybe it's not enough of a problem in practice though.

Ah, that's a good data point. It seems like we can address it by specifying that hosts must not do those optimizations? And if people care enough, we could work with them to support making them configurable?

Overall, I do appreciate the argument that the most expedient "cut point" is in the standard library HTTP implementation, where the context that we're doing gRPC has been lost. But then it seems like the next-best option is to do the minimal addition to wasi:http, perhaps what @pavelsavara is suggesting.

As I said, I do agree that we should have a dynamic way to configure this, so I'm happy to focus on this for wasi:http.

I'd like the static analyzability that wasi:http2 would give us, and it seems like it would be reasonably straight-forward to make work in some, though not all, language ecosystems. So giving up on that makes me a bit sad, but I'll for now stop pursuing this—it's purely additive to the dynamic configuration anyway, so we can always pick it up again later.

@pavelsavara
Copy link

Could we just add set-minimal-version and set-maximal-version to existing WIT ?

It remains to define if the host would prefer max or min version in given range. Or we are better off with another field/enum version-policy like in dotnet. I don't have enough knowledge (yet) to know what would it mean for HTTP3 and how it impacts performance, when version is re-negotiated.

I also don' know if this is all that's missing for grpc.

Today we also mentioned TLS version in some meeting. Should that be also something that we want to set min/max range ? I don't have specific use-case for this at the moment.

@tschneidereit
Copy link
Member Author

Today we also mentioned TLS version in some meeting. Should that be also something that we want to set min/max range ? I don't have specific use-case for this at the moment.

Are there situations in which an application will only work with a specific TLS version used, but that specific version won't be negotiated by the normal protocol negotiation process? If so, I agree that a similar situation exists, but it's not something I've heard of.

@pavelsavara
Copy link

pavelsavara commented Sep 11, 2024

Are there situations in which an application will only work with a specific TLS version used, but that specific version won't be negotiated by the normal protocol negotiation process? If so, I agree that a similar situation exists, but it's not something I've heard of.

I imagine that particular application could have stronger security expectation than the host it's running in. Requiring higher TLS version and breaking rather than compromising the communication. There is lot of complexity in it's governance. Those decisions are split differently between OS (or WASI host) and the application. I'm not an expert in that.

I guess we don't need to solve it now. I just wanted to show that there are other dimensions/features than HTTP version.

@tschneidereit
Copy link
Member Author

I imagine that particular application could have stronger security expectation than the host it's running in. Requiring higher TLS version and breaking rather than compromising the communication.

Oh, that is indeed a compelling scenario, thank you!

Maybe that points to the fact that if we do want to have good static analyzability for these kinds of things, we might want to have a WIT-level mechanism for composing interfaces in fine-grained ways. That all would only be useful if it can be made use of in toolchains, of course. I.e., if it'd be possible to create good developer experiences that result in components that have the interface they really do need, instead of one that they might need in order to support all the configurability the toolchain wants to provide.

Anyway, all the more reason to focus on the dynamic configuration part for now.

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.

6 participants