h1 (h1 v0.2.0)
View SourceHTTP/1.1 public API.
Mirrors the surface of h2 (HTTP/2) and quic_h3 (HTTP/3) so applications can swap protocols without rewriting call sites.
Client
{ok, Conn} = h1:connect("example.com", 80, #{}).
{ok, StreamId} = h1:request(Conn, <<"GET">>, <<"/">>,
[{<<"host">>, <<"example.com">>}]).
receive
{h1, Conn, {response, StreamId, Status, _Headers}} -> ok
end.
ok = h1:close(Conn).Server
{ok, S} = h1:start_server(8080, #{
transport => tcp,
handler => fun(Conn, Id, _Method, _Path, _Hs) ->
h1:send_response(Conn, Id, 200, [{<<"content-length">>, <<"2">>}]),
h1:send_data(Conn, Id, <<"ok">>, true)
end}).
Summary
Functions
Server: reply 200 Connection Established to a classic HTTP/1.1 CONNECT (RFC 9110 §9.3.6, RFC 9112 §3.2.3 authority-form request-target) and take ownership of the raw socket. Mirror of accept_upgrade/3 for the 101 Switching Protocols case, but writes status 200 and injects no Connection/Upgrade headers so bytes after CRLF belong to the tunnel.
Server: reply 101 Switching Protocols to an upgrade request.
Server: send 100 Continue to a client waiting on Expect.
Toggle request pipelining on a client connection.
Send a request using h2-compatible pseudo-headers. The list may contain :method, :path, :authority; they're translated into the HTTP/1.1 request line + Host header.
Client: send an Upgrade request and wait for 101 Switching Protocols.
Types
-type connect_opts() :: #{transport => tcp | ssl, ssl_opts => [ssl:tls_client_option()], connect_timeout => timeout(), timeout => timeout(), pipeline => boolean(), max_keepalive_requests => pos_integer(), idle_timeout => timeout(), request_timeout => timeout()}.
-type connection() :: pid().
-type server_opts() :: #{transport => tcp | ssl, cert => binary() | string(), key => binary() | string(), cacerts => [binary()], handler := fun((connection(), stream_id(), binary(), binary(), headers()) -> any()) | module(), acceptors => pos_integer(), handshake_timeout => timeout(), idle_timeout => timeout(), request_timeout => timeout(), max_keepalive_requests => pos_integer()}.
-type server_ref() :: {pid(), reference(), inet:port_number()}.
-type status() :: 100..599.
-type stream_id() :: non_neg_integer().
Functions
-spec accept_connect(connection(), stream_id(), headers()) -> {ok, gen_tcp | ssl, term(), binary()} | {error, term()}.
Server: reply 200 Connection Established to a classic HTTP/1.1 CONNECT (RFC 9110 §9.3.6, RFC 9112 §3.2.3 authority-form request-target) and take ownership of the raw socket. Mirror of accept_upgrade/3 for the 101 Switching Protocols case, but writes status 200 and injects no Connection/Upgrade headers so bytes after CRLF belong to the tunnel.
-spec accept_upgrade(connection(), stream_id(), headers()) -> {ok, term(), binary()} | {error, term()}.
Server: reply 101 Switching Protocols to an upgrade request.
-spec cancel(connection(), stream_id()) -> ok | {error, term()}.
-spec cancel(connection(), stream_id(), term()) -> ok | {error, term()}.
-spec cancel_stream(connection(), stream_id()) -> ok | {error, term()}.
-spec cancel_stream(connection(), stream_id(), term()) -> ok | {error, term()}.
-spec close(connection()) -> ok.
-spec connect(string() | binary(), inet:port_number()) -> {ok, connection()} | {error, term()}.
-spec connect(string() | binary(), inet:port_number(), connect_opts()) -> {ok, connection()} | {error, term()}.
-spec continue(connection(), stream_id()) -> ok | {error, term()}.
Server: send 100 Continue to a client waiting on Expect.
-spec controlling_process(connection(), pid()) -> ok | {error, term()}.
-spec get_peer_settings(connection()) -> map().
-spec get_settings(connection()) -> map().
-spec goaway(connection()) -> ok | {error, term()}.
-spec goaway(connection(), term()) -> ok | {error, term()}.
-spec pipeline(connection(), boolean()) -> ok | {error, term()}.
Toggle request pipelining on a client connection.
-spec request(connection(), headers()) -> {ok, stream_id()} | {error, term()}.
Send a request using h2-compatible pseudo-headers. The list may contain :method, :path, :authority; they're translated into the HTTP/1.1 request line + Host header.
-spec request(connection(), headers(), map()) -> {ok, stream_id()} | {error, term()}.
-spec send_data(connection(), stream_id(), binary()) -> ok | {error, term()}.
-spec send_data(connection(), stream_id(), binary(), boolean()) -> ok | {error, term()}.
-spec send_response(connection(), stream_id(), status(), headers()) -> ok | {error, term()}.
-spec send_trailers(connection(), stream_id(), headers()) -> ok | {error, term()}.
-spec server_port(server_ref()) -> inet:port_number().
-spec set_stream_handler(connection(), stream_id(), pid()) -> ok | {error, term()}.
-spec set_stream_handler(connection(), stream_id(), pid(), map()) -> ok | {error, term()}.
-spec start_server(inet:port_number(), server_opts()) -> {ok, server_ref()} | {error, term()}.
-spec start_server(atom(), inet:port_number(), server_opts()) -> {ok, server_ref()} | {error, term()}.
-spec stop_server(server_ref()) -> ok.
-spec unset_stream_handler(connection(), stream_id()) -> ok.
-spec upgrade(connection(), binary(), headers()) -> {ok, stream_id(), term(), binary(), headers()} | {error, term()}.
Client: send an Upgrade request and wait for 101 Switching Protocols.
-spec wait_connected(connection()) -> ok | {error, term()}.
-spec wait_connected(connection(), timeout()) -> ok | {error, term()}.