livery_body (livery v0.1.0)

View Source

Streaming request-body reader.

The adapter delivers body chunks, trailers, end-of-body, and reset notifications as messages to the per-request process:

  • {livery_body, Ref, {data, IoData}}
  • {livery_body, Ref, {trailers, Headers}}
  • {livery_body, Ref, eof}
  • {livery_body, Ref, {reset, Reason}}

A reader is a small value held by the handler that knows the stream reference and tracks terminal state. read/2 returns the next chunk, blocking on the mailbox up to a caller-supplied timeout. read_all/1,2 drains the entire body.

Backpressure is per-chunk: the handler reads one chunk per call, so the engine can size its windows accordingly. Real demand signaling lands with the H1 adapter; this module exposes signal_demand/2 as the hook.

Summary

Functions

Account Chunk against a running byte total and a ceiling.

Drop the remainder of the body.

discard/1 with an explicit per-chunk timeout.

Reader with a fresh reference and no demand source.

Reader for the given reference, no demand source.

Reader bound to a reference and an adapter source pid.

Read one chunk from the body, blocking up to Timeout.

Drain the entire body, returning the concatenated bytes.

read_all/1 with an explicit per-chunk timeout (16 MiB cap).

read_all/2 with an explicit byte cap (infinity disables it).

Hint to the adapter that the handler is ready for more bytes.

Types

error_reason()

-type error_reason() :: timeout | body_too_large | {limit, max_size} | {client_reset, term()}.

read_result()

-type read_result() :: {ok, iodata(), reader()} | {done, reader()} | {error, error_reason(), reader()}.

reader()

-opaque reader()

Functions

account/3

-spec account(non_neg_integer() | aborted, iodata(), non_neg_integer() | infinity) ->
                 {ok, non_neg_integer()} | over | aborted.

Account Chunk against a running byte total and a ceiling.

Used by the adapter translators to bound how much request body they forward into the per-request worker's mailbox. Returns {ok, NewTotal} while under Max, over once the ceiling is exceeded, and threads an aborted sentinel through once the stream has been cut so later chunks are ignored. Max may be infinity to disable the ceiling.

discard(R)

-spec discard(reader()) -> {ok, reader()}.

Drop the remainder of the body.

discard(R, Timeout)

-spec discard(reader(), timeout()) -> {ok, reader()}.

discard/1 with an explicit per-chunk timeout.

ended/1

-spec ended(reader()) -> boolean().

new()

-spec new() -> reader().

Reader with a fresh reference and no demand source.

new(Ref)

-spec new(reference()) -> reader().

Reader for the given reference, no demand source.

new(Ref, Source)

-spec new(reference(), pid()) -> reader().

Reader bound to a reference and an adapter source pid.

read/2

-spec read(reader(), timeout()) -> read_result().

Read one chunk from the body, blocking up to Timeout.

read_all(R)

-spec read_all(reader()) -> {ok, binary(), reader()} | {error, error_reason(), reader()}.

Drain the entire body, returning the concatenated bytes.

Buffers at most 16 MiB by default; a larger body yields {error, {limit, max_size}, _} so a handler reading an unbounded client body cannot exhaust memory. Use read_all/3 to raise or disable the cap.

read_all(R, Timeout)

-spec read_all(reader(), timeout()) -> {ok, binary(), reader()} | {error, error_reason(), reader()}.

read_all/1 with an explicit per-chunk timeout (16 MiB cap).

read_all(R, Timeout, Max)

-spec read_all(reader(), timeout(), non_neg_integer() | infinity) ->
                  {ok, binary(), reader()} | {error, error_reason(), reader()}.

read_all/2 with an explicit byte cap (infinity disables it).

ref/1

-spec ref(reader()) -> reference().

signal_demand/2

-spec signal_demand(reader(), non_neg_integer()) -> ok.

Hint to the adapter that the handler is ready for more bytes.

A no-op when no source pid is registered. Real adapters will translate this into engine-level demand (h1 read_size, h2 flow control, h3 receive credit).

source/1

-spec source(reader()) -> pid() | undefined.

trailers/1

-spec trailers(reader()) -> undefined | [{binary(), binary()}].