# erlang_qpack
QPACK header compression for HTTP/3 (RFC 9204) in pure Erlang.
## Features
- Full RFC 9204 compliance
- Static table with O(1) map-based lookups (99 entries)
- Dynamic table with O(1) lookups and FIFO eviction
- Encoder/decoder stream support for HTTP/3
- Optional Huffman coding (RFC 7541 Appendix B)
- Stateless and stateful APIs
- Drop-in replacement for hackney_qpack/livery_qpack
## Installation
Add to your `rebar.config`:
```erlang
{deps, [
{qpack, {git, "https://github.com/benoitc/erlang_qpack.git", {tag, "0.1.0"}}}
]}.
```
## Quick Start
### Stateless API (static table only)
```erlang
%% Encode headers
Headers = [{<<":method">>, <<"GET">>}, {<<":path">>, <<"/">>}],
Encoded = qpack:encode(Headers).
%% Decode headers
{ok, Decoded} = qpack:decode(Encoded).
```
### Stateful API (with dynamic table)
```erlang
%% Create state with dynamic table
State0 = qpack:new(#{max_dynamic_size => 4096}),
%% Encode with state
{Encoded, State1} = qpack:encode(Headers, State0),
%% Decode with state
{{ok, Decoded}, State2} = qpack:decode(Encoded, State1).
```
### HTTP/3 Stream Integration
```erlang
%% Process encoder instructions from peer
{ok, State1} = qpack:process_encoder_instructions(Data, State0),
%% Get encoder instructions to send to peer
Instructions = qpack:get_encoder_instructions(State1),
%% Process decoder instructions from peer
{ok, State2} = qpack:process_decoder_instructions(AckData, State1).
```
## API Reference
See [Usage Guide](docs/usage.md) for detailed documentation.
## Benchmarks
Performance on Apple M3 Pro (Erlang/OTP 28):
| Operation | Time | Throughput |
|-----------|------|------------|
| Encode simple request (4 headers, static) | 0.45 us | 2.2M ops/s |
| Encode typical request (8 headers) | 1.25 us | 800K ops/s |
| Encode large (50 custom headers) | 7.23 us | 138K ops/s |
| Decode simple request (4 headers) | 0.14 us | 7.0M ops/s |
| Decode typical request (8 headers) | 0.43 us | 2.3M ops/s |
| Huffman encode (15 bytes) | 0.15 us | 6.5M ops/s |
| Huffman decode (15 bytes) | 0.15 us | 6.7M ops/s |
| Process encoder instruction | 0.07 us | 14.9M ops/s |
Run benchmarks:
```bash
rebar3 eunit && erl -pa _build/test/lib/qpack/ebin -pa _build/test/lib/qpack/test \
-noshell -eval "qpack_bench:run(), halt()."
```
## Development
Clone with submodules for interop test data:
```bash
git clone --recurse-submodules https://github.com/benoitc/erlang_qpack.git
```
Or initialize submodules after cloning:
```bash
git submodule update --init --recursive
```
Run tests:
```bash
rebar3 eunit # Unit tests
rebar3 ct # Common Test (includes interop tests)
```
### Interoperability Testing
The `test/qifs` submodule contains QPACK Interop Files (QIFs) from the [qpackers/qifs](https://github.com/qpackers/qifs) repository. These are used to verify compatibility with other QPACK implementations.
The interop test suite (`qpack_interop_SUITE`) tests:
- **Decoding** encoded data from other implementations (nghttp3, ls-qpack)
- **Round-trip** encoding/decoding of QIF test files
Run interop tests specifically:
```bash
rebar3 ct --suite=qpack_interop_SUITE
```
QIF files are tab-separated header blocks. Encoded files use the format:
- 8 bytes: stream ID (big-endian)
- 4 bytes: block length (big-endian)
- N bytes: encoded QPACK data
Build documentation:
```bash
rebar3 ex_doc
```
## License
Apache License 2.0