]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
fix: NO_PROXY should support IPv4, IPv6 and localhost (#2659)
authorJiayun Shen <jiayun.shen@foxmail.com>
Wed, 19 Apr 2023 12:14:37 +0000 (20:14 +0800)
committerGitHub <noreply@github.com>
Wed, 19 Apr 2023 12:14:37 +0000 (13:14 +0100)
* fix: NO_PROXY supports IPv4, IPv6 and localhost

* add more tests for test_get_environment_proxies

---------

Co-authored-by: Tom Christie <tom@tomchristie.com>
httpx/_utils.py
tests/test_utils.py

index c55d33a6f5be5878055295b1858f008a26ae4bb3..2568fdca1c63af632829d0f5ac18a1b8ff0e3ab6 100644 (file)
@@ -1,5 +1,6 @@
 import codecs
 import email.message
+import ipaddress
 import mimetypes
 import os
 import re
@@ -259,7 +260,16 @@ def get_environment_proxies() -> typing.Dict[str, typing.Optional[str]]:
             # NO_PROXY=google.com is marked as "all://*google.com,
             #   which disables "www.google.com" and "google.com".
             #   (But not "wwwgoogle.com")
-            mounts[f"all://*{hostname}"] = None
+            # NO_PROXY can include domains, IPv6, IPv4 addresses and "localhost"
+            #   NO_PROXY=example.com,::1,localhost,192.168.0.0/16
+            if is_ipv4_hostname(hostname):
+                mounts[f"all://{hostname}"] = None
+            elif is_ipv6_hostname(hostname):
+                mounts[f"all://[{hostname}]"] = None
+            elif hostname.lower() == "localhost":
+                mounts[f"all://{hostname}"] = None
+            else:
+                mounts[f"all://*{hostname}"] = None
 
     return mounts
 
@@ -449,3 +459,19 @@ class URLPattern:
 
     def __eq__(self, other: typing.Any) -> bool:
         return isinstance(other, URLPattern) and self.pattern == other.pattern
+
+
+def is_ipv4_hostname(hostname: str) -> bool:
+    try:
+        ipaddress.IPv4Address(hostname.split("/")[0])
+    except:
+        return False
+    return True
+
+
+def is_ipv6_hostname(hostname: str) -> bool:
+    try:
+        ipaddress.IPv6Address(hostname.split("/")[0])
+    except:
+        return False
+    return True
index 3eaf2451d68bef6763eb7d79aa5cd5ea61af0397..ab0fcbecd98eb9956ee1f495ae30110632e7e326 100644 (file)
@@ -185,6 +185,12 @@ def test_get_ssl_cert_file():
         ),
         ({"all_proxy": "http://127.0.0.1"}, {"all://": "http://127.0.0.1"}),
         ({"TRAVIS_APT_PROXY": "http://127.0.0.1"}, {}),
+        ({"no_proxy": "127.0.0.1"}, {"all://127.0.0.1": None}),
+        ({"no_proxy": "192.168.0.0/16"}, {"all://192.168.0.0/16": None}),
+        ({"no_proxy": "::1"}, {"all://[::1]": None}),
+        ({"no_proxy": "localhost"}, {"all://localhost": None}),
+        ({"no_proxy": "github.com"}, {"all://*github.com": None}),
+        ({"no_proxy": ".github.com"}, {"all://*.github.com": None}),
     ],
 )
 def test_get_environment_proxies(environment, proxies):