DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
hpack.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file hpack.h
6 * @brief HPACK header compression for HTTP/2 (RFC 7541).
7 *
8 * HPACK encodes an HTTP header list into a compact byte block and back. It combines a fixed
9 * static table (61 common header entries), a per-connection FIFO dynamic table, prefix-integer
10 * and length-prefixed string coding, and a canonical Huffman code (RFC 7541 Appendix B) for
11 * string literals. All tables are generated verbatim from the RFC.
12 *
13 * This codec is pure and host-tested (against the RFC 7541 Appendix C worked examples). The
14 * decoder resolves indexed fields, literals (with / without / never indexed), and dynamic-table
15 * size updates, maintaining the dynamic table with FIFO eviction. The encoder (server side) uses
16 * static-table indexing and literal-without-indexing with Huffman-coded strings, so it needs no
17 * dynamic-table state of its own. Zero heap; the dynamic table is a fixed byte ring.
18 *
19 * @author Douglas Quigg (dstroy0)
20 * @date 2026
21 */
22
23#ifndef DETERMINISTICESPASYNCWEBSERVER_HPACK_H
24#define DETERMINISTICESPASYNCWEBSERVER_HPACK_H
25
26#include "ServerConfig.h"
27
28#if DETWS_ENABLE_HTTP2
29
30#include <stddef.h>
31#include <stdint.h>
32
33/** @brief One dynamic-table entry descriptor (its bytes live in the table's byte ring). */
34struct HpackEntry
35{
36 uint16_t name_len; ///< header name length
37 uint16_t val_len; ///< header value length
38 uint16_t ring_pos; ///< start of name||value in the byte ring
39};
40
41/**
42 * @brief Per-connection HPACK dynamic table (the peer encoder's state, tracked by our decoder).
43 * FIFO: newest entry is dynamic index 62, oldest is evicted first. Fixed storage, no heap.
44 */
45struct HpackDynTable
46{
47 uint32_t max_size; ///< negotiated maximum size in bytes (RFC 7541 sec 4.2)
48 uint32_t used; ///< current size = sum of (name_len + val_len + 32) over entries
49 uint16_t ehead; ///< descriptor ring: index one past the newest entry
50 uint16_t ecount; ///< number of live entries
51 uint16_t rtail; ///< byte ring: start of the oldest entry's bytes
52 uint16_t rused; ///< byte ring: bytes in use
53 HpackEntry ent[DETWS_HPACK_MAX_ENTRIES];
54 char ring[DETWS_HPACK_TABLE_BYTES];
55};
56
57/** @brief Callback invoked for each decoded header; return false to abort the decode. */
58typedef bool (*HpackEmitFn)(void *ctx, const char *name, size_t name_len, const char *value, size_t value_len);
59
60/** @brief Initialize a dynamic table to empty, max size @p max_bytes (0 = DETWS_HPACK_TABLE_BYTES). */
61void hpack_dyn_init(HpackDynTable *t, uint32_t max_bytes);
62
63/**
64 * @brief Decode an HPACK header block, emitting each (name, value) via @p emit.
65 * @param scratch caller buffer that holds one header's name+value during each emit call.
66 * @return true if the whole block decoded cleanly; false on any malformed input or overflow.
67 */
68bool hpack_decode(HpackDynTable *t, const uint8_t *block, size_t len, char *scratch, size_t scratch_cap,
69 HpackEmitFn emit, void *ctx);
70
71/**
72 * @brief Encode one header field into @p out (server side: static-index a full or name match,
73 * else literal-without-indexing; strings Huffman-coded when that is not longer).
74 * @return bytes written, or 0 on overflow.
75 */
76size_t hpack_encode_header(uint8_t *out, size_t cap, const char *name, size_t name_len, const char *value,
77 size_t value_len);
78
79// The prefix-integer and Huffman primitives moved to hpack_prim.h (shared with QPACK).
80
81#endif // DETWS_ENABLE_HTTP2
82#endif // DETERMINISTICESPASYNCWEBSERVER_HPACK_H
User-facing configuration for DeterministicESPAsyncWebServer.
#define DETWS_HPACK_TABLE_BYTES
Per-connection HPACK dynamic-table size in bytes (our decoder; advertised to the peer as SETTINGS_HEA...
#define DETWS_HPACK_MAX_ENTRIES
Max HPACK dynamic-table entries (>= DETWS_HPACK_TABLE_BYTES / 32, the min entry size).