Skip to content

Commit 265e772

Browse files
committed
ProxyEnvironment: Handle no_proxy="*"
Add support for leading dots in no_proxy and "*" as a no_proxy value. Both are supported in requests and based on https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/ both are somewhat common. Signed-off-by: Jussi Kukkonen <[email protected]>
1 parent 9a4e749 commit 265e772

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

tests/test_proxy_environment.py

+29
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,35 @@ def test_no_proxy_subdomain_match(self, mock_getproxies: Mock) -> None:
137137
# and a https proxymanager
138138
self.assert_pool_managers(env, [None, "http://localhost:9999"])
139139

140+
@patch("tuf.ngclient._internal.proxy.getproxies")
141+
def test_no_proxy_wildcard(self, mock_getproxies: Mock) -> None:
142+
mock_getproxies.return_value = {
143+
"https": "http://localhost:8888",
144+
"no": "*",
145+
}
146+
147+
env = ProxyEnvironment()
148+
env.get_pool_manager("https", "example.com")
149+
env.get_pool_manager("https", "differentsite.com")
150+
env.get_pool_manager("https", "subdomain.example.com")
151+
152+
# There is a single pool manager, no proxies
153+
self.assert_pool_managers(env, [None])
154+
155+
@patch("tuf.ngclient._internal.proxy.getproxies")
156+
def test_no_proxy_leading_dot(self, mock_getproxies: Mock) -> None:
157+
mock_getproxies.return_value = {
158+
"https": "http://localhost:8888",
159+
"no": ".example.com",
160+
}
161+
162+
env = ProxyEnvironment()
163+
env.get_pool_manager("https", "example.com")
164+
env.get_pool_manager("https", "subdomain.example.com")
165+
166+
# There is a single pool manager, no proxies
167+
self.assert_pool_managers(env, [None])
168+
140169
@patch("tuf.ngclient._internal.proxy.getproxies")
141170
def test_all_proxy_set(self, mock_getproxies: Mock) -> None:
142171
mock_getproxies.return_value = {

tuf/ngclient/_internal/proxy.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ def __init__(
3838
if no_proxy is None:
3939
self._no_proxy_hosts = []
4040
else:
41+
# split by comma, remove leading periods
4142
self._no_proxy_hosts = [
42-
h for h in no_proxy.replace(" ", "").split(",") if h
43+
h.lstrip(".") for h in no_proxy.replace(" ", "").split(",") if h
4344
]
4445

4546
def _get_proxy(self, scheme: str | None, host: str | None) -> str | None:
@@ -50,10 +51,12 @@ def _get_proxy(self, scheme: str | None, host: str | None) -> str | None:
5051
# even for schemes that don't require host (like file)
5152
return None
5253

53-
# does host match "no_proxy" hosts?
54+
# does host match any of the "no_proxy" hosts?
5455
for no_proxy_host in self._no_proxy_hosts:
55-
# exact hostname match or parent domain match
56-
if host == no_proxy_host or host.endswith(f".{no_proxy_host}"):
56+
# wildcard match, exact hostname match, or parent domain match
57+
if no_proxy_host in ("*", host) or host.endswith(
58+
f".{no_proxy_host}"
59+
):
5760
return None
5861

5962
if scheme in self._proxies:

0 commit comments

Comments
 (0)