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
|
import functools
import re
from typing import Optional, Tuple
from urllib.parse import urlparse, unquote
from ._types import ProxyType
# pylint:disable-next=invalid-name
_ipv4_pattern = (
r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}'
r'(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
)
# pylint:disable-next=invalid-name
_ipv6_pattern = (
r'^(?:(?:(?:[A-F0-9]{1,4}:){6}|(?=(?:[A-F0-9]{0,4}:){0,6}'
r'(?:[0-9]{1,3}\.){3}[0-9]{1,3}$)(([0-9A-F]{1,4}:){0,5}|:)'
r'((:[0-9A-F]{1,4}){1,5}:|:)|::(?:[A-F0-9]{1,4}:){5})'
r'(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}'
r'(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])|(?:[A-F0-9]{1,4}:){7}'
r'[A-F0-9]{1,4}|(?=(?:[A-F0-9]{0,4}:){0,7}[A-F0-9]{0,4}$)'
r'(([0-9A-F]{1,4}:){1,7}|:)((:[0-9A-F]{1,4}){1,7}|:)|(?:[A-F0-9]{1,4}:){7}'
r':|:(:[A-F0-9]{1,4}){7})$'
)
_ipv4_regex = re.compile(_ipv4_pattern)
_ipv6_regex = re.compile(_ipv6_pattern, flags=re.IGNORECASE)
_ipv4_regexb = re.compile(_ipv4_pattern.encode('ascii'))
_ipv6_regexb = re.compile(_ipv6_pattern.encode('ascii'), flags=re.IGNORECASE)
def _is_ip_address(regex, regexb, host):
# if host is None:
# return False
if isinstance(host, str):
return bool(regex.match(host))
elif isinstance(host, (bytes, bytearray, memoryview)):
return bool(regexb.match(host))
else:
raise TypeError(
'{} [{}] is not a str or bytes'.format(host, type(host)) # pragma: no cover
)
is_ipv4_address = functools.partial(_is_ip_address, _ipv4_regex, _ipv4_regexb)
is_ipv6_address = functools.partial(_is_ip_address, _ipv6_regex, _ipv6_regexb)
def is_ip_address(host):
return is_ipv4_address(host) or is_ipv6_address(host)
def parse_proxy_url(url: str) -> Tuple[ProxyType, str, int, Optional[str], Optional[str]]:
parsed = urlparse(url)
scheme = parsed.scheme
if scheme == 'socks5':
proxy_type = ProxyType.SOCKS5
elif scheme == 'socks4':
proxy_type = ProxyType.SOCKS4
elif scheme == 'http':
proxy_type = ProxyType.HTTP
else:
raise ValueError(f'Invalid scheme component: {scheme}') # pragma: no cover
host = parsed.hostname
if not host:
raise ValueError('Empty host component') # pragma: no cover
try:
port = parsed.port
assert port is not None
except (ValueError, TypeError, AssertionError) as e: # pragma: no cover
raise ValueError('Invalid port component') from e
try:
username, password = (unquote(parsed.username), unquote(parsed.password))
except (AttributeError, TypeError):
username, password = '', ''
return proxy_type, host, port, username, password
|