livery_body (livery v0.13.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

A reader built with a source (the adapter's translator) gives credit back for every chunk read/2 hands out, by sending {livery_body_demand, Ref, Bytes} to the source. The adapter turns it into its wire library's flow control, so a handler that reads slowly holds the client back to one flow window instead of letting the body pile up in its mailbox. Nothing is needed in handler code. HTTP/1.1, HTTP/2 and HTTP/3 all do this.

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.

The reader with a byte limit: once more than Max bytes have been read through it, read/2 returns {error, body_too_large, _}, and keeps returning it. A limit already set is only ever lowered.

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).

signal_demand/2 deprecated

Deprecated: read/2 already gives credit back for every chunk it hands out (see the module docs).

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().

limit/2

-spec limit(reader(), non_neg_integer()) -> reader().

The reader with a byte limit: once more than Max bytes have been read through it, read/2 returns {error, body_too_large, _}, and keeps returning it. A limit already set is only ever lowered.

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

This function is deprecated. livery_body:signal_demand/2 is deprecated; read/2 gives credit back for every chunk it hands out.
-spec signal_demand(reader(), non_neg_integer()) -> ok.

Deprecated: read/2 already gives credit back for every chunk it hands out (see the module docs).

Sends N bytes of credit to the reader's source. The wire libraries never grant more than was received, so a call is harmless, but it is never needed.

source/1

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

trailers/1

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