117 lines
3.2 KiB
Python
117 lines
3.2 KiB
Python
import socket
|
|
from typing import Optional, Any
|
|
import warnings
|
|
|
|
from .._errors import ProxyConnectionError, ProxyTimeoutError, ProxyError
|
|
|
|
from .._types import ProxyType
|
|
from .._helpers import parse_proxy_url
|
|
from .._protocols.errors import ReplyError
|
|
from .._connectors.factory_sync import create_connector
|
|
|
|
from ._stream import SyncSocketStream
|
|
from ._resolver import SyncResolver
|
|
from ._connect import connect_tcp
|
|
|
|
|
|
DEFAULT_TIMEOUT = 60
|
|
|
|
|
|
class SyncProxy:
|
|
def __init__(
|
|
self,
|
|
proxy_type: ProxyType,
|
|
host: str,
|
|
port: int,
|
|
username: Optional[str] = None,
|
|
password: Optional[str] = None,
|
|
rdns: Optional[bool] = None,
|
|
):
|
|
self._proxy_type = proxy_type
|
|
self._proxy_host = host
|
|
self._proxy_port = port
|
|
self._password = password
|
|
self._username = username
|
|
self._rdns = rdns
|
|
|
|
self._resolver = SyncResolver()
|
|
|
|
def connect(
|
|
self,
|
|
dest_host: str,
|
|
dest_port: int,
|
|
timeout: Optional[float] = None,
|
|
**kwargs: Any,
|
|
) -> socket.socket:
|
|
if timeout is None:
|
|
timeout = DEFAULT_TIMEOUT
|
|
|
|
_socket = kwargs.get('_socket')
|
|
if _socket is not None:
|
|
warnings.warn(
|
|
"The '_socket' argument is deprecated and will be removed in the future",
|
|
DeprecationWarning,
|
|
stacklevel=2,
|
|
)
|
|
|
|
if _socket is None:
|
|
local_addr = kwargs.get('local_addr')
|
|
try:
|
|
_socket = connect_tcp(
|
|
host=self._proxy_host,
|
|
port=self._proxy_port,
|
|
timeout=timeout,
|
|
local_addr=local_addr,
|
|
)
|
|
except OSError as e:
|
|
msg = 'Could not connect to proxy {}:{} [{}]'.format(
|
|
self._proxy_host,
|
|
self._proxy_port,
|
|
e.strerror,
|
|
)
|
|
raise ProxyConnectionError(e.errno, msg) from e
|
|
|
|
stream = SyncSocketStream(_socket)
|
|
|
|
try:
|
|
connector = create_connector(
|
|
proxy_type=self._proxy_type,
|
|
username=self._username,
|
|
password=self._password,
|
|
rdns=self._rdns,
|
|
resolver=self._resolver,
|
|
)
|
|
connector.connect(
|
|
stream=stream,
|
|
host=dest_host,
|
|
port=dest_port,
|
|
)
|
|
|
|
return _socket
|
|
except socket.timeout as e:
|
|
stream.close()
|
|
raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
|
|
except ReplyError as e:
|
|
stream.close()
|
|
raise ProxyError(e, error_code=e.error_code)
|
|
except Exception:
|
|
stream.close()
|
|
raise
|
|
|
|
@property
|
|
def proxy_host(self):
|
|
return self._proxy_host
|
|
|
|
@property
|
|
def proxy_port(self):
|
|
return self._proxy_port
|
|
|
|
@classmethod
|
|
def create(cls, *args, **kwargs): # for backward compatibility
|
|
return cls(*args, **kwargs)
|
|
|
|
@classmethod
|
|
def from_url(cls, url: str, **kwargs) -> 'SyncProxy':
|
|
url_args = parse_proxy_url(url)
|
|
return cls(*url_args, **kwargs)
|