跳转至

web.serve

HTTP 序列化咽喉:reason 表 + render(全仓唯一状态行/头区拼接点) + serve 循环(§6;2b Task 3 填充) 设计: docs/superpowers/specs/2026-09-27-web-framework-design.md §4.4/§6;纪律 §14-1

§4.4 演进契约支点:报文组装只有 render 一处——状态行、头区、Content-Length、 Connection: close 全在此拼;其余代码只造 Resp(值语义),永不手拼报文串。 render 无需转义(headers/body 均为上游已构建的成品段;json_esc/ht_esc 各守其界)。 Connection: close 为 2a 同款串行口径;keep-alive 挂 L6/L7 后的并发波(spec §13-④)。

serve 循环(§6;探针定界见 task-3-report): Step 0 探针(2026-09-28)——引导 interp 双臂(bootstrap ctc.sh 裸跑 + ctron-cc run)对 use net 合并态一律 W8052 ×3(Box[Box64] extern 形参非 C-ABI)→ rc=1: interp-net 死,net 内建不可 interp 执行,真 socket e2e 挂 L6/L7 原生翻账(在册)。 因此 socket 边界做成值驱动 SrvIo(fn 值五件 listen/accept/read/write/close): 循环本体 serve_with 全量 interp 可测(fake 驱动脚本化 feed,文件尾测试即证); 真 net 接线 = 调用点十余行(net.* 五件映射进 SrvIo,例见 task-3-report)—— 不入本件:use net 会把 net/bind 的 W8052 拉进 web 合并态,check/run 门全红 (interp 净土纪律;驱动注入 = 依赖倒置的 Ctron 形,fn 值字段 Route.chain 同族)。 头解析为 Str 面自建(parse_head):todo_api 骨架的 http_parse_head 走 &I64[] lane,interp 执行面未证且 web 载体即 Str——「增量读、逐块试解析」的骨架形态 原样保留(parse 每 read 一块),载体偏离如实登记。

panic 面(执行时核实,task-3-report 在册):Ctron 无进程内 catch(? 是 Option/Result-try,非异常);探针实证 panic = 印消息后整跑中止(两 interp 臂 rc=1;native ctron_panic 终止进程)——§6「panic 兜 500」不可进程内实现,登记为 进程级边界:handler panic 即服务进程亡。缓解 = 装配期 has_conflict 自检(§7-5 失败在启动,不在半夜)+ handler 测试门(test_call);真兜底挂语言项翻账。

职责落点(§6):listen(127.0.0.1,port 参)→ accept → 增量头读(头区上限 32KB,超 400)→ CL 读体(body_limit 默认 1MB;形坏 400/超限 413 不读体)→ 构造 Req(hdrs/cookies 经 dispatch_h→req_full,params 随匹配)→ 预拼链 →handler→render→write;路径安全默认(.. 段一票 404;多余斜杠由 router path_segs 空段丢弃归一);HEAD 自动应 GET 路由(去 body 保头);内置排空端点 POST /__shutdown(loop 直拦,不过路由表;200 "draining" 后断循环关监听)。 访问日志不做 loop 侧行(log_requests 中间件即声明序挂点,§4.5 形态①)。 装配面(Task 1/2 交接,调用点口径):with_sessions(key, now) 时钟参须 | | now_ms() / 1000(now/ttl 恒 unix 秒,now_ms 是毫秒——勿直喂);会话/flash v1 边界重申(M-T1b-3):drop_session 忽略 key,flash 自清仅随 with_sessions 链。 v1 串行(§8.2):一连接一请求,多余缓冲字节(pipelining)随 close 丢弃。

pub struct

struct SrvIo

SrvIo —— socket 边界值驱动(fn 值五件;fd 全 I64 句柄,与 net/bind 同口径)。
rc 约定:listen <0 失败;accept <0 关停/失败;read 返 "" = eof/err(超时政策
由真驱动的 read 闭包内嵌,如 net_read_t 5000ms);write 返 n(<0 err);close 无值。

Field Type
listen fn(Str, I64) -> I64
accept fn(I64) -> I64
read fn(I64, I64) -> Str
write fn(I64, Str) -> I64
close fn(I64)

struct HeadReq

Field Type
method Str
target Str
hdrs List[Pair]

struct Pair

Field Type
k Str
v Str

struct Resp

Field Type
status I32
headers List[Pair]
body Str

struct JObj

Field Type
parts List[Str]

struct Req[S]

Field Type
method Str
path Str
query Str
body Str
headers List[Pair]
cookies List[Pair]
params List[Pair]
session List[Pair]
state S

struct RouteSeg

Field Type
kind Str
text Str

struct Route[S]

Field Type
m Str
segs List[RouteSeg]
chain List[fn(&Req[S], fn(&Req[S]) -> Resp) -> Resp]
h fn(&Req[S]) -> Resp

struct Router[S]

Field Type
state S
routes List[Route[S]]
mws List[fn(&Req[S], fn(&Req[S]) -> Resp) -> Resp]
not_found_h List[fn(&Req[S]) -> Resp]
not_allowed_h List[fn(&Req[S]) -> Resp]

struct Match[S]

Field Type
kind I32
route Route[S]
params List[Pair]
splat Str
allow Str

