nhttp_h2_frame (nhttp_lib v1.0.0)

View Source

HTTP/2 binary frame encoding and decoding.

This module implements RFC 9113 Section 4-6 binary framing layer. It provides zero-copy parsing using binary pattern matching and efficient encoding using iolists.

Decoding

case nhttp_h2_frame:decode(Data) of
    {ok, Frame, Rest} -> handle_frame(Frame), decode(Rest);
    {more, MinBytes} -> wait_for_data(MinBytes);
    {error, Error} -> handle_error(Error)
end.

Encoding

{ok, Frame} = nhttp_h2_frame:headers(StreamId, fin, fin, HeaderBlock),
ok = ssl:send(Socket, Frame).

Summary

Functions

Encode a DATA frame.

Decode a single frame from binary data. Returns {ok, Frame, BytesConsumed} where BytesConsumed is the number of bytes consumed from the input. Use split_at/2 to get the remaining buffer. Uses default max frame size (16384 bytes).

Decode a single frame with custom max frame size. The max frame size should come from peer's SETTINGS_MAX_FRAME_SIZE.

Decode all complete frames from binary data. Returns {ok, Frames, BytesConsumed} with list of decoded frames.

Decode settings payload (for use in connection layer).

Encode a HEADERS frame without priority.

Split header block into HEADERS + CONTINUATION frames if needed.

Encode a PING frame.

Encode a PING acknowledgment.

HTTP/2 connection preface magic string.

Encode a PRIORITY frame.

Encode a RST_STREAM frame.

Encode a SETTINGS frame.

Encode a SETTINGS acknowledgment.

Split buffer at position, returning the remainder. This is the intentional single allocation point for callers.

Encode a connection-level WINDOW_UPDATE frame.

Encode a stream-level WINDOW_UPDATE frame.

Types

decode_all_result()

-type decode_all_result() :: {ok, [t()], BytesConsumed :: non_neg_integer()} | {error, decode_error()}.

decode_error()

-type decode_error() ::
          {connection_error, nhttp_h2:error_code(), Reason :: binary()} |
          {stream_error, nhttp_lib:stream_id(), nhttp_h2:error_code(), Reason :: binary()}.

decode_result()

-type decode_result() ::
          {ok, t(), BytesConsumed :: pos_integer()} |
          {more, MinBytes :: pos_integer()} |
          {error, decode_error()}.

t()

-type t() ::
          {data, nhttp_lib:stream_id(), nhttp_h2:fin(), Payload :: binary()} |
          {headers, nhttp_lib:stream_id(), nhttp_h2:fin(), nhttp_h2:fin(), HeaderBlock :: binary()} |
          {headers,
           nhttp_lib:stream_id(),
           nhttp_h2:fin(),
           nhttp_h2:fin(),
           nhttp_h2:priority(),
           HeaderBlock :: binary()} |
          {priority, nhttp_lib:stream_id(), nhttp_h2:priority()} |
          {rst_stream, nhttp_lib:stream_id(), nhttp_h2:error_code()} |
          {settings, nhttp_h2:settings()} |
          settings_ack |
          {push_promise,
           nhttp_lib:stream_id(),
           nhttp_h2:fin(),
           PromisedStreamId :: nhttp_lib:stream_id(),
           HeaderBlock :: binary()} |
          {ping, OpaqueData :: binary()} |
          {ping_ack, OpaqueData :: binary()} |
          {goaway, LastStreamId :: nhttp_lib:stream_id(), nhttp_h2:error_code(), DebugData :: binary()} |
          {window_update, Increment :: pos_integer()} |
          {window_update, nhttp_lib:stream_id(), Increment :: pos_integer()} |
          {continuation, nhttp_lib:stream_id(), nhttp_h2:fin(), HeaderBlock :: binary()} |
          {unknown, Type :: non_neg_integer()} |
          preface.

Functions

continuation(StreamId, EndHeaders, HeaderBlock)

-spec continuation(StreamId, EndHeaders, HeaderBlock) -> {ok, iodata()}
                      when
                          StreamId :: nhttp_lib:stream_id(),
                          EndHeaders :: nhttp_h2:fin(),
                          HeaderBlock :: iodata().

Encode a CONTINUATION frame.

data(StreamId, EndStream, Payload)

-spec data(StreamId, EndStream, Payload) -> {ok, iodata()}
              when StreamId :: nhttp_lib:stream_id(), EndStream :: nhttp_h2:fin(), Payload :: iodata().

Encode a DATA frame.

decode(Data)

-spec decode(Data :: binary()) -> decode_result().

Decode a single frame from binary data. Returns {ok, Frame, BytesConsumed} where BytesConsumed is the number of bytes consumed from the input. Use split_at/2 to get the remaining buffer. Uses default max frame size (16384 bytes).

