x/net/http2/h2c: deprecate h2c package
要約
概要
golang.org/x/net/http2/h2c パッケージの非推奨化を提案するものです。Go 1.24 で標準ライブラリの net/http パッケージが暗号化なしの HTTP/2(h2c)接続を公式サポートするようになったため、外部パッケージとして提供されてきた h2c パッケージの役割が終わりを迎えたと判断されています。
ステータス変更
(なし) → active
2026年3月26日の週次 Proposal Review Meeting において、@aclements を含む Proposal Review グループがこの提案を active 列に移動させました。Go 1.24 での標準ライブラリへの h2c サポート追加が完了しており、h2c パッケージの非推奨化を正式に検討する段階に達したという判断です。
技術的背景
現状の問題点
golang.org/x/net/http2/h2c パッケージは、暗号化なしの HTTP/2(h2c)接続をサーバー側で受け付けるために 2018 年頃に作成されました(#14141, #25363)。当初、標準ライブラリや x/net/http2 パッケージに直接 h2c サポートを追加することに消極的だったため、外部パッケージとして提供された経緯があります。
h2c パッケージは RFC 7540 で定義された以下の 2 種類の接続方式をサポートします。
- Protocol Upgrade(プロトコルアップグレード): クライアントが
Upgrade: h2cヘッダーを付けた HTTP/1.1 リクエストを送信し、サーバーが101 Switching Protocolsで応答して HTTP/2 に切り替える仕組み - Prior Knowledge(事前知識): クライアントが最初から HTTP/2 プロトコルで通信を始める仕組み
しかし、RFC 9113(HTTP/2 の更新 RFC)はアップグレードメカニズム自体を非推奨と定めています。
「
h2c文字列は HTTP Upgrade メカニズムのために使用されてきたが、広く普及することはなく、本文書によって非推奨とする」(RFC 9113 Section 3.1)
さらに、h2c パッケージのアップグレードサポートは実装上の問題も抱えていました。
- アップグレードにはリクエストボディ全体をメモリに読み込む必要があり、大きなリクエストで問題が生じる
- テストカバレッジがほぼ存在しない(クライアント側でアップグレードを行う方法が
net/httpに存在しないため) - 過去に深刻なバグが存在していた(CL 407454 参照)
提案された解決策
golang.org/x/net/http2/h2c パッケージ全体を deprecated(非推奨) とし、Go 1.24 以降では標準ライブラリの net/http が提供する Server.Protocols および Transport.Protocols を使用するよう移行を促します。
Go 1.24 で追加された標準 API は、Prior Knowledge 方式のみをサポートします。非推奨となったアップグレードメカニズムの実装は含まれておらず、今後も追加する予定はないとされています。
これによって何ができるようになるか
h2c パッケージを非推奨化することで、net/http 標準ライブラリへの移行が促進されます。標準ライブラリの API はよりシンプルで明快であり、外部パッケージへの依存を削減できます。
コード例
// Before: h2c パッケージを使った従来の書き方
import (
"golang.org/x/net/http2/h2c"
"golang.org/x/net/http2"
"net/http"
)
h2s := &http2.Server{}
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil)
})
server := &http.Server{
Addr: ":8080",
Handler: h2c.NewHandler(handler, h2s),
}
server.ListenAndServe()
// After: Go 1.24 の net/http 標準 API を使った書き方
import "net/http"
var protocols http.Protocols
protocols.SetHTTP1(true)
protocols.SetUnencryptedHTTP2(true)
server := &http.Server{
Addr: ":8080",
Protocols: &protocols,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil)
}),
}
server.ListenAndServe()
議論のハイライト
- 非推奨化の主な動機: Go 1.24 で
net/httpに h2c(Prior Knowledge 方式)が組み込まれたことで、外部パッケージの必要性がなくなった。これは #67816 で提案・実装された機能 - アップグレードメカニズムのサポート打ち切り: RFC 9113 によってアップグレード方式自体が非推奨とされており、Go チームとして将来的にもサポートを追加する意図はないと明言されている
- 実用的な懸念への回答: アップグレードメカニズムを必要とするユースケースの大半は「両エンドポイントを自分でコントロールできる」ケースであり、そのような場合は Prior Knowledge 方式(標準 API がサポート)で代替可能
- 実装品質の問題: h2c パッケージのアップグレードサポートはバグが多く、初期リクエストのボディ全体をメモリに読み込む必要があるため、大規模なリクエストに対して本質的に問題がある
- 関連する議論 (#63565): アップグレードメカニズムが非推奨であることは以前から認識されていたが、当時は「後方互換性のために機能を残しつつ非推奨注記を追加する」という穏やかな対応が検討されていた。今回の提案はより踏み込んでパッケージ全体の非推奨化を提案している