Phase 2 of issue #8. Adds Brotli (br) and zstd (zstd) backends through the
already-shipped http_encoder_t vtable. No architectural changes — phase 1
specifically built the registry, negotiation, response pipeline and request
decoder to take additional codecs as drop-ins.
Scope
- Brotli —
libbrotlienc (encode) + libbrotlidec (decode). Optional at
build time via pkg-config; --disable-brotli opts out. Default level 4
(production-typical; level 11 is research-quality but ~50× slower).
- zstd —
libzstd. Optional; --disable-zstd opts out. Default level 3
(the zstd team's own production default).
- Negotiation: extend the parser with
br / zstd recognition; preference
order at select time zstd > brotli > gzip (matches typical server policy).
q=0 rejection still wins per-codec.
- Inbound decoding:
Content-Encoding: br and zstd decoded transparently,
same anti-bomb cap as gzip; unknown codings still 415.
Config
Per-codec level setters on HttpServerConfig, frozen at server construction:
| Setter |
Default |
Range |
setBrotliLevel(int) |
4 |
0..11 |
setZstdLevel(int) |
3 |
1..22 |
setCompressionLevel keeps its gzip-only meaning. Universal interpretation
considered and rejected — codec level scales differ enough that linear mapping
loses the high end of brotli/zstd.
Out of scope
- Pre-compressed static assets (
*.br / *.zst on disk via sendfile) —
phase 3, requires file-serving rework.
- q-value-based client preference. Server-side preference order covers ~99%
of real Accept-Encoding strings; honouring client q-values exactly would
require storing q as a number (not bool) in the parser. Tracked but
not in this phase.
- Threadpool offload for very large bodies. Inline encoding measured first.
Implementation plan
- build + brotli backend — pkg-config detection,
http_compression_brotli.c
implementing the encoder vtable + a brotli decoder for inbound.
- build + zstd backend — same shape for
libzstd.
- negotiation extension — add
br / zstd token recognition + the
preference-order select; unit tests for both new codings.
- config knobs —
setBrotliLevel / setZstdLevel setters, frozen-snapshot
plumbing, phpt for setter validation + locked-config guard.
- wiring + phpt — integrate both codecs into the existing apply_buffered /
stream wrapper / decode paths (no changes there if the registry lookup
succeeds for the chosen codec); H1 buffered round-trip phpt per codec.
- docs — extend
docs/COMPRESSION.md, CHANGELOG entry.
Phase 2 of issue #8. Adds Brotli (
br) and zstd (zstd) backends through thealready-shipped
http_encoder_tvtable. No architectural changes — phase 1specifically built the registry, negotiation, response pipeline and request
decoder to take additional codecs as drop-ins.
Scope
libbrotlienc(encode) +libbrotlidec(decode). Optional atbuild time via pkg-config;
--disable-brotliopts out. Default level 4(production-typical; level 11 is research-quality but ~50× slower).
libzstd. Optional;--disable-zstdopts out. Default level 3(the zstd team's own production default).
br/zstdrecognition; preferenceorder at select time zstd > brotli > gzip (matches typical server policy).
q=0 rejection still wins per-codec.
Content-Encoding: brandzstddecoded transparently,same anti-bomb cap as gzip; unknown codings still 415.
Config
Per-codec level setters on
HttpServerConfig, frozen at server construction:setBrotliLevel(int)setZstdLevel(int)setCompressionLevelkeeps its gzip-only meaning. Universal interpretationconsidered and rejected — codec level scales differ enough that linear mapping
loses the high end of brotli/zstd.
Out of scope
*.br/*.zston disk via sendfile) —phase 3, requires file-serving rework.
of real Accept-Encoding strings; honouring client q-values exactly would
require storing q as a number (not bool) in the parser. Tracked but
not in this phase.
Implementation plan
http_compression_brotli.cimplementing the encoder vtable + a brotli decoder for inbound.
libzstd.br/zstdtoken recognition + thepreference-order select; unit tests for both new codings.
setBrotliLevel/setZstdLevelsetters, frozen-snapshotplumbing, phpt for setter validation + locked-config guard.
stream wrapper / decode paths (no changes there if the registry lookup
succeeds for the chosen codec); H1 buffered round-trip phpt per codec.
docs/COMPRESSION.md, CHANGELOG entry.