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

[インデックス 14553] ファイルの概要

このコミットは、Go言語の標準ライブラリである net/http パッケージと net/url パッケージにおける Host フィールドのドキュメントを明確化し、関連するテストを追加するものです。具体的には、Request.Host および URL.Host フィールドがポート番号を含む可能性があることを明示することで、開発者の誤解を防ぎ、より堅牢なコード記述を促進します。

コミット

commit add1bed735e190abb03943a73e415576de211245
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Tue Dec 4 07:09:01 2012 -0800

    net/http: clarify that Request.Host may contain a port number
    
    Fixes #4172
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/6872055

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/add1bed735e190abb03943a73e415576de211245

元コミット内容

net/http: clarify that Request.Host may contain a port number

このコミットは、net/http パッケージの Request.Host フィールドがポート番号を含む可能性があることを明確にするものです。また、関連するテストが追加されています。

変更の背景

この変更の背景には、net/http.Request 構造体の Host フィールドの挙動に関する開発者の誤解があったと考えられます。HTTP/1.1 の仕様である RFC 2616 では、Host ヘッダはホスト名とオプションでポート番号を含むことができると定義されています。しかし、Goの net/http パッケージの Request.Host フィールドのドキュメントには、この「ポート番号を含む可能性がある」という点が明示されていませんでした。

これにより、開発者が Request.Host を利用する際に、ポート番号が含まれている可能性を考慮せずにホスト名のみを期待し、パースエラーや予期せぬ挙動を引き起こす可能性がありました。例えば、Host フィールドからポート番号を分離せずに直接データベース接続文字列や他のURLを構築しようとすると、問題が発生する可能性があります。

このコミットは、このような潜在的な問題を解消し、Request.Host フィールドの正確な挙動を開発者に伝えることを目的としています。コミットメッセージにある "Fixes #4172" は、この曖昧さが原因で報告されたバグや問題に対応するものであることを示唆しています。

前提知識の解説

HTTP Host ヘッダ (RFC 2616)

HTTP/1.1 (RFC 2616) において、Host ヘッダはリクエストされたリソースのインターネットホストとポート番号を指定するために使用されます。これは、単一のIPアドレスで複数のウェブサイトをホストするバーチャルホスティングにおいて特に重要です。

Host ヘッダの一般的な形式は以下の通りです。

Host: <host>:<port>

ここで、<host> はホスト名またはIPアドレスであり、<port> はオプションのポート番号です。ポート番号が省略された場合、HTTPのデフォルトポートである80番が使用されたと見なされます。

Go言語の net/http.Request 構造体

Go言語の net/http パッケージは、HTTPクライアントとサーバーの実装を提供します。http.Request 構造体は、受信したHTTPリクエストを表し、その中にリクエストに関する様々な情報が含まれています。

Request 構造体には Host フィールドがあり、これはHTTPリクエストの Host ヘッダの値、またはリクエストURL自体から抽出されたホスト名(とポート番号)を格納します。このフィールドは、サーバーがどのバーチャルホストに対するリクエストであるかを判断するために使用されます。

Go言語の net/url.URL 構造体

Go言語の net/url パッケージは、URLのパースと生成のための機能を提供します。url.URL 構造体は、パースされたURLの各コンポーネント(スキーム、ホスト、パス、クエリなど)を保持します。

URL 構造体にも Host フィールドがあり、これはURLのホスト部分(ホスト名とオプションでポート番号)を格納します。

これらの Host フィールドがポート番号を含む可能性があるという点は、特にネットワークプログラミングにおいて重要であり、このコミットはそれを明確にすることで、開発者がより正確なコードを書けるように支援します。

技術的詳細

このコミットは、主にGo言語の標準ライブラリ内の2つのファイル、src/pkg/net/http/request.gosrc/pkg/net/url/url.go のドキュメント文字列に修正を加えています。加えて、src/pkg/net/http/request_test.go に新しいテストケースが追加され、Request.Host の挙動が期待通りであることを検証しています。

ドキュメントの明確化

  • src/pkg/net/http/request.go: Request 構造体の Host フィールドのコメントに // It may be of the form "host:port". という行が追加されました。これにより、Host フィールドがホスト名だけでなく、ポート番号も含む host:port 形式である可能性があることが明示されました。

  • src/pkg/net/url/url.go: URL 構造体の Host フィールドのコメントが Host string から Host string // host or host:port に変更されました。これも同様に、URL.Host フィールドが host または host:port の形式を取りうることを明確にしています。

これらのドキュメントの変更は、コードの動作自体を変更するものではなく、APIの利用者がフィールドの正確な内容を理解し、それに応じてコードを記述できるようにするためのものです。これにより、Host フィールドからポート番号を適切に分離するなどの処理が必要な場合に、開発者がその必要性を認識しやすくなります。

テストケースの追加

  • src/pkg/net/http/request_test.go: TestNewRequestHost という新しいテスト関数が追加されました。このテストは、NewRequest 関数を使用して http://localhost:1234/ というURLでリクエストを作成し、その結果生成される Request オブジェクトの Host フィールドが期待通り "localhost:1234" であることを検証します。

    このテストの追加は非常に重要です。ドキュメントの変更が意図した通りの挙動を反映していることを保証するだけでなく、将来的なリファクタリングや変更があった際に、Request.Host の挙動が意図せず変更されないようにするための回帰テストとしても機能します。これは、Go言語のテスト駆動開発(TDD)や堅牢なソフトウェア開発のプラクティスに沿ったものです。

これらの変更は全体として、GoのネットワークライブラリのAPIの明確性を向上させ、開発者がより正確でバグの少ないコードを書くための支援となります。

コアとなるコードの変更箇所

変更されたファイルと行数は以下の通りです。

  • src/pkg/net/http/request.go: 1行追加
  • src/pkg/net/http/request_test.go: 10行追加
  • src/pkg/net/url/url.go: 2行変更 (1行追加, 1行削除)

src/pkg/net/http/request.go

--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -124,6 +124,7 @@ type Request struct {
 	// The host on which the URL is sought.
 	// Per RFC 2616, this is either the value of the Host: header
 	// or the host name given in the URL itself.
+	// It may be of the form "host:port".
 	Host string
 
 	// Form contains the parsed form data, including both the URL

src/pkg/net/http/request_test.go

--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -228,6 +228,16 @@ func TestReadRequestErrors(t *testing.T) {
 	}
 }
 
+func TestNewRequestHost(t *testing.T) {
+	req, err := NewRequest("GET", "http://localhost:1234/", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if req.Host != "localhost:1234" {
+		t.Errorf("Host = %q; want localhost:1234", req.Host)
+	}
+}
+
 func testMissingFile(t *testing.T, req *Request) {
 	f, fh, err := req.FormFile("missing")
 	if f != nil {

src/pkg/net/url/url.go

--- a/src/pkg/net/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -224,7 +224,7 @@ type URL struct {
 	Scheme   string
 	Opaque   string    // encoded opaque data
 	User     *Userinfo // username and password information
-	Host     string
+	Host     string    // host or host:port
 	Path     string
 	RawQuery string // encoded query values, without '?'
 	Fragment string // fragment for references, without '#'

コアとなるコードの解説

src/pkg/net/http/request.go の変更

Request 構造体の Host フィールドのコメントに // It may be of the form "host:port". という行が追加されました。これは、Host フィールドが単なるホスト名だけでなく、ホスト名:ポート番号 の形式でポート番号を含む可能性があることを明示しています。

この変更は、Host フィールドの値を処理する開発者にとって非常に重要です。例えば、Host フィールドからホスト名とポート番号を分離する必要がある場合(例: データベース接続文字列の構築、特定のポートへのルーティングなど)、このコメントは開発者にその必要性を認識させ、適切なパース処理(例: net.SplitHostPort 関数などを使用)を促します。これにより、ポート番号が含まれている場合に発生しうる潜在的なバグを防ぐことができます。

src/pkg/net/http/request_test.go の変更

TestNewRequestHost という新しいテスト関数が追加されました。このテストは以下の手順を実行します。

  1. NewRequest("GET", "http://localhost:1234/", nil) を呼び出して、ポート番号を含むURLを持つHTTPリクエストを作成します。
  2. エラーが発生した場合は、テストを失敗させます。
  3. 作成されたリクエストの req.Host フィールドが "localhost:1234" と等しいかどうかを検証します。もし等しくなければ、エラーメッセージを出力してテストを失敗させます。

このテストの追加は、Request.Host フィールドが実際にポート番号を正しく保持することを確認するためのものです。これは、ドキュメントの変更が単なる説明だけでなく、実際の挙動と一致していることを保証する「実行可能なドキュメント」としての役割も果たします。また、将来的に NewRequest 関数や関連するパースロジックが変更された際に、このテストが回帰テストとして機能し、意図しない挙動の変更を早期に検出するのに役立ちます。

src/pkg/net/url/url.go の変更

URL 構造体の Host フィールドのコメントが Host string から Host string // host or host:port に変更されました。

この変更は、net/url パッケージの URL 構造体における Host フィールドも、net/http.RequestHost フィールドと同様に、ホスト名とポート番号の両方を含む可能性があることを明確にしています。net/http パッケージは内部的に net/url パッケージを利用しているため、両方のドキュメントを整合させることは、Goの標準ライブラリ全体の一貫性を保つ上で重要です。これにより、URLを扱う開発者が Host フィールドの正確な形式を理解し、適切な処理を行うことができます。

これらの変更は、Go言語のAPIの使いやすさと堅牢性を向上させるための、小さくも重要な改善です。

関連リンク

参考にした情報源リンク