HPACK Implementation for Erlang
Erlang Makefile
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src
test
.gitignore
.travis.yml
LICENSE
Makefile
README.md
rebar.config
rebar.lock

README.md

hpack

HPACK Implementation for Erlang

HPACK RFC-7541

This implementation was designed for use by Chatterbox, but could be used by any HTTP/2 implementation (or, if something other than HTTP/2 has need for HPACK, this would work as well).

Why Separate?

  • Use in other projects
  • A separate RFC seemed like a really clear abstraction

What's Covered

What's not covered

HTTP/2 Frames

An HTTP/2 implementation should be responsible for anything you need to do in order to read a compressed header block from various PUSH_PROMISE, HEADERS, and/or CONTINUATION frames. Once you have a complete block, you can use this library to turn it into something you can use for fulfilling HTTP requests

API

Creating Contexts

hpack provides a single type that represents both encoding and decoding contexts. A new context can be created with hpack:new_context/0 or hpack:new_context/1 (passing the size for the HEADER_TABLE_SIZE setting).

Changing table size

If HTTP/2 settings get renegotiated, you can pass that information along by calling hpack:new_max_table_size/2, like this:

NewContext = hpack:new_max_table_size(NewSize, OldContext).

Decoding Headers

Decode a headers binary with hpack:decode/2. It's your job to assemble the binary if it's coming from multiple HTTP/2 frames.

{ok, {Headers, NewContext}} = hpack:decode(Binary, OldContext).

Headers is a list of headers, where each header is a {binary(), binary()} tuple.

Encoding Headers

Encoding headers works the same way, only a [{binary(), binary()}] goes in, and a binary() comes out.

{Bin, NewContext} = hpack:encode(Headers, OldContext),

Soup to nuts

Here's how to do the whole thing!

DecodeContext1 = hpack:new_context(), %% Server context
EncodeContext1 = hpack:new_context(), %% Client context

ClientRequestHeaders = [
        {<<":method">>, <<"GET">>},
        {<<":path">>, <<"/">>},
        {<<"X-Whatev">>, <<"commands">>}
    ],

%% Client operation
{RequestHeadersBin, EncodeContext2} = hpack:encode(
    ClientRequestHeaders,
    EncodeContext1),

%% Server operation, after receiving RequestHeadersBin
{ok, {ServerRequestHeaders, DecodeContext2}} = hpack:decode(
    RequestHeadersBin,
    DecodeContext1),

%% Note the following truths:
ClientRequestHeaders = ServerRequestHeaders,
EncodeContext1 = DecodeContext1,
EncodeContext2 = DecodeContext2.

The whole reason HPACK works is that the client and server both keep their contexts in sync with each other.

Note: I used the terms client and server here, but it could as easily be sender and receiver if you're a proxy.