README.md

# 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