[インデックス 13374] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http
パッケージにおける Client
構造体の CheckRedirect
メソッドに関するドキュメントの不正確さを修正し、同時にテストコードをより厳密にするものです。具体的には、CheckRedirect
がエラーを返した場合の url.Error
によるエラーラッピングについて明記し、タイプミスを修正しています。
コミット
- コミットハッシュ:
93b7d1bf1eefbc3ff33ec935b3c15601820bd4f3
- 作者: Brad Fitzpatrick bradfitz@golang.org
- 日付: 2012年6月24日 (日) 10:41:12 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/93b7d1bf1eefbc3ff33ec935b3c15601820bd4f3
元コミット内容
net/http: fix doc inaccuracy and typo; tighten test
Note url.Error wrapping, and s/issue/issuing/.
Fixes #3724
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/6294093
変更の背景
この変更は、GoのIssue #3724 に対応するものです。元の net/http
パッケージの Client.CheckRedirect
メソッドのドキュメントには、CheckRedirect
がエラーを返した場合に、そのエラーがどのように呼び出し元に伝播されるかについての記述が不正確でした。具体的には、返されたエラーが url.Error
型でラップされるという重要な情報が欠けていました。また、ドキュメント内にタイプミス (issue
が issuing
であるべき箇所) が存在しました。
この不正確なドキュメントは、開発者が CheckRedirect
メソッドの挙動を誤解し、エラーハンドリングを適切に行えない可能性がありました。そのため、ドキュメントを修正し、その挙動を検証するためのテストコードをより厳密にすることで、ライブラリの正確性と堅牢性を向上させる必要がありました。
前提知識の解説
Go言語の net/http
パッケージ
net/http
パッケージは、Go言語でHTTPクライアントおよびサーバーを実装するための標準ライブラリです。WebアプリケーションやAPIクライアントを構築する上で中心的な役割を果たします。
http.Client
構造体: HTTPリクエストを送信するためのクライアントを表します。この構造体を通じて、GET、POSTなどのHTTPメソッドを実行し、リダイレクト処理やクッキー管理など、HTTPクライアントとしての様々な挙動を制御できます。http.Client.CheckRedirect
メソッド:http.Client
のフィールドの一つで、リダイレクトを処理するためのカスタム関数を設定できます。この関数は、リダイレクトが発生するたびに呼び出され、リダイレクトを許可するか、特定のエラーを返すかなどを決定できます。もしこの関数がエラーを返した場合、http.Client
はそれ以上のリダイレクトを停止し、そのエラーを呼び出し元に返します。url.Error
型:net/url
パッケージで定義されているエラー型です。URLのパースや処理中に発生したエラーをラップするために使用されます。net/http
パッケージでは、HTTPリクエストの処理中にURLに関連する問題が発生した場合に、このurl.Error
で元のエラーをラップして返すことがあります。これにより、エラーが発生した操作(例: "Get"、"Post")とURL、そして元のエラー情報を一貫した形式で提供できます。
Go言語のエラーハンドリングとエラーラッピング
Go言語では、エラーは error
インターフェースを実装する値として扱われます。エラーハンドリングは通常、関数の戻り値として (result, error)
のペアを返すことで行われます。
エラーラッピングとは、あるエラーを別のエラーの内部に含めることで、エラーのコンテキストや原因をより詳細に伝える手法です。Go 1.13以降では fmt.Errorf
の %w
動詞を使ってエラーをラップする標準的な方法が導入されましたが、このコミットが作成された2012年時点では、カスタムエラー型(今回の url.Error
のように)が内部に別のエラーを保持する形でラッピングが行われていました。これにより、エラーチェーンを辿って元のエラーやその発生コンテキストを特定することが可能になります。
技術的詳細
このコミットの技術的な変更点は以下の2つです。
-
ドキュメントの修正 (
src/pkg/net/http/client.go
):http.Client
構造体のCheckRedirect
フィールドのコメントが修正されました。- タイプミス:
instead of issue the Request req.
からinstead of issuing the Request req.
へとissue
がissuing
に修正されました。これは単なるスペルミス修正です。 - 不正確な記述の修正:
returns that error
の後に(wrapped in a url.Error)
という記述が追加されました。これにより、CheckRedirect
がエラーを返した場合、そのエラーが直接返されるのではなく、url.Error
型でラップされて返されるという重要な挙動が明示されました。これは、開発者がCheckRedirect
から返されるエラーを適切に型アサートしたり、エラーチェーンを処理したりするために不可欠な情報です。
- タイプミス:
-
テストコードの厳密化 (
src/pkg/net/http/client_test.go
):TestRedirects
関数内のテストアサーションが変更されました。- 変更前は、エラーメッセージの文字列比較によってエラーの検証を行っていました。これはエラーメッセージの変更に脆弱であり、エラーの型や内部構造を検証していませんでした。
- 変更後は、返されたエラーが
*url.Error
型であり、かつその内部に期待するエラー (checkErr
) が含まれていることをurlError.Err != checkErr
で確認するように変更されました。これは、ドキュメントの修正内容(url.Error
でラップされること)と整合性を保ち、より堅牢で正確なエラー検証を行うための改善です。これにより、エラーメッセージの文字列に依存することなく、エラーの構造と内容を直接検証できるようになりました。
これらの変更により、net/http
クライアントのリダイレクト処理におけるエラーの挙動がより明確になり、開発者がより正確なコードを書けるようになりました。
コアとなるコードの変更箇所
diff --git a/src/pkg/net/http/client.go b/src/pkg/net/http/client.go
index fba775fddc..89441424e1 100644
--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -36,7 +36,8 @@ type Client struct {
// following an HTTP redirect. The arguments req and via
// are the upcoming request and the requests made already,
// oldest first. If CheckRedirect returns an error, the client
- // returns that error instead of issue the Request req.
+ // returns that error (wrapped in a url.Error) instead of
+ // issuing the Request req.
//
// If CheckRedirect is nil, the Client uses its default policy,
// which is to stop after 10 consecutive requests.
diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index e2a08204e0..fe4b626a31 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -231,8 +231,8 @@ func TestRedirects(t *testing.T) {
checkErr = errors.New("no redirects allowed")
res, err = c.Get(ts.URL)
- if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v\", err); e != g {
- t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
+ if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr {
+ t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err)
}
}
コアとなるコードの解説
src/pkg/net/http/client.go
の変更
// If CheckRedirect returns an error, the client
-// returns that error instead of issue the Request req.
+// returns that error (wrapped in a url.Error) instead of
+// issuing the Request req.
この変更は、Client.CheckRedirect
メソッドのドキュメントコメントを修正しています。
- // returns that error instead of issue the Request req.
- 元の記述では、「クライアントはそのエラーを返す」とだけ書かれていました。また、「issue」は「issuing」のタイプミスでした。
+ // returns that error (wrapped in a url.Error) instead of
+ // issuing the Request req.
- 修正後では、「そのエラーを
url.Error
でラップして返す」という重要な情報が追加されました。これにより、CheckRedirect
がカスタムエラーを返した場合、それが直接返されるのではなく、url.Error
型のラッパーの中に含まれて返されることが明確になります。 - タイプミスも
issue
からissuing
に修正され、文法的に正しくなりました。
- 修正後では、「そのエラーを
このドキュメントの修正は、CheckRedirect
のカスタムエラーハンドリングを実装する開発者にとって非常に重要です。これにより、返されるエラーの型を正しく予測し、適切なエラー処理ロジック(例: errors.As
や型アサーションによる url.Error
のチェック)を記述できるようになります。
src/pkg/net/http/client_test.go
の変更
if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr {
t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err)
}
このテストコードの変更は、CheckRedirect
がエラーを返した際の挙動をより厳密に検証するためのものです。
-
- if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v", err); e != g {
-
- t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
- 元のテストでは、
fmt.Sprintf("%v", err)
を使ってエラーを文字列に変換し、その文字列が期待するエラーメッセージと一致するかどうかを比較していました。この方法は、エラーメッセージのテキストが変更されるとテストが失敗するという脆弱性がありました。また、エラーがurl.Error
でラップされているという事実を検証していませんでした。
- 元のテストでは、
-
+ if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr {
-
+ t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err)
- 修正後のテストでは、まず
err.(*url.Error)
を使って、返されたエラーが*url.Error
型に型アサートできるかを確認しています。!ok
は型アサートが失敗した場合(つまり、エラーが*url.Error
でない場合)に真となります。 - 次に、
urlError.Err != checkErr
で、url.Error
の内部にラップされているエラー (urlError.Err
) が、テストで意図的に設定したエラー (checkErr
) と一致するかどうかを検証しています。 - この変更により、テストはエラーの「メッセージ」ではなく、エラーの「型」と「内部にラップされたエラー」という構造的な側面を検証するようになり、より堅牢で正確なテストになりました。これは、ドキュメントの修正内容と完全に一致する検証方法です。
- 修正後のテストでは、まず
関連リンク
- Go Change-Id:
https://golang.org/cl/6294093
- Go Issue:
https://github.com/golang/go/issues/3724
参考にした情報源リンク
- Go言語の公式ドキュメント (
net/http
パッケージ、net/url
パッケージ) - Go言語のエラーハンドリングに関する一般的な情報源
- GitHubのGoリポジトリにおける関連Issue (
#3724
) とコミット履歴 - Go言語の
url.Error
型に関する解説記事 - Go言語の
CheckRedirect
メソッドに関する解説記事