模块契约HTTP TE
线程
传输编码解析/编码 API 为无共享状态的纯函数,可任意线程并发调用。
成员
xhttptecoding 借用完整 Element、大小写不敏感的 Coding,以及不包含最终 q 权重的原始 Parameters。Quality 使用 0 到 1000 的定点值,缺省为 1000; ParameterCount 只统计传输编码参数。
trailers 是独立能力标记,表示客户端不会丢弃响应 Trailer。它不能携带参数或权重。 其他成员遵循 transfer-coding [ weight ]:参数必须有值,最终 q 只能出现一次、不能加 引号,并严格使用 q= 形式。参数可用 xrtHttpParamNext 继续迭代。
列表与重复字段
xrtHttpTeNext 迭代一个字段值,xrtHttpTeFieldNext 按线路顺序跨越全部重复 TE 字段。两种游标必须由初始化函数建立,并在发布第一项前完成输入全集校验;畸形后缀不会 留下半份结果。quoted-string 内的逗号不会被当作列表分隔符,HTTP #list 空成员被 忽略。
xrtHttpTeValid 与 xrtHttpTeCount 处理单字段值。xrtHttpTeParse 汇总字段数量、成员 数量、传输编码数量、字段是否存在和 trailers 能力。描述符、游标和输出均支持未对齐 存储,输入在迭代期间必须保持不变。
xrtHttpTeQuality 返回同一传输编码所有声明中的最高权重;字段缺失或没有匹配时返回零, 语法错误也返回零但会设置错误。xrtHttpTeAcceptsTrailers 使用 ERROR、END、ITEM 区分错误、不接受和接受。
HTTP/1.1 组合约束
RFC 9110 要求发送 TE 的发起端同时在 Connection 中声明 TE,使中间节点知道该 字段逐跳生效。核心层不构建拥有型请求,因此调用方应使用 xrtHttpTeParse 验证 TE, 使用 xrtHttpConnectionParse 验证连接选项,再把两条字段一并交给 HTTP/1 写出函数。 代理或自定义协议代码仍可按自身策略组合这些公开原语。
范例
参见 examples/http/te/main.c。
模块边界
| 模块 | 裁剪宏 | 作用 |
|---|---|---|
http | XRT_MODULE_HTTP | token、字段、方法、状态和 Content-Length |
http_param | XRT_MODULE_HTTP_PARAM | 参数与 quoted-string 语法 |
http_param_host | XRT_MODULE_HTTP_PARAM_HOST | 参数解码后的无分配 Host 验证 |
http_expect | XRT_MODULE_HTTP_EXPECT | Expect 字段 |
http_upgrade | XRT_MODULE_HTTP_UPGRADE | Upgrade 字段与写出 |
http_te | XRT_MODULE_HTTP_TE | TE 与 transfer-coding 参数 |
http_connection | XRT_MODULE_HTTP_CONNECTION | Connection 选项与持久连接 |
http_trailer | XRT_MODULE_HTTP_TRAILER | Trailer 声明和尾字段约束 |
http_encoding | XRT_MODULE_HTTP_ENCODING | Accept-Encoding 与 Content-Encoding |
http_decode | XRT_MODULE_HTTP_DECODE | 流式 gzip/deflate 自动解码 |
http_host | XRT_MODULE_HTTP_HOST | Host authority |
http_target | XRT_MODULE_HTTP_TARGET | 四种 request-target |
http1_head | XRT_MODULE_HTTP1_HEAD | 起始行、Header 解析与写入 |
http1_net | XRT_MODULE_HTTP1_NET | TCP 块链 Header 解析与余量保留 |
http1_tls | XRT_MODULE_HTTP1_TLS | TLS 明文块链增量 Header 解析 |
http1_body | XRT_MODULE_HTTP1_BODY | 正文计划、chunked 和 trailer |
http1_message | XRT_MODULE_HTTP1_MESSAGE | 连续内存完整消息便利层 |
http_decode 才依赖 Inflate,http1_net 才依赖网络块链,http1_tls 才依赖 TLS Stream。 只启用连续内存 HTTP/1 解析不会带入压缩、网络、TLS 或 WebSocket。
借用模型
xhttpfield、xhttp1head、xhttp1message 和所有语法游标都借用调用方输入。 解析器不复制字段名称和值,输入缓冲和字段描述符数组必须覆盖借用视图的使用期。
请求方法同时以原始 xhttp1head.Method 视图和 xhttp1head.MethodCode 枚举发布。 xrtHttpMethodParse 按大小写敏感规则识别 GET、HEAD、POST、PUT、DELETE、CONNECT、 OPTIONS、TRACE 和 PATCH;合法但未内置的方法返回 XHTTP_METHOD_OTHER,非法 token 返回 XHTTP_METHOD_INVALID。每个非零枚举值占用独立 bit,既可以作为实际方法直接 比较,也可以通过位或组合成路由方法集合。XHTTP_METHOD_CRUD 覆盖 GET、POST、PUT、 PATCH 和 DELETE,XHTTP_METHOD_ANY 覆盖全部内置方法及 OTHER;应用仍应保留原始 视图处理具体的扩展方法。
字段描述符允许位于合法的未对齐存储。实现使用安全加载,不要求调用方为了协议 解析调整缓冲布局。
XRT 不再提供动态 Header 容器。需要拥有、修改或索引 Header 的框架应在 xhttp 中建立对象模型;快速路径可以直接使用栈数组或应用自己的存储。
Host 语法
xrtHttpHostParse 保留 Host、可选端口和 IP-literal 分类,任意长度十进制端口在 协议层仍然合法,只有可放入 uint16 的值才带 XHTTP_AUTHORITY_PORT_VALUE。 xrtHttpIpv4Valid 与 xrtHttpIpv6Valid 是无错误副作用的纯谓词,公开同一套严格 IP 文本规则,扩展协议无需复制 Host 内部解析器。
xrtHttpParamHostValid 直接消费 xhttpparam 的语义值。quoted-pair 会在验证时 流式解码,任意长度 reg-name 与 IPvFuture 不进入固定缓冲,也不申请堆内存。
Header 解析
xrtHttp1RequestParse 和 xrtHttp1ResponseParse 接受从消息首字节开始的累计输入:
XHTTP1_MORE:输入尚未包含完整 Header;XHTTP1_FIELDS:Header 完整,但字段描述符容量不足,FieldCount给出需求;XHTTP1_READY:解析完成;XHTTP1_ERROR:协议、限额或参数错误。
解析器只接受 CRLF,拒绝 obs-fold、裸 LF、非法字段名、控制字符、冲突的 Content-Length、歧义 Transfer-Encoding 和非法 Upgrade。xhttp1errorinfo 提供稳定错误码、消息相对偏移和行号。
xhttp1limits 分别限制 Header 总长度、起始行、单字段行和字段数量。默认值面向 公网输入,服务端应按路由策略进一步收紧,而不是无上限增长接收缓冲。
网络热路径使用 xrtHttp1RequestParseBuffer、xrtHttp1ResponseParseBuffer 直接扫描 xnetbuf。只有完整 Header 跨块时才连续化实际 Header 前缀,函数不消费输入,Upgrade 后的余量 保持原位。TLS 对应入口是 xrtHttp1RequestParseTls、xrtHttp1ResponseParseTls;输入不足时它们 通过 xrtTlsStreamReadMore 请求下一段受限明文,Header 完成后仍由调用方消费 Head.Bytes。
正文计划
Header 完成后必须调用:
xrtHttp1RequestBodyPlan处理请求;xrtHttp1ResponseBodyPlan处理响应,并传入原请求方法。
xhttp1bodyplan 的模式是唯一分帧结论:
XHTTP1_BODY_NONE:没有正文;XHTTP1_BODY_FIXED:Content-Length 定长;XHTTP1_BODY_CHUNKED:分块编码;XHTTP1_BODY_CLOSE:由可靠 EOF 定界;XHTTP1_BODY_TUNNEL:CONNECT 或 101 后的字节不再属于 HTTP。
响应计划覆盖 HEAD、成功 CONNECT、1xx、204 和 304。调用方不应仅凭 Content-Length 判断响应正文。
流式接收
xrtHttp1BodyInit 创建无分配 reader。xrtHttp1BodyRead 每次返回一个借用正文 片段、容量请求或终态,并通过 Consumed 精确说明已消费线路字节。
xrtHttp1BodyLimitsInit 的 MaxBody 默认为 UINT64_MAX,因为底层 reader 不拥有、 聚合或分配正文。服务端、代理以及任何会持有正文的上层必须在接收前按路由和内存预算 设置有限上限,不能把该协议层默认值直接作为公网接收策略。
对于 chunked,reader 会验证 chunk-size、扩展语法、CRLF、last-chunk 和 trailer, 并严格拒绝 chunk-size 与分号或 CRLF 之间的空白,避免端点对报文边界产生分歧。 正文视图不包含分块元数据。Received 是应用正文长度,WireBytes 是正文区实际 线路长度。
当返回 XHTTP1_BODY_FIELDS 时,TrailerCount 给出所需描述符数量。调用 xrtHttp1BodyTrailers 绑定足够存储后,用同一输入继续解析,不会丢失进度。
close-delimited 模式只有在传输层给出可靠 EOF 时才传入 bEnd = true。超时、取消、 RST 和普通 EOF 不能混为同一种上层状态。
gzip 自动解码
xrtHttpDecodeCreate 直接读取解析后的字段数组。把 xrtHttp1BodyRead 发布的每个 正文片段交给 xrtHttpDecodeWrite,并只在 body reader 完成时设置 bFinal。
identity 和显式原样回退路径不复制输入。gzip/deflate 路径按 Content-Encoding 逆序流式解码,验证 gzip Header、CRC、ISIZE 和压缩流终态。每个中间层与最终 输出都受同一明文硬限额约束。
详见 HTTP 正文解码。
原始写出
xrtHttp1RequestWrite 和 xrtHttp1ResponseWrite 不添加 Host、Date、Server 或其他 策略字段。空输出用于精确测量,容量不足不会产生半个 Header。
高性能发送建议:
1. 在连接或协程栈上的小缓冲中写 Header; 2. 用 xrtNetStreamSendVec 一次提交 Header 与小正文; 3. 大正文用 xrtNetStreamSendRef、SendRefs、SendTake 或 SendBuffer; 4. chunked 正文只用 xrtHttp1ChunkLineWrite 生成短前缀,数据本身保持引用发送; 5. XNET_RESULT_AGAIN 时等待 writable/drain,不绕过网络队列硬上限。
这条路径只构造必需的线路字节,不创建请求、响应、字典或正文对象。
报文长度
xhttp1head.Bytes:起始行、Header 和最终空行的线路长度;xhttp1bodyplan.Length:定长正文长度,仅在FIXED模式有效;xhttp1body.Received:已经发布的应用正文长度;xhttp1body.WireBytes:已经消费的正文线路长度;xhttp1message.Wire.Size:连续输入中第一条完整消息的线路总长度;xhttp1message.BodyBytes:移除 chunked 元数据后的正文长度。
chunked 和 close-delimited 消息在完成前不存在可提前得知的总线路长度。
TLS 与 Upgrade
HTTP 不拥有 TLS。http1_tls 只是块链适配器,不创建连接或安全策略;证书验证、SNI、会话恢复和 ALPN 仍属于通用 TLS 模块。它按需连续化实际 Header,不增加连接级固定缓冲。
xrtHttpUpgrade*、xrtHttpConnection* 和 WebSocket 握手函数共同完成 Upgrade 验证。101 后的剩余字节必须原样交给新协议,不能继续送入 HTTP body reader。
完整消息便利层
xrtHttp1RequestMessageParse 和 xrtHttp1ResponseMessageParse 适合已经连续驻留在 内存中的报文、测试和协议网关。它们仍只借用输入,不持有堆对象。
固定长度或 close-delimited 正文可由 xrtHttp1MessageBodyView 直接查看;chunked 正文使用 xrtHttp1MessageBodyCopy 去除分帧。真正的网络热路径应优先使用流式 body reader,避免等待和复制整个消息。
扩展库边界
客户端池、重定向、重试、缓存、认证、Cookie、MIME、Multipart、FormData、SSE、 服务器路由和中间件属于独立发布的 xhttp 扩展;它们不参与 XRT 核心构建、单头包或 兼容性承诺。
xhttptecodingflag类型
单个 TE 成员标志区分 trailers、传输参数和显式权重。
| 值 | 语义 |
|---|---|
XHTTP_TE_CODING_NONE | 无 |
XHTTP_TE_CODING_TRAILERS | 支持 trailer |
XHTTP_TE_CODING_HAS_PARAMETERS | 带参数 |
XHTTP_TE_CODING_HAS_WEIGHT | 带 q 权重 |
xhttptecoding类型
TE 成员借用完整元素、编码名称和不含 q 权重的传输参数。
| 字段 | 类型 | 语义 |
|---|---|---|
Element | xstrview | Element |
Coding | xstrview | Coding |
Parameters | xstrview | Parameters |
ParameterCount | size_t | ParameterCount |
Quality | uint16 | Quality |
Flags | uint32 | 标志位 |
xhttptecursor类型
单字段游标由初始化函数建立,调用方不得直接修改。
| 字段 | 类型 | 语义 |
|---|---|---|
Offset | size_t | 偏移量 |
Validated | uint8 | 是否已校验 |
xhttptefieldcursor类型
重复字段游标同时记录当前字段和字段内位置。
| 字段 | 类型 | 语义 |
|---|---|---|
Field | size_t | Field |
Offset | size_t | 偏移量 |
Validated | uint8 | 是否已校验 |
xhttpteflag类型
TE 汇总标志明确区分字段缺失、空字段和 trailers 能力。
| 值 | 语义 |
|---|---|
XHTTP_TE_NONE | 无 |
XHTTP_TE_PRESENT | 请求携带 TE |
XHTTP_TE_ACCEPTS_TRAILERS | 接受 trailer |
XHTTP_TE_HAS_TRANSFER_CODINGS | 含传输编码 |
xhttpteinfo类型
TE 汇总保留字段、总成员和实际传输编码数量。
| 字段 | 类型 | 语义 |
|---|---|---|
FieldCount | size_t | FieldCount |
CodingCount | size_t | CodingCount |
TransferCodingCount | size_t | TransferCodingCount |
Flags | uint32 | 标志位 |
xrtHttpTeCursorInit函数
初始化单个 TE 字段值游标。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pCursor | 输出 | 非空 | 调用方存储 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
| 无 | 纯初始化 | — |
- 无 — 初始化不失败
xrtHttpTeCodingParse函数
严格解析一个不含列表分隔逗号的 TE 成员。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
Element | 输入 | 借用 | 单个成员文本 |
pCoding | 输出 | 非空 | 接收名称/权重 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
true | 已解析 | — |
false | 语法错误 | 输出不变 |
xrt.http域错误
范例已编译验证
if ( !xrtHttpTeCodingParse(SV("trailers"), &TeCoding) ||
(TeCoding.Quality != 1000u) ||
!xrtHttpTeCodingParse(SV("gzip;q=0.8"), &TeCoding) ||
(TeCoding.Quality != 800u) ) {
xrtHttpTeValid函数
完整验证一个 TE 字段值;HTTP 列表空成员会被忽略。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
Value | 输入 | 借用 | 字段值 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
true | 合法 | — |
false | 非法 | 纯谓词 |
- 无 — 纯谓词
范例已编译验证
if ( !xrtHttpTeValid(SV("gzip, deflate")) ||
!xrtHttpTeValid(SV("gzip,, ,")) ||
xrtHttpTeValid(SV("gzip;;")) ||
!xrtHttpTeCount(SV("gzip, deflate, br"), &iCount) ||
(iCount != 3u) ) {
xrtHttpTeCount函数
完整验证并统计一个 TE 字段值中的非空成员。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
Value | 输入 | 借用 | 字段值 |
pCount | 输出 | 非空 | 接收计数 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
true | 计数已写出 | — |
false | 语法错误 | 计数不变 |
xrt.http域错误
范例已编译验证
!xrtHttpTeCount(SV("gzip, deflate, br"), &iCount) ||
(iCount != 3u) ) {
xrtHttpTeNext函数
按线路顺序迭代一个完整 TE 字段值。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
Value | 输入 | 借用 | 字段值 |
pCursor | 输入/输出 | 已初始化 | 游标 |
pCoding | 输出 | 非空 | 接收成员 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
XHTTP_NEXT_ITEM | 已产出一项 | — |
XHTTP_NEXT_END | 遍历结束 | 不设错误 |
XHTTP_NEXT_ERROR | 解析失败 | xrt.http 域错误 |
xrt.http域错误
范例已编译验证
while ( xrtHttpTeNext(SV("gzip, trailers"), &TeCursor,
&TeCoding) == XHTTP_NEXT_ITEM ) {
xrtHttpTeFieldCursorInit函数
初始化跨重复 TE 字段游标。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pCursor | 输出 | 非空 | 调用方存储 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
| 无 | 纯初始化 | — |
- 无 — 初始化不失败
xrtHttpTeFieldNext函数
跨重复 TE 字段行按线路顺序迭代全部成员。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pFields | 输入 | 借用数组 | 字段数组 |
iCount | 输入 | — | 条目数 |
pCursor | 输入/输出 | 已初始化 | 游标 |
pCoding | 输出 | 非空 | 接收成员 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
XHTTP_NEXT_ITEM | 已产出一项 | — |
XHTTP_NEXT_END | 遍历结束 | 不设错误 |
XHTTP_NEXT_ERROR | 解析失败 | xrt.http 域错误 |
xrt.http域错误
范例已编译验证
while ( xrtHttpTeFieldNext(arrTeFields, 2u, &TeFieldCursor,
&TeCoding) == XHTTP_NEXT_ITEM ) {
xrtHttpTeParse函数
完整解析全部重复 TE 字段并发布零分配汇总。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pFields | 输入 | 借用数组 | 字段数组 |
iCount | 输入 | — | 条目数 |
pInfo | 输出 | 非空 | 接收汇总(chunked/编码集等) |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
true | 汇总已发布 | — |
false | 任一字段非法 | 输出不变 |
xrt.http域错误
xrtHttpTeQuality函数
返回指定传输编码的最高有效权重;缺失或不匹配返回零。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pFields | 输入 | 借用数组 | TE 字段数组 |
iCount | 输入 | — | 条目数 |
Coding | 输入 | 借用 | 编码名 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
0–1000 | 最高有效权重 | — |
0 | 缺失或不匹配(或参数错误) | XERR_ARGUMENT(非法时) |
XERR_ARGUMENT— 指针为空xrt.http域错误 — 字段值非法
xrtHttpTeAcceptsTrailers函数
完整验证并判断客户端是否声明不会丢弃 Trailer。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pFields | 输入 | 借用数组 | 字段数组 |
iCount | 输入 | — | 条目数 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
XHTTP_NEXT_ITEM | 声明 trailers(TE: trailers) | — |
XHTTP_NEXT_END | 未声明 | 不设错 |
XHTTP_NEXT_ERROR | 字段非法 | xrt.http 域错误 |
xrt.http域错误
范例已编译验证
if ( xrtHttpTeAcceptsTrailers(arrTeFields, 2u) !=
XHTTP_NEXT_ITEM ) {
常量索引常量
以下常量在本页所属头文件中定义,语义见公共头注释。
| 常量 | 说明 |
|---|---|
| XHTTP_TE_ACCEPTS_TRAILERS | 见头文件注释 |
| XHTTP_TE_CODING_HAS_PARAMETERS | 见头文件注释 |
| XHTTP_TE_CODING_HAS_WEIGHT | 见头文件注释 |
| XHTTP_TE_CODING_NONE | 见头文件注释 |
| XHTTP_TE_CODING_TRAILERS | 见头文件注释 |
| XHTTP_TE_HAS_TRANSFER_CODINGS | 见头文件注释 |
| XHTTP_TE_NONE | 见头文件注释 |
| XHTTP_TE_PRESENT | 见头文件注释 |