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

[インデックス 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_PROXYHTTPS_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処理を、業界標準の期待される挙動に合わせることで、互換性と使いやすさを向上させることを目的としています。

前提知識の解説

このコミットを理解するためには、以下の概念について知っておく必要があります。

  1. HTTPプロキシ: HTTPプロキシサーバーは、クライアントとインターネットの間の仲介役として機能します。クライアントからのリクエストをプロキシが受け取り、それを目的のサーバーに転送し、サーバーからのレスポンスをクライアントに返します。プロキシは、セキュリティ(ファイアウォール)、キャッシュ、ロードバランシング、アクセス制御などの目的で利用されます。

  2. 環境変数によるプロキシ設定 (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): プロキシをバイパスすべきホスト名やドメイン名のリストをカンマ区切りで指定します。このリストに含まれる宛先へのリクエストは、直接インターネットに送信されます。
  3. 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の両方に一致するというのが一般的な期待です。
  4. 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つのケースでプロキシをバイパスしていました。

  1. addr == p: 宛先アドレスがNO_PROXYパターンと完全に一致する場合(例: NO_PROXY="example.com"example.comに一致)。
  2. p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]): NO_PROXYパターンがドットで始まる場合(例: NO_PROXY=".example.com")。この場合、addrpで終わる(foo.example.com.example.comで終わる)か、addrpから先頭のドットを除いたものと完全に一致する(example.comexample.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番目の条件が追加されました。

  1. addr == p: これは変更前と同じく、宛先アドレスがNO_PROXYパターンと完全に一致する場合です。例えば、NO_PROXY="example.com"example.comに一致します。

  2. p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]): これも変更前と同じく、NO_PROXYパターンがドットで始まる場合(例: NO_PROXY=".example.com")の処理です。bar.example.comexample.com.example.comに一致します。

  3. 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.comexample.comで終わる)。
    • addr[len(addr)-len(p)-1] == '.': ここが肝心な部分です。addrの末尾からpの長さ分を引いた位置の文字がドットであるかをチェックします。これにより、foo.example.comexample.comに一致する一方で、fooexample.comのような、ドメイン名が単にサフィックスとして含まれるだけのケースは除外されます。つまり、example.comの直前がドットである(サブドメインである)ことを確認しています。

この3番目の条件の追加により、NO_PROXY="example.com"という指定が、www.example.comapi.example.comといったサブドメインにも正しく適用されるようになりました。これにより、Goのnet/httpパッケージのNO_PROXY処理が、curlやPythonなどの他のツールと一貫した挙動を示すようになります。

テストファイル(proxy_test.gotransport_test.go)も、この新しい挙動を検証するために更新されています。特にproxy_test.goUseProxyTestsでは、{"www.foobar.com", true}{"www.foobar.com", false}に変更されており、NO_PROXYfoobar.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)で結合していました。

  1. addr == p: アドレスがNO_PROXYパターンと完全に一致する場合。
  2. p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]): NO_PROXYパターンが.で始まる場合(例: .example.com)に、アドレスがそのパターンで終わるか、またはパターンから.を除いたものと一致する場合。

新しいコードでは、これを3つの独立したif文に分割し、特に3番目のif文が追加されました。

  1. if addr == p { return false } これは、アドレスがNO_PROXYパターンと完全に一致する場合(例: NO_PROXY="localhost"localhostに一致)にプロキシをバイパスする、最も基本的なケースです。

  2. 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.comexample.com*.example.comの両方に適用されます。
  3. 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.comexample.comで終わる)。
    • addr[len(addr)-len(p)-1] == '.': ここが重要です。addrの末尾からpの長さ分を引いた位置の文字が.であるかをチェックします。 例えば、addrwww.example.compexample.comの場合、len(addr)-len(p)-115 - 10 - 1 = 4となります。www.example.comのインデックス4の文字は.です。これにより、www.example.comexample.comに一致します。 しかし、addrfooexample.compexample.comの場合、len(addr)-len(p)-114 - 10 - 1 = 3となります。fooexample.comのインデックス3の文字はeであり、.ではありません。したがって、fooexample.comexample.comに一致しません。 この条件により、NO_PROXY="example.com"example.com*.example.comの両方に適用されるようになりますが、fooexample.comのような誤ったマッチングは防がれます。

これらの変更により、Goのnet/httpパッケージは、NO_PROXY環境変数の処理において、より直感的で一般的な期待に沿った挙動を提供するようになりました。

関連リンク

参考にした情報源リンク

  • curlNO_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_PROXYHTTPS_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処理を、業界標準の期待される挙動に合わせることで、互換性と使いやすさを向上させることを目的としています。

前提知識の解説

