Skip to content

net/http: support unencrypted HTTP/2 (h2c) #67816

Closed
@neild

Description

@neild

This issue is part of a project to move x/net/http2 into std: #67810

This proposal depends on the version selection API proposed in #67814.

The net/http package does not directly support unencrypted HTTP/2, sometimes referred to as "h2c".

Users may send HTTP/2 requests over an unencrypted connection by setting http2.Transport.AllowHTTP and providing a DialTLS function which opens an unencrypted connection. Users may accept unencrypted HTTP/2 requests by using the golang.org/x/net/http2/h2c package.

Neither of these mechanisms is very clean: Returning an unencrypted connection from DialTLS is unfortunate, and the interactions between net/http, h2c, and golang.org/x/net/http2 are fairly complicated.

I propose adding support for unencrypted HTTP/2 as a first-class feature to net/http.

HTTP/2 will be enabled by a new http.Protocol value:

const (
	// HTTP2 is the HTTP/2 protocol over an unsecured TCP connection.
	UnencryptedHTTP2 Protocol
)

When Server.Protocol contains UnencryptedHTTP2, the server will accept HTTP/2 requests on its unencrypted port(s).

When Transport.Protocol contains UnencryptedHTTP2 but not HTTP1, the transport will use unencrypted HTTP/2 for requests for http:// URLs ("Starting HTTP/2 with prior knowledge", RFC 9113 Section 3.3).

The HTTP/2 http2.Transport.AllowHTTP setting controls whether the transport permits requests using the http:// scheme. When Protocols contains UnencryptedHTTP1, the transport will ignore this setting and always permit http:// requests.

Upgrade: h2c

RFC 7540 Section 3.2 defines a mechanism for upgrading an HTTP/1 request to HTTP/2. The client sends an HTTP/1 request with a Upgrade: h2c header and a Http2-Settings header containing the proposed HTTP/2 settings. The server may respond with 101 Switching Protocols and convert the connection to HTTP/2.

RFC 9113 Section 3.1 deprecates this upgrade mechanism, stating: "This usage was never widely deployed and is deprecated by this document."

(For encrypted connections, the protocol is negotiated using TLS ALPN and the Upgrade header is not used.)

The golang.org/x/net/http2/h2c package supports Upgrade: h2c on server connections.

We do not currently support Upgrade: h2c for client connections. (This means that the h2c package's support for Upgrade: h2c has no test coverage, since we don't have any ability to make a client connection to exercise it with.)

I propose that we only add support for unencrypted HTTP/2 with prior knowledge, not Upgrade: h2c. Connection upgrade is complicated, since it requires us to convert a connection from one protocol to another mid-request. It comes with surprising limitations that are difficult to describe. (The initial HTTP/1 request body on an upgraded connection must be sent in its entirety before the client can begin transmitting HTTP/2 frames.) Most requests for unencrypted HTTP/2 focus on cases where the user has full control of both endpoints and can use prior knowledge. The current lack of support for client-side upgrade means that any users depending on it are doing so with non-Go clients. And, of course, the mechanism is deprecated.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Accepted

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions