Add support for no-proxy configurations (#1099)

* Add internal URLMatcher class

* Use URLMatcher for proxy lookups in transport_for_url

* Docstring

* Pin pytest

* Add support for no-proxies configurations
This commit is contained in:
Tom Christie 2020-07-31 10:21:11 +01:00 committed by GitHub
parent df54890c15
commit 16893e414f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 14 deletions

View File

@ -86,7 +86,7 @@ class BaseClient:
def _get_proxy_map(
self, proxies: typing.Optional[ProxiesTypes], trust_env: bool,
) -> typing.Dict[str, Proxy]:
) -> typing.Dict[str, typing.Optional[Proxy]]:
if proxies is None:
if trust_env:
return {
@ -94,15 +94,15 @@ class BaseClient:
for key, url in get_environment_proxies().items()
}
return {}
elif isinstance(proxies, (str, URL, Proxy)):
proxy = Proxy(url=proxies) if isinstance(proxies, (str, URL)) else proxies
return {"all": proxy}
else:
if isinstance(proxies, dict):
new_proxies = {}
for key, value in proxies.items():
proxy = Proxy(url=value) if isinstance(value, (str, URL)) else value
new_proxies[str(key)] = proxy
return new_proxies
else:
proxy = Proxy(url=proxies) if isinstance(proxies, (str, URL)) else proxies
return {"all": proxy}
@property
def headers(self) -> Headers:
@ -472,8 +472,12 @@ class Client(BaseClient):
app=app,
trust_env=trust_env,
)
self._proxies: typing.Dict[URLMatcher, httpcore.SyncHTTPTransport] = {
URLMatcher(key): self._init_proxy_transport(
self._proxies: typing.Dict[
URLMatcher, typing.Optional[httpcore.SyncHTTPTransport]
] = {
URLMatcher(key): None
if proxy is None
else self._init_proxy_transport(
proxy,
verify=verify,
cert=cert,
@ -543,7 +547,7 @@ class Client(BaseClient):
if self._proxies and not should_not_be_proxied(url):
for matcher, transport in self._proxies.items():
if matcher.matches(url):
return transport
return self._transport if transport is None else transport
return self._transport
@ -885,7 +889,8 @@ class Client(BaseClient):
def close(self) -> None:
self._transport.close()
for proxy in self._proxies.values():
proxy.close()
if proxy is not None:
proxy.close()
def __enter__(self) -> "Client":
return self
@ -989,8 +994,12 @@ class AsyncClient(BaseClient):
app=app,
trust_env=trust_env,
)
self._proxies: typing.Dict[URLMatcher, httpcore.AsyncHTTPTransport] = {
URLMatcher(key): self._init_proxy_transport(
self._proxies: typing.Dict[
URLMatcher, typing.Optional[httpcore.AsyncHTTPTransport]
] = {
URLMatcher(key): None
if proxy is None
else self._init_proxy_transport(
proxy,
verify=verify,
cert=cert,
@ -1060,7 +1069,7 @@ class AsyncClient(BaseClient):
if self._proxies and not should_not_be_proxied(url):
for matcher, transport in self._proxies.items():
if matcher.matches(url):
return transport
return self._transport if transport is None else transport
return self._transport
@ -1402,7 +1411,8 @@ class AsyncClient(BaseClient):
async def aclose(self) -> None:
await self._transport.aclose()
for proxy in self._proxies.values():
await proxy.aclose()
if proxy is not None:
await proxy.aclose()
async def __aenter__(self) -> "AsyncClient":
return self

View File

@ -54,7 +54,7 @@ TimeoutTypes = Union[
Tuple[Optional[float], Optional[float], Optional[float], Optional[float]],
"Timeout",
]
ProxiesTypes = Union[URLTypes, "Proxy", Dict[URLTypes, Union[URLTypes, "Proxy"]]]
ProxiesTypes = Union[URLTypes, "Proxy", Dict[URLTypes, Union[None, URLTypes, "Proxy"]]]
AuthTypes = Union[
Tuple[Union[str, bytes], Union[str, bytes]],

View File

@ -58,6 +58,7 @@ PROXY_URL = "http://[::1]"
("http://example.com", {"http://example.net": PROXY_URL}, None),
("http://example.com:443", {"http://example.com": PROXY_URL}, PROXY_URL),
("http://example.com", {"all": PROXY_URL}, PROXY_URL),
("http://example.com", {"all": PROXY_URL, "http://example.com": None}, None),
("http://example.com", {"http": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://example.com": PROXY_URL}, PROXY_URL),
("http://example.com", {"all://example.com:80": PROXY_URL}, None),