DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
deflate.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 deflate.h
6 * @brief Bounded RFC 1951 DEFLATE compressor (DEFLATE) - no heap.
7 *
8 * The outbound counterpart to inflate.* : a small, host-testable DEFLATE used by
9 * WebSocket permessage-deflate (RFC 7692) to compress server-to-client messages.
10 * It emits a single fixed-Huffman block (no dynamic tables to build) with LZ77
11 * back-references found over a bounded sliding window, then byte-aligns with an
12 * empty stored block and removes the trailing 0x00 0x00 0xff 0xff per
13 * RFC 7692 sec 7.2.1 - so the result is a ready-to-frame permessage-deflate
14 * payload. The peer's INFLATE re-appends that marker before decompressing (our
15 * own RX path does exactly that, see websocket.cpp).
16 *
17 * Matching reads from the source buffer itself - there is no kept window across
18 * messages, which is correct for `no_context_takeover` (the mode the handshake
19 * negotiates) and bounds memory: distances never exceed DEFLATE_WINDOW and the
20 * only working memory is a caller-supplied scratch (DEFLATE_SCRATCH_SIZE bytes,
21 * borrowed from the per-dispatch arena, like inflate).
22 *
23 * Fixed (not dynamic) Huffman keeps the encoder tiny and deterministic; it never
24 * builds an optimal tree, so the ratio is modest, but for the small JSON/text
25 * frames this serves it still shrinks the wire while costing no dedicated buffer.
26 * If the output would not be smaller than the input the caller simply sends the
27 * message uncompressed (the per-message RSV1 flag makes that legal).
28 *
29 * @author Douglas Quigg (dstroy0)
30 * @date 2026
31 */
32
33#ifndef DETERMINISTICESPASYNCWEBSERVER_DEFLATE_H
34#define DETERMINISTICESPASYNCWEBSERVER_DEFLATE_H
35
36#include "ServerConfig.h"
37#include <stddef.h>
38#include <stdint.h>
39
40#if DETWS_ENABLE_WS_DEFLATE
41
42/**
43 * @brief Working-memory bytes deflate_raw() needs (hash chains + code tables).
44 *
45 * Pass a buffer at least this large as @p scratch. An internal static_assert
46 * keeps it honest against the table layout.
47 */
48#define DEFLATE_SCRATCH_SIZE 4096
49
50/** @brief deflate_raw() return codes (mirror ::InflateResult). */
51enum class DeflateResult : int32_t
52{
53 DEFLATE_OK = 0, ///< success; *out_len holds the compressed length
54 DEFLATE_ERR_OVERFLOW = -2, ///< output would exceed dst_cap (incompressible)
55 DEFLATE_ERR_SCRATCH = -3 ///< scratch_len < DEFLATE_SCRATCH_SIZE
56};
57
58/**
59 * @brief Compress @p src into a raw permessage-deflate payload (RFC 7692).
60 *
61 * The output is a fixed-Huffman DEFLATE stream with the trailing 0x00 0x00 0xff
62 * 0xff marker removed (RFC 7692 sec 7.2.1), i.e. exactly what a compressed
63 * WebSocket data frame carries. To decompress, re-append that 4-byte marker and
64 * call inflate_raw().
65 *
66 * @param src,src_len input bytes to compress.
67 * @param dst,dst_cap output buffer and its capacity.
68 * @param out_len set to the compressed length on success.
69 * @param scratch,scratch_len caller working memory (>= DEFLATE_SCRATCH_SIZE).
70 * @return DeflateResult::DEFLATE_OK (0) on success, else a negative ::DeflateResult.
71 */
72DeflateResult deflate_raw(const uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_cap, size_t *out_len,
73 void *scratch, size_t scratch_len);
74
75#endif // DETWS_ENABLE_WS_DEFLATE
76#endif // DETERMINISTICESPASYNCWEBSERVER_DEFLATE_H
User-facing configuration for DeterministicESPAsyncWebServer.