decode(Data, MaxFrameSize)

-spec decode(Data :: binary(), MaxFrameSize :: pos_integer()) -> decode_result().

Decode a single frame with custom max frame size. The max frame size should come from peer's SETTINGS_MAX_FRAME_SIZE.

decode_all/1

-spec decode_all(binary()) -> decode_all_result().

Decode all complete frames from binary data. Returns {ok, Frames, BytesConsumed} with list of decoded frames.

decode_settings_payload(Payload)

-spec decode_settings_payload(binary()) -> {ok, nhttp_h2:settings()} | {error, decode_error()}.

Decode settings payload (for use in connection layer).

goaway(LastStreamId, ErrorCode, DebugData)

-spec goaway(LastStreamId, ErrorCode, DebugData) -> {ok, iodata()}
                when
                    LastStreamId :: nhttp_lib:stream_id(),
                    ErrorCode :: nhttp_h2:error_code(),
                    DebugData :: iodata().

Encode a GOAWAY frame.

headers(StreamId, EndStream, EndHeaders, HeaderBlock)

-spec headers(StreamId, EndStream, EndHeaders, HeaderBlock) -> {ok, iodata()}
                 when
                     StreamId :: nhttp_lib:stream_id(),
                     EndStream :: nhttp_h2:fin(),
                     EndHeaders :: nhttp_h2:fin(),
                     HeaderBlock :: iodata().

Encode a HEADERS frame without priority.

headers(StreamId, EndStream, EndHeaders, Priority, HeaderBlock)

-spec headers(StreamId, EndStream, EndHeaders, Priority, HeaderBlock) -> {ok, iodata()}
                 when
                     StreamId :: nhttp_lib:stream_id(),
                     EndStream :: nhttp_h2:fin(),
                     EndHeaders :: nhttp_h2:fin(),
                     Priority :: nhttp_h2:priority(),
                     HeaderBlock :: iodata().

Encode a HEADERS frame with priority.

headers_with_continuation(StreamId, EndStream, HeaderBlock, MaxFrameSize)

-spec headers_with_continuation(StreamId, EndStream, HeaderBlock, MaxFrameSize) -> {ok, iodata()}
                                   when
                                       StreamId :: nhttp_lib:stream_id(),
                                       EndStream :: nhttp_h2:fin(),
                                       HeaderBlock :: iodata(),
                                       MaxFrameSize :: pos_integer().

Split header block into HEADERS + CONTINUATION frames if needed.

ping(OpaqueData)

-spec ping(OpaqueData :: binary()) -> {ok, binary()}.

Encode a PING frame.

ping_ack(OpaqueData)

-spec ping_ack(OpaqueData :: binary()) -> {ok, binary()}.

Encode a PING acknowledgment.

preface()

-spec preface() -> {ok, binary()}.

HTTP/2 connection preface magic string.

priority(StreamId, Priority)

-spec priority(StreamId, Priority) -> {ok, iodata()}
                  when StreamId :: nhttp_lib:stream_id(), Priority :: nhttp_h2:priority().

Encode a PRIORITY frame.

push_promise(StreamId, PromisedStreamId, EndHeaders, HeaderBlock)

-spec push_promise(StreamId, PromisedStreamId, EndHeaders, HeaderBlock) -> {ok, iodata()}
                      when
                          StreamId :: nhttp_lib:stream_id(),
                          PromisedStreamId :: nhttp_lib:stream_id(),
                          EndHeaders :: nhttp_h2:fin(),
                          HeaderBlock :: iodata().

Encode a PUSH_PROMISE frame.

rst_stream(StreamId, ErrorCode)

-spec rst_stream(StreamId, ErrorCode) -> {ok, binary()}
                    when StreamId :: nhttp_lib:stream_id(), ErrorCode :: nhttp_h2:error_code().

Encode a RST_STREAM frame.

settings(Settings)

-spec settings(Settings :: nhttp_h2:settings()) -> {ok, iodata()}.

Encode a SETTINGS frame.

settings_ack()

-spec settings_ack() -> {ok, binary()}.

Encode a SETTINGS acknowledgment.

split_at/2

-spec split_at(binary(), non_neg_integer()) -> binary().

Split buffer at position, returning the remainder. This is the intentional single allocation point for callers.

window_update(Increment)

-spec window_update(Increment :: pos_integer()) -> {ok, binary()}.

Encode a connection-level WINDOW_UPDATE frame.

window_update(StreamId, Increment)

-spec window_update(StreamId, Increment) -> {ok, binary()}
                       when StreamId :: nhttp_lib:stream_id(), Increment :: pos_integer().

Encode a stream-level WINDOW_UPDATE frame.