首页
/ mitmproxy.net.server_spec 模块深度解析:ServerSpec 类型与 parse() 解析规则

mitmproxy.net.server_spec 模块深度解析:ServerSpec 类型与 parse() 解析规则

2026-09-05 12:53:30作者:余洋婵Anita

mitmproxy.net.server_spec 是 mitmproxy 中用于描述“上游代理或目标服务器”的基础模块。它定义了 ServerSpec 类型别名和唯一的对外函数 parse(),负责把形如 https://example.com:443example.org[::1]:8080 这样的服务器地址字符串解析为结构化的 (scheme, (host, port)) 元组。读完本文,你将掌握 ServerSpec 的完整取值范围、parse() 的正则解析规则与默认端口逻辑,以及它在 upstreamreverse 等代理模式中的实际调用链。

1. 模块定位:一个模块,一个类型,一个函数

该模块的文档页位于 API 文档入口,对应源码为 mitmproxy/net/server_spec.py。模块 docstring 开篇即点明其职责:

Server specs are used to describe an upstream proxy or server.

模块只导出两样东西,结构极其精简:

  1. ServerSpec:服务器地址的类型别名;
  2. parse():把字符串解析为 ServerSpec 的函数(带 @cache 装饰器)。

理解这两个入口,就理解了整个模块。

2. ServerSpec 类型:scheme 与 (host, port) 的元组组合

源码中的类型定义如下(见 mitmproxy/net/server_spec.py#L11-L14):

ServerSpec = tuple[
    Literal["http", "https", "http3", "tls", "dtls", "tcp", "udp", "dns", "quic"],
    tuple[str, int],
]

也就是说,一个合法的 ServerSpec 是二元组:

位置 内容 约束
第一项 协议 scheme 必须是 http / https / http3 / tls / dtls / tcp / udp / dns / quic 九种之一
第二项 (host, port) 元组 host 为字符串(支持 DNS 名、IPv4、IPv6),port 为 0–65535 的整数

例如 parse("http://example.com", "https") 返回 ("http", ("example.com", 80))

这个类型在代码库中有多处直接消费,说明它是 mitmproxy 内部“服务器地址”的统一表示:

3. parse() 函数:签名、参数与异常

parse() 的签名与官方示例(摘自 mitmproxy/net/server_spec.py#L29-L40 的 docstring):

@cache
def parse(server_spec: str, default_scheme: str) -> ServerSpec:
    """
    Parses a server mode specification, e.g.:

     - http://example.com/
     - example.org
     - example.com:443

    *Raises:*
     - ValueError, if the server specification is invalid.
    """

要点说明:

  • 参数 server_spec:待解析的地址字符串。scheme 可省略,省略时使用 default_scheme;port 也可省略,省略时使用该 scheme 的默认端口。
  • 参数 default_scheme:字符串,当输入未带 scheme:// 前缀时的兜底协议。调用方根据业务语义传入不同默认值(后文第 5 节会看到 upstream 模式传 "http"reverse 模式传 "https")。
  • 返回值ServerSpec,即 (scheme, (host, port))
  • 异常:任何非法输入都抛出 ValueError,且错误信息能精确定位到具体出错阶段(见第 6 节测试验证)。
  • @cache 装饰器:相同输入直接返回缓存结果,parse() 在代理模式解析等路径上可被反复调用而无需重复正则匹配。

4. 正则与校验:解析规则逐层拆解

4.1 匹配正则

解析的核心是一条 VERBOSE 正则(mitmproxy/net/server_spec.py#L16-L26):

server_spec_re = re.compile(
    r"""
        ^
        (?:(?P<scheme>\w+)://)?  # scheme is optional
        (?P<host>[^:/]+|\[.+\])  # hostname can be DNS name, IPv4, or IPv6 address.
        (?::(?P<port>\d+))?  #  port is optional
        /?  #  we allow a trailing backslash, but no path
        $
        """,
    re.VERBOSE,
)

逐段解读:

片段 含义
(?:(?P<scheme>\w+)://)? scheme 可选,形如 http://tls://;整个前缀可有可无
`(?P[^:/]+ [.+])`
(?::(?P<port>\d+))? port 可选,以 :数字 形式出现
/? 允许一个结尾斜杠(如 http://example.com/),但不允许任何路径——带 /path 的输入会匹配失败

4.2 三层校验

正则命中之后,parse() 还做三层显式校验,每层抛出信息不同的 ValueError

  1. scheme 白名单mitmproxy/net/server_spec.py#L45-L60):显式给出的 scheme 或 default_scheme 都必须属于九种合法值,否则抛出 Invalid server scheme: {scheme}。例如 ftp://example.com 会被拒绝。
  2. host 校验mitmproxy/net/server_spec.py#L62-L67):若 host 以 [ 开头并以 ] 结尾,先剥掉括号(即 [::1] 解析为 ::1);随后调用 mitmproxy/net/check.py 中的 check.is_valid_host(host)。该函数接受合法的 DNS 标签(字母、数字、-_,单标签不超过 63 字节)、完整主机名(总长不超过 255 字节,符合 RFC 1035)、以及可通过 ipaddress 解析的 IPv4/IPv6 地址,非法输入抛出 Invalid hostname: {host}
  3. port 校验mitmproxy/net/server_spec.py#L69-L83):显式端口直接取整;未给端口时按下表查默认值,查不到(即 tls/dtls/tcp/udp/quic……不,是其中五个无默认端口的 scheme)就抛出 Port specification missing;最后用 check.is_valid_port 确认 0 <= port <= 65535,越界抛出 Invalid port: {port}

4.3 scheme 默认端口表

源码中的默认端口映射(mitmproxy/net/server_spec.py#L73-L79):

scheme 默认端口
http 80
https 443
quic 443
http3 443
dns 53
tls / dtls / tcp / udp 无默认端口,必须显式指定 port

这是一个容易踩坑的细节:tcpudptlsdtls 这类裸传输层协议没有公认默认端口,所以 parse("example.com", "tcp") 会直接抛出 Port specification missing,而 parse("smtp.example.com:25", "tcp") 才能成功得到 ("tcp", ("smtp.example.com", 25))

5. 调用链:parse() 在代理模式解析中的位置

parse() 最主要的生产调用方是代理模式解析模块 mitmproxy/proxy/mode_specs.py。该模块负责解析 --mode 参数,其通用语法为:

mode [: mode_configuration] [@ [listen_addr:]listen_port]

例如 reverse:https://example.com@127.0.0.1:443 表示在 localhost 的 443 端口上启动一个反向代理。模式名之后的 mode_configuration 部分正是 server_spec.parse() 的输入。两个关键子类:

  • UpstreamModemitmproxy/proxy/mode_specs.py#L207-L220):对应 --mode upstream:http://proxy:8080。它调用 server_spec.parse(self.data, default_scheme="http"),随后强制要求 scheme 只能是 httphttps,否则抛出 invalid upstream proxy scheme——也就是说,虽然 parse() 本身认识九种 scheme,但 upstream 模式只接受其中两种。
  • ReverseModemitmproxy/proxy/mode_specs.py#L223-L246):对应 --mode reverse:https://target。它调用 server_spec.parse(self.data, default_scheme="https"),接受全部九种 scheme,并根据解析结果决定监听协议:http3/dtls/udp/quic 走 UDP,dns/https 同时监听 TCP 与 UDP,其余走 TCP;dns 的默认监听端口还会被覆写为 53。

从源码结构看,parse()default_scheme 参数设计正是为了这种“同一段字符串在不同模式下语义不同”的场景:example.com 作为 upstream 数据解释为 http://example.com:80,作为 reverse 数据解释为 https://example.com:443

另一个实际使用场景是 examples/contrib/upstream_pac.py 脚本,它在运行时把 PAC 脚本选出的代理 URL 送入 server_spec.parse(proxy_url, "http"),动态决定每条流量走哪个上游代理;ctx.options.direct_upstream_proxy 也经由同一函数解析。

6. 测试用例验证:合法输入与四类错误

单元测试 test/mitmproxy/net/test_server_spec.py 用参数化方式覆盖了合法路径与全部错误分支,是最好的行为规格说明。

6.1 合法输入行为

输入 spec default_scheme 解析结果
example.com https ("https", ("example.com", 443))
http://example.com https ("http", ("example.com", 80))
smtp.example.com:25 tcp ("tcp", ("smtp.example.com", 25))
http://127.0.0.1 https ("http", ("127.0.0.1", 80))
http://[::1] https ("http", ("::1", 80))
http://[::1]/ https ("http", ("::1", 80))(结尾斜杠被允许)
https://[::1]/ https ("https", ("::1", 443))
http://[::1]:8080 https ("http", ("::1", 8080))

可以看到:IPv6 字面量必须用方括号包裹(否则冒号会与端口语法冲突),解析结果中括号被剥离。

6.2 错误分支(均抛 ValueError)

输入 异常信息 触发阶段
: Invalid server specification 正则整体不匹配
ftp://example.com Invalid server scheme scheme 白名单校验
$$$ Invalid hostname check.is_valid_host 校验
example.com:999999 Invalid port 端口范围校验
example.com(default_scheme=tcp Port specification missing 该 scheme 无默认端口

7. 小结与使用建议

mitmproxy.net.server_spec 虽然只有 85 行左右源码,却是 mitmproxy 所有“指向某台服务器”配置的公共入口:--mode upstream:--mode reverse: 的目标地址、connection.via 上游记录、PAC 动态代理选择最终都收敛到同一个 parse() 函数。使用或扩展该模块时,记住三条规则即可:

  1. 输入形如 [scheme://]host[:port][/],路径部分不被接受;
  2. scheme 缺省时由调用方决定默认协议(upstream 为 http,reverse 为 https);
  3. tls/dtls/tcp/udp 没有默认端口,必须显式写 port,否则解析失败。

如需进一步深入,可继续阅读 mitmproxy/proxy/mode_specs.py 中各 ProxyMode 子类的校验逻辑,以及 test/mitmproxy/proxy/test_mode_specs.py 中对整体模式语法的测试。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384