| 58 | |
| 59 | |
| 60 | class ProxyServer: |
| 61 | # Pulled from constants.py so users can override any subset via config. |
| 62 | _GOOGLE_DIRECT_EXACT_EXCLUDE = GOOGLE_DIRECT_EXACT_EXCLUDE |
| 63 | _GOOGLE_DIRECT_SUFFIX_EXCLUDE = GOOGLE_DIRECT_SUFFIX_EXCLUDE |
| 64 | _GOOGLE_DIRECT_ALLOW_EXACT = GOOGLE_DIRECT_ALLOW_EXACT |
| 65 | _GOOGLE_DIRECT_ALLOW_SUFFIXES = GOOGLE_DIRECT_ALLOW_SUFFIXES |
| 66 | _TRACE_HOST_SUFFIXES = TRACE_HOST_SUFFIXES |
| 67 | _DOWNLOAD_DEFAULT_EXTS = tuple(sorted(LARGE_FILE_EXTS)) |
| 68 | _DOWNLOAD_ACCEPT_MARKERS = ( |
| 69 | "application/octet-stream", |
| 70 | "application/zip", |
| 71 | "application/x-bittorrent", |
| 72 | "video/", |
| 73 | "audio/", |
| 74 | ) |
| 75 | |
| 76 | def __init__(self, config: dict): |
| 77 | self.host = config.get("listen_host", "127.0.0.1") |
| 78 | # Prefer the new key (http_port) but keep listen_port for old configs. |
| 79 | self.port = config.get("http_port", config.get("listen_port", 8080)) |
| 80 | self.socks_enabled = True |
| 81 | self.socks_host = config.get("socks5_host", self.host) |
| 82 | self.socks_port = config.get("socks5_port", 1080) |
| 83 | if self.socks_enabled and self.socks_host == self.host \ |
| 84 | and int(self.socks_port) == int(self.port): |
| 85 | raise ValueError( |
| 86 | f"http_port and socks5_port must differ on the same host " |
| 87 | f"(both set to {self.port} on {self.host}). " |
| 88 | f"Change one of them in config.json." |
| 89 | ) |
| 90 | self.fronter = DomainFronter(config) |
| 91 | self.mitm = None |
| 92 | self._cache = ResponseCache(max_mb=CACHE_MAX_MB) |
| 93 | self._direct_fail_until: dict[str, float] = {} |
| 94 | self._servers: list[asyncio.base_events.Server] = [] |
| 95 | self._client_tasks: set[asyncio.Task] = set() |
| 96 | self._tcp_connect_timeout = self._cfg_float( |
| 97 | config, "tcp_connect_timeout", TCP_CONNECT_TIMEOUT, minimum=1.0, |
| 98 | ) |
| 99 | self._download_min_size = self._cfg_int( |
| 100 | config, "chunked_download_min_size", 5 * 1024 * 1024, minimum=0, |
| 101 | ) |
| 102 | self._download_chunk_size = self._cfg_int( |
| 103 | config, "chunked_download_chunk_size", 512 * 1024, minimum=64 * 1024, |
| 104 | ) |
| 105 | self._download_max_parallel = self._cfg_int( |
| 106 | config, "chunked_download_max_parallel", 8, minimum=1, |
| 107 | ) |
| 108 | self._download_max_chunks = self._cfg_int( |
| 109 | config, "chunked_download_max_chunks", 256, minimum=1, |
| 110 | ) |
| 111 | self._warmup_before_listen = True |
| 112 | self._warmup_timeout = 20.0 |
| 113 | self._download_extensions, self._download_any_extension = ( |
| 114 | self._normalize_download_extensions( |
| 115 | config.get( |
| 116 | "chunked_download_extensions", |
| 117 | list(self._DOWNLOAD_DEFAULT_EXTS), |