Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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 パッケージがヘッダーのケースをどのように扱うかについて、将来的な回帰を防ぐためのテストを追加することで、その挙動の一貫性を保証することを目的としています。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  1. HTTPヘッダー: HTTP(Hypertext Transfer Protocol)通信において、クライアントとサーバー間で送受信されるメッセージ(リクエストとレスポンス)のメタデータを提供する部分です。ヘッダーは「フィールド名: フィールド値」の形式で構成され、例えば Content-Type: application/json のように使われます。
  2. HTTPヘッダーのケースセンシティブ性: HTTPの仕様(RFC 7230, Section 3.2.4 Field Names)では、HTTPヘッダーのフィールド名(キー)はケースインセンシティブであると規定されています。つまり、Content-Typecontent-typeCONTENT-TYPE はすべて同じヘッダーとして扱われるべきです。しかし、前述の通り、一部のシステムではこの規定に厳密に従わず、ケースセンシティブにヘッダーを処理する場合があります。
  3. Go言語の net/http パッケージ: Go言語の標準ライブラリであり、HTTPクライアントとサーバーを構築するための機能を提供します。このパッケージ内の http.Header 型は、HTTPヘッダーを表す map[string][]string のエイリアスです。
  4. ヘッダーの正規化 (Canonicalization): net/http パッケージが内部的に行う処理で、HTTPヘッダーのキーを標準的な形式(例: Content-Type)に変換することです。これは、HTTPの仕様に準拠し、ヘッダーの比較を容易にするために行われます。
  5. Goのテストフレームワーク: Go言語には、標準でテストを記述するための testing パッケージが用意されています。テスト関数は Test で始まり、*testing.T 型の引数を取ります。テストケースは通常、構造体のスライスとして定義され、ループで各テストケースを実行します。
  6. Goの url.URL 構造体: URL(Uniform Resource Locator)を表現するための構造体で、スキーム、ホスト、パスなどのURLの各要素を保持します。
  7. Goの Request 構造体: HTTPリクエストを表す構造体で、メソッド、URL、プロトコルバージョン、ヘッダーなどのリクエストの各要素を保持します。
  8. Goの Header: map[string][]string のエイリアスであり、HTTPヘッダーのキーと値のペアを格納するために使用されます。キーは文字列、値は文字列のスライスです(同じヘッダーキーに複数の値が設定される場合があるため)。

技術的詳細

このコミットは、net/http パッケージがHTTPヘッダーのキーの大文字・小文字をどのように扱うか、特にカスタムケースのヘッダーが正しく保持されることを検証するためのテストケースを追加しています。

Goの net/http パッケージは、HTTPヘッダーのキーを正規化する(例: content-typeContent-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",
	},

このテストケースの主要なポイントは以下の通りです。

  1. コメント: // Testing custom case in header keys. Issue 5022. というコメントが追加されており、このテストがIssue 5022に関連し、ヘッダーキーのカスタムケースをテストするものであることを明確に示しています。
  2. Req フィールド:
    • Method, URL, Proto, ProtoMajor, ProtoMinor は標準的なHTTP GETリクエストの設定です。
    • 最も重要なのは Header フィールドです。ここで Header{"ALL-CAPS": {"x"}} と設定されています。ALL-CAPS は、Goの net/http パッケージの通常の正規化ルール(例: Content-Type)では生成されない、全て大文字のヘッダーキーです。この設定は、開発者が http.Header マップに直接キーを設定した場合に、そのケースが保持されることを意図しています。
  3. WantWrite フィールド:
    • これは、Req で定義されたリクエストが実際にHTTPリクエストとしてバイト列に書き出された場合に期待される文字列です。
    • 注目すべきは、"ALL-CAPS: x\r\n" の行です。これは、Req で設定した ALL-CAPS というヘッダーキーが、期待される出力においてもそのままの大文字・小文字で保持されていることを示しています。

このテストケースは、net/http パッケージが http.Request.Header に直接設定されたヘッダーキーのケースを尊重し、正規化せずにそのまま出力するという挙動を検証しています。これにより、特定のケースセンシティブなAPIと連携する必要があるGoアプリケーションが、ヘッダーのケースを制御できることが保証されます。

関連リンク

参考にした情報源リンク

  • 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 パッケージのドキュメント (一般的な知識として)