h2 (h2 v0.6.0)

View Source

HTTP/2 Public API

This module provides the public API for HTTP/2 client and server operations. It wraps the h2_connection state machine with a clean interface.

Client Usage

  %% Connect to a server
  {ok, Conn} = h2:connect("example.com", 443, #{}).
 
  %% Send a request
  {ok, StreamId} = h2:request(Conn, <<"GET">>, <<"/">>, [
      {<<"host">>, <<"example.com">>}
  ]).
 
  %% Receive response (messages sent to caller)
  receive
      {h2, Conn, {response, StreamId, Status, Headers}} ->
          io:format("Status: ~p~n", [Status]);
      {h2, Conn, {data, StreamId, Data, IsFin}} ->
          io:format("Data: ~p~n", [Data])
  end.
 
  %% Close connection
  ok = h2:close(Conn).

Server Usage

  %% Start server
  {ok, Server} = h2:start_server(8443, #{
      cert => "server.pem",
      key => "server-key.pem",
      handler => fun(Conn, StreamId, Method, Path, Headers) ->
          h2:send_response(Conn, StreamId, 200, [{<<"content-type">>, <<"text/plain">>}]),
          h2:send_data(Conn, StreamId, <<"Hello World!">>, true)
      end
  }).
 
  %% Stop server
  ok = h2:stop_server(Server).

Event Messages

The owner process receives the following messages:

Client: - {h2, Conn, {response, StreamId, Status, Headers}} - {h2, Conn, {data, StreamId, Data, IsFin}} - {h2, Conn, {trailers, StreamId, Trailers}} - {h2, Conn, {stream_reset, StreamId, ErrorCode}} - {h2, Conn, {goaway, LastStreamId, ErrorCode}} - {h2, Conn, closed}

Server handler receives direct calls.

Summary

Functions

Cancel a stream.

Cancel a stream with a specific error code.

Close the connection immediately.

Connect to an HTTP/2 server. Uses TLS by default on port 443.

Connect to an HTTP/2 server with options.

Transfer connection ownership.

Get peer settings.

Get local settings.

Initiate graceful connection shutdown.

Initiate connection shutdown with error code.

Send an HTTP/2 request with pre-built headers (matches quic_h3:request/2). Headers should include pseudo-headers (:method, :path, :scheme, :authority).

Send an HTTP/2 request. For body-less requests (GET, HEAD, etc.), sends HEADERS with END_STREAM. For CONNECT (RFC 7540 §8.3) leaves the stream open so the caller can send tunnel bytes via send_data.

Send an HTTP/2 request with body. Sends HEADERS without END_STREAM, then sends DATA with END_STREAM.

Send data on a stream.

Send data on a stream with end_stream flag.

Send an HTTP/2 response (server mode).

Send trailers on a stream.

Return the TCP port the server is actually listening on.

Register a pid to receive body data for a stream. By default the connection replays any DATA frames buffered before the handler was registered as {h2, Conn, {data, StreamId, Data, Fin}} messages, and the call returns ok. Pass #{drain_buffer => true} to receive the buffered frames in the reply ({ok, [{Data, Fin}, ...]}) and forward them yourself — useful for tests, rarely for production code.

Start an HTTP/2 server.

Start a named HTTP/2 server (matches quic_h3:start_server/3).

Stop an HTTP/2 server.

Wait for a client connection to reach the connected state.

Types

connect_opts/0

-type connect_opts() ::
          #{transport => tcp | ssl,
            ssl_opts => [ssl:tls_client_option()],
            cert => binary() | string(),
            key => binary() | string(),
            cacerts => [binary()],
            verify => verify_none | verify_peer,
            settings => h2_settings:settings(),
            timeout => timeout(),
            connect_timeout => timeout(),
            sync => boolean()}.

connection/0

-type connection() :: pid().

error_code/0

-type error_code() :: h2_error:error_code().

headers/0

-type headers() :: [{binary(), binary()}].

server_opts/0

-type server_opts() ::
          #{transport => ssl | tcp,
            cert => binary() | string(),
            key => binary() | string(),
            cacerts => [binary()],
            verify => verify_none | verify_peer,
            ssl_opts => [ssl:tls_option()],
            handler := fun((connection(), stream_id(), binary(), binary(), headers()) -> any()),
            settings => h2_settings:settings(),
            acceptors => pos_integer(),
            enable_connect_protocol => boolean()}.

server_ref/0

-type server_ref() :: {pid(), reference(), inet:port_number()}.

status/0

-type status() :: 100..599.

stream_id/0

-type stream_id() :: non_neg_integer().

Functions

cancel(Conn, StreamId)

-spec cancel(connection(), stream_id()) -> ok | {error, term()}.

Cancel a stream.

cancel(Conn, StreamId, ErrorCode)

-spec cancel(connection(), stream_id(), error_code()) -> ok | {error, term()}.

Cancel a stream with a specific error code.

cancel_stream(Conn, StreamId)

This function is deprecated. Use cancel/2 instead..
-spec cancel_stream(connection(), stream_id()) -> ok | {error, term()}.

cancel_stream(Conn, StreamId, ErrorCode)

