From: Jiayun Shen Date: Wed, 19 Apr 2023 12:14:37 +0000 (+0800) Subject: fix: NO_PROXY should support IPv4, IPv6 and localhost (#2659) X-Git-Tag: 0.24.1~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=15d09a3bbc20372cd87e48f17f7c9381c8220a0f;p=thirdparty%2Fhttpx.git fix: NO_PROXY should support IPv4, IPv6 and localhost (#2659) * fix: NO_PROXY supports IPv4, IPv6 and localhost * add more tests for test_get_environment_proxies --------- Co-authored-by: Tom Christie --- diff --git a/httpx/_utils.py b/httpx/_utils.py index c55d33a6..2568fdca 100644 --- a/httpx/_utils.py +++ b/httpx/_utils.py @@ -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 diff --git a/tests/test_utils.py b/tests/test_utils.py index 3eaf2451..ab0fcbec 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -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):