-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add SOCKS support to proxy configuration parameter (#1861)
* Unify proxy URL handling for HTTP and SOCKS Both HTTP and SOCKS proxy URL can be read from either the 'mirror.proxy' configuration option or <PROTO>_PROXY environment variables. * Update documentation for mirror.proxy config option * fixup! Unify proxy URL handling for HTTP and SOCKS - Add IPv6 addresses to test cases (excellent sanity check since aiohttp_socks does some url validation) - Always log an 'info' level message if proxy configuration is being used
- Loading branch information
1 parent
9de17bb
commit d11b6b5
Showing
6 changed files
with
276 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
""" | ||
Implements 2 aspects of network proxy support: | ||
1. Detecting proxy configuration in the runtime environment | ||
2. Configuring aiohttp for different proxy protocol families | ||
""" | ||
|
||
import logging | ||
import urllib.request | ||
from collections.abc import Mapping | ||
from typing import Any | ||
|
||
from aiohttp_socks import ProxyConnector | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
# The protocols we accept from 'getproxies()' in the an arbitrary but reasonable seeming precedence order. | ||
# These roughly correspond to environment variables `(f"{p.upper()}_PROXY" for p in _supported_protocols)`. | ||
_supported_protocols = ( | ||
"socks5", | ||
"socks4", | ||
"socks", | ||
"https", | ||
"http", | ||
"all", | ||
) | ||
|
||
|
||
def proxy_address_from_env() -> str | None: | ||
""" | ||
Find an HTTP or SOCKS proxy server URL in the environment using urllib's | ||
'getproxies' function. This checks both environment variables and OS-specific sources | ||
like the Windows registry and returns a mapping of protocol name to address. If there | ||
are URLs for multiple protocols we use an arbitrary precedence order based roughly on | ||
protocol sophistication and specificity: | ||
'socks5' > 'socks4' > 'https' > 'http' > 'all' | ||
Note that nothing actually constrains the value of an environment variable to have a | ||
URI scheme/protocol that matches the protocol indicated by the variable name - e.g. | ||
not only is `ALL_PROXY=socks4://...` possible but so is `HTTP_PROXY=socks4://...`. We | ||
use the protocol from the variable name for address selection but should generate | ||
connection configuration based on the scheme. | ||
""" | ||
proxies_in_env = urllib.request.getproxies() | ||
for proto in _supported_protocols: | ||
if proto in proxies_in_env: | ||
address = proxies_in_env[proto] | ||
logger.debug("Found %s proxy address in environment: %s", proto, address) | ||
return address | ||
return None | ||
|
||
|
||
def get_aiohttp_proxy_kwargs(proxy_url: str) -> Mapping[str, Any]: | ||
""" | ||
Return initializer keyword arguments for `aiohttp.ClientSession` for either an HTTP | ||
or SOCKS proxy based on the scheme of the given URL. | ||
Proxy support uses aiohttp's built-in support for HTTP(S), and uses aiohttp_socks for | ||
SOCKS{4,5}. Initializing an aiohttp session is different for each. An HTTP proxy | ||
address can be passed to ClientSession's 'proxy' option: | ||
ClientSession(..., proxy=<PROXY_ADDRESS>, trust_env=True) | ||
'trust_env' enables aiohttp to read additional configuration from environment variables | ||
and net.rc. `aiohttp_socks` works by replacing the default transport (TcpConnector) | ||
with a custom one: | ||
socks_transport = aiohttp_socks.ProxyConnector.from_url(<PROXY_ADDRESS>) | ||
ClientSession(..., connector=socks_transport) | ||
This uses the protocol family of the URL to select one or the other and return the | ||
corresponding keyword arguments in a dictionary. | ||
""" | ||
lowered = proxy_url.lower() | ||
if lowered.startswith("socks"): | ||
logger.debug("Using SOCKS ProxyConnector for %s", proxy_url) | ||
return {"connector": ProxyConnector.from_url(proxy_url)} | ||
|
||
if lowered.startswith("http"): | ||
logger.debug("Using HTTP proxy address %s", proxy_url) | ||
return {"proxy": proxy_url, "trust_env": True} | ||
|
||
return {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.