Kestrel support for WebSockets over HTTP/2
johncrim opened this issue ยท 15 comments
Is your feature request related to a problem? Please describe.
I would like to be able to use WebSockets over HTTP2 - my understanding is that this is not currently supported, though I have not found any documentation about it or API support for it. My research shows that WebSockets and HTTP2 are independent within Kestrel and ASP.NET Core.
Describe the solution you'd like
If HttpProtocols.Http2
is enabled, and the WebSocketsMiddleware is enabled, support WebSockets over HTTP2 connections, per RFC 8441.
What client are you looking to use? I'm not aware of any browsers that support WebSockets over HTTP/2, nor does the .NET client (or any other language client that I'm aware of looks like node has this on the server at least). Can you provide more information on why WebSockets over HTTP/2 is important to your scenario?
Certainly: We want to use HTTP/2 whenever supported, for better user-perceived perf, and better mobile experience. Primary clients are Chrome, Chrome/Android, Safari, Safari/iOS. We also use WebSockets in our app, and want to be able to establish a WebSocket connection from an HTTP/2 connection.
Good to know. Right now Chrome is the only browser that supports this. Firefox is apparently developing support and with Edge moving to the Chromium engine, it will likely inherit Chrome's support. Safari has made no public signals either way.
What scalability benefit do you expect to get from using WebSockets over HTTP/2? In high scalability environments, it's generally recommended to run WebSocket traffic through a separate server. When doing that, the benefits of WebSockets over HTTP/2 almost entirely disappear since you only have one connection from each client anyway. There are benefits to be gained from mixed environments where WebSocket traffic is running on the same server. Plus, we don't fully understand yet what those benefits would be (I'd anticipate them to be fairly minor).
There's certainly nothing incorrect about running standard HTTP traffic over HTTP/2 and WebSockets through HTTP/1.1 (this is how most browsers/servers/applications behave today).
In order to get a better idea of how this could help (so we can prioritized accordingly) it would help to know if you are seeing scalability issues due to a high number of WebSocket connections from the same clients. That's a scenario where WebSockets over HTTP/2 has a benefit.
Isn't a heavy tabbing user in a server side blazor app exactly that use case?
When I think further it may also be a general fitting framework/solution for any kind of TCP connection framing capabilities based on a well understood and supported standard (as far as I know http2 itself can do that also, but I'd like to go the web sockets road with my experimental projects).
And last but not least, it will allow some simple ways to do "little" scale-out (i.e. if needed 200 client connections instead of 100 default limit) by simply put the application server behind two "front end" servers (I don't know if generally CPU or connections is the bottleneck)
What about reverse proxy scenarios?
Disclaimer: some of the ideas may not survive a real project attempt - not even an experimental project attempt.
Isn't a heavy tabbing user in a server side blazor app exactly that use case?
Yep, this is a major reason why Blazor added support for using the Azure SignalR Service back in 0.6.0 (see https://devblogs.microsoft.com/aspnet/blazor-0-6-0-experimental-release-now-available/). When using the Azure SignalR Service, the WebSockets traffic is offloaded to a different server. When do you offload to a different server you'll always end up with a new TCP connection (even on HTTP/2, since connections are per-origin). Thus reducing the value of WebSockets over HTTP/2.
I do want to clarify that I agree this is a spec that we should look to supporting in the future. I'm just laying out our thoughts on priority. We're basically fully-booked for 3.0, so this is on the Backlog.
IMO how WebSockets are partitioned and used is an application concern. Our specific use-case is low-traffic websockets, and the app supports partitioning by user subscription (eg ServiceFabric stateful service). For us it makes sense to handle API requests and websocket connections on the same server, though in the event of an outage we'll fail over to another server.
Until this is supported by all browsers that we care about we'll have to support using separate HTTP 1.1 websockets in addition to H2 websockets; my first reason for posting this issue was to flag it for consideration, and secondly we'd like to use it when possible. It's not a blocker for us, but I would expect efficiency benefits from the feature.
We need to bring this back to life now that it's in chrome https://chromestatus.com/feature/6251293127475200
Clients: This is now supported in Chrome, Edge, and Firefox.
https://wpt.fyi/results/websockets/opening-handshake/002.html%3Fwpt_flags%3Dh2?label=experimental&label=master&aligned
While any .NET service hosting websockets should benefit from this, the YARP Reverse Proxy Library will likely benefit, saving a number of Microsoft products some money....
i am using nginx as the reverse proxy. is there any guide or sample configuration for nginx that i can look into so i can apply it when this feature is ready? currently my nginx is terminating https connection and the upstream is via http 1.1. thanks
Does nginx support websockets over h2?
Does nginx support websockets over h2?
No, not yet, according to: https://trac.nginx.org/nginx/ticket/1992
Api Proposal:
Also includes #42002
This feature allows the server to communicate to the middleware support for this new H2 Connect mechanism. WebTransport will likely use the same mechanism for H2 and H3.
namespace Microsoft.AspNetCore.Http.Features;
public interface IHttpConnectFeature
{
bool IsConnectRequest { get; }
string? Protocol { get; }
ValueTask<Stream> AcceptAsync();
}
Risks:
It's unclear if other servers like Http.Sys will eventually support H2 WebSockets or this H2 CONNECT mechanism, and if they do, if this abstraction will match. At a guess, they'd re-map the request to look like HTTP/1.1 WebSockets and re-use the original APIs.
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
- The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
- The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
- Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.
API Review notes:
- Do we need another way to check if the request is using the "CONNECT" verb?
- We only set this to true for "extended" CONNECT requests.
- Let's rename to
IsExtendedConnect
.
- Should we rename the interface to
IHttpExtendedConnectFeature
.- Why not? It won't be referenced much directly by apps.
- When
IsExtendedConnect
is true,Protocol
is not null. Let's use the attribute for that.
namespace Microsoft.AspNetCore.Http.Features;
+ public interface IHttpExtendedConnectFeature
+ {
+ [MemberNotNullWhen(true, nameof(Protocol))]
+ bool IsExtendedConnect { get; }
+ string? Protocol { get; }
+ ValueTask<Stream> AcceptAsync();
+ }