[インデックス 15685] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http
パッケージにおいて、HTTPヘッダーのキーの大文字・小文字の保存に関するテストを追加するものです。具体的には、カスタムケース(全て大文字)のヘッダーキーが正しく保持されることを検証するためのテストケースが requestwrite_test.go
に追加されています。これは、Issue 5022で報告された問題への対応の一環として行われました。
コミット
- コミットハッシュ:
f0396caf12abe7abb4ac6e29a743f0f6246f8f77
- 作者: Brad Fitzpatrick bradfitz@golang.org
- コミット日時: Mon Mar 11 11:10:43 2013 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f0396caf12abe7abb4ac6e29a743f0f6246f8f77
元コミット内容
net/http: add a test verifying header case preservation
Fixes #5022
R=golang-dev, minux.ma
CC=golang-dev
https://golang.org/cl/7712043
変更の背景
このコミットの背景には、Go言語の net/http
パッケージにおけるHTTPヘッダーのキーの大文字・小文字の扱いに関する問題、具体的にはIssue 5022が存在します。
Goの net/http
パッケージは、http.Header.Add()
や Set()
のようなメソッドを使用する際に、HTTPヘッダーのキーを自動的に正規化(canonicalize)する挙動を持っていました。この正規化とは、ヘッダー名の最初の文字とハイフンの後の文字を大文字に、それ以外を小文字に変換する処理を指します(例: "content-type" が "Content-Type" になる)。この挙動は、HTTPの仕様(RFC 822など)においてHTTPヘッダー名がケースインセンシティブ(大文字・小文字を区別しない)であるという規定に基づいています。
しかし、現実世界のHTTPサーバーやAPIの中には、HTTPの仕様に厳密に従わず、ヘッダーのキーの大文字・小文字を区別する(ケースセンシティブな)ものも存在します。このような非準拠のシステムとGoアプリケーションが連携する場合、Goの自動的な正規化が原因でリクエストが失敗するという互換性の問題が発生していました。
Issue 5022は、この問題、特に http.Header.Add()
関数がヘッダーキーのケースを変更してしまうという挙動について報告されたものです。Goチームは一般的に、HTTPヘッダー名はRFCに従ってケースインセンシティブとして扱われるべきであるという立場を維持していましたが、一部の非標準的なAPIとの互換性のために、ヘッダーの書き込みに関するいくつかの回避策が実装されていました。
このコミットは、このような背景のもと、net/http
パッケージがヘッダーのケースをどのように扱うかについて、将来的な回帰を防ぐためのテストを追加することで、その挙動の一貫性を保証することを目的としています。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
- HTTPヘッダー: HTTP(Hypertext Transfer Protocol)通信において、クライアントとサーバー間で送受信されるメッセージ(リクエストとレスポンス)のメタデータを提供する部分です。ヘッダーは「フィールド名: フィールド値」の形式で構成され、例えば
Content-Type: application/json
のように使われます。 - HTTPヘッダーのケースセンシティブ性: HTTPの仕様(RFC 7230, Section 3.2.4 Field Names)では、HTTPヘッダーのフィールド名(キー)はケースインセンシティブであると規定されています。つまり、
Content-Type
、content-type
、CONTENT-TYPE
はすべて同じヘッダーとして扱われるべきです。しかし、前述の通り、一部のシステムではこの規定に厳密に従わず、ケースセンシティブにヘッダーを処理する場合があります。 - Go言語の
net/http
パッケージ: Go言語の標準ライブラリであり、HTTPクライアントとサーバーを構築するための機能を提供します。このパッケージ内のhttp.Header
型は、HTTPヘッダーを表すmap[string][]string
のエイリアスです。 - ヘッダーの正規化 (Canonicalization):
net/http
パッケージが内部的に行う処理で、HTTPヘッダーのキーを標準的な形式(例:Content-Type
)に変換することです。これは、HTTPの仕様に準拠し、ヘッダーの比較を容易にするために行われます。 - Goのテストフレームワーク: Go言語には、標準でテストを記述するための
testing
パッケージが用意されています。テスト関数はTest
で始まり、*testing.T
型の引数を取ります。テストケースは通常、構造体のスライスとして定義され、ループで各テストケースを実行します。 - Goの
url.URL
構造体: URL(Uniform Resource Locator)を表現するための構造体で、スキーム、ホスト、パスなどのURLの各要素を保持します。 - Goの
Request
構造体: HTTPリクエストを表す構造体で、メソッド、URL、プロトコルバージョン、ヘッダーなどのリクエストの各要素を保持します。 - Goの
Header
型:map[string][]string
のエイリアスであり、HTTPヘッダーのキーと値のペアを格納するために使用されます。キーは文字列、値は文字列のスライスです(同じヘッダーキーに複数の値が設定される場合があるため)。
技術的詳細
このコミットは、net/http
パッケージがHTTPヘッダーのキーの大文字・小文字をどのように扱うか、特にカスタムケースのヘッダーが正しく保持されることを検証するためのテストケースを追加しています。
Goの net/http
パッケージは、HTTPヘッダーのキーを正規化する(例: content-type
を Content-Type
に変換する)という挙動を持っていました。これは、HTTPの仕様がヘッダー名をケースインセンシティブと定めているためです。しかし、一部の非標準的なHTTPサーバーやAPIは、ヘッダーのキーの大文字・小文字を厳密に区別するため、Goの自動正規化が問題となるケースがありました。
このコミットで追加されたテストケースは、Request
構造体の Header
フィールドに、通常の正規化ルールでは生成されないような「ALL-CAPS」(全て大文字)というカスタムケースのヘッダーキーを設定しています。そして、この Request
が実際にHTTPリクエストとして書き出された際に、ALL-CAPS: x
というヘッダーがそのままのケースで出力されることを WantWrite
フィールドで期待しています。
これは、net/http
パッケージが http.Header
型のマップに直接設定されたキーについては、そのケースを尊重して出力することを示唆しています。つまり、http.Header.Add()
や Set()
のようなヘルパー関数を使用すると正規化が行われる可能性がある一方で、http.Request.Header
のような http.Header
型のマップに直接キーと値を設定する場合には、開発者が指定したケースが保持されるという挙動を検証しています。
このテストの追加は、GoチームがHTTPヘッダーのケースセンシティブ性に関する問題(Issue 5022)を認識しており、少なくとも特定のシナリオ(直接マップに設定する場合)においては、開発者が指定したヘッダーのケースが保持されるべきであるという意図を示しています。これにより、非標準的なAPIとの互換性を必要とする開発者が、Goの net/http
パッケージを使用する際に、ヘッダーのケースを制御できることを保証しようとしています。
コアとなるコードの変更箇所
変更は src/pkg/net/http/requestwrite_test.go
ファイルに集中しています。
--- a/src/pkg/net/http/requestwrite_test.go
+++ b/src/pkg/net/http/requestwrite_test.go
@@ -391,6 +391,30 @@ var reqWriteTests = []reqWriteTest{
"Host: x.google.com\r\n" +\
"User-Agent: Go 1.1 package http\r\n\r\n",
},
+
+ // Testing custom case in header keys. Issue 5022.
+ {
+ Req: Request{
+ Method: "GET",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{
+ "ALL-CAPS": {"x"},
+ },
+ },
+
+ WantWrite: "GET / HTTP/1.1\r\n" +\
+ "Host: www.google.com\r\n" +\
+ "User-Agent: Go 1.1 package http\r\n" +\
+ "ALL-CAPS: x\r\n" +\
+ "\r\n",
+ },
}
func TestRequestWrite(t *testing.T) {
コアとなるコードの解説
追加されたコードは、reqWriteTests
という reqWriteTest
型のスライスに新しいテストケースを追加しています。
// Testing custom case in header keys. Issue 5022.
{
Req: Request{
Method: "GET",
URL: &url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: Header{
"ALL-CAPS": {"x"}, // ここでカスタムケースのヘッダーキー "ALL-CAPS" を設定
},
},
WantWrite: "GET / HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
"User-Agent: Go 1.1 package http\r\n" +
"ALL-CAPS: x\r\n" + // 期待される出力でも "ALL-CAPS" がそのまま保持されている
"\r\n",
},
このテストケースの主要なポイントは以下の通りです。
- コメント:
// Testing custom case in header keys. Issue 5022.
というコメントが追加されており、このテストがIssue 5022に関連し、ヘッダーキーのカスタムケースをテストするものであることを明確に示しています。 Req
フィールド:Method
,URL
,Proto
,ProtoMajor
,ProtoMinor
は標準的なHTTP GETリクエストの設定です。- 最も重要なのは
Header
フィールドです。ここでHeader{"ALL-CAPS": {"x"}}
と設定されています。ALL-CAPS
は、Goのnet/http
パッケージの通常の正規化ルール(例:Content-Type
)では生成されない、全て大文字のヘッダーキーです。この設定は、開発者がhttp.Header
マップに直接キーを設定した場合に、そのケースが保持されることを意図しています。
WantWrite
フィールド:- これは、
Req
で定義されたリクエストが実際にHTTPリクエストとしてバイト列に書き出された場合に期待される文字列です。 - 注目すべきは、
"ALL-CAPS: x\r\n"
の行です。これは、Req
で設定したALL-CAPS
というヘッダーキーが、期待される出力においてもそのままの大文字・小文字で保持されていることを示しています。
- これは、
このテストケースは、net/http
パッケージが http.Request.Header
に直接設定されたヘッダーキーのケースを尊重し、正規化せずにそのまま出力するという挙動を検証しています。これにより、特定のケースセンシティブなAPIと連携する必要があるGoアプリケーションが、ヘッダーのケースを制御できることが保証されます。
関連リンク
- Go Issue 5022: https://github.com/golang/go/issues/5022 (Web検索結果から推測されるリンク)
- Go Change List 7712043: https://golang.org/cl/7712043
参考にした情報源リンク
- Web検索結果: "Go issue 5022 net/http header case preservation"
- Web検索結果: "https://golang.org/cl/7712043"
- HTTP/1.1 Message Syntax and Routing (RFC 7230): https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 (特に Section 3.2.4 Field Names)
- Go言語の
net/http
パッケージのドキュメント (一般的な知識として) - Go言語の
testing
パッケージのドキュメント (一般的な知識として)