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

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

このコミットは、Go言語の標準ライブラリである net/http パッケージにおいて、HTTPリダイレクト時にクッキーが正しく送信されるように修正を加えるものです。特に、http.Client がリダイレクトを処理する際に、設定された http.CookieJar からクッキーを取得し、後続のリクエストに含める動作を改善しています。

コミット

commit 650b936b0c4f7ee6d4f74d30a71013de300fbb90
Author: Jeff Hodges <jeff@somethingsimilar.com>
Date:   Mon Jan 16 12:57:59 2012 -0800

    net/http: send cookies in jar on redirect
    
    Until a RFC 6265 jar lands, Request.AddCookie() will work incorrectly.
    
    Fixes #2692
    
    R=bradfitz, rsc
    CC=golang-dev, r
    https://golang.org/cl/5544069

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

https://github.com/golang/go/commit/650b936b0c4f7ee6d4f74d30a71013de300fbb90

元コミット内容

このコミットは、net/http パッケージの Client がリダイレクトを処理する際に、CookieJar に保存されているクッキーを後続のリクエストに適切に含めるように修正します。コミットメッセージには、「RFC 6265 に準拠したクッキーJarが実装されるまでは、Request.AddCookie() が正しく動作しない」という注意書きがあります。これは、この修正が暫定的なものであり、より堅牢なクッキー管理メカニズムが将来的に導入されることを示唆しています。また、このコミットはIssue #2692を修正するものです。

変更の背景

この変更の背景には、Goの net/http クライアントがリダイレクトを処理する際に、クッキーの取り扱いが不完全であったという問題があります。具体的には、リダイレクト先のURLに対して、クライアントに設定された http.CookieJar から取得したクッキーが、新しいリクエストに適切に追加されないケースが存在したと考えられます。

コミットメッセージにある Fixes #2692 は、GoのIssueトラッカーに登録されていた特定のバグを指しています。このバグは、おそらくリダイレクト時のクッキーの欠落や誤った送信に関連するものでした。ユーザーが期待する動作として、ブラウザのようにリダイレクト時にもクッキーが自動的に引き継がれるべきですが、当時の実装ではそれが保証されていなかったため、この修正が必要となりました。

また、「Until a RFC 6265 jar lands」という記述から、当時のGoの net/http パッケージのクッキー管理が、まだHTTPクッキーの最新の標準であるRFC 6265に完全に準拠していなかったことが伺えます。このコミットは、RFC 6265準拠の完全なCookie Jarが実装されるまでの間、リダイレクト時のクッキー送信の動作を改善するための暫定的な、しかし重要な修正として位置づけられています。

前提知識の解説

HTTP クッキー (HTTP Cookies)

HTTPクッキーは、ウェブサイトがユーザーのブラウザに保存する小さなデータのことです。主にセッション管理(ログイン状態の維持)、パーソナライゼーション(ユーザー設定の記憶)、トラッキング(ユーザー行動の追跡)などに利用されます。

  • Set-Cookie ヘッダ: サーバーがクライアントにクッキーを送信する際に使用するHTTPレスポンスヘッダです。
  • Cookie ヘッダ: クライアントがサーバーにクッキーを送信する際に使用するHTTPリクエストヘッダです。
  • ドメインとパス: クッキーが送信されるドメインとパスを制限します。これにより、特定のウェブサイトやその一部でのみクッキーが利用されるようになります。
  • 有効期限: クッキーがいつまで有効であるかを指定します。

HTTP リダイレクト (HTTP Redirects)

HTTPリダイレクトは、ウェブサーバーがクライアントに対して、要求されたリソースが別のURLに移動したことを伝えるメカニズムです。サーバーは特定のHTTPステータスコード(例: 301 Moved Permanently, 302 Found, 303 See Other, 307 Temporary Redirect, 308 Permanent Redirect)と Location ヘッダを返します。クライアント(ブラウザやHTTPクライアントライブラリ)は、この Location ヘッダに示された新しいURLに自動的にリクエストを再送信します。

リダイレクト時には、元のリクエストに含まれていたクッキーが新しいリクエストにも引き継がれるべきかどうかが重要な考慮事項となります。

RFC 6265: HTTP State Management Mechanism

RFC 6265は、HTTPクッキーの動作を定義するインターネット標準です。これは、以前のRFC 2965やRFC 2109を置き換えるもので、クッキーのセキュリティ、プライバシー、および実装の複雑さを改善することを目的としています。

