メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#72039likely_accept

x/net/http2/h2c: deprecate h2c package

ステータス変更: active likely_accept

要約

AIによる要約であり、誤りを含む場合があります。

概要

golang.org/x/net/http2/h2c パッケージ(暗号化なしのHTTP/2接続を提供するサーバサイドパッケージ)を非推奨(deprecated)にするというproposalです。Go 1.24 で net/http 標準ライブラリに同等の機能が組み込まれたため、x/net側のパッケージは役割を終えたと判断されました。

ステータス変更

activelikely_accept
2026年4月8日に @aclements(proposalレビューグループ代表)が「上記の議論に基づき、このproposalはlikely acceptと判断する」と宣言し、最終コメント期間(Proposal-FinalCommentPeriod)ラベルも付与されました。Go 1.24での標準ライブラリへの機能統合という明確な移行先があること、RFC 9113によるプロトコルアップグレード機能の公式非推奨化、既存実装の品質上の問題(テスト未カバー・過去のバグ)が重なり、反対意見がほぼ出なかったと考えられます。

技術的背景

現状の問題点

x/net/http2/h2c パッケージはもともと、標準ライブラリがHTTP/2の非暗号化接続(h2c)をサポートすることに消極的だった時代(issue #14141 参照)に、回避策として golang.org のx/netリポジトリに作成されました。
このパッケージはRFC 7540が定義する2つのh2c接続確立方式を実装しています:

  1. プロトコルアップグレード方式(RFC 7540 Section 3.2): クライアントが Upgrade: h2c ヘッダと HTTP2-Settings ヘッダを含むHTTP/1.1リクエストを送信し、サーバが 101 Switching Protocols で応答してHTTP/2に切り替える方式
  2. Prior Knowledge方式(RFC 7540 Section 3.4): クライアントが最初からHTTP/2プロトコルで接続を開始する方式
    しかし、RFC 9113(HTTP/2の改定版仕様)がプロトコルアップグレード方式を正式に非推奨化しました。さらに、h2c パッケージのアップグレード実装にはテストカバレッジが存在せず、CL 407454 の修正前まで深刻なバグも存在していました(初回リクエストのボディ全体をメモリに読み込んでからアップグレードを実行するという設計上の制約もあります)。

提案された解決策

Go 1.24 で net/http 標準ライブラリが UnencryptedHTTP2 プロトコルを正式サポートしました。これにより x/net/http2/h2c パッケージを非推奨にし、標準ライブラリへの移行を促す提案です。

  • サーバ側: Server.ProtocolsUnencryptedHTTP2 を設定することで、暗号化なしのHTTP/2接続を受け付けられます
  • クライアント側: Transport.ProtocolsUnencryptedHTTP2 を設定し HTTP1 を除外することで、http:// URLに対してHTTP/2を使用できます

これによって何ができるようになるか

h2c パッケージを使っていた既存ユーザは、標準ライブラリの一貫したAPIへ移行できます。主なユースケースは、ロードバランサでTLSを終端し、バックエンド間の通信は暗号化なしのHTTP/2で行うような内部サービス間RPCのシナリオ(gRPC利用など)です。

コード例

// Before: h2cパッケージを使った暗号化なしHTTP/2サーバ
import (
    "golang.org/x/net/http2"
    "golang.org/x/net/http2/h2c"
)
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello world")
})
h2s := &http2.Server{}
server := &http.Server{
    Addr:    ":8080",
    Handler: h2c.NewHandler(handler, h2s),
}
log.Fatal(server.ListenAndServe())
// After: Go 1.24の標準ライブラリを使った暗号化なしHTTP/2サーバ
import "net/http"
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello world")
})
var protos http.Protocols
protos.SetUnencryptedHTTP2(true)
server := &http.Server{
    Addr:      ":8080",
    Handler:   handler,
    Protocols: &protos,
}
log.Fatal(server.ListenAndServe())

議論のハイライト

  • RFC 9113による公式非推奨化: h2cパッケージが実装していたプロトコルアップグレード方式(Upgrade: h2c ヘッダによる切り替え)は、RFC 9113 Section 3.1で「広く普及しなかった」として正式に非推奨化されました。Goはこの非推奨の機能を標準ライブラリに新たに実装する予定はありません。
  • 実装品質の問題: クライアント側のプロトコルアップグレード機能が net/http に存在しないため、h2cパッケージのアップグレードサポートはテストカバレッジがゼロの状態で放置されており、信頼性に欠けます。
  • Prior Knowledge方式のみ標準ライブラリへ: Go 1.24はプロトコルアップグレードをサポートせず、Prior Knowledge方式のみを実装しました。実需要の大半はユーザが両エンドポイントを制御するシナリオであり、Prior Knowledgeで十分という判断です。
  • 将来的なアップグレードサポートの可能性: もしプロトコルアップグレードを将来サポートしたい場合は、x/netではなく net/http に統合すべきという方針が明示されています。
  • 既存issue #63565との関連: 2023年にもh2cパッケージのアップグレード機能が廃止RFCを参照していると指摘するissueが提出されていました(クローズ済み)。今回の提案はその流れを受けた自然な帰結と言えます。

関連リンク