Background and motivation
Currently we are supporting WebSockets over HTTP/1.1 only. For WebSockets over HTTP/2 the protocol is quite different and described by RFC #8441. It is already supported by Chrome and there are an interest from YARP and ASP.NET partners. The main improvement is that supporting WebSockets over HTTP/2 will give advantage of multiplexing connection.
API Proposal
// EXISTING
class ClientWebSocket : WebSocket
{
// EXISTING
public Task ConnectAsync(Uri uri, CancellationToken cancellationToken);
// NEW
public Task ConnectAsync(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken);
}
// EXISTING
class ClientWebSocketOptions
{
// NEW
public System.Version HttpVersion { get { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
set { } };
public System.Net.Http.HttpVersionPolicy HttpVersionPolicy { get { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
set { } };
}
class HttpMethod : IEquatable<HttpMethod>
{
// EXISTING
// internal static HttpMethod Connect { get { throw null; } }
// NEW
public static HttpMethod Connect { get { throw null; } }
}
class HttpRequestHeaders : HttpHeaders
{
public string? Protocol { get { } set { } };
}
API Usage
var handler = new SocketsHttpHandler();
ClientWebSocket ws = new();
ws.Options.HttpVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher;
ws.Options.HttpVersion = HttpVersion.Version20;
ws.ConnectAsync(uri, new HttpMessageInvoker(handler), cancellationToken);
HttpRequestMessage request = new(HttpMethod.Connect, server.Address);
request.Headers.Protocol = "websocket";
Notes
-
HttpVersion and HttpVersionPolicy in ClientWebSocketOptions are similar to HttpClient's property. ClientWebSocketOptions for browser is a class with completely different properties, so the new properties don't affect it.
-
Providing an external handler to ClientWebSocket is important because it enables advantage of HTTP/2 multiplexing by reusing the same handler for other ordinary HTTP/2 streams. Generic handler HttpMessageInvoker in ConnectAsync is a better alternative than SocketsHttpHandler. There is no need to check that it is SocketsHttpHandler but it should be able to handle WebSocket requests and it is up to the user who provides it.
-
The property for the :protocol header in HttpRequestHeaders is required because we need to guarantee that pseudo headers are appeared before all regular headers based on spec.
Other alternatives considered, but rejected:
- Pass a low-level
SocketsHttpHandler instead of HttpMessageInvoker.
- Only one property
HttpVersion if we do not require downgrade handling. In that case we rely on the version the user provides.
Risks
Adding new fields might increase memory usage.
Background and motivation
Currently we are supporting WebSockets over HTTP/1.1 only. For WebSockets over HTTP/2 the protocol is quite different and described by RFC #8441. It is already supported by Chrome and there are an interest from YARP and ASP.NET partners. The main improvement is that supporting WebSockets over HTTP/2 will give advantage of multiplexing connection.
API Proposal
API Usage
Notes
HttpVersionandHttpVersionPolicyinClientWebSocketOptionsare similar toHttpClient's property.ClientWebSocketOptionsfor browser is a class with completely different properties, so the new properties don't affect it.Providing an external handler to
ClientWebSocketis important because it enables advantage of HTTP/2 multiplexing by reusing the same handler for other ordinary HTTP/2 streams. Generic handlerHttpMessageInvokerin ConnectAsync is a better alternative thanSocketsHttpHandler. There is no need to check that it isSocketsHttpHandlerbut it should be able to handle WebSocket requests and it is up to the user who provides it.The property for the
:protocolheader inHttpRequestHeadersis required because we need to guarantee that pseudo headers are appeared before all regular headers based on spec.Other alternatives considered, but rejected:
SocketsHttpHandlerinstead ofHttpMessageInvoker.HttpVersionif we do not require downgrade handling. In that case we rely on the version the user provides.Risks
Adding new fields might increase memory usage.