diff --git a/CHANGES/4648.bugfix b/CHANGES/4648.bugfix new file mode 100644 index 0000000000..094eb9d492 --- /dev/null +++ b/CHANGES/4648.bugfix @@ -0,0 +1 @@ +Fix supporting WebSockets proxies configured via environment variables. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 5fa48f14ed..1ebe25b7b7 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -175,6 +175,7 @@ Manuel Miranda Marat Sharafutdinov Marco Paolini Mariano Anaya +Mariusz Masztalerczuk Martijn Pieters Martin Melka Martin Richard diff --git a/aiohttp/helpers.py b/aiohttp/helpers.py index 82665e772c..77ecfe2df2 100644 --- a/aiohttp/helpers.py +++ b/aiohttp/helpers.py @@ -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 diff --git a/docs/client_advanced.rst b/docs/client_advanced.rst index e2007352a5..e8aa05922a 100644 --- a/docs/client_advanced.rst +++ b/docs/client_advanced.rst @@ -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* (all are case insensitive):: async with aiohttp.ClientSession(trust_env=True) as session: async with session.get("http://python.org") as resp: diff --git a/tests/test_helpers.py b/tests/test_helpers.py index e46a463c79..19b51aed5d 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -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: