Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support websocket proxies configured via environment variables #4661

Merged
merged 9 commits into from Mar 26, 2020
Merged
1 change: 1 addition & 0 deletions CHANGES/4648.bugfix
@@ -0,0 +1 @@
Fix issue with proxy configured by environment variables for websockets.
webknjaz marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Expand Up @@ -175,6 +175,7 @@ Manuel Miranda
Marat Sharafutdinov
Marco Paolini
Mariano Anaya
Mariusz Masztalerczuk
Martijn Pieters
Martin Melka
Martin Richard
Expand Down
7 changes: 4 additions & 3 deletions aiohttp/helpers.py
Expand Up @@ -229,15 +229,16 @@ class ProxyInfo:

def proxies_from_env() -> Dict[str, ProxyInfo]:
proxy_urls = {k: URL(v) for k, v in getproxies().items()
if k in ('http', 'https')}
if k in ('http', 'https', 'ws', 'wss')}
netrc_obj = netrc_from_env()
stripped = {k: strip_auth_from_url(v) for k, v in proxy_urls.items()}
ret = {}
for proto, val in stripped.items():
proxy, auth = val
if proxy.scheme == 'https':
if proxy.scheme in ('https', 'wss'):
client_logger.warning(
"HTTPS proxies %s are not supported, ignoring", proxy)
"%s proxies %s are not supported, ignoring",
proxy.scheme.upper(), proxy)
continue
if netrc_obj and auth is None:
auth_from_netrc = None
Expand Down
4 changes: 2 additions & 2 deletions docs/client_advanced.rst
Expand Up @@ -527,8 +527,8 @@ Contrary to the ``requests`` library, it won't read environment
variables by default. But you can do so by passing
``trust_env=True`` into :class:`aiohttp.ClientSession`
constructor for extracting proxy configuration from
*HTTP_PROXY* or *HTTPS_PROXY* *environment variables* (both are case
insensitive)::
*HTTP_PROXY*, *HTTPS_PROXY*, *WS_PROXY* or *WSS_PROXY* *environment
variables* (both are case insensitive)::
webknjaz marked this conversation as resolved.
Show resolved Hide resolved

async with aiohttp.ClientSession(trust_env=True) as session:
async with session.get("http://python.org") as resp:
Expand Down
36 changes: 16 additions & 20 deletions tests/test_helpers.py
Expand Up @@ -414,31 +414,27 @@ def test_set_content_disposition_bad_param() -> None:

# --------------------- proxies_from_env ------------------------------

def test_proxies_from_env_http(mocker) -> None:
@pytest.mark.parametrize('protocol', ['http', 'https', 'ws', 'wss'])
def test_proxies_from_env(monkeypatch, protocol) -> None:
url = URL('http://aiohttp.io/path')
mocker.patch.dict(os.environ, {'http_proxy': str(url)})
ret = helpers.proxies_from_env()
assert ret.keys() == {'http'}
assert ret['http'].proxy == url
assert ret['http'].proxy_auth is None


def test_proxies_from_env_http_proxy_for_https_proto(mocker) -> None:
url = URL('http://aiohttp.io/path')
mocker.patch.dict(os.environ, {'https_proxy': str(url)})
monkeypatch.setenv(protocol + '_proxy', str(url))
ret = helpers.proxies_from_env()
assert ret.keys() == {'https'}
assert ret['https'].proxy == url
assert ret['https'].proxy_auth is None
assert ret.keys() == {protocol}
assert ret[protocol].proxy == url
assert ret[protocol].proxy_auth is None


def test_proxies_from_env_https_proxy_skipped(mocker) -> None:
url = URL('https://aiohttp.io/path')
mocker.patch.dict(os.environ, {'https_proxy': str(url)})
log = mocker.patch('aiohttp.log.client_logger.warning')
@pytest.mark.parametrize('protocol', ['https', 'wss'])
def test_proxies_from_env_skipped(monkeypatch, caplog, protocol) -> None:
url = URL(protocol + '://aiohttp.io/path')
monkeypatch.setenv(protocol + '_proxy', str(url))
assert helpers.proxies_from_env() == {}
log.assert_called_with('HTTPS proxies %s are not supported, ignoring',
URL('https://aiohttp.io/path'))
assert len(caplog.records) == 1
log_message = (
'{proto!s} proxies {url!s} are not supported, ignoring'.
format(proto=protocol.upper(), url=url)
)
assert caplog.record_tuples == [('aiohttp.client', 30, log_message)]


def test_proxies_from_env_http_with_auth(mocker) -> None:
Expand Down