[インデックス 14740] ファイルの概要
このコミットは、Go言語の標準ライブラリであるnet/http
パッケージにおけるNO_PROXY
環境変数の挙動を修正し、curl
やPythonなどの他の一般的なツールとの互換性を向上させるものです。具体的には、NO_PROXY="example.com"
のような指定が、foo.example.com
のようなサブドメインにも適用されるように変更されました。
コミット
commit 82ae6434b3a95beb64f708078af5a525088d6ccc
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Sat Dec 22 17:41:00 2012 -0800
net/http: match curl and others' NO_PROXY wildcard handling
NO_PROXY="example.com" should match "foo.example.com", just
the same as NO_PROXY=".example.com". This is what curl and
Python do.
Fixes #4574
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7005049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/82ae6434b3a95beb64f708078af5a525088d6ccc
元コミット内容
このコミットは、net/http
パッケージのNO_PROXY
環境変数の処理ロジックを調整するものです。以前のGoの実装では、NO_PROXY="example.com"
と設定した場合、example.com
自体はプロキシをバイパスするものの、foo.example.com
のようなサブドメインはプロキシ経由でアクセスされていました。これは、curl
やPythonなどの他のシステムにおけるNO_PROXY
の一般的な挙動とは異なっていました。このコミットは、この不一致を解消し、NO_PROXY="example.com"
がfoo.example.com
にも適用されるように変更します。
この変更は、GoのIssue #4574を修正するものです。
変更の背景
プロキシ設定は、企業ネットワークや特定の環境下でインターネットアクセスを制御するために広く利用されます。HTTP_PROXY
やHTTPS_PROXY
といった環境変数は、HTTP/HTTPSリクエストを特定のプロキシサーバー経由でルーティングするために使われます。一方で、NO_PROXY
(またはno_proxy
)環境変数は、特定のホストやドメインへのアクセス時にプロキシをバイパスするための例外リストを提供します。
このコミットの背景にある問題は、Goのnet/http
パッケージがNO_PROXY
のワイルドカード(部分一致)処理において、他の主要なHTTPクライアント(例: curl
、Pythonのrequests
ライブラリ、wget
など)と異なる挙動を示していた点にあります。
一般的なNO_PROXY
の慣習では、NO_PROXY="example.com"
と指定した場合、example.com
だけでなく、そのサブドメイン(例: www.example.com
, api.example.com
)もプロキシの対象外となることが期待されます。しかし、Goの以前の実装では、NO_PROXY="example.com"
はexample.com
にのみ厳密に一致し、www.example.com
のようなサブドメインはプロキシ経由でアクセスされてしまっていました。サブドメインも対象に含めるには、明示的にNO_PROXY=".example.com"
のようにドットを先頭に付ける必要がありました。
この挙動の不一致は、Goアプリケーションを既存のインフラストラクチャに統合する際に、予期せぬプロキシ経由の通信や、プロキシバイパスの失敗を引き起こす可能性がありました。開発者は、Goの挙動が他のツールと異なるために、追加の設定や回避策を講じる必要がありました。
このコミットは、Goのnet/http
パッケージのNO_PROXY
処理を、業界標準の期待される挙動に合わせることで、互換性と使いやすさを向上させることを目的としています。
前提知識の解説
このコミットを理解するためには、以下の概念について知っておく必要があります。
-
HTTPプロキシ: HTTPプロキシサーバーは、クライアントとインターネットの間の仲介役として機能します。クライアントからのリクエストをプロキシが受け取り、それを目的のサーバーに転送し、サーバーからのレスポンスをクライアントに返します。プロキシは、セキュリティ(ファイアウォール)、キャッシュ、ロードバランシング、アクセス制御などの目的で利用されます。
-
環境変数によるプロキシ設定 (
HTTP_PROXY
,HTTPS_PROXY
,NO_PROXY
): 多くのオペレーティングシステムやアプリケーションでは、環境変数を使用してプロキシ設定を構成する標準的な方法が提供されています。HTTP_PROXY
(またはhttp_proxy
): HTTPリクエストに使用するプロキシサーバーのアドレスを指定します(例:http://proxy.example.com:8080
)。HTTPS_PROXY
(またはhttps_proxy
): HTTPSリクエストに使用するプロキシサーバーのアドレスを指定します。NO_PROXY
(またはno_proxy
): プロキシをバイパスすべきホスト名やドメイン名のリストをカンマ区切りで指定します。このリストに含まれる宛先へのリクエストは、直接インターネットに送信されます。
-
NO_PROXY
のワイルドカードマッチング:NO_PROXY
の一般的な実装では、指定されたドメイン名に対して部分一致(ワイルドカードマッチング)が行われます。- ドットプレフィックス (
.example.com
): 先頭にドットがある場合、そのドメイン自体(example.com
)と、そのすべてのサブドメイン(www.example.com
,api.example.com
など)に一致します。これは最も明確なワイルドカード指定です。 - ドットなし (
example.com
): 先頭にドットがない場合でも、多くのツール(curl
, Pythonなど)では、そのドメイン自体と、そのすべてのサブドメインに一致すると解釈されます。これがGoの以前の挙動と異なっていた点です。例えば、NO_PROXY="localhost"
はlocalhost
にのみ一致し、NO_PROXY="127.0.0.1"
は127.0.0.1
にのみ一致しますが、NO_PROXY="example.com"
はexample.com
と*.example.com
の両方に一致するというのが一般的な期待です。
- ドットプレフィックス (
-
Go言語の
net/http
パッケージ: Goの標準ライブラリであるnet/http
パッケージは、HTTPクライアントとサーバーの機能を提供します。このパッケージ内のTransport
構造体は、HTTPリクエストの送信方法(例: プロキシの使用)を制御します。ProxyFromEnvironment
関数は、環境変数からプロキシ設定を読み取り、useProxy
関数は、特定のアドレスがプロキシをバイパスすべきかどうかを判断します。
技術的詳細
このコミットの核心は、src/pkg/net/http/transport.go
ファイル内のuseProxy
関数のロジック変更にあります。この関数は、与えられた宛先アドレス(addr
)がNO_PROXY
環境変数で指定されたパターン(p
)に一致するかどうかを判断し、プロキシをバイパスすべきであればfalse
を返します(useProxy
は「プロキシを使うべきか」を問う関数なので、バイパスする場合はfalse
)。
変更前のuseProxy
関数の関連ロジックは以下のようでした。
if addr == p || (p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])) {
return false
}
このロジックでは、以下の2つのケースでプロキシをバイパスしていました。
addr == p
: 宛先アドレスがNO_PROXY
パターンと完全に一致する場合(例:NO_PROXY="example.com"
がexample.com
に一致)。p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])
:NO_PROXY
パターンがドットで始まる場合(例:NO_PROXY=".example.com"
)。この場合、addr
がp
で終わる(foo.example.com
が.example.com
で終わる)か、addr
がp
から先頭のドットを除いたものと完全に一致する(example.com
がexample.com
に一致)場合にバイパスしていました。
この変更により、useProxy
関数のロジックは以下のように拡張されました。
if addr == p {
return false
}
if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) {
// no_proxy ".foo.com" matches "bar.foo.com" or "foo.com"
return false
}
if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' {
// no_proxy "foo.com" matches "bar.foo.com"
return false
}
新しいロジックは、3つの独立した条件に分解され、特に3番目の条件が追加されました。
-
addr == p
: これは変更前と同じく、宛先アドレスがNO_PROXY
パターンと完全に一致する場合です。例えば、NO_PROXY="example.com"
がexample.com
に一致します。 -
p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])
: これも変更前と同じく、NO_PROXY
パターンがドットで始まる場合(例:NO_PROXY=".example.com"
)の処理です。bar.example.com
やexample.com
が.example.com
に一致します。 -
p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.'
: これがこのコミットで追加された最も重要なロジックです。p[0] != '.'
:NO_PROXY
パターンがドットで始まらないことを確認します(例:example.com
)。strings.HasSuffix(addr, p)
: 宛先アドレスがNO_PROXY
パターンで終わることを確認します(例:foo.example.com
がexample.com
で終わる)。addr[len(addr)-len(p)-1] == '.'
: ここが肝心な部分です。addr
の末尾からp
の長さ分を引いた位置の文字がドットであるかをチェックします。これにより、foo.example.com
がexample.com
に一致する一方で、fooexample.com
のような、ドメイン名が単にサフィックスとして含まれるだけのケースは除外されます。つまり、example.com
の直前がドットである(サブドメインである)ことを確認しています。
この3番目の条件の追加により、NO_PROXY="example.com"
という指定が、www.example.com
やapi.example.com
といったサブドメインにも正しく適用されるようになりました。これにより、Goのnet/http
パッケージのNO_PROXY
処理が、curl
やPythonなどの他のツールと一貫した挙動を示すようになります。
テストファイル(proxy_test.go
とtransport_test.go
)も、この新しい挙動を検証するために更新されています。特にproxy_test.go
のUseProxyTests
では、{"www.foobar.com", true}
が{"www.foobar.com", false}
に変更されており、NO_PROXY
にfoobar.com
が含まれる場合にwww.foobar.com
がプロキシをバイパスするようになったことを示しています。
コアとなるコードの変更箇所
変更は主にsrc/pkg/net/http/transport.go
ファイル内のuseProxy
関数に集中しています。
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -450,7 +450,15 @@ func useProxy(addr string) bool {
if hasPort(p) {
p = p[:strings.LastIndex(p, ":")]
}
- if addr == p || (p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])) {
+ if addr == p {
+ return false
+ }
+ if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) {
+ // no_proxy ".foo.com" matches "bar.foo.com" or "foo.com"
+ return false
+ }
+ if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' {
+ // no_proxy "foo.com" matches "bar.foo.com"
return false
}
}
また、テストファイルも変更されています。
src/pkg/net/http/proxy_test.go
:UseProxyTests
のテストケースが1つ変更されています。src/pkg/net/http/transport_test.go
:proxyFromEnvTests
の構造が変更され、より多くのテストケースが追加されています。
コアとなるコードの解説
上記のtransport.go
の差分が示すように、useProxy
関数内のプロキシバイパス判定ロジックが拡張されています。
元のコードでは、単一のif
文で2つの条件を||
(OR)で結合していました。
addr == p
: アドレスがNO_PROXY
パターンと完全に一致する場合。p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])
:NO_PROXY
パターンが.
で始まる場合(例:.example.com
)に、アドレスがそのパターンで終わるか、またはパターンから.
を除いたものと一致する場合。
新しいコードでは、これを3つの独立したif
文に分割し、特に3番目のif
文が追加されました。
-
if addr == p { return false }
これは、アドレスがNO_PROXY
パターンと完全に一致する場合(例:NO_PROXY="localhost"
がlocalhost
に一致)にプロキシをバイパスする、最も基本的なケースです。 -
if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) { return false }
これは、NO_PROXY
パターンが.
で始まる場合(例:NO_PROXY=".example.com"
)の処理です。strings.HasSuffix(addr, p)
:foo.example.com
が.example.com
で終わる場合に一致します。addr == p[1:]
:example.com
が.example.com
から.
を除いたexample.com
と一致する場合に一致します。 この条件により、.example.com
はexample.com
と*.example.com
の両方に適用されます。
-
if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' { return false }
これが、curl
やPythonの挙動に合わせるための新しいロジックです。p[0] != '.'
:NO_PROXY
パターンが.
で始まらないことを確認します(例:NO_PROXY="example.com"
)。strings.HasSuffix(addr, p)
: 宛先アドレスがNO_PROXY
パターンで終わることを確認します(例:www.example.com
がexample.com
で終わる)。addr[len(addr)-len(p)-1] == '.'
: ここが重要です。addr
の末尾からp
の長さ分を引いた位置の文字が.
であるかをチェックします。 例えば、addr
がwww.example.com
でp
がexample.com
の場合、len(addr)-len(p)-1
は15 - 10 - 1 = 4
となります。www.example.com
のインデックス4の文字は.
です。これにより、www.example.com
はexample.com
に一致します。 しかし、addr
がfooexample.com
でp
がexample.com
の場合、len(addr)-len(p)-1
は14 - 10 - 1 = 3
となります。fooexample.com
のインデックス3の文字はe
であり、.
ではありません。したがって、fooexample.com
はexample.com
に一致しません。 この条件により、NO_PROXY="example.com"
はexample.com
と*.example.com
の両方に適用されるようになりますが、fooexample.com
のような誤ったマッチングは防がれます。
これらの変更により、Goのnet/http
パッケージは、NO_PROXY
環境変数の処理において、より直感的で一般的な期待に沿った挙動を提供するようになりました。
関連リンク
- Go Issue #4574: https://github.com/golang/go/issues/4574
- Go Code Review: https://golang.org/cl/7005049
参考にした情報源リンク
curl
のNO_PROXY
に関するドキュメント(または関連する議論)- Pythonの
requests
ライブラリのプロキシ設定に関するドキュメント - 一般的な
NO_PROXY
環境変数の仕様や慣習に関する情報 - Go言語の
net/http
パッケージのドキュメント - GoのIssueトラッカーとコードレビューシステム# [インデックス 14740] ファイルの概要
このコミットは、Go言語の標準ライブラリであるnet/http
パッケージにおけるNO_PROXY
環境変数の挙動を修正し、curl
やPythonなどの他の一般的なツールとの互換性を向上させるものです。具体的には、NO_PROXY="example.com"
のような指定が、foo.example.com
のようなサブドメインにも適用されるように変更されました。
コミット
commit 82ae6434b3a95beb64f708078af5a525088d6ccc
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Sat Dec 22 17:41:00 2012 -0800
net/http: match curl and others' NO_PROXY wildcard handling
NO_PROXY="example.com" should match "foo.example.com", just
the same as NO_PROXY=".example.com". This is what curl and
Python do.
Fixes #4574
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7005049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/82ae6434b3a95beb64f708078af5a525088d6ccc
元コミット内容
このコミットは、net/http
パッケージのNO_PROXY
環境変数の処理ロジックを調整するものです。以前のGoの実装では、NO_PROXY="example.com"
と設定した場合、example.com
自体はプロキシをバイパスするものの、foo.example.com
のようなサブドメインはプロキシ経由でアクセスされていました。これは、curl
やPythonなどの他のシステムにおけるNO_PROXY
の一般的な挙動とは異なっていました。このコミットは、この不一致を解消し、NO_PROXY="example.com"
がfoo.example.com
にも適用されるように変更します。
この変更は、GoのIssue #4574を修正するものです。
変更の背景
プロキシ設定は、企業ネットワークや特定の環境下でインターネットアクセスを制御するために広く利用されます。HTTP_PROXY
やHTTPS_PROXY
といった環境変数は、HTTP/HTTPSリクエストを特定のプロキシサーバー経由でルーティングするために使われます。一方で、NO_PROXY
(またはno_proxy
)環境変数は、特定のホストやドメインへのアクセス時にプロキシをバイパスするための例外リストを提供します。
このコミットの背景にある問題は、Goのnet/http
パッケージがNO_PROXY
のワイルドカード(部分一致)処理において、他の主要なHTTPクライアント(例: curl
、Pythonのrequests
ライブラリ、wget
など)と異なる挙動を示していた点にあります。
一般的なNO_PROXY
の慣習では、NO_PROXY="example.com"
と指定した場合、example.com
だけでなく、そのサブドメイン(例: www.example.com
, api.example.com
)もプロキシの対象外となることが期待されます。しかし、Goの以前の実装では、NO_PROXY="example.com"
はexample.com
にのみ厳密に一致し、www.example.com
のようなサブドメインはプロキシ経由でアクセスされてしまっていました。サブドメインも対象に含めるには、明示的にNO_PROXY=".example.com"
のようにドットを先頭に付ける必要がありました。
この挙動の不一致は、Goアプリケーションを既存のインフラストラクチャに統合する際に、予期せぬプロキシ経由の通信や、プロキシバイパスの失敗を引き起こす可能性がありました。開発者は、Goの挙動が他のツールと異なるために、追加の設定や回避策を講じる必要がありました。
このコミットは、Goのnet/http
パッケージのNO_PROXY
処理を、業界標準の期待される挙動に合わせることで、互換性と使いやすさを向上させることを目的としています。
前提知識の解説
このコミットを理解するためには、以下の概念について知っておく必要があります。
-
HTTPプロキシ: HTTPプロキシサーバーは、クライアントとインターネットの間の仲介役として機能します。クライアントからのリクエストをプロキシが受け取り、それを目的のサーバーに転送し、サーバーからのレスポンスをクライアントに返します。プロキシは、セキュリティ(ファイアウォール)、キャッシュ、ロードバランシング、アクセス制御などの目的で利用されます。
-
環境変数によるプロキシ設定 (
HTTP_PROXY
,HTTPS_PROXY
,NO_PROXY
): 多くのオペレーティングシステムやアプリケーションでは、環境変数を使用してプロキシ設定を構成する標準的な方法が提供されています。HTTP_PROXY
(またはhttp_proxy
): HTTPリクエストに使用するプロキシサーバーのアドレスを指定します(例:http://proxy.example.com:8080
)。HTTPS_PROXY
(またはhttps_proxy
): HTTPSリクエストに使用するプロキシサーバーのアドレスを指定します。NO_PROXY
(またはno_proxy
): プロキシをバイパスすべきホスト名やドメイン名のリストをカンマ区切りで指定します。このリストに含まれる宛先へのリクエストは、直接インターネットに送信されます。
-
NO_PROXY
のワイルドカードマッチング:NO_PROXY
の一般的な実装では、指定されたドメイン名に対して部分一致(ワイルドカードマッチング)が行われます。- ドットプレフィックス (
.example.com
): 先頭にドットがある場合、そのドメイン自体(example.com
)と、そのすべてのサブドメイン(www.example.com
,api.example.com
など)に一致します。これは最も明確なワイルドカード指定です。 - ドットなし (
example.com
): 先頭にドットがない場合でも、多くのツール(curl
, Pythonなど)では、そのドメイン自体と、そのすべてのサブドメインに一致すると解釈されます。これがGoの以前の挙動と異なっていた点です。例えば、NO_PROXY="localhost"
はlocalhost
にのみ一致し、NO_PROXY="127.0.0.1"
は127.0.0.1
にのみ一致しますが、NO_PROXY="example.com"
はexample.com
と*.example.com
の両方に一致するというのが一般的な期待です。
- ドットプレフィックス (
-
Go言語の
net/http
パッケージ: Goの標準ライブラリであるnet/http
パッケージは、HTTPクライアントとサーバーの機能を提供します。このパッケージ内のTransport
構造体は、HTTPリクエストの送信方法(例: プロキシの使用)を制御します。ProxyFromEnvironment
関数は、環境変数からプロキシ設定を読み取り、useProxy
関数は、特定のアドレスがプロキシをバイパスすべきかどうかを判断します。
技術的詳細
このコミットの核心は、src/pkg/net/http/transport.go
ファイル内のuseProxy
関数のロジック変更にあります。この関数は、与えられた宛先アドレス(addr
)がNO_PROXY
環境変数で指定されたパターン(p
)に一致するかどうかを判断し、プロキシをバイパスすべきであればfalse
を返します(useProxy
は「プロキシを使うべきか」を問う関数なので、バイパスする場合はfalse
)。
変更前のuseProxy
関数の関連ロジックは以下のようでした。
if addr == p || (p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])) {
return false
}
このロジックでは、以下の2つのケースでプロキシをバイパスしていました。
addr == p
: 宛先アドレスがNO_PROXY
パターンと完全に一致する場合(例:NO_PROXY="example.com"
がexample.com
に一致)。p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])
:NO_PROXY
パターンがドットで始まる場合(例:NO_PROXY=".example.com"
)。この場合、addr
がp
で終わる(foo.example.com
が.example.com
で終わる)か、addr
がp
から先頭のドットを除いたものと完全に一致する(example.com
がexample.com
に一致)場合にバイパスしていました。
この変更により、useProxy
関数のロジックは以下のように拡張されました。
if addr == p {
return false
}
if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) {
// no_proxy ".foo.com" matches "bar.foo.com" or "foo.com"
return false
}
if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' {
// no_proxy "foo.com" matches "bar.foo.com"
return false
}
新しいロジックは、3つの独立した条件に分解され、特に3番目の条件が追加されました。
-
addr == p
: これは変更前と同じく、宛先アドレスがNO_PROXY
パターンと完全に一致する場合です。例えば、NO_PROXY="example.com"
がexample.com
に一致します。 -
p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])
: これも変更前と同じく、NO_PROXY
パターンがドットで始まる場合(例:NO_PROXY=".example.com"
)の処理です。bar.example.com
やexample.com
が.example.com
に一致します。 -
p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.'
: これがこのコミットで追加された最も重要なロジックです。p[0] != '.'
:NO_PROXY
パターンがドットで始まらないことを確認します(例:example.com
)。strings.HasSuffix(addr, p)
: 宛先アドレスがNO_PROXY
パターンで終わることを確認します(例:foo.example.com
がexample.com
で終わる)。addr[len(addr)-len(p)-1] == '.'
: ここが肝心な部分です。addr
の末尾からp
の長さ分を引いた位置の文字がドットであるかをチェックします。これにより、foo.example.com
がexample.com
に一致する一方で、fooexample.com
のような、ドメイン名が単にサフィックスとして含まれるだけのケースは除外されます。つまり、example.com
の直前がドットである(サブドメインである)ことを確認しています。
この3番目の条件の追加により、NO_PROXY="example.com"
という指定が、www.example.com
やapi.example.com
といったサブドメインにも正しく適用されるようになりました。これにより、Goのnet/http
パッケージのNO_PROXY
処理が、curl
やPythonなどの他のツールと一貫した挙動を示すようになります。
テストファイル(proxy_test.go
とtransport_test.go
)も、この新しい挙動を検証するために更新されています。特にproxy_test.go
のUseProxyTests
では、{"www.foobar.com", true}
が{"www.foobar.com", false}
に変更されており、NO_PROXY
にfoobar.com
が含まれる場合にwww.foobar.com
がプロキシをバイパスするようになったことを示しています。
コアとなるコードの変更箇所
変更は主にsrc/pkg/net/http/transport.go
ファイル内のuseProxy
関数に集中しています。
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -450,7 +450,15 @@ func useProxy(addr string) bool {
if hasPort(p) {
p = p[:strings.LastIndex(p, ":")]
}
- if addr == p || (p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])) {
+ if addr == p {
+ return false
+ }
+ if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) {
+ // no_proxy ".foo.com" matches "bar.foo.com" or "foo.com"
+ return false
+ }
+ if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' {
+ // no_proxy "foo.com" matches "bar.foo.com"
return false
}
}
また、テストファイルも変更されています。
src/pkg/net/http/proxy_test.go
:UseProxyTests
のテストケースが1つ変更されています。src/pkg/net/http/transport_test.go
:proxyFromEnvTests
の構造が変更され、より多くのテストケースが追加されています。
コアとなるコードの解説
上記のtransport.go
の差分が示すように、useProxy
関数内のプロキシバイパス判定ロジックが拡張されています。
元のコードでは、単一のif
文で2つの条件を||
(OR)で結合していました。
addr == p
: アドレスがNO_PROXY
パターンと完全に一致する場合。p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:])
:NO_PROXY
パターンが.
で始まる場合(例:.example.com
)に、アドレスがそのパターンで終わるか、またはパターンから.
を除いたものと一致する場合。
新しいコードでは、これを3つの独立したif
文に分割し、特に3番目のif
文が追加されました。
-
if addr == p { return false }
これは、アドレスがNO_PROXY
パターンと完全に一致する場合(例:NO_PROXY="localhost"
がlocalhost
に一致)にプロキシをバイパスする、最も基本的なケースです。 -
if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) { return false }
これは、NO_PROXY
パターンが.
で始まる場合(例:NO_PROXY=".example.com"
)の処理です。strings.HasSuffix(addr, p)
:foo.example.com
が.example.com
で終わる場合に一致します。addr == p[1:]
:example.com
が.example.com
から.
を除いたexample.com
と一致する場合に一致します。 この条件により、.example.com
はexample.com
と*.example.com
の両方に適用されます。
-
if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' { return false }
これが、curl
やPythonの挙動に合わせるための新しいロジックです。p[0] != '.'
:NO_PROXY
パターンが.
で始まらないことを確認します(例:NO_PROXY="example.com"
)。strings.HasSuffix(addr, p)
: 宛先アドレスがNO_PROXY
パターンで終わることを確認します(例:www.example.com
がexample.com
で終わる)。addr[len(addr)-len(p)-1] == '.'
: ここが重要です。addr
の末尾からp
の長さ分を引いた位置の文字が.
であるかをチェックします。 例えば、addr
がwww.example.com
でp
がexample.com
の場合、len(addr)-len(p)-1
は15 - 10 - 1 = 4
となります。www.example.com
のインデックス4の文字は.
です。これにより、www.example.com
はexample.com
に一致します。 しかし、addr
がfooexample.com
でp
がexample.com
の場合、len(addr)-len(p)-1
は14 - 10 - 1 = 3
となります。fooexample.com
のインデックス3の文字はe
であり、.
ではありません。したがって、fooexample.com
はexample.com
に一致しません。 この条件により、NO_PROXY="example.com"
はexample.com
と*.example.com
の両方に適用されるようになりますが、fooexample.com
のような誤ったマッチングは防がれます。
これらの変更により、Goのnet/http
パッケージは、NO_PROXY
環境変数の処理において、より直感的で一般的な期待に沿った挙動を提供するようになりました。
関連リンク
- Go Issue #4574: https://github.com/golang/go/issues/4574
- Go Code Review: https://golang.org/cl/7005049
参考にした情報源リンク
curl
のNO_PROXY
に関するドキュメント(または関連する議論)- Pythonの
requests
ライブラリのプロキシ設定に関するドキュメント - 一般的な
NO_PROXY
環境変数の仕様や慣習に関する情報 - Go言語の
net/http
パッケージのドキュメント - GoのIssueトラッカーとコードレビューシステム