Sign in

    gaato/http/multipart does not have a README file

    MultipartError

    pub(all) suberror MultipartError {
    InvalidBoundary(String)
    BoundaryCollision
    InvalidHeaderValue(String)
    StreamPart(String)
    } derive(
    Debug
    )

    Multipart validation and encoding failures.

    MultipartError::to_repr

    Formats a multipart failure for debugging.

    Part

    pub(all) struct Part {
    name : String
    filename : String?
    content_type : String?
    body :
    Body

    } derive(Eq,
    Debug
    )

    A single multipart/form-data field with an optional filename and media type. Its body is bytes, or a stream read as the request is sent (Part::file_stream).

    Part::equal

    fn Part::equal(Part, Part) -> Bool

    Compares every part field, including the body bytes.

    Part::file

    fn Part::file(name : String, filename : String, content_type : String, body : Bytes) -> Part

    Creates a file field, preserving the supplied body bytes exactly.

    test {
    let part = @multipart.Part::file(
    "upload", "data.bin", "application/octet-stream", b"\x00\xFF",
    )
    assert_eq(part.filename, Some("data.bin"))
    assert_eq(part.body, Bytes(b"\x00\xFF"))
    }

    Part::file_stream

    fn Part::file_stream(name : String, filename : String, content_type : String, stream : &
    BodyStream
    , length? : Int64) -> Part

    Creates a file field whose body is read from stream as the request is sent, so the file need not be held in memory. With length, the stream must produce exactly that many bytes; when every part's length is known, the multipart body is sent with Content-Length, otherwise chunked. The part can be sent once, like any stream body (@http.StreamBody).

    Part::json

    fn Part::json(name : String, value : Json) -> Part

    Creates a JSON field encoded as UTF-8 with content type application/json.

    test {
    let part = @multipart.Part::json("metadata", { "ok": true })
    assert_eq(part.content_type, Some("application/json"))
    assert_eq(part.body, Bytes(b"{\"ok\":true}"))
    }

    Part::not_equal

    fn Part::not_equal(x : Part, y : Part) -> Bool

    Compares every part field, including the body bytes.

    Part::text

    fn Part::text(name : String, value : String) -> Part

    Creates a UTF-8 text field without a content type.

    test {
    assert_eq(@multipart.Part::text("message", "hello").body, Bytes(b"hello"))
    }

    Part::to_repr

    Formats a part for debugging.

    apply

    fn apply(request :
    Request
    , parts : Array[Part], boundary : String) ->
    Request
    raise MultipartError

    Returns an independent request with an encoded multipart body (encode_body) and replaces every existing Content-Type value.

    test {
    let request = @http.Request::post("/upload").header("x-id", "42")
    let result = @multipart.apply(
    request,
    [@multipart.Part::text("message", "hello")],
    "example",
    )
    assert_eq(
    result.headers.get("content-type"),
    Some("multipart/form-data; boundary=example"),
    )
    assert_eq(request.headers.get("content-type"), None)
    }

    encode

    fn encode(parts : Array[Part], boundary : String) -> (String, Bytes) raise MultipartError

    Encodes fields as multipart/form-data and returns its Content-Type value and byte-exact body. A stream part raises StreamPart: see encode_body.

    test {
    let (content_type, body) = @multipart.encode(
    [@multipart.Part::text("message", "hello")],
    "example",
    )
    assert_eq(content_type, "multipart/form-data; boundary=example")
    assert_true(body.has_suffix(b"--example--\r\n"[:]))
    }

    encode_body

    fn encode_body(parts : Array[Part], boundary : String) -> (String,
    Body
    ) raise MultipartError

    Encodes fields as a request body: the bytes encode returns when every part is in memory, and otherwise a stream that reads each stream part as it is sent. The stream has a known length, so a transport sends Content-Length, only when every stream part was given one.

    A stream part cannot be checked for the boundary before it is sent, so each is scanned as it streams: one that contains the delimiter fails the request with HttpError::Protocol before the colliding bytes go out. With make_boundary's 165 random bits a collision is not expected; the scan makes it an error instead of a corrupt body.

    test {
    let (_, body) = @multipart.encode_body(
    [@multipart.Part::text("message", "hello")],
    "B",
    )
    assert_eq(body.length(), Some(69L))
    }

    encode_segments

    fn encode_segments(parts : Array[Part], boundary : String) -> (String, Array[Bytes]) raise MultipartError

    Encodes fields like encode, but returns the body as ordered segments instead of one buffer: the framing between parts, and each part's body exactly as supplied, not copied. The segments concatenated are the body encode returns, so a host can stream a large upload without building it in memory first. A stream part raises StreamPart.

    test {
    let file = b"\x00\x01"
    let (_, segments) = @multipart.encode_segments(
    [@multipart.Part::file("upload", "a.bin", "application/octet-stream", file)],
    "example",
    )
    assert_eq(segments.length(), 3)
    assert_true(physical_equal(segments[1], file))
    }

    encode_segments_fresh

    fn encode_segments_fresh(parts : Array[Part], random? : () -> Double, attempts? : Int) -> (String, Array[Bytes]) raise MultipartError

    Encodes with a fresh random boundary, retrying only BoundaryCollision up to attempts draws. Nonpositive attempts raise BoundaryCollision without drawing.

    join_segments

    fn join_segments(segments : Array[Bytes]) -> Bytes

    Joins encoded segments into one buffer, preserving their order.

    make_boundary

    fn make_boundary(random : () -> Double) -> String

    Creates a 40-character boundary from 32 base-36 random digits. Values outside the random function's [0, 1) contract are clamped.

    test {
    assert_eq(
    @multipart.make_boundary(() => 0.0),
    "mbt-sdk-00000000000000000000000000000000",
    )
    }

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io