面向 MoonBit HTTP 生态的流式 multipart/form-data 解析与生成库,支持 RFC 7578 标准。
moon add Songyz002/moon-multipartlet content_type = "multipart/form-data; boundary=----WebKitFormBoundary"
let boundary = parse_boundary_from_content_type(content_type)?
let form = parse_all(body, boundary, ParseOptions::default())?
// 读取字段
let username = form.field("username")
// 读取同名多值
let tags = form.field_values("tag")
// 读取文件
match form.file("avatar") {
Some(part) => { let data = part.data(); let fname = part.filename() }
None => { }
}
// 读取同名多文件
let images = form.files("image")let boundary = parse_boundary_from_content_type(content_type)?
let parser = Parser::new(boundary, ParseOptions::default())
for chunk in incoming_chunks {
let events = parser.feed(chunk)?
for event in events {
match event {
PartBegin(name, filename, content_type) => { /* 新 part 开始 */ }
PartData(data) => { /* body 数据块,直接写文件/哈希 */ }
PartEnd => { /* part 结束 */ }
Finished => { /* 解析完成 */ }
}
}
}
parser.finish()?let writer = MultipartWriter::new()
writer.add_field("username", "alice")
writer.add_file("avatar", "photo.png", Some("image/png"), image_bytes)
let (boundary, body) = writer.finish()
// Content-Type: multipart/form-data; boundary=<boundary>let sw = StreamingWriter::new(boundary)
sw.begin_part("file", Some("large.bin"), Some("application/octet-stream"))
for chunk in read_file_in_chunks("large.bin") {
sw.write_chunk(chunk)
}
sw.end_part()
let body = sw.finish()// 验证
validate_filename("photo.jpg", 255)?
// 清理危险字符
let safe = safe_filename("../../../etc/passwd") // → "______etc_passwd"
// 生成唯一名称
let unique = unique_filename("photo.jpg") // → "photo_3A7F2C1D.jpg"| 类型 | 说明 |
|---|---|
| Limits | 安全限制配置,提供 default() / strict() / permissive() |
| ParseMode | Strict / Compatible |
| ParseOptions | 解析选项:mode + limits + reject_filename_star |
| Part | 解析后的 part:Field(String, String) / File(String, String, String?, Bytes) |
| MultipartForm | 高层解析结果,有序 parts,支持 field() / field_values() / file() / files() |
| MultipartError | 16 种错误类型 |
| ParseEvent | 流式事件:PartBegin / PartData / PartEnd / Finished |
| Parser | 流式解析器 |
| MultipartWriter | 基础请求体生成器 |
| StreamingWriter | 流式请求体生成器(begin_part / write_chunk / end_part) |
| 限制 | 默认值 | strict() |
|---|---|---|
| 最大 part 数量 | 1,000 | 50 |
| 最大 header 大小 | 8 KB | 4 KB |
| 最大字段大小 | 1 MB | 64 KB |
| 最大文件大小 | 100 MB | 10 MB |
| 最大总请求体 | 500 MB | 50 MB |
| 最大文件名长度 | 255 | 255 |
| 项目 | 状态 |
|---|---|
| CRLF + -- + boundary 分隔符 | ✅ |
| 首 boundary 可选前缀 CRLF | ✅ |
| boundary 参数必需 | ✅ |
| 引号 boundary | ✅ |
| boundary 长度 1-70 | ✅ |
| closing boundary -- 后缀 | ✅ |
| Content-Disposition 必需 | ✅ |
| name 参数必需 | ✅ |
| filename 参数可选 | ✅ |
| 同名字段多次出现 | ✅ MultipartForm |
| preamble 忽略 | ✅ |
| epilogue 忽略 | ✅ |
| filename* (RFC 5987) | ✅ Strict 拒绝 / Compat 接受 |
| 路径穿越防护 | ✅ |
| 流式解析(不缓存文件) | ✅ PartData 逐块输出 |
pub(all) enum BoundaryMatch {
Delimiter(Bytes, Bool)
Pending(Bytes)
NoData
}pub(all) struct Limits {
max_parts : Int
max_header_size : Int
max_field_size : Int
max_file_size : Int
max_total_size : Int
max_filename_len : Int
} derive(Debug)pub(all) enum MultipartError {
MissingBoundary
InvalidBoundary(String)
HeaderTooLarge(Int)
FieldTooLarge(String, Int)
FileTooLarge(String, Int)
TotalSizeExceeded(Int)
TooManyParts(Int)
MalformedHeader(String)
MissingName
MissingDisposition
PathTraversal(String)
FilenameTooLong(String, Int)
IncompleteBody
InvalidEncoding(String)
NonCompliantHeader(String)
ProcessingError(String)
} derive(Debug)fn MultipartWriter::add_file(self : MultipartWriter, name : String, filename : String, content_type : String?, data : Bytes) -> Unitpub(all) enum ParseEvent {
PartBegin(String, String?, String?)
PartData(Bytes)
PartEnd
Finished
} derive(Debug)pub(all) struct Parser {
boundary : String
delimiter : Bytes
boundary_prefix : Bytes
delimiter_len : Int
options : ParseOptions
buf : Buffer
phase : ParsePhase
body_buf : Buffer
part_name : String
part_filename : String?
part_content_type : String?
part_is_file : Bool
part_count : Int
total_size : Int
first_boundary_found : Bool
finished : Bool
offset : Int
}pub(all) struct StreamingWriter {
boundary : String
buf : Buffer
part_count : Int
current_part_open : Bool
}fn StreamingWriter::begin_part(self : StreamingWriter, name : String, filename : String?, content_type : String?) -> Unitfn is_dangerous_filename(filename : String) -> Boolfn parse_all(body : Bytes, boundary : String, options : ParseOptions) -> Result[MultipartForm, MultipartError]fn parse_content_disposition(header_value : String, opts : ParseOptions) -> Result[(String, String?), MultipartError]fn parse_content_disposition_simple(header_value : String) -> Result[(String, String?), MultipartError]fn safe_filename(original : String) -> Stringfn unique_filename(original : String) -> String面向 MoonBit HTTP 生态的流式 multipart/form-data 解析与生成库,支持 RFC 7578 标准。