DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
stomp.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 stomp.h
6 * @brief STOMP 1.2 frame codec (DETWS_ENABLE_STOMP) - zero-heap frame builder + parser,
7 * so a device can talk to a STOMP broker (ActiveMQ / RabbitMQ / Artemis) over the
8 * shipped outbound client transport (TCP, or STOMP-over-WebSocket via the WS client).
9 *
10 * STOMP 1.2 (https://stomp.github.io/stomp-specification-1.2.html) frame:
11 * @code
12 * COMMAND\n
13 * header:value\n
14 * header:value\n
15 * \n
16 * body^@ // body ends at the NUL octet (0x00)
17 * @endcode
18 * - The command and header lines end with EOL (`\n`, optionally preceded by `\r`).
19 * - A blank line separates the headers from the body; the body ends at a NUL.
20 * - When a `content-length` header is present the body is exactly that many octets
21 * (so it may itself contain NULs); otherwise the body runs to the first NUL.
22 * - In header keys/values these octets are escaped: `\r`(CR) `\n`(LF) `\c`(:) `\\`(\\‍).
23 *
24 * The parser is non-mutating: it reports the command, header key/value slices, and body
25 * as pointers INTO the source buffer (header values are still escaped - decode one with
26 * @ref stomp_unescape when needed). The builder escapes header keys/values for you.
27 *
28 * @author Douglas Quigg (dstroy0)
29 * @date 2026
30 */
31
32#ifndef DETERMINISTICESPASYNCWEBSERVER_STOMP_H
33#define DETERMINISTICESPASYNCWEBSERVER_STOMP_H
34
35#include "ServerConfig.h"
36
37#if DETWS_ENABLE_STOMP
38
39#include <stddef.h>
40#include <stdint.h>
41
42/** @brief One parsed header line: key/value slices point INTO the source buffer (raw, still escaped). */
43struct StompHeader
44{
45 const char *key;
46 size_t key_len;
47 const char *val;
48 size_t val_len;
49};
50
51/** @brief One parsed STOMP frame. All pointers reference the source buffer (nothing copied). */
52struct StompFrame
53{
54 const char *command; ///< command verb (e.g. "MESSAGE"); not NUL-terminated
55 size_t command_len;
56 StompHeader headers[DETWS_STOMP_MAX_HEADERS];
57 size_t header_count; ///< number of parsed headers (capped at DETWS_STOMP_MAX_HEADERS)
58 const char *body; ///< frame body (may contain NULs when content-length is given)
59 size_t body_len;
60};
61
62/**
63 * @brief Build a STOMP frame: `COMMAND\n` + each `key:value\n` (keys/values escaped) + `\n` + body + NUL.
64 *
65 * @param header_keys NUL-terminated header names (argv-style), length @p nheaders.
66 * @param header_vals NUL-terminated header values, parallel to @p header_keys.
67 * @param body body bytes, or nullptr for an empty body.
68 * @param body_len body length in bytes.
69 * @return bytes written (including the terminating NUL), or 0 on overflow / bad input.
70 */
71size_t stomp_build_frame(char *buf, size_t cap, const char *command, const char *const *header_keys,
72 const char *const *header_vals, size_t nheaders, const char *body, size_t body_len);
73
74/**
75 * @brief Parse one STOMP frame at the head of [buf, buf+len).
76 *
77 * Leading EOL octets (broker heart-beats / inter-frame newlines) are skipped and counted
78 * in @p consumed.
79 *
80 * @param consumed receives the bytes the frame occupied (past its terminating NUL), so the
81 * caller can advance to the next frame.
82 * @return true on a complete frame; false if the buffer holds an incomplete or malformed
83 * frame (then @p out / @p consumed are unspecified).
84 */
85bool stomp_parse_frame(const char *buf, size_t len, StompFrame *out, size_t *consumed);
86
87/**
88 * @brief Find a header by name; returns the RAW (still escaped) value slice.
89 * @return true and fills @p val / @p val_len on the first match (per spec), else false.
90 */
91bool stomp_header(const StompFrame *f, const char *name, const char **val, size_t *val_len);
92
93/**
94 * @brief Decode STOMP 1.2 header escapes (`\r` `\n` `\c` `\\`) from @p src into @p dst.
95 * @return decoded length, or 0 on overflow or an invalid escape sequence.
96 */
97size_t stomp_unescape(char *dst, size_t cap, const char *src, size_t src_len);
98
99#endif // DETWS_ENABLE_STOMP
100
101#endif // DETERMINISTICESPASYNCWEBSERVER_STOMP_H
User-facing configuration for DeterministicESPAsyncWebServer.
#define DETWS_STOMP_MAX_HEADERS
Max header lines parsed per STOMP frame (extras beyond this are ignored).