Expand description
multipart/mixed reader used by streaming clients.
Translates a byte stream into a stream of typed items, one JSON item per
body part. This is streaming response framing only — multipart/form-data
requests, mixed per-part content types and Content-Disposition are all out
of scope, and every part is assumed to carry a JSON document decodable as
T.
§Framing is length-driven, not parse-driven
A part’s extent is decided by its MIME headers, never by where its JSON payload happens to become syntactically complete. Two modes, in this precedence:
Content-Length: Npresent — consume exactlyNbody bytes, decode, then expect the delimiter. Exact, one part per part, no lookahead, so a part is yielded the instant its own bytes have arrived — the reader never runs a part behind a live stream.- Absent — strict RFC 2046 delimiter scan. Correct, but a part is only
emitted once the next delimiter (or the close delimiter) arrives, so a
live producer that writes part
N+1’s delimiter only when itemN+1exists leaves the reader one part behind.
Content-Length on a body part is unusual but well-formed: RFC 2046 §5.1
makes the delimiter the authoritative boundary mechanism, so a strict
parser that ignores the header still reads the stream correctly. The header
is a fast path, not a protocol fork.
§A missing close delimiter is a truncation
A complete multipart body ends with the --<boundary>-- close delimiter
(RFC 2046). A graceful end of the byte stream that did not see it is a
truncation — a proxy idle-timeout, an LB half-close, or a rolling deploy
that closed the connection mid-body — and the streaming client surfaces it
as a TransportError::Framing end-of-stream error, exactly as the SSE
path errors on a close without a terminal event: done.
This is reported by the transport rather than left to the consumer because
on the public path the consumer cannot detect it: send_streaming /
open_streaming return a boxed stream that erases the concrete
MultipartStream, so MultipartStream::saw_close_delimiter is
unreachable there, and a generic item type carries no terminal marker of its
own. (saw_close_delimiter remains available to a caller holding the
concrete stream, as diagnostic detail about the framing.) A partially
buffered part at end of stream is discarded rather than surfaced, mirroring
how the SSE parser discards an unterminated trailing event.
An aborted body — the peer’s byte stream erroring, which is what a
truncated chunked encoding looks like — is a different thing and is
surfaced as TransportError::Network. That is reserved for a genuine
transport fault (a server item that would not serialize at all).
A post-open domain failure is not an abort: the framer sends it as a
typed error part — one application/problem+json part whose body is an
RFC 9457 Problem — followed by the close delimiter. This reader decodes
such a part into TransportError::Problem (which the generated client
recovers as a typed CanonicalError), so a mid-stream domain error arrives
as a typed Err item, not a truncation. An error part is terminal: the
reader stops after it and treats it as a clean end, so a non-conforming peer
cannot smuggle further data items past a reported error.
Accumulated buffers are bounded by MAX_ACCUMULATED_BYTES for the same
reason the SSE parser bounds its own: otherwise a peer that streams an
unterminated construct grows the buffer without limit for the lifetime of a
self-healing, indefinitely-reconnecting client.
Structs§
- Multipart
Stream - Stream yielded by
parse_multipart_stream.
Constants§
- MAX_
ACCUMULATED_ BYTES - Maximum bytes the reader accumulates for a single not-yet-complete
construct — the preamble, a part’s header block, a length-less part body, or
a delimiter — before treating the peer as protocol-violating and
terminating the stream with
TransportError::Framing. Same value and same rationale as the SSE parser’s own guard.
Functions§
- boundary_
from_ content_ type - Extract the
boundaryparameter from aContent-Typeheader value. - parse_
multipart_ stream - Parse a
multipart/mixedbyte stream into a stream of typed items.