nhttp_stream (nhttp v1.0.0)
View SourceStreaming response constructors for nhttp.
Handlers return {stream, nhttp_stream:spec(), State} from
nhttp_handler:handle_request/2 to start a chunked response. Build the
spec() with producer/3.
A fun((SendChunk) -> _) runs in a dedicated worker process. SendChunk/1
blocks until the connection has accepted the chunk, applying end-to-end
backpressure (TCP for HTTP/1.1, stream flow control for HTTP/2 and HTTP/3).
On peer close SendChunk/1 returns {error, closed} so the producer can
clean up via try/after.
handle_request(#{method := get, path := <<"/export.csv">>}, State) ->
Producer = fun(SendChunk) ->
SendChunk(<<"id,name\\n">>),
Cursor = db:open_cursor(users),
try
stream_rows(Cursor, SendChunk)
after
db:close_cursor(Cursor)
end
end,
Headers = [{<<"content-type">>, <<"text/csv">>}],
Spec = nhttp_stream:producer(200, Headers, Producer),
{stream, Spec, State}.Trailers
Return {trailers, Headers} from the producer fun to send HTTP trailers
after the body (RFC 9110 §6.5). Trailers terminate the response stream.
Producer = fun(SendChunk) ->
_ = SendChunk(ResponseBody),
{trailers, [{<<"grpc-status">>, <<"0">>}]}
end.Trailers are wired natively on HTTP/2. On HTTP/1.1 the response is terminated with the chunked-encoding terminator (without the trailer fields, since most clients do not implement RFC 9112 §7.1.2 trailer parsing). On HTTP/3 the stream is closed with FIN.
Summary
Functions
Build a producer-form streaming spec.
Types
-type producer() :: fun((send_chunk_fun()) -> ok | {trailers, nhttp_lib:headers()} | {error, term()}).
-type send_chunk_fun() :: fun((iodata()) -> ok | {error, closed | timeout}).
-type spec() :: {producer, nhttp_lib:status(), nhttp_lib:headers(), producer()}.
Functions
-spec producer(nhttp_lib:status(), nhttp_lib:headers(), producer()) -> spec().
Build a producer-form streaming spec.
Producer is a fun of arity 1 that receives a SendChunk fun and runs
in a dedicated worker process. SendChunk(IoData) blocks until the chunk
has been accepted by the connection (end-to-end backpressure). On peer
close it returns {error, closed}.
The producer terminates the body by returning. Returning ok (or
{error, _}) closes the stream cleanly. Returning
{trailers, Headers} sends those trailers as the terminator.