RFC 6265の重要な側面には以下が含まれます。

  • ドメインとパスのマッチング規則: クッキーがどのドメインとパスに属し、どのリクエストで送信されるべきかに関する厳密な規則。
  • Secure 属性: HTTPS接続でのみクッキーを送信するように指定する。
  • HttpOnly 属性: クライアントサイドのスクリプト(JavaScriptなど)からクッキーにアクセスできないようにする。これにより、XSS攻撃によるクッキーの盗難を防ぐ。
  • SameSite 属性 (RFC 6265bisで追加): クロスサイトリクエストフォージェリ (CSRF) 攻撃を防ぐために、クッキーがクロスサイトリクエストで送信されるかどうかを制御する。

このコミットが作成された時点では、Goの net/http パッケージのクッキー管理はまだRFC 6265に完全に準拠していなかったため、TestJar のような簡易的な実装でテストが行われています。

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

Go言語の net/http パッケージは、HTTPクライアントとサーバーの実装を提供します。

  • http.Client: HTTPリクエストを送信し、HTTPレスポンスを受信するクライアントを表します。
  • http.Request: HTTPリクエストを表します。
  • http.Response: HTTPレスポンスを表します。
  • http.Cookie: HTTPクッキーを表す構造体です。
  • http.CookieJar インターフェース: クッキーの保存と取得を行うためのインターフェースです。http.Client はこのインターフェースを実装したオブジェクトを Jar フィールドに設定することで、自動的なクッキー管理を行うことができます。

技術的詳細

このコミットの技術的な核心は、net/http パッケージの Client 型の doFollowingRedirects メソッドにおけるクッキーの処理ロジックの変更です。

変更前

変更前のコードでは、http.CookieJar からクッキーを取得し、リクエストに追加する処理が、特定の条件(if jar != nil ブロック内)に限定されていました。これは、jar が存在する場合にのみクッキーが追加されることを意味します。しかし、リダイレクトの連鎖において、クッキーが適切に引き継がれないシナリオが存在した可能性があります。

変更後

変更後のコードでは、jar.Cookies(req.URL) からクッキーを取得し、req.AddCookie(cookie) でリクエストに追加する処理が、if jar != nil ブロックの外に移動されました。これにより、jar が設定されている限り、リダイレクト後の各リクエストに対して、そのURLに関連するクッキーが常に明示的に追加されるようになりました。

この変更は、リダイレクト時にクッキーが失われる可能性のあるエッジケースを解消し、より堅牢なクッキー管理を実現します。特に、http.Client が自動的にリダイレクトを追跡する際に、セッションクッキーなどが正しく維持されることを保証します。

テストケースの追加

このコミットでは、src/pkg/net/http/client_test.go に多数のテストケースが追加されています。

  • TestJar 構造体: これは http.CookieJar インターフェースを実装したテスト用の簡易的なクッキーJarです。sync.Mutex を使用して並行アクセスから保護された map[string][]*Cookie でクッキーを管理します。これは、当時のGo標準ライブラリにRFC 6265に完全に準拠したクッキーJarがまだ存在しなかったため、テスト目的で一時的に作成されたものです。
  • echoCookiesRedirectHandler: テスト用のHTTPハンドラで、受信したクッキーをレスポンスに設定し、その後リダイレクトを行います。これにより、リダイレクトチェーンにおけるクッキーの伝播をテストできます。
  • TestRedirectCookiesJar: このテストは、http.ClientTestJar を設定し、リダイレクトが発生するHTTPリクエストを送信します。そして、最終的なレスポンスに含まれるクッキーが期待通りであるかを検証します。これにより、リダイレクト時のクッキーの自動送信が正しく機能することを確認します。
  • TestRedirectCookiesOnRequest: このテストはコメントアウトされていますが、「RFC6265クッキーJarの実装が完了したらコメントを外す」と明記されています。これは、より包括的なクッキー管理が将来的に導入されることを示唆しており、このコミットがその過渡期にあることを示しています。

これらのテストは、リダイレクト時のクッキー処理の正確性を保証するために不可欠であり、バグの再発を防ぐための重要なセーフティネットとなります。

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

src/pkg/net/http/client.go

--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -213,11 +213,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
 			        break
 			    }
 			}
-			for _, cookie := range jar.Cookies(req.URL) {
-				req.AddCookie(cookie)
-			}
 		}
 
