Skip to content

[API Proposal]: WebSockets over HTTP/2 #69669

Closed
@greenEkatherine

Description

@greenEkatherine

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.

Metadata

Metadata

Labels

api-approvedAPI was approved in API review, it can be implementedarea-System.NetblockingMarks issues that we want to fast track in order to unblock other important work

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions