Architecture

System Overview

mkhpack is a C library that implements the low-level encoding and decoding primitives defined in RFC 7541 (HPACK: Header Compression for HTTP/2). It is a stateless, single-file library with no runtime dependencies beyond the C standard library.

The library currently covers:

Full HPACK dynamic/static table support and header field representation are planned for the future.

Component Architecture

graph TB
    Consumer["Consumer Application"]

    subgraph mkhpack ["mkhpack library"]
        IntAPI["Integer API<br/>mkhpack_encode_int / mkhpack_decode_int"]
        StrAPI["String API<br/>mkhpack_encode_str / mkhpack_decode_str<br/>mkhpack_encode_raw_str / mkhpack_encode_huff_str"]
        HuffAPI["Huffman API<br/>huffman_encode / huffman_decode<br/>huffman_length"]
        Tables["Generated Huffman Tables<br/>HuffmanCodes[] / HuffmanDecodes[]"]
    end

    Consumer --> IntAPI
    Consumer --> StrAPI
    Consumer --> HuffAPI
    StrAPI --> IntAPI
    StrAPI --> HuffAPI
    HuffAPI --> Tables

Module Breakdown

Public API (src/mkhpack.h)

Declares all exported function signatures, the MKHPACK_INT_T type alias, and include guards. This is the only header consumers need.

Error Codes (src/mkhpack_errors.h)

Defines the five error constants used across all API functions:

Code Name Meaning
0 ERROR_NONE Success
1 ERROR_OVERFLOW Output buffer full
2 ERROR_TRUNCATED Input buffer exhausted mid-value
3 ERROR_EOS Invalid Huffman code (EOS symbol encountered)
4 ERROR_BAD_PREFIX Invalid prefix width or prefix byte

Implementation (src/mkhpack.c)

Single-file implementation containing all encoding and decoding logic. Includes huffman_codes.inc for the generated Huffman lookup tables.

Generated Tables (src/huffman_codes.inc)

Contains two C arrays generated by huffman_codes.rb:

Data Flow

Integer encoding

Input integer + prefix config
        │
        ▼
  mkhpack_encode_int()
        │
        ├─ Fits in prefix bits? → single byte output
        │
        └─ Exceeds prefix? → prefix byte + variable-length continuation bytes
                              (7-bit groups with continuation flag)

Integer decoding

Encoded byte sequence
        │
        ▼
  mkhpack_decode_int()
        │
        ├─ Extract prefix bits from first byte
        │
        └─ If all prefix bits set → read continuation bytes
                                    (7-bit groups until continuation flag clear)
        │
        ▼
  Decoded integer + prefix remainder

String encoding (mkhpack_encode_str)

Input string
        │
        ▼
  huffman_length()  →  Compare Huffman length vs raw length
        │
        ├─ Huffman shorter? → mkhpack_encode_int(length, HUFFMAN_FLAG)
        │                     + huffman_encode(string)
        │
        └─ Not shorter?    → mkhpack_encode_int(length, 0x00)
                              + raw memcpy(string)

Huffman decoding

Huffman-encoded bytes
        │
        ▼
  huffman_decode()
        │
        ├─ Walk HuffmanDecodes[] trie bit-by-bit
        │
        ├─ Leaf node (IS_INT flag set)? → emit decoded byte, reset trie
        │
        ├─ Internal node? → follow branch based on next bit
        │
        ├─ End of input with valid padding? → success
        │
        └─ End of input mid-code or EOS? → error

Build Architecture

graph LR
    RubyScript["huffman_codes.rb"]
    IncFile["src/huffman_codes.inc"]
    Source["src/mkhpack.c"]
    Header["src/mkhpack.h"]
    Object["obj/mkhpack.o"]
    SharedLib["lib/libmkhpack.so.2.0.0"]
    StaticLib["lib/libmkhpack.a"]
    SOLink["lib/libmkhpack.so.2"]
    DevLink["lib/libmkhpack.so"]
    PkgConfig["lib/mkhpack.pc"]

    RubyScript -->|ruby| IncFile
    Source -->|gcc -fPIC -c| Object
    Header --> Object
    IncFile --> Source
    Object -->|gcc -shared| SharedLib
    Object -->|ar rcs| StaticLib
    SharedLib -->|symlink| SOLink
    SOLink -->|symlink| DevLink
    PkgConfig