codekingpro/portable-devtools
115k
1"""2Server specs are used to describe an upstream proxy or server.3"""4 5import re6from functools import cache7from typing import Literal8 9from mitmproxy.net import check10 11ServerSpec = tuple[12 Literal["http", "https", "http3", "tls", "dtls", "tcp", "udp", "dns", "quic"],13 tuple[str, int],14]15 16server_spec_re = re.compile(17 r"""18 ^19 (?:(?P<scheme>\w+)://)? # scheme is optional20 (?P<host>[^:/]+|\[.+\]) # hostname can be DNS name, IPv4, or IPv6 address.21 (?::(?P<port>\d+))? # port is optional22 /? # we allow a trailing backslash, but no path23 $24 """,25 re.VERBOSE,26)27 28 29@cache30def parse(server_spec: str, default_scheme: str) -> ServerSpec:31 """32 Parses a server mode specification, e.g.:33 34 - http://example.com/35 - example.org36 - example.com:44337 38 *Raises:*39 - ValueError, if the server specification is invalid.40 """41 m = server_spec_re.match(server_spec)42 if not m:43 raise ValueError(f"Invalid server specification: {server_spec}")44 45 if m.group("scheme"):46 scheme = m.group("scheme")47 else:48 scheme = default_scheme49 if scheme not in (50 "http",51 "https",52 "http3",53 "tls",54 "dtls",55 "tcp",56 "udp",57 "dns",58 "quic",59 ):60 raise ValueError(f"Invalid server scheme: {scheme}")61 62 host = m.group("host")63 # IPv6 brackets64 if host.startswith("[") and host.endswith("]"):65 host = host[1:-1]66 if not check.is_valid_host(host):67 raise ValueError(f"Invalid hostname: {host}")68 69 if m.group("port"):70 port = int(m.group("port"))71 else:72 try:73 port = {74 "http": 80,75 "https": 443,76 "quic": 443,77 "http3": 443,78 "dns": 53,79 }[scheme]80 except KeyError:81 raise ValueError(f"Port specification missing.")82 if not check.is_valid_port(port):83 raise ValueError(f"Invalid port: {port}")84 85 return scheme, (host, port) # type: ignore86 