pub fn

Signature Returns Description
reason(n: I32) Str —
render(r: Resp) Str —
body_limit_default() I64 —
serve_with[S](io: SrvIo, host: Str, port: I64, r: Router[S]) I32 serve_with —— §6 循环(阻塞;排空即返 0,监听失败返 1)。启动自检 has_conflict
(路由装配 panic 的静默双兜,router.ct 前置口径)。真 net 装配 = SrvIo 五件
映射 net.*(见 task-3-report 例);端口 :0 时实际端口由驱动方经 net_tcp_sockname
回读(本件不藏 sockname——驱动句柄面已是调用点能力)。
serve_with_limit[S](io: SrvIo, host: Str, port: I64, r: Router[S], body_limit: I64) I32 —
loop_one[S](r: Router[S], method: Str, target: Str, hdrs: List[Pair], body: Str) Str loop_one —— 单请求纯核(fake 直驱可测):.. 段拒(§6 路径安全默认)→
HEAD 自动应 GET 路由 → dispatch_h(全 target;查询串在 dispatch_h 内分裂)→
render;HEAD 去 body 保头(状态行+头区原样,Content-Length 保持 GET 形态)。
head_end(buf: Str) I32 头区终点:首个 "\r\n\r\n" 起点(其 +4 起为体);未完 -1
parse_head(head: Str) HeadReq 请求行 + 头区:首行 "METHOD SP target SP HTTP/x.y"(HTTP 版后缀丢弃);
头行 "K: V" OWS 削平;同名头逗并,键保留首见大小写(值合并语义以
eq_ignore_ascii_case 同名可达为准——core hdr_get/serve cl_of 均大小写
不敏感;§8.1 请求侧政策;Cookie 双头并后 ';'-解析见 task-3-report
登记——v1 单 Cookie 头为常态面)。行切 '\n' 后削尾 '\r'。
html(body: Str) Resp —
json(body: Str) Resp —
text(body: Str) Resp —
redirect(loc: Str) Resp —
status(n: I32, body: Str) Resp —
xml(body: Str) Resp —
yaml(body: Str) Resp —
err_json(n: I32, msg: Str) Resp —
attachment(r: Resp, filename: Str) Resp —
with(r: Resp, k: Str, v: Str) Resp —
with_status(r: Resp, n: I32) Resp —
resp_header(r: Resp, k: Str) Str —
resp_body(r: Resp) Str —
resp_status(r: Resp) I32 —
json_obj() JObj —
str(b: JObj, k: Str, v: Str) JObj —
i64(b: JObj, k: Str, v: I64) JObj —
bool(b: JObj, k: Str, v: Bool) JObj —
strs(b: JObj, k: Str, xs: List[Str]) JObj —
end(b: JObj) Str —
end_status(b: JObj, n: I32) Resp —
csv_rows(headers: List[Str], rows: List[List[Str]]) Str —
req_of[S](method: Str, path: Str, state: S) Req[S] —
req_full[S](method: Str, path: Str, body: Str, hdrs: List[Pair], state: S) Req[S] —
req_set_params[S](r: &Req[S], params: List[Pair]) Req[S] —
req_set_session[S](r: &Req[S], sess: List[Pair]) Req[S] —
pdec(s: Str) Str —
param[S](r: &Req[S], name: Str) Str —
pair_get(ps: List[Pair], k: Str) Str —
param_i64[S](r: &Req[S], name: Str) Option[I64] —
param_f64[S](r: &Req[S], name: Str) Option[F64] —
query[S](r: &Req[S], name: Str) Str —
query_all[S](r: &Req[S], name: Str) List[Str] —
form[S](r: &Req[S], name: Str) Str —
form_all[S](r: &Req[S], name: Str) List[Str] —
header[S](r: &Req[S], name: Str) Str —
cookie[S](r: &Req[S], name: Str) Str —
session[S](r: &Req[S], name: Str) Str —
router[S](state: S) Router[S] —
get[S](r: Router[S], p: Str, h: fn(&Req[S]) -> Resp) Router[S] —
post[S](r: Router[S], p: Str, h: fn(&Req[S]) -> Resp) Router[S] —
put[S](r: Router[S], p: Str, h: fn(&Req[S]) -> Resp) Router[S] —
middleware[S](r: Router[S], mw: fn(&Req[S], fn(&Req[S]) -> Resp) -> Resp) Router[S] —
mount_at[S](r: Router[S], prefix: Str, sub: Router[S]) Router[S] —
has_conflict[S](r: Router[S]) Bool —
install[S](r: Router[S], p: fn(Router[S]) -> Router[S]) Router[S] —
not_found[S](r: Router[S], h: fn(&Req[S]) -> Resp) Router[S] —
method_not_allowed[S](r: Router[S], h: fn(&Req[S]) -> Resp) Router[S] —
test_call[S](r: Router[S], method: Str, path: Str, body: Str) Resp —
route_match[S](r: Router[S], m: Str, path: Str) Match[S] —
dispatch_h[S](r: Router[S], method: Str, path: Str, body: Str, hdrs: List[Pair]) Resp —
dispatch[S](r: Router[S], method: Str, path: Str, body: Str) Resp —