Skip to content

Add HTTP/2 HPACK (RFC 7541) and LHA -lh2- codecs#89

Merged
MagicalTux merged 2 commits into
masterfrom
add-hpack-lh2
Jun 12, 2026
Merged

Add HTTP/2 HPACK (RFC 7541) and LHA -lh2- codecs#89
MagicalTux merged 2 commits into
masterfrom
add-hpack-lh2

Conversation

@MagicalTux

Copy link
Copy Markdown
Member

Adds the two requested codecs so the crate covers "h2 huffman" and LHA -lh2-.

HTTP/2 HPACK — new hpack feature (compcol::hpack)

Full RFC 7541 header compression, not just the Huffman primitive:

  • Integer coding (§5.1) N-bit-prefix, with overflow/overlong guards.
  • String literals (§5.2) raw or Huffman, with EOS-padding validation.
  • Static table (Appendix A, 61 entries) + dynamic table with §4.1 byte
    accounting, §4.4 eviction, and §6.3 size updates.
  • All field representations: §6.1 indexed, §6.2.1 literal+incremental
    indexing, §6.2.2 without indexing, §6.2.3 never-indexed, §6.3 size update.
  • HpackEncoder / HpackDecoder hold dynamic-table state across header
    blocks. HPACK works on (name, value) header lists with per-connection
    state — not a byte stream — so it gets its own API rather than the
    Encoder/Decoder traits.
  • The §5.2 string Huffman code (Appendix B) is also exposed as the
    Http2Huffman codec (name h2-huffman) on the uniform trait surface and is
    registered in the factory.

Validation: byte-for-byte against the RFC 7541 Appendix C worked examples —
C.1 integers, C.3 (raw) and C.4 (Huffman) request sequences including dynamic
table evolution, plus the C.4 string vectors. Decoder error paths (index 0,
bad index, oversized size update, decoded EOS, bad Huffman padding, truncation)
are covered, plus a decoder_h2_huffman fuzz target.

LHA -lh2- — extends the lha feature

8 KiB-window LZSS with adaptive (dynamic) Huffman for both literals/lengths
and match positions — the dynamic position tree is what separates lh2 from
lh1's fixed position code. The adaptive-tree machinery is generalized to a
runtime alphabet size shared by the 510-symbol char tree and the 14-symbol
position-class tree. Like lh1 it is continuous/size-terminated, so its decoder
takes the length via DecoderConfig::with_len. Registered in the factory.

Validation: clean-room from the public dynamic-Huffman description;
round-trip validated (empty/small/incompressible/repetitive/binary, plus a
far-window match). There is no public -lh2- reference fixture (no mainstream
tool emits the method), so bit-exact interop with archives in the wild is
best-effort — documented in the module and matching how the other LHA methods
are validated ("own round-trip, no reference fixture").

Checks

  • cargo build --all-features and no_std (--no-default-features --features hpack / --features lha) both clean.
  • cargo test --all-features green (all suites, incl. 17 hpack unit + 5 hpack
    integration + lh2 round-trip/refusal/large-window tests).
  • cargo clippy --all-features — no warnings.

🤖 Generated with Claude Code

MagicalTux and others added 2 commits June 12, 2026 10:02
Two requested additions to broaden codec coverage.

HPACK (new `hpack` feature, `compcol::hpack`):
- Full HTTP/2 header compression per RFC 7541 — N-bit-prefix integers
  (§5.1), string literals (§5.2), the static table (Appendix A) and a
  byte-accounted dynamic table with eviction (§4), and every header-field
  representation (§6.1 indexed; §6.2.1/.2/.3 literals; §6.3 size update).
- `HpackEncoder`/`HpackDecoder` carry dynamic-table state across header
  blocks (HPACK is a stateful header codec, not a byte stream, so it has
  its own API rather than the Encoder/Decoder traits).
- The §5.2 string Huffman primitive (Appendix B table) is also exposed as
  the `Http2Huffman` codec (name "h2-huffman") on the uniform trait
  surface, registered in the factory.
- Validated byte-for-byte against the RFC 7541 Appendix C worked examples
  (C.1 integers, C.3 raw + C.4 Huffman request sequences incl. dynamic
  table evolution), plus decoder error-path rejection (bad index, oversized
  size update, EOS symbol, bad padding, truncation) and a fuzz target.

LHA -lh2- (extends the `lha` feature):
- 8 KiB-window LZSS with adaptive (dynamic) Huffman for both
  literals/lengths and match positions — the latter is what distinguishes
  lh2 from lh1's fixed position code. Generalizes the adaptive-tree
  machinery to a runtime alphabet size shared by the 510-symbol char tree
  and the 14-symbol position-class tree.
- Continuous + size-terminated like lh1, so its decoder needs the
  uncompressed length via DecoderConfig::with_len; registered in factory.
- Clean-room from the public dynamic-Huffman description; round-trip
  validated (no public reference fixture exists — documented as such,
  matching the other LHA methods).

Builds: --all-features and no_std (--no-default-features --features hpack/lha)
both clean; cargo test --all-features green; no clippy warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- rustfmt the new hpack/lha files (collapse multi-line expressions CI's
  `cargo fmt --check` rejected).
- dynamic_huff module doc: demote `[NC]`/`[NP]` intra-doc links to plain
  code spans (they are private consts; rustdoc runs with `-D warnings` and
  rejects public-doc links to private items).
- clippy `-D warnings --all-targets`: replace a manual slice-copy loop with
  the array's Copy in a test, and `repeat().take()` with `repeat_n()`.

No behavior change. fmt/doc/clippy/test all clean locally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MagicalTux MagicalTux merged commit ddc6428 into master Jun 12, 2026
41 checks passed
@MagicalTux MagicalTux mentioned this pull request Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant