| @@ -15,7 +15,7 @@ SOCKS proxy client for asyncio and aiohttp | |||||
| Dependencies | Dependencies | ||||
| ------------ | ------------ | ||||
| python 3.5+ | python 3.5+ | ||||
| aiohttp 2.0+ | |||||
| aiohttp 2.1+ | |||||
| Features | Features | ||||
| -------- | -------- | ||||
| @@ -185,3 +185,22 @@ aiohttp usage | |||||
| loop = asyncio.get_event_loop() | loop = asyncio.get_event_loop() | ||||
| loop.run_until_complete(load_github_main()) | loop.run_until_complete(load_github_main()) | ||||
| loop.close() | loop.close() | ||||
| Proxy from environment | |||||
| ^^^^^^^^^^^^^^^^^^^^^^ | |||||
| .. code-block:: python | |||||
| import os | |||||
| from aiosocks.connector import ProxyConnector, ProxyClientRequest | |||||
| os.environ['socks4_proxy'] = 'socks4://127.0.0.1:333' | |||||
| # or | |||||
| os.environ['socks5_proxy'] = 'socks5://127.0.0.1:444' | |||||
| conn = ProxyConnector() | |||||
| with aiohttp.ClientSession(connector=conn, request_class=ProxyClientRequest) as session: | |||||
| async with session.get('http://github.com/', proxy_from_env=True) as resp: | |||||
| if resp.status == 200: | |||||
| print(await resp.text()) | |||||
| @@ -8,7 +8,7 @@ from .helpers import ( | |||||
| ) | ) | ||||
| from .protocols import Socks4Protocol, Socks5Protocol, DEFAULT_LIMIT | from .protocols import Socks4Protocol, Socks5Protocol, DEFAULT_LIMIT | ||||
| __version__ = '0.2.2' | |||||
| __version__ = '0.2.3' | |||||
| __all__ = ('Socks4Protocol', 'Socks5Protocol', 'Socks4Auth', | __all__ = ('Socks4Protocol', 'Socks5Protocol', 'Socks4Auth', | ||||
| 'Socks5Auth', 'Socks4Addr', 'Socks5Addr', 'SocksError', | 'Socks5Auth', 'Socks4Addr', 'Socks5Addr', 'SocksError', | ||||
| @@ -4,6 +4,9 @@ try: | |||||
| except ImportError: | except ImportError: | ||||
| raise ImportError('aiosocks.SocksConnector require aiohttp library') | raise ImportError('aiosocks.SocksConnector require aiohttp library') | ||||
| from yarl import URL | |||||
| from urllib.request import getproxies | |||||
| from .errors import SocksError, SocksConnectionError | from .errors import SocksError, SocksConnectionError | ||||
| from .helpers import Socks4Auth, Socks5Auth, Socks4Addr, Socks5Addr | from .helpers import Socks4Auth, Socks5Auth, Socks4Addr, Socks5Addr | ||||
| from . import create_connection | from . import create_connection | ||||
| @@ -12,7 +15,16 @@ __all__ = ('ProxyConnector', 'ProxyClientRequest') | |||||
| class ProxyClientRequest(aiohttp.ClientRequest): | class ProxyClientRequest(aiohttp.ClientRequest): | ||||
| def update_proxy(self, proxy, proxy_auth): | |||||
| def update_proxy(self, proxy, proxy_auth, proxy_from_env): | |||||
| if proxy_from_env and not proxy: | |||||
| proxies = getproxies() | |||||
| proxy_url = proxies.get(self.original_url.scheme) | |||||
| if not proxy_url: | |||||
| proxy_url = proxies.get('socks4') or proxies.get('socks5') | |||||
| proxy = URL(proxy_url) if proxy_url else None | |||||
| if proxy and proxy.scheme not in ['http', 'socks4', 'socks5']: | if proxy and proxy.scheme not in ['http', 'socks4', 'socks5']: | ||||
| raise ValueError( | raise ValueError( | ||||
| "Only http, socks4 and socks5 proxies are supported") | "Only http, socks4 and socks5 proxies are supported") | ||||
| @@ -177,3 +177,38 @@ def test_proxy_client_request_invalid(loop): | |||||
| proxy=URL('socks5://proxy.org'), proxy_auth=Socks4Auth('l')) | proxy=URL('socks5://proxy.org'), proxy_auth=Socks4Auth('l')) | ||||
| assert 'proxy_auth must be None or Socks5Auth() ' \ | assert 'proxy_auth must be None or Socks5Auth() ' \ | ||||
| 'tuple for socks5 proxy' in str(cm) | 'tuple for socks5 proxy' in str(cm) | ||||
| def test_proxy_from_env_http(loop): | |||||
| proxies = {'http': 'http://proxy.org'} | |||||
| with mock.patch('aiosocks.connector.getproxies', return_value=proxies): | |||||
| req = ProxyClientRequest('GET', URL('http://python.org'), loop=loop) | |||||
| req.update_proxy(None, None, True) | |||||
| assert req.proxy == URL('http://proxy.org') | |||||
| req.original_url = URL('https://python.org') | |||||
| req.update_proxy(None, None, True) | |||||
| assert req.proxy is None | |||||
| proxies.update({'https': 'http://proxy.org', | |||||
| 'socks4': 'socks4://127.0.0.1:33', | |||||
| 'socks5': 'socks5://localhost:44'}) | |||||
| req.update_proxy(None, None, True) | |||||
| assert req.proxy == URL('http://proxy.org') | |||||
| def test_proxy_from_env_socks(loop): | |||||
| proxies = {'socks4': 'socks4://127.0.0.1:33', | |||||
| 'socks5': 'socks5://localhost:44'} | |||||
| with mock.patch('aiosocks.connector.getproxies', return_value=proxies): | |||||
| req = ProxyClientRequest('GET', URL('http://python.org'), loop=loop) | |||||
| req.update_proxy(None, None, True) | |||||
| assert req.proxy == URL('socks4://127.0.0.1:33') | |||||
| del proxies['socks4'] | |||||
| req.update_proxy(None, None, True) | |||||
| assert req.proxy == URL('socks5://localhost:44') | |||||