このコミットを理解するためには、以下の概念について知っておく必要があります。

  1. HTTPプロキシ: HTTPプロキシサーバーは、クライアントとインターネットの間の仲介役として機能します。クライアントからのリクエストをプロキシが受け取り、それを目的のサーバーに転送し、サーバーからのレスポンスをクライアントに返します。プロキシは、セキュリティ(ファイアウォール)、キャッシュ、ロードバランシング、アクセス制御などの目的で利用されます。

  2. 環境変数によるプロキシ設定 (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): プロキシをバイパスすべきホスト名やドメイン名のリストをカンマ区切りで指定します。このリストに含まれる宛先へのリクエストは、直接インターネットに送信されます。
  3. 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の両方に一致するというのが一般的な期待です。
  4. 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つのケースでプロキシをバイパスしていました。

  1. addr == p: 宛先アドレスがNO_PROXYパターンと完全に一致する場合(例: NO_PROXY="example.com"example.comに一致)。
  2. p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]): NO_PROXYパターンがドットで始まる場合(例: NO_PROXY=".example.com")。この場合、addrpで終わる(foo.example.com.example.comで終わる)か、addrpから先頭のドットを除いたものと完全に一致する(example.comexample.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番目の条件が追加されました。

  1. addr == p: これは変更前と同じく、宛先アドレスがNO_PROXYパターンと完全に一致する場合です。例えば、NO_PROXY="example.com"example.comに一致します。

  2. p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]): これも変更前と同じく、NO_PROXYパターンがドットで始まる場合(例: NO_PROXY=".example.com")の処理です。bar.example.comexample.com.example.comに一致します。

  3. 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.comexample.comで終わる)。
    • addr[len(addr)-len(p)-1] == '.': ここが肝心な部分です。addrの末尾からpの長さ分を引いた位置の文字がドットであるかをチェックします。これにより、foo.example.comexample.comに一致する一方で、fooexample.comのような、ドメイン名が単にサフィックスとして含まれるだけのケースは除外されます。つまり、example.comの直前がドットである(サブドメインである)ことを確認しています。

この3番目の条件の追加により、NO_PROXY="example.com"という指定が、www.example.comapi.example.comといったサブドメインにも正しく適用されるようになりました。これにより、Goのnet/httpパッケージのNO_PROXY処理が、curlやPythonなどの他のツールと一貫した挙動を示すようになります。

テストファイル(proxy_test.gotransport_test.go)も、この新しい挙動を検証するために更新されています。特にproxy_test.goUseProxyTestsでは、{"www.foobar.com", true}{"www.foobar.com", false}に変更されており、NO_PROXYfoobar.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)で結合していました。

  1. addr == p: アドレスがNO_PROXYパターンと完全に一致する場合。
  2. p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]): NO_PROXYパターンが.で始まる場合(例: .example.com)に、アドレスがそのパターンで終わるか、またはパターンから.を除いたものと一致する場合。

新しいコードでは、これを3つの独立したif文に分割し、特に3番目のif文が追加されました。

  1. if addr == p { return false } これは、アドレスがNO_PROXYパターンと完全に一致する場合(例: NO_PROXY="localhost"localhostに一致)にプロキシをバイパスする、最も基本的なケースです。

  2. 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.comexample.com*.example.comの両方に適用されます。
  3. 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.comexample.comで終わる)。
    • addr[len(addr)-len(p)-1] == '.': ここが重要です。addrの末尾からpの長さ分を引いた位置の文字が.であるかをチェックします。 例えば、addrwww.example.compexample.comの場合、len(addr)-len(p)-115 - 10 - 1 = 4となります。www.example.comのインデックス4の文字は.です。これにより、www.example.comexample.comに一致します。 しかし、addrfooexample.compexample.comの場合、len(addr)-len(p)-114 - 10 - 1 = 3となります。fooexample.comのインデックス3の文字はeであり、.ではありません。したがって、fooexample.comexample.comに一致しません。 この条件により、NO_PROXY="example.com"example.com*.example.comの両方に適用されるようになりますが、fooexample.comのような誤ったマッチングは防がれます。

これらの変更により、Goのnet/httpパッケージは、NO_PROXY環境変数の処理において、より直感的で一般的な期待に沿った挙動を提供するようになりました。

関連リンク

参考にした情報源リンク

  • curlNO_PROXYに関するドキュメント(または関連する議論)
  • Pythonのrequestsライブラリのプロキシ設定に関するドキュメント
  • 一般的なNO_PROXY環境変数の仕様や慣習に関する情報
  • Go言語のnet/httpパッケージのドキュメント
  • GoのIssueトラッカーとコードレビューシステム