+		for _, cookie := range jar.Cookies(req.URL) {
+			req.AddCookie(cookie)
+		}
 		urlStr = req.URL.String()
 		if r, err = send(req, c.Transport); err != nil {
 			break

src/pkg/net/http/client_test.go

このファイルには、TestJar の実装、echoCookiesRedirectHandlerTestRedirectCookiesOnRequest (コメントアウト)、TestRedirectCookiesJarmatchReturnedCookies など、多数の新しいテストコードが追加されています。変更が広範囲にわたるため、ここでは差分全体は掲載しませんが、主な追加はリダイレクト時のクッキー処理を検証するためのものです。

コアとなるコードの解説

src/pkg/net/http/client.godoFollowingRedirects 関数は、http.Client がHTTPリダイレクトを自動的に追跡する際の中心的なロジックを含んでいます。

変更の核心は、以下の行の移動です。

for _, cookie := range jar.Cookies(req.URL) {
    req.AddCookie(cookie)
}

このコードブロックは、jar (つまり http.CookieJar インターフェースを実装したオブジェクト) から現在のリクエストURL (req.URL) に関連するクッキーを取得し、それらを req (新しいHTTPリクエスト) に追加する役割を担っています。

変更前: このブロックは、if jar != nil の内部、かつ、その直前の for ループ(おそらくリダイレクトのループ)の内部にありました。これにより、クッキーの追加が特定の条件に依存し、リダイレクトの連鎖においてクッキーが適切に引き継がれないケースが発生する可能性がありました。例えば、jar が初期化された直後や、特定のリダイレクトパスでクッキーが正しく処理されないといった状況が考えられます。

変更後: このブロックは、if jar != nil のブロックの外、しかし send(req, c.Transport) (実際にHTTPリクエストを送信する部分) の直前に移動されました。 この変更により、jarnil でない限り、常にリダイレクト後の新しいリクエストが送信される直前に、CookieJar から最新のクッキーが取得され、リクエストに追加されることが保証されます。これにより、リダイレクトの各ステップでクッキーの状態が適切に更新され、セッション情報などが維持されるようになります。

この修正は、リダイレクト時のクッキー処理の堅牢性を高め、ユーザーが期待するブラウザのようなクッキーの自動引き継ぎ動作に近づけるための重要なステップです。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語の標準ライブラリである `net/http` パッケージにおいて、HTTPリダイレクト時にクッキーが正しく送信されるように修正を加えるものです。特に、`http.Client` がリダイレクトを処理する際に、設定された `http.CookieJar` からクッキーを取得し、後続のリクエストに含める動作を改善しています。

## コミット

commit 650b936b0c4f7ee6d4f74d30a71013de300fbb90 Author: Jeff Hodges jeff@somethingsimilar.com Date: Mon Jan 16 12:57:59 2012 -0800

net/http: send cookies in jar on redirect

Until a RFC 6265 jar lands, Request.AddCookie() will work incorrectly.

Fixes #2692

R=bradfitz, rsc
CC=golang-dev, r
https://golang.org/cl/5544069

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

[https://github.com/golang/go/commit/650b936b0c4f7ee6d4f74d30a71013de300fbb90](https://github.com/golang/go/commit/650b936b0c4f7ee6d4f74d30a71013de300fbb90)

## 元コミット内容

このコミットは、`net/http` パッケージの `Client` がリダイレクトを処理する際に、`CookieJar` に保存されているクッキーを後続のリクエストに適切に含めるように修正します。コミットメッセージには、「RFC 6265 に準拠したクッキーJarが実装されるまでは、`Request.AddCookie()` が正しく動作しない」という注意書きがあります。これは、この修正が暫定的なものであり、より堅牢なクッキー管理メカニズムが将来的に導入されることを示唆しています。また、このコミットはIssue #2692を修正するものです。

## 変更の背景

この変更の背景には、Goの `net/http` クライアントがリダイレクトを処理する際に、クッキーの取り扱いが不完全であったという問題があります。具体的には、リダイレクト先のURLに対して、クライアントに設定された `http.CookieJar` から取得したクッキーが、新しいリクエストに適切に追加されないケースが存在したと考えられます。

コミットメッセージにある `Fixes #2692` は、GoのIssueトラッカーに登録されていた特定のバグを指しています。このバグは、おそらくリダイレクト時のクッキーの欠落や誤った送信に関連するものでした。ユーザーが期待する動作として、ブラウザのようにリダイレクト時にもクッキーが自動的に引き継がれるべきですが、当時の実装ではそれが保証されていなかったため、この修正が必要となりました。

また、「Until a RFC 6265 jar lands」という記述から、当時のGoの `net/http` パッケージのクッキー管理が、まだHTTPクッキーの最新の標準であるRFC 6265に完全に準拠していなかったことが伺えます。このコミットは、RFC 6265準拠の完全なCookie Jarが実装されるまでの間、リダイレクト時のクッキー送信の動作を改善するための暫定的な、しかし重要な修正として位置づけられています。

## 前提知識の解説

### HTTP クッキー (HTTP Cookies)

HTTPクッキーは、ウェブサイトがユーザーのブラウザに保存する小さなデータのことです。主にセッション管理(ログイン状態の維持)、パーソナライゼーション(ユーザー設定の記憶)、トラッキング(ユーザー行動の追跡)などに利用されます。

*   **Set-Cookie ヘッダ**: サーバーがクライアントにクッキーを送信する際に使用するHTTPレスポンスヘッダです。
*   **Cookie ヘッダ**: クライアントがサーバーにクッキーを送信する際に使用するHTTPリクエストヘッダです。
*   **ドメインとパス**: クッキーが送信されるドメインとパスを制限します。これにより、特定のウェブサイトやその一部でのみクッキーが利用されるようになります。
*   **有効期限**: クッキーがいつまで有効であるかを指定します。

### HTTP リダイレクト (HTTP Redirects)

HTTPリダイレクトは、ウェブサーバーがクライアントに対して、要求されたリソースが別のURLに移動したことを伝えるメカニズムです。サーバーは特定のHTTPステータスコード(例: 301 Moved Permanently, 302 Found, 303 See Other, 307 Temporary Redirect, 308 Permanent Redirect)と `Location` ヘッダを返します。クライアント(ブラウザやHTTPクライアントライブラリ)は、この `Location` ヘッダに示された新しいURLに自動的にリクエストを再送信します。

リダイレクト時には、元のリクエストに含まれていたクッキーが新しいリクエストにも引き継がれるべきかどうかが重要な考慮事項となります。

### RFC 6265: HTTP State Management Mechanism

RFC 6265は、HTTPクッキーの動作を定義するインターネット標準です。これは、以前のRFC 2965やRFC 2109を置き換えるもので、クッキーのセキュリティ、プライバシー、および実装の複雑さを改善することを目的としています。

RFC 6265の重要な側面には以下が含まれます。
*   **ドメインとパスのマッチング規則**: クッキーがどのドメインとパスに属し、どのリクエストで送信されるべきかに関する厳密な規則。
*   **Secure 属性**: HTTPS接続でのみクッキーを送信するように指定する。
*   **HttpOnly 属性**: クライアントサイドのスクリプト(JavaScriptなど)からクッキーにアクセスできないようにする。これにより、XSS攻撃によるクッキーの盗難を防ぐ。
*   **SameSite 属性 (RFC 6265bisで追加)**: クロスサイトリクエストフォージェリ (CSRF) 攻撃を防ぐために、クッキーがクロスサイトリクエストで送信されるかどうかを制御する。

このコミットが作成された時点では、Goの `net/http` パッケージのクッキー管理はまだRFC 6265に完全に準拠していなかったため、`TestJar` のような簡易的な実装でテストが行われています。

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

Go言語の `net/http` パッケージは、HTTPクライアントとサーバーの実装を提供します。

*   `http.Client`: HTTPリクエストを送信し、HTTPレスポンスを受信するクライアントを表します。
*   `http.Request`: HTTPリクエストを表します。
*   `http.Response`: HTTPレスポンスを表します。
*   `http.Cookie`: HTTPクッキーを表す構造体です。
*   `http.CookieJar` インターフェース: クッキーの保存と取得を行うためのインターフェースです。`http.Client` はこのインターフェースを実装したオブジェクトを `Jar` フィールドに設定することで、自動的なクッキー管理を行うことができます。

## 技術的詳細

このコミットの技術的な核心は、`net/http` パッケージの `Client` 型の `doFollowingRedirects` メソッドにおけるクッキーの処理ロジックの変更です。

### 変更前

変更前のコードでは、`http.CookieJar` からクッキーを取得し、リクエストに追加する処理が、特定の条件(`if jar != nil` ブロック内)に限定されていました。これは、`jar` が存在する場合にのみクッキーが追加されることを意味します。しかし、リダイレクトの連鎖において、クッキーが適切に引き継がれないシナリオが存在した可能性があります。

### 変更後

変更後のコードでは、`jar.Cookies(req.URL)` からクッキーを取得し、`req.AddCookie(cookie)` でリクエストに追加する処理が、`if jar != nil` ブロックの外に移動されました。これにより、`jar` が設定されている限り、リダイレクト後の各リクエストに対して、そのURLに関連するクッキーが常に明示的に追加されるようになりました。

この変更は、リダイレクト時にクッキーが失われる可能性のあるエッジケースを解消し、より堅牢なクッキー管理を実現します。特に、`http.Client` が自動的にリダイレクトを追跡する際に、セッションクッキーなどが正しく維持されることを保証します。

### テストケースの追加

このコミットでは、`src/pkg/net/http/client_test.go` に多数のテストケースが追加されています。

*   **`TestJar` 構造体**: これは `http.CookieJar` インターフェースを実装したテスト用の簡易的なクッキーJarです。`sync.Mutex` を使用して並行アクセスから保護された `map[string][]*Cookie` でクッキーを管理します。これは、当時のGo標準ライブラリにRFC 6265に完全に準拠したクッキーJarがまだ存在しなかったため、テスト目的で一時的に作成されたものです。
*   **`echoCookiesRedirectHandler`**: テスト用のHTTPハンドラで、受信したクッキーをレスポンスに設定し、その後リダイレクトを行います。これにより、リダイレクトチェーンにおけるクッキーの伝播をテストできます。
*   **`TestRedirectCookiesJar`**: このテストは、`http.Client` に `TestJar` を設定し、リダイレクトが発生するHTTPリクエストを送信します。そして、最終的なレスポンスに含まれるクッキーが期待通りであるかを検証します。これにより、リダイレクト時のクッキーの自動送信が正しく機能することを確認します。
*   **`TestRedirectCookiesOnRequest`**: このテストはコメントアウトされていますが、「RFC6265クッキーJarの実装が完了したらコメントを外す」と明記されています。これは、より包括的なクッキー管理が将来的に導入されることを示唆しており、このコミットがその過渡期にあることを示しています。

これらのテストは、リダイレクト時のクッキー処理の正確性を保証するために不可欠であり、バグの再発を防ぐための重要なセーフティネットとなります。

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

### `src/pkg/net/http/client.go`

```diff
--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -213,11 +213,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
 			        break
 			    }
 			}
-			for _, cookie := range jar.Cookies(req.URL) {
-				req.AddCookie(cookie)
-			}
 		}
 
+		for _, cookie := range jar.Cookies(req.URL) {
+			req.AddCookie(cookie)
+		}
 		urlStr = req.URL.String()
 		if r, err = send(req, c.Transport); err != nil {
 			break

src/pkg/net/http/client_test.go

このファイルには、TestJar の実装、echoCookiesRedirectHandlerTestRedirectCookiesOnRequest (コメントアウト)、TestRedirectCookiesJarmatchReturnedCookies など、多数の新しいテストコードが追加されています。変更が広範囲にわたるため、ここでは差分全体は掲載しませんが、主な追加はリダイレクト時のクッキー処理を検証するためのものです。

コアとなるコードの解説

src/pkg/net/http/client.godoFollowingRedirects 関数は、http.Client がHTTPリダイレクトを自動的に追跡する際の中心的なロジックを含んでいます。

変更の核心は、以下の行の移動です。

for _, cookie := range jar.Cookies(req.URL) {
    req.AddCookie(cookie)
}

このコードブロックは、jar (つまり http.CookieJar インターフェースを実装したオブジェクト) から現在のリクエストURL (req.URL) に関連するクッキーを取得し、それらを req (新しいHTTPリクエスト) に追加する役割を担っています。

変更前: このブロックは、if jar != nil の内部、かつ、その直前の for ループ(おそらくリダイレクトのループ)の内部にありました。これにより、クッキーの追加が特定の条件に依存し、リダイレクトの連鎖においてクッキーが適切に引き継がれないケースが発生する可能性がありました。例えば、jar が初期化された直後や、特定のリダイレクトパスでクッキーが正しく処理されないといった状況が考えられます。

変更後: このブロックは、if jar != nil のブロックの外、しかし send(req, c.Transport) (実際にHTTPリクエストを送信する部分) の直前に移動されました。 この変更により、jarnil でない限り、常にリダイレクト後の新しいリクエストが送信される直前に、CookieJar から最新のクッキーが取得され、リクエストに追加されることが保証されます。これにより、リダイレクトの各ステップでクッキーの状態が適切に更新され、セッション情報などが維持されるようになります。

この修正は、リダイレクト時のクッキー処理の堅牢性を高め、ユーザーが期待するブラウザのようなクッキーの自動引き継ぎ動作に近づけるための重要なステップです。

関連リンク

参考にした情報源リンク