multipartkit/stream
Types
One streamed multipart part.
Opaque — inspect through all_headers/1, name/1, filename/1,
content_type/1, and body/1. The internal layout may evolve
without breaking external callers.
Body semantics:
body/1returns a single-pass yielder; once consumed it cannot be replayed. Errors that arise while reading the body (PartTooLarge,UnexpectedEndOfInput, etc.) are surfaced inline asError(_)items rather than swallowed.- The body yielder emits the part body in fixed-size chunks (up to
~64 KiB each) so consumers can fold over a large part without
loading the whole body into a single
BitArray. Smaller bodies fit in a single chunk. Per-part memory inside the parser is still bounded bymax_part_bytes.
Note: the public spec describes body as iterator.Iterator(_).
The current implementation uses gleam/yielder.Yielder(_) because
gleam_stdlib 1.0.0 dropped the iterator module.
pub opaque type StreamPart
Values
pub fn all_headers(
stream_part: StreamPart,
) -> List(#(String, String))
All headers as (name, value) pairs in input order.
pub fn body(
stream_part: StreamPart,
) -> yielder.Yielder(Result(BitArray, error.MultipartError))
The single-pass body yielder. See the type-level doc for streaming semantics.
pub fn content_type(
stream_part: StreamPart,
) -> option.Option(String)
The Content-Type header value, or None.
pub fn drain_body(
source: yielder.Yielder(Result(BitArray, error.MultipartError)),
) -> Result(BitArray, error.MultipartError)
Consume a StreamPart’s body yielder and return the concatenated bytes.
Stops at the first Error(_) and returns it. The body yielder may
emit multiple Ok(BitArray) items for large parts; this helper folds
them into a single BitArray for callers that only need the full
body in memory.
pub fn filename(stream_part: StreamPart) -> option.Option(String)
The convenience filename field derived from Content-Disposition
for form-data parts, or None.
pub fn from_datastream(
source: yielder.Yielder(BitArray),
) -> yielder.Yielder(BitArray)
Adapter that returns the source unchanged. Exists so callers can write
source |> from_datastream in a pipeline.
pub fn from_part(the_part: part.Part) -> StreamPart
Build a StreamPart from a fully buffered Part.
Useful when feeding parts into encode_stream or when adapting a
buffered parse result into the streaming API surface. The resulting
body yielder emits the buffered bytes in chunks of up to
body_chunk_size, matching the behaviour of parse_stream.
pub fn name(stream_part: StreamPart) -> option.Option(String)
The convenience name field derived from Content-Disposition for
form-data parts, or None.
pub fn parse_stream(
chunks: yielder.Yielder(BitArray),
content_type: String,
) -> Result(
yielder.Yielder(Result(StreamPart, error.MultipartError)),
error.MultipartError,
)
Parse a stream of input chunks using default_limits().
The outer Result reports errors decidable from content_type alone.
Each yielded item is a Result because once body consumption begins,
failures can arise later from message structure, limits, or truncation.
After the first Error(_) is yielded the iterator is exhausted.
pub fn parse_stream_with_limits(
chunks: yielder.Yielder(BitArray),
content_type: String,
limits: limit.Limits,
) -> Result(
yielder.Yielder(Result(StreamPart, error.MultipartError)),
error.MultipartError,
)
Parse a stream of input chunks with caller-supplied limits.
Chunks are pulled lazily: bytes are consumed from chunks only as needed
to deliver the next part’s headers and body. max_body_bytes and
max_part_bytes are both enforced incrementally as chunks arrive, so an
oversized stream — or an oversized individual part — is rejected at the
chunk that crosses the limit, not after the whole part is buffered.
Per-part memory is bounded by max_part_bytes. Body bytes are surfaced
to consumers in fixed-size chunks via StreamPart.body (see the
StreamPart doc).
pub fn to_datastream(
source: yielder.Yielder(BitArray),
) -> yielder.Yielder(BitArray)
Adapter that returns the source unchanged. Mirror of from_datastream.