This function is deprecated. Use cancel/3 instead..
-spec cancel_stream(connection(), stream_id(), error_code()) -> ok | {error, term()}.

close(Conn)

-spec close(connection()) -> ok.

Close the connection immediately.

connect(Host, Port)

-spec connect(string() | binary(), inet:port_number()) -> {ok, connection()} | {error, term()}.

Connect to an HTTP/2 server. Uses TLS by default on port 443.

connect(Host, Port, Opts)

-spec connect(string() | binary(), inet:port_number(), connect_opts()) ->
                 {ok, connection()} | {error, term()}.

Connect to an HTTP/2 server with options.

controlling_process(Conn, NewOwner)

-spec controlling_process(connection(), pid()) -> ok | {error, term()}.

Transfer connection ownership.

get_peer_settings(Conn)

-spec get_peer_settings(connection()) -> h2_settings:settings().

Get peer settings.

get_settings(Conn)

-spec get_settings(connection()) -> h2_settings:settings().

Get local settings.

goaway(Conn)

-spec goaway(connection()) -> ok | {error, term()}.

Initiate graceful connection shutdown.

goaway(Conn, ErrorCode)

-spec goaway(connection(), error_code()) -> ok | {error, term()}.

Initiate connection shutdown with error code.

request(Conn, Headers)

-spec request(connection(), headers()) -> {ok, stream_id()} | {error, term()}.

Send an HTTP/2 request with pre-built headers (matches quic_h3:request/2). Headers should include pseudo-headers (:method, :path, :scheme, :authority).

request(Conn, Headers, Opts)

-spec request(connection(), headers(), map()) -> {ok, stream_id()} | {error, term()}.

request(Conn, Method, Path, Headers)

-spec request(connection(), binary(), binary(), headers()) -> {ok, stream_id()} | {error, term()}.

Send an HTTP/2 request. For body-less requests (GET, HEAD, etc.), sends HEADERS with END_STREAM. For CONNECT (RFC 7540 §8.3) leaves the stream open so the caller can send tunnel bytes via send_data.

request(Conn, Method, Path, Headers, Body)

-spec request(connection(), binary(), binary(), headers(), binary()) ->
                 {ok, stream_id()} | {error, term()}.

Send an HTTP/2 request with body. Sends HEADERS without END_STREAM, then sends DATA with END_STREAM.

send_data(Conn, StreamId, Data)

-spec send_data(connection(), stream_id(), binary()) -> ok | {error, term()}.

Send data on a stream.

send_data(Conn, StreamId, Data, EndStream)

-spec send_data(connection(), stream_id(), binary(), boolean()) -> ok | {error, term()}.

Send data on a stream with end_stream flag.

send_response(Conn, StreamId, Status, Headers)

-spec send_response(connection(), stream_id(), status(), headers()) -> ok | {error, term()}.

Send an HTTP/2 response (server mode).

send_trailers(Conn, StreamId, Trailers)

-spec send_trailers(connection(), stream_id(), headers()) -> ok | {error, term()}.

Send trailers on a stream.

server_port(_)

-spec server_port(server_ref()) -> inet:port_number().

Return the TCP port the server is actually listening on.

set_stream_handler(Conn, StreamId, Pid)

-spec set_stream_handler(connection(), stream_id(), pid()) ->
                            ok | {ok, [{binary(), boolean()}]} | {error, term()}.

Register a pid to receive body data for a stream. By default the connection replays any DATA frames buffered before the handler was registered as {h2, Conn, {data, StreamId, Data, Fin}} messages, and the call returns ok. Pass #{drain_buffer => true} to receive the buffered frames in the reply ({ok, [{Data, Fin}, ...]}) and forward them yourself — useful for tests, rarely for production code.

Backpressure: incoming DATA is rate-limited at the HTTP/2 flow-control layer only after we dispatch it to the handler. If the handler pid cannot keep up, its mailbox grows unbounded — bound your own consumer (e.g. with a selective receive + flow-control settings) when streaming large bodies from an untrusted peer.

set_stream_handler(Conn, StreamId, Pid, Opts)

-spec set_stream_handler(connection(), stream_id(), pid(), map()) ->
                            ok | {ok, [{binary(), boolean()}]} | {error, term()}.

start_server(Port, Opts)

-spec start_server(inet:port_number(), server_opts()) -> {ok, server_ref()} | {error, term()}.

Start an HTTP/2 server.

start_server(Name, Port, Opts)

-spec start_server(atom(), inet:port_number(), server_opts()) -> {ok, server_ref()} | {error, term()}.

Start a named HTTP/2 server (matches quic_h3:start_server/3).

stop_server(_)

-spec stop_server(server_ref()) -> ok.

Stop an HTTP/2 server.

unset_stream_handler(Conn, StreamId)

-spec unset_stream_handler(connection(), stream_id()) -> ok.

wait_connected(Conn)

-spec wait_connected(connection()) -> ok | {error, term()}.

Wait for a client connection to reach the connected state.

wait_connected(Conn, Timeout)

-spec wait_connected(connection(), timeout()) -> ok | {error, term()}.