16static bool emit_escaped(
char *buf,
size_t cap,
size_t *pos,
char c)
48static bool emit_escaped_str(
char *buf,
size_t cap,
size_t *pos,
const char *s)
51 if (!emit_escaped(buf, cap, pos, *s))
56size_t stomp_build_frame(
char *buf,
size_t cap,
const char *command,
const char *
const *header_keys,
57 const char *
const *header_vals,
size_t nheaders,
const char *body,
size_t body_len)
59 if (!buf || cap == 0 || !command || (nheaders && (!header_keys || !header_vals)))
65 if (!emit_escaped_str(buf, cap, &pos, command))
72 for (
size_t i = 0; i < nheaders; i++)
74 if (!header_keys[i] || !header_vals[i])
76 if (!emit_escaped_str(buf, cap, &pos, header_keys[i]))
81 if (!emit_escaped_str(buf, cap, &pos, header_vals[i]))
94 if (!body || pos + body_len > cap)
96 memcpy(buf + pos, body, body_len);
107static bool parse_len(
const char *s,
size_t len,
size_t *out)
112 for (
size_t i = 0; i < len; i++)
114 if (s[i] <
'0' || s[i] >
'9')
116 if (v > (SIZE_MAX - 9) / 10)
118 v = v * 10 + (size_t)(s[i] -
'0');
125static size_t line_len(
const char *buf,
size_t start,
size_t nl)
128 if (end > start && buf[end - 1] ==
'\r')
133bool stomp_parse_frame(
const char *buf,
size_t len, StompFrame *out,
size_t *consumed)
135 if (!buf || !out || !consumed)
140 while (i < len && (buf[i] ==
'\r' || buf[i] ==
'\n'))
145 out->command =
nullptr;
146 out->command_len = 0;
147 out->header_count = 0;
153 while (nl < len && buf[nl] !=
'\n')
157 out->command = buf + i;
158 out->command_len = line_len(buf, i, nl);
159 if (out->command_len == 0)
165 size_t content_length = 0;
166 bool have_content_length =
false;
170 while (nl < len && buf[nl] !=
'\n')
174 size_t ll = line_len(buf, cur, nl);
182 size_t line_end = cur + ll;
183 while (colon < line_end && buf[colon] !=
':')
185 if (colon >= line_end)
189 StompHeader *h = &out->headers[out->header_count++];
191 h->key_len = colon - cur;
192 h->val = buf + colon + 1;
193 h->val_len = line_end - (colon + 1);
197 if (!have_content_length && h->key_len == 14 && memcmp(h->key,
"content-length", 14) == 0)
199 if (!parse_len(h->val, h->val_len, &content_length))
201 have_content_length =
true;
210 if (have_content_length)
212 if (cur + content_length >= len)
214 if (buf[cur + content_length] !=
'\0')
216 out->body = buf + cur;
217 out->body_len = content_length;
218 *consumed = cur + content_length + 1;
223 while (b < len && buf[b] !=
'\0')
227 out->body = buf + cur;
228 out->body_len = b - cur;
233bool stomp_header(
const StompFrame *f,
const char *name,
const char **val,
size_t *val_len)
237 constexpr size_t name_max = 128;
238 size_t nlen = strnlen(name, name_max);
239 for (
size_t i = 0; i < f->header_count; i++)
240 if (f->headers[i].key_len == nlen && memcmp(f->headers[i].key, name, nlen) == 0)
243 *val = f->headers[i].val;
245 *val_len = f->headers[i].val_len;
251size_t stomp_unescape(
char *dst,
size_t cap,
const char *src,
size_t src_len)
256 for (
size_t i = 0; i < src_len; i++)
261 if (i + 1 >= src_len)
#define DETWS_STOMP_MAX_HEADERS
Max header lines parsed per STOMP frame (extras beyond this are ignored).
STOMP 1.2 frame codec (DETWS_ENABLE_STOMP) - zero-heap frame builder + parser, so a device can talk t...