Bounded FastCGI 1.0 codec, Responder state machine and native async TCP server
moon check --target native
moon build --target native
moon test --target native
moon run cmd/main --target native -- 127.0.0.1:9000curl 'http://127.0.0.1:8080/api/hello?name=MoonBit'
# {"message":"hello","query":"name=MoonBit"},字段顺序不作保证
curl --data-binary @payload.bin http://127.0.0.1:8080/api/echo -o echoed.bin
curl -i http://127.0.0.1:8080/missing// moon.pkg: import { "Ryan-1125/moonfcgi" @fcgi }
fn decode_fragmented() -> Unit raise {
let decoder = @fcgi.Decoder::new()
ignore(decoder.feed(b"\x01\x05\x00"))
let records = decoder.feed(b"\x01\x00\x00\x00\x00")
assert_eq(records[0].content, b"")
decoder.finish()
}async fn main {
let handler : @server.Handler = request => {
@fcgi.Response::new(request.body, headers=[("Content-Type", "application/octet-stream")])
}
@server.serve("127.0.0.1:9000", handler)
}| API | 契约 |
|---|---|
| Decoder.feed/finish | 增量 record 解码,每次 feed 最多 65536 字节;固定约 66 KiB 暂存;EOF 检查截断;错误后不可复用 |
| encode_record / stream_records | 8 字节 header、合法 padding、65535 字节分片、显式空记录结束流;输入是 bytes |
| ParamsDecoder.feed/finish | 真正逐字节解析,长度前缀/名字/值可跨任意边界;总大小和数量有界;保留重复及非 UTF-8 参数 |
| Session.accept | 接受完整 record,依次产生 Send / Ready / Aborted / Close;不操作 socket |
| Session.complete | 绑定所属会话及请求代次;跨会话和中止后的旧结果忽略;先验证全部输出再完成会话 |
| Request.param/text_param | 原始 bytes;显式严格 UTF-8 转换可抛错;重复键取最后一项,完整列表仍保留 |
| Response.new/cgi_bytes | 有界缓冲正文;状态 200..599;有序重复头;生成 CGI Status 头、长度及输出流结束标记 |
| server.Handler/serve | async 函数接口,多连接并发;每连接一个活动请求,拥有 listener 和所有已接收 socket |
| server.serve_connection | 接管 socket,所有退出路径负责关闭;不可再交给自动关闭 socket 的回调包装器 |
moon fmt --check
moon check --target native
moon build --target native
moon test --target native
go build -o ../work/go-ref tools/reference/main.go
MOONFCGI_BIN=<native可执行文件> GO_REFERENCE_BIN=<go-ref> NGINX_BIN=<nginx> node tools/integration.mjs
node tools/consumer.mjspub struct Decoder {
// private fields
}pub struct Limits {
body_bytes : Int
params_bytes : Int
param_count : Int
response_bytes : Int
connections : Int
}fn Limits::new(body_bytes? : Int, params_bytes? : Int, param_count? : Int, response_bytes? : Int, connections? : Int) -> Limits raise ProtocolErrorpub struct ParamsDecoder {
// private fields
}pub struct Request {
id : Int
token : Int64
params : Array[(Bytes, Bytes)]
body : Bytes
// private fields
}fn Response::new(body : Bytes, status? : Int, headers? : Array[(String, String)], stderr? : Bytes) -> Response raise ProtocolErrorpub struct Session {
// private fields
}Install
Download zipBounded FastCGI 1.0 codec, Responder state machine and native async TCP server