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

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

このコミットは、Go言語の標準ライブラリ net/http パッケージにおける Client.Timeout フィールドのドキュメント改善と、関連するテストコードの調整を目的としています。具体的には、Client.Timeout の動作に関する説明をより明確にし、テストログの冗長な出力を抑制しています。

コミット

commit 3b015616f7623571cde190965c15bd60fd83ef72
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Tue Mar 4 13:41:05 2014 -0800

    net/http: improve Client.Timeout docs, quiet test
    
    LGTM=adg
    R=adg
    CC=golang-codereviews
    https://golang.org/cl/70930043

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

https://github.com/golang/go/commit/3b015616f7623571cde190965c15bd60fd83ef72

元コミット内容

net/http: improve Client.Timeout docs, quiet test

このコミットは、net/http パッケージの Client 型における Timeout フィールドのドキュメントを改善し、テストの出力を静かにすることを目的としています。

変更の背景

Goの net/http パッケージは、HTTPクライアント機能を提供する上で非常に重要な役割を担っています。Client.Timeout は、HTTPリクエストのタイムアウトを設定するための重要なフィールドですが、その動作、特にレスポンスボディの読み取り中にタイムアウトがどのように機能するかについて、既存のドキュメントが不明瞭であるという問題がありました。

以前のドキュメントでは、「TimeoutはGet, Head, Post, or Doが返された後も実行され続け、EOFに達していない場合にResponse.Bodyの読み取りを中断する」と記述されていました。この表現は、タイムアウトがリクエスト全体のライフサイクル(接続確立、リダイレクト、ヘッダ受信、ボディ読み取り)にわたって適用されることを示唆しつつも、特にボディ読み取りの段階での挙動について誤解を招く可能性がありました。

また、TestClientTimeout というテスト関数において、期待されるエラーが発生した際に冗長なログメッセージが出力されており、テスト結果の可読性を損ねていました。このコミットは、これらの問題を解決し、ドキュメントの正確性を向上させ、テストの出力をクリーンにすることを目的としています。

前提知識の解説

Go言語の net/http パッケージ

net/http パッケージは、Go言語でHTTPクライアントおよびサーバーを構築するための基本的な機能を提供します。このパッケージは、HTTP/1.1およびHTTP/2プロトコルをサポートし、リクエストの送信、レスポンスの受信、クッキーの管理、リダイレクトの処理など、HTTP通信に必要な多くの機能を含んでいます。

http.Client

http.Client は、単一のHTTPトランザクション(リクエストとレスポンスのやり取り)を実行するための構造体です。通常、アプリケーション内で一度だけ作成され、複数のリクエストで再利用されます。これにより、接続の再利用(Keep-Alive)やクッキーの共有などが効率的に行われます。

Client.Timeout フィールド

Client.Timeout は、http.Client の重要な設定項目の一つで、HTTPリクエスト全体のタイムアウト期間を指定します。このタイムアウトは、以下の要素を含む「エンドツーエンド」のタイムアウトです。

  1. 接続確立 (Connection establishment): サーバーへのTCP接続を確立するまでの時間。
  2. リクエスト送信 (Request sending): リクエストヘッダとボディをサーバーに送信するまでの時間。
  3. リダイレクトの追跡 (Following redirects): リダイレクトが発生した場合、そのリダイレクト先のURLへのリクエストもこのタイムアウトに含まれます。
  4. レスポンスヘッダの受信 (Receiving response headers): サーバーからレスポンスヘッダを受け取るまでの時間。
  5. レスポンスボディの読み取り (Reading response body): レスポンスボディの読み取りが完了するまでの時間。

Client.Timeout は、これらのフェーズ全体にわたって適用されるため、例えば接続が確立されてレスポンスヘッダが受信された後でも、レスポンスボディの読み取りが指定されたタイムアウト期間を超えると、その読み取り操作は中断されます。

Go言語におけるエラーハンドリングとテスト

Go言語では、エラーは戻り値として明示的に扱われます。error インターフェースを実装する型がエラーを表し、通常は関数の最後の戻り値として返されます。 テストにおいては、testing パッケージが提供され、*testing.T 型を通じてテストの実行、ログ出力、エラー報告などが行われます。t.Error()t.Errorf() はテスト失敗を報告し、t.Logf() はテスト中に情報をログに出力するために使用されます。

技術的詳細

このコミットの主要な変更点は、net/http/client.go 内の Client.Timeout フィールドのコメントの修正と、net/http/client_test.go 内のテストログの調整です。

Client.Timeout ドキュメントの改善

以前のドキュメントは、Timeout が「Get, Head, Post, or Doが返された後も実行され続け、EOFに達していない場合にResponse.Bodyの読み取りを中断する」と説明していました。この表現は、タイムアウトがリクエストの初期フェーズ(接続、ヘッダ受信)だけでなく、ボディの読み取りフェーズにも適用されることを意図していましたが、そのニュアンスが不明瞭でした。

新しいドキュメントでは、以下のように変更されました。

変更前:

	// Timeout specifies the end-to-end timeout for requests made
	// via this Client. The timeout includes connection time, any
	// redirects, and reading the response body. The timeout
	// remains running once Get, Head, Post, or Do returns and
	// will interrupt the read of the Response.Body if EOF hasn't
	// been reached.

変更後:

	// Timeout specifies a time limit for requests made by this
	// Client. The timeout includes connection time, any
	// redirects, and reading the response body. The timer remains
	// running after Get, Head, Post, or Do return and will
	// interrupt reading of the Response.Body.

この変更により、以下の点が明確化されました。

  1. 「end-to-end timeout」から「time limit」へ: 「end-to-end timeout」という表現は、タイムアウトがリクエストの開始から終了まで全体に適用されることを示唆していましたが、「time limit」というより一般的な表現にすることで、その性質をより簡潔に伝えています。機能的な意味合いは変わりませんが、表現がより直接的になりました。
  2. 「The timeout remains running once Get, Head, Post, or Do returns」から「The timer remains running after Get, Head, Post, or Do return」へ: 「timeout」という名詞から「timer」という名詞に変わったことで、タイムアウトが単なる設定値ではなく、実際に時間を計測する「タイマー」として機能し続けることがより直感的に理解できるようになりました。
  3. 「will interrupt the read of the Response.Body if EOF hasn't been reached」から「will interrupt reading of the Response.Body」へ: 「if EOF hasn't been reached」という条件が削除されました。これは、タイムアウトがボディの読み取り中に発生した場合、EOFに達しているかどうかに関わらず読み取りが中断されるという、より一般的な挙動を反映しています。実際には、EOFに達していれば読み取りは完了しているため、タイムアウトが中断する必要はありません。この変更は、ドキュメントの冗長性を排除し、より簡潔で正確な説明を提供しています。

このドキュメントの改善は、Client.Timeout の挙動、特にレスポンスボディの読み取り中にタイムアウトがどのように適用されるかについての開発者の理解を深めることを目的としています。これにより、開発者はタイムアウト設定をより適切に行い、予期せぬ挙動を避けることができます。

テストログの調整

src/pkg/net/http/client_test.go 内の TestClientTimeout 関数では、タイムアウトによって ReadAll がエラーを返した場合に、そのエラーと読み取ったボディの一部をログに出力していました。

変更前:

		if err == nil {
			t.Error("expected error from ReadAll")
		}
		t.Logf("Got expected ReadAll error of %v after reading body %q", err, all)

変更後:

		if err == nil {
			t.Error("expected error from ReadAll")
		}
		// Expected error.

この変更により、t.Logf によるログ出力がコメントアウトされました。これは、テストが期待通りのエラーを受け取った場合に、その詳細をログに出力する必要がないと判断されたためです。テストが成功している(つまり、期待されるエラーが発生している)にもかかわらず、詳細なログが出力されるのは冗長であり、テスト結果のノイズとなる可能性があります。この変更は、テストの出力をクリーンにし、本当に問題がある場合にのみログが注目されるようにするためのものです。

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

src/pkg/net/http/client.go

--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -56,12 +56,11 @@ type Client struct {
 	// in responses.
 	Jar CookieJar
 
-	// Timeout specifies the end-to-end timeout for requests made
-	// via this Client. The timeout includes connection time, any
-	// redirects, and reading the response body. The timeout
-	// remains running once Get, Head, Post, or Do returns and
-	// will interrupt the read of the Response.Body if EOF hasn't
-	// been reached.
+	// Timeout specifies a time limit for requests made by this
+	// Client. The timeout includes connection time, any
+	// redirects, and reading the response body. The timer remains
+	// running after Get, Head, Post, or Do return and will
+	// interrupt reading of the Response.Body.
 	//
 	// A Timeout of zero means no timeout.
 	//

src/pkg/net/http/client_test.go

--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -874,7 +874,7 @@ func TestClientTimeout(t *testing.T) {
 		if err == nil {
 			t.Error("expected error from ReadAll")
 		}
-		t.Logf("Got expected ReadAll error of %v after reading body %q", err, all)
+		// Expected error.
 	case <-time.After(failTime):
 		t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout)
 	}

コアとなるコードの解説

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

このファイルでは、http.Client 構造体の Timeout フィールドに付随するコメントが修正されています。これはコードの動作自体を変更するものではなく、そのドキュメント(説明)をより正確かつ簡潔にするためのものです。Go言語では、エクスポートされたフィールドや関数のコメントは、GoDocツールによって自動的にドキュメントとして生成されるため、このコメントの変更はGoDocの出力に直接影響します。これにより、net/http パッケージを利用する開発者が Client.Timeout の挙動をより正確に理解できるようになります。

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

このファイルでは、TestClientTimeout 関数内の t.Logf の呼び出しがコメントアウトされています。このテストは、Client.Timeout が正しく機能し、レスポンスボディの読み取り中にタイムアウトが発生することを検証しています。ReadAll がエラーを返すことはこのテストの成功条件の一部であるため、そのエラーが発生したことをログに明示的に出力する必要はありません。コメントアウトされた行は、テストが期待通りの結果(エラー)を得た場合に、その情報をログに出力していましたが、これはテストの成功を示すものであり、通常はログに表示する必要がない「ノイズ」と見なされます。この変更は、テストの出力を簡潔にし、テストが失敗した場合にのみ重要な情報がログに表示されるようにするためのものです。

関連リンク

参考にした情報源リンク

  • GitHub: golang/go commit 3b015616f7623571cde190965c15bd60fd83ef72: https://github.com/golang/go/commit/3b015616f7623571cde190965c15bd60fd83ef72
  • Go言語の公式ドキュメント (pkg.go.dev)
  • Go言語のテストに関するドキュメント (testing package)
  • Go言語のコードレビュープロセスに関する情報 (golang.org/cl)
  • 一般的なHTTPプロトコルとタイムアウトの概念に関する知識