h2_connection (h2 v0.10.2)
View SourceHTTP/2 Connection State Machine (RFC 7540)
This module implements the HTTP/2 connection protocol using gen_statem. It handles both client and server modes, managing the connection preface, settings exchange, stream lifecycle, flow control, and frame dispatch.
States: - preface: Exchanging connection preface - settings: Exchanging SETTINGS frames - connected: Ready for requests/responses - goaway_sent: Graceful shutdown initiated by us - goaway_received: Peer initiated shutdown - closing: Connection closing
Summary
Functions
Activate the socket after ownership transfer. Must be called after transferring socket ownership to this process. Synchronous so the caller knows the preface + SETTINGS have been sent and the socket has been set to active mode before it proceeds.
Cancel a stream.
Cancel a stream with a specific error code.
Close the connection.
Acknowledge consumption of ByteCount received bytes on a manual-flow stream, replenishing its receive window via WINDOW_UPDATE. No-op for streams in the default auto flow-control mode. This is the receive-side backpressure knob: a handler calls it only after it has processed data, so the peer's send window tracks consumer progress instead of growing the mailbox unboundedly.
Transfer ownership of the connection.
Get peer settings.
Get local settings.
Send a complete response (headers + full body) in one call. Returns need_fallback when the fast path does not apply; callers (h2:respond/5) then use send_response/4 + send_data/4.
Send data on a stream.
Send data on a stream with end_stream flag.
Send data with per-call options. #{block => Timeout} turns send_data into a blocking call: when the peer's window cannot accept the data yet the caller is parked (bypassing the send_buffer_full cap) until the buffer drains, returning ok, or {error, timeout} if Timeout ms elapse first. Without block this behaves exactly like send_data/4.
Send GOAWAY frame.
Send GOAWAY frame with error code.
Send a request (client mode).
Send a request with EndStream flag (client mode).
Send a request with a pre-built header list (including pseudo-headers).
Send a request with a pre-built header list and per-stream options. For gRPC bidi a dedicated call process passes #{handler => self()} so the stream's events route to it from creation (race-free, no owner detour), and optionally #{flow_control => manual} to apply receive-side backpressure. #{defer => true} buffers events until a later set_stream_handler/3 replays them when the handler pid is not known at creation time.
Send a response (server mode).
Send trailers on a stream.
Register a pid to receive body data for StreamId. By default any DATA frames that arrived before the handler was registered are replayed to the handler pid as {h2, Conn, {data, StreamId, Data, Fin}} messages, and the call returns ok. Pass #{drain_buffer => true} to receive the raw buffer in the reply ({ok, [{Data, Fin}, ...]}) and forward it manually. Matches quic_h3:set_stream_handler/3,4.
Start a connection as a client.
Start a connection with explicit owner.
Test/debug invariant: recompute the stream counters by folding the live streams` map and compare against the incrementally maintained fields. Returns `ok when they agree, {mismatch, ...} otherwise.
Wait for the connection to reach connected state.
Wait for the connection to reach connected state with timeout.
Functions
Activate the socket after ownership transfer. Must be called after transferring socket ownership to this process. Synchronous so the caller knows the preface + SETTINGS have been sent and the socket has been set to active mode before it proceeds.
-spec cancel_stream(pid(), non_neg_integer()) -> ok | {error, term()}.
Cancel a stream.
-spec cancel_stream(pid(), non_neg_integer(), atom()) -> ok | {error, term()}.
Cancel a stream with a specific error code.
-spec close(pid()) -> ok.
Close the connection.
-spec consume(pid(), non_neg_integer(), non_neg_integer()) -> ok | {error, term()}.
Acknowledge consumption of ByteCount received bytes on a manual-flow stream, replenishing its receive window via WINDOW_UPDATE. No-op for streams in the default auto flow-control mode. This is the receive-side backpressure knob: a handler calls it only after it has processed data, so the peer's send window tracks consumer progress instead of growing the mailbox unboundedly.
Transfer ownership of the connection.
-spec get_peer_settings(pid()) -> h2_settings:settings().
Get peer settings.
-spec get_settings(pid()) -> h2_settings:settings().
Get local settings.
-spec respond(pid(), non_neg_integer(), non_neg_integer(), [{binary(), binary()}], binary()) -> ok | need_fallback | {error, term()}.
Send a complete response (headers + full body) in one call. Returns need_fallback when the fast path does not apply; callers (h2:respond/5) then use send_response/4 + send_data/4.
-spec send_data(pid(), non_neg_integer(), binary()) -> ok | {error, term()}.
Send data on a stream.
-spec send_data(pid(), non_neg_integer(), binary(), boolean()) -> ok | {error, term()}.
Send data on a stream with end_stream flag.
Default (non-blocking) backpressure: when the peer's flow-control window is exhausted the data is buffered, and once the buffer would exceed the per-stream cap the call returns {error, send_buffer_full} so the caller backs off rather than growing the connection unboundedly.
Send data with per-call options. #{block => Timeout} turns send_data into a blocking call: when the peer's window cannot accept the data yet the caller is parked (bypassing the send_buffer_full cap) until the buffer drains, returning ok, or {error, timeout} if Timeout ms elapse first. Without block this behaves exactly like send_data/4.
Send GOAWAY frame.
Send GOAWAY frame with error code.
-spec send_request(pid(), binary(), binary(), [{binary(), binary()}]) -> {ok, non_neg_integer()} | {error, term()}.
Send a request (client mode).
-spec send_request(pid(), binary(), binary(), [{binary(), binary()}], boolean()) -> {ok, non_neg_integer()} | {error, term()}.
Send a request with EndStream flag (client mode).
-spec send_request_headers(pid(), [{binary(), binary()}], boolean()) -> {ok, non_neg_integer()} | {error, term()}.
Send a request with a pre-built header list (including pseudo-headers).
-spec send_request_headers(pid(), [{binary(), binary()}], boolean(), map()) -> {ok, non_neg_integer()} | {error, term()}.
Send a request with a pre-built header list and per-stream options. For gRPC bidi a dedicated call process passes #{handler => self()} so the stream's events route to it from creation (race-free, no owner detour), and optionally #{flow_control => manual} to apply receive-side backpressure. #{defer => true} buffers events until a later set_stream_handler/3 replays them when the handler pid is not known at creation time.
-spec send_response(pid(), non_neg_integer(), non_neg_integer(), [{binary(), binary()}]) -> ok | {error, term()}.
Send a response (server mode).
-spec send_trailers(pid(), non_neg_integer(), [{binary(), binary()}]) -> ok | {error, term()}.
Send trailers on a stream.
-spec set_stream_handler(pid(), non_neg_integer(), pid()) -> ok | {ok, [{binary(), boolean()}]} | {error, term()}.
Register a pid to receive body data for StreamId. By default any DATA frames that arrived before the handler was registered are replayed to the handler pid as {h2, Conn, {data, StreamId, Data, Fin}} messages, and the call returns ok. Pass #{drain_buffer => true} to receive the raw buffer in the reply ({ok, [{Data, Fin}, ...]}) and forward it manually. Matches quic_h3:set_stream_handler/3,4.
-spec start_link(client, gen_tcp:socket() | ssl:sslsocket(), map()) -> {ok, pid()} | {error, term()}.
Start a connection as a client.
-spec start_link(client | server, gen_tcp:socket() | ssl:sslsocket(), pid(), map()) -> {ok, pid()} | {error, term()}.
Start a connection with explicit owner.
-spec unset_stream_handler(pid(), non_neg_integer()) -> ok.
Test/debug invariant: recompute the stream counters by folding the live streams` map and compare against the incrementally maintained fields. Returns `ok when they agree, {mismatch, ...} otherwise.
Wait for the connection to reach connected state.
Wait for the connection to reach connected state with timeout.