http.ws
WebSocket(P4-C):upgrade 握手面 + RFC 6455 §5 帧编解码 形态(与 http/parse.ct 头注同源,皆发射面已证形态): ① use 图(本波实测加码,见 client.ct 头注):唯一子依赖 = std.crypto (sha1_hex;E5020 树互斥)。base64 不取 std/enc —— 其 b64_encode 入参 受 C8 printable-ASCII 约束,摘要原始字节不可作 Str 承载(登记:std/enc 字节构建面放宽后可收编);本文件自出 lane-b64(RFC 4648 标准字母表 + '=' 填充)。 ② SHA-1 仅服务 RFC 6455 握手(协议指定),非安全承载原语(见 crypto.ct SHA-1 注)。Sec-WebSocket-Accept = b64(SHA1(key + GUID))(§4.2.2); 黄金向量 = RFC 6455 §1.3 / §4.2.2 示例双锚。 ③ 升级判 = ws_upgrade_ok:upgrade 值 CI 等于 "websocket" / connection 值 逗号表含 "upgrade"(CI,OWS 容忍)/ key 严格 24 字节(16 字节 b64 —— §4.2.1 |key|==16 的串面等价,从严档)。全部收 lane 切片(消费方零 Str 转换);Host 齐备性等报文级判归 parse.ct 消费方。 ④ 帧编解码(RFC 6455 §5):编码 ws_frame_encode(掩码可选,掩码键显参 —— RFC 仅要求"不可预测",种子 RNG 面(v1 登记限制)由调用方给); 解码 ws_step 可重入状态机(chunk_step 契约同款):rc = 1 完整帧 / 0 需要更多(consumed = 真实推进;半帧状态全在 st)/ 2 dst 满(真实 推进照计,排空后重调)/ -1 协议错。掩码卸载在拷贝内联完成(掩码索引 = 载荷全局位,分片跨调用连续)。 ⑤ 从严档(协议错 → 对端应 close 1002):RSV 非零(err 1,无扩展协商)、 保留 opcode(err 2)、控制帧 FIN=0(err 3,§5.5)、控制帧载荷 >125 (err 4,§5.5)、【应掩码面未掩码】(err 5 —— 服务端读客户端帧必掩码, §5.1 MUST)/【服务端帧带掩码】(err 6,§5.1 MUST NOT)、len64 符号位 置位(err 7,§5.2)、【DATA 帧遇进行中分片】(err 9,§5.4 MUST)/ 【CONT 无进行中分片】(err 10,§5.4 MUST;控制帧插续不受限)。方向性 经 ws_st_new(expect) 注入(expect=1 解码客户端帧,=0 解码服务端帧); 消息态 frag(0 = 无进行中分片,否则 = 发起 opcode)随 WsSt 携带, fin=1 数据/续帧完成即清零。 ⑤b 文本 UTF-8(§8.1,close 1007 面):ws_utf8_valid 全量校验器(拒续 项游离/C0 C1 过长/代理区/超 U+10FFFF/F5..FF);校验点 = 消费方重组 完成处(增量宽松档:分片中段非法字节延迟到完成才报 —— RFC 8.1 Auto 惰性校验档,登记)。 ⑥ close 语义:关闭码白名单 ws_close_code_ok(1000..1003 / 1007..1011 / 3000..4999 私用段;1004/1005/1006/1015 不得上线);回声面 = 收 close 后以其码回 close(消费方经 ws_close_payload 出 2 字节 BE 载荷)。 permessage-deflate 列 P9(RSV 从严即其前置)。消息重组(text/binary 分片拼装)= 消费方按 (opcode,fin) 驱动 dst 累积(帧边界即状态,同 chunked 重组归消费方口径),本文件出 ws_is_cont/ws_is_data 判件。 ⑦ 无闭包、无 Drop 局部、无方法调用;while 体仅标量局部((f)/(g) 纪律); 成员访问不出模块(getter 面,(h) 缺口绕行)。
pub struct
struct WsSt
相:0 头1 / 1 头2 / 2 len16 / 3 len64 / 4 掩码键 / 5 载荷;
frag = 消息态(0 无进行中分片,否则发起 opcode —— §5.4 分片序列校验)
| Field | Type |
|---|---|
phase |
I64 |
fin |
I64 |
opcode |
I64 |
masked |
I64 |
expect |
I64 |
frag |
I64 |
remain |
I64 |
plen |
I64 |
mk |
I64 |
struct WsRet
解码一步结果(③ 契约;st 恒带回新状态 —— rc=1 时相已复位)
| Field | Type |
|---|---|
rc |
I64 |
err |
I64 |
consumed |
I64 |
produced |
I64 |
fin |
I64 |
opcode |
I64 |
st |
WsSt |
pub fn
| Signature | Returns | Description |
|---|---|---|
ws_guid() |
Str |
— |
ws_accept_key(key: Str) |
Str |
Sec-WebSocket-Accept = b64(SHA1(key + GUID))(§4.2.2 步骤 4;Str 面) |
ws_accept_key_lane(key: &[I64], off: I64, n: I64) |
Str |
lane 面(消费方自报文 lane 切片直取,零 Str 转换) |
ws_upgrade_ok(upg: &[I64], us: I64, ul: I64, conn: &[I64], cs: I64, cl: I64, key: &[I64], ks: I64, kl: I64, ver: &[I64], vs: I64, vl: I64) |
I64 |
升级判(§4.2.1 从严子集):1 = 可升级;0 = 拒(消费方应 400)。 upgrade 值 CI "websocket" / connection 逗号表 CI 含 "upgrade" / key 恰 24 字节 / version 值恰 "13"(§4.2.1.6 MUST 验版,非 13 → fail)。 |
ws_op_cont() |
I64 |
— |
ws_op_text() |
I64 |
— |
ws_op_binary() |
I64 |
— |
ws_op_close() |
I64 |
— |
ws_op_ping() |
I64 |
— |
ws_op_pong() |
I64 |
— |
ws_is_control(op: I64) |
I64 |
控制帧判(0x8..0xF) |
ws_is_data(op: I64) |
I64 |
数据帧判(text/binary;分片重组面用) |
ws_is_cont(op: I64) |
I64 |
分片判(continuation) |
ws_close_normal() |
I64 |
— |
ws_close_going_away() |
I64 |
— |
ws_close_protocol_error() |
I64 |
— |
ws_close_unsupported() |
I64 |
— |
ws_close_invalid_payload() |
I64 |
— |
ws_close_policy() |
I64 |
— |
ws_close_too_big() |
I64 |
— |
ws_close_no_extension() |
I64 |
— |
ws_close_unexpected() |
I64 |
— |
ws_close_code_ok(code: I64) |
I64 |
可上线关闭码白名单(1000..1003 / 1007..1011 / 3000..4999;1004/1005/1006 /1012..1014/1015 与 <1000 不得发 —— RFC 6455 §7.4) |
ws_close_payload(code: I64, out: &[I64]) |
I64 |
close 帧载荷(2 字节 BE 码);返回 2 |
ws_frame_head(out: &[I64], out_off: I64, cap: I64, opcode: I64, fin: I64, plen: I64, masked: I64, mkey: I64) |
I64 |
编码帧头(FIN/opcode/len 7/16/64/[掩码键]);返回头长。 -1 容量不足;-3 控制帧载荷 >125(§5.5)。masked=1 时 mkey = 32 位掩码键。 len64 档(>65535)10 字节头在此单点,黄金向量测试锚。 |
ws_frame_encode(out: &[I64], out_off: I64, cap: I64, opcode: I64, fin: I64, payload: &[I64], off: I64, plen: I64, masked: I64, mkey: I64) |
I64 |
编码一帧 = 帧头 + 载荷(掩码内联);返回总长。 |
ws_utf8_valid(src: &[I64], off: I64, n: I64) |
I64 |
校验 src[off..off+n) 为良构 UTF-8:1 = 全良构 / 0 = 有违(游离续项、 C0 C1 过长、E0 ED F0 F4 边界外、代理区 ED A0..BF、> U+10FFFF、F5..FF)。 |
ws_st_new(expect: I64) |
WsSt |
— |
wst_phase(st: WsSt) |
I64 |
— |
wst_opcode(st: WsSt) |
I64 |
— |
wst_fin(st: WsSt) |
I64 |
— |
wst_frag(st: WsSt) |
I64 |
— |
wst_remain(st: WsSt) |
I64 |
— |
wst_plen(st: WsSt) |
I64 |
— |
wr_rc(r: WsRet) |
I64 |
— |
wr_err(r: WsRet) |
I64 |
— |
wr_consumed(r: WsRet) |
I64 |
— |
wr_produced(r: WsRet) |
I64 |
— |
wr_fin(r: WsRet) |
I64 |
— |
wr_opcode(r: WsRet) |
I64 |
— |
wr_st(r: WsRet) |
WsSt |
— |
ws_step(src: &[I64], n: I64, pos: I64, st: WsSt, dst: &[I64], dfill: I64, dcap: I64) |
WsRet |
一步:src[pos..n) → dst[dfill..dcap)。协议错 err 码见头注⑤。 |
sha256_hex(msg: Str) |
Str |
— |
sha1_hex(msg: Str) |
Str |
— |
sha256_bytes(msg: List[I32]) |
List[I32] |
— |
hmac_sha256(key: List[I32], msg: List[I32]) |
List[I32] |
— |
bytes_to_hex(b: List[I32]) |
Str |
— |
bytes_from_hex(s: Str) |
List[I32] |
— |