Source code for ogu_api.proxy
from __future__ import annotations
import re
__all__ = ['Proxy']
_AUTH_AT_PATTERN = re.compile(r'^([^:@]+):([^:@]+)@([^:]+):(\d+)$')
[docs]
class Proxy:
"""Normalize proxy strings to the ``http://...`` form ``tls_client`` expects.
Accepts:
- ``user:pass@host:port`` (standard URL form)
- ``host:port:user:pass`` (proxy-list form)
- ``host:port`` (no auth)
Existing scheme prefixes (``http://``, ``socks5://``, etc.) are stripped
before matching; the result is always ``http://...``.
Args:
proxy: Raw proxy string in any of the accepted forms. ``None`` to
disable.
Attributes:
proxy: Normalized proxy URL, or ``None`` when no input was provided
or the input couldn't be parsed.
Example:
>>> Proxy('user:pass@host:8080').proxy
'http://user:pass@host:8080'
>>> Proxy('host:8080:user:pass').proxy
'http://user:pass@host:8080'
>>> Proxy('host:8080').proxy
'http://host:8080'
"""
def __init__(self, proxy: str | None = None) -> None:
self.proxy: str | None = self._format_proxy(proxy)
@staticmethod
def _format_proxy(proxy: str | None) -> str | None:
if not proxy:
return None
proxy = re.sub(r'^[a-z]+://', '', proxy.strip())
auth_at_match = _AUTH_AT_PATTERN.match(proxy)
if auth_at_match:
username, password, hostname, port = auth_at_match.groups()
return f'http://{username}:{password}@{hostname}:{port}'
parts = proxy.split(':')
if len(parts) == 4:
if parts[1].isdigit():
hostname, port, username, password = parts
return f'http://{username}:{password}@{hostname}:{port}'
username, password, hostname, port = parts
if port.isdigit():
return f'http://{username}:{password}@{hostname}:{port}'
if len(parts) == 2 and parts[1].isdigit():
hostname, port = parts
return f'http://{hostname}:{port}'
return None