1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
# -*- coding: utf-8 -*-
import socket
from aiohttp import TCPConnector
from aiohttp.abc import AbstractResolver
from yarl import URL
from .helpers import create_socket_wrapper, parse_proxy_url
from .proto import ProxyType
class NoResolver(AbstractResolver):
async def resolve(self, host, port=0, family=socket.AF_INET):
return [{'hostname': host,
'host': host, 'port': port,
'family': family, 'proto': 0,
'flags': 0}]
async def close(self):
pass # pragma: no cover
class ProxyConnector(TCPConnector):
def __init__(self, proxy_type=ProxyType.HTTP,
host=None, port=None,
username=None, password=None,
rdns=False, family=socket.AF_INET, **kwargs):
if rdns:
kwargs['resolver'] = NoResolver()
super().__init__(**kwargs)
self._proxy_type = proxy_type
self._proxy_host = host
self._proxy_port = port
self._proxy_username = username
self._proxy_password = password
self._rdns = rdns
self._proxy_family = family
@property
def proxy_url(self):
if self._proxy_username:
url = '{scheme}://{host}:{port}'.format(
scheme=self._proxy_type, host=self._proxy_host,
port=self._proxy_port)
else:
url = '{scheme}://{host}:{port}'.format(
scheme=self._proxy_type, host=self._proxy_host,
port=self._proxy_port)
return URL(url)
# noinspection PyMethodOverriding
async def _wrap_create_connection(
self, protocol_factory, host=None, port=None, *args, **kwargs):
if not self._proxy_type.is_http():
sock = create_socket_wrapper(
loop=self._loop,
proxy_type=self._proxy_type,
host=self._proxy_host, port=self._proxy_port,
username=self._proxy_username, password=self._proxy_password,
rdns=self._rdns, family=self._proxy_family)
await sock.connect((host, port))
return await super()._wrap_create_connection(
protocol_factory, None, None, *args, sock=sock.socket,
**kwargs)
else:
return await super(ProxyConnector, self)._wrap_create_connection(
protocol_factory, host, port, *args, **kwargs)
async def connect(self, req, traces, timeout):
if self._proxy_type.is_http():
req.update_proxy(self.proxy_url.with_scheme('http'), None,
req.proxy_headers)
return await super(ProxyConnector, self).connect(
req=req, traces=traces, timeout=timeout)
@classmethod
def from_url(cls, url, **kwargs):
proxy_type, host, port, username, password = parse_proxy_url(url)
return cls(proxy_type=proxy_type, host=host, port=port,
username=username, password=password, **kwargs)
|