Description
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.