16static bool emit_escaped(
char *buf,
size_t cap,
size_t *pos,
char c)
52static bool emit_escaped_str(
char *buf,
size_t cap,
size_t *pos,
const char *s)
56 if (!emit_escaped(buf, cap, pos, *s))
64size_t pc_stomp_build_frame(
char *buf,
size_t cap,
const char *command,
const char *
const *header_keys,
65 const char *
const *header_vals,
size_t nheaders,
const char *body,
size_t body_len)
67 if (!buf || cap == 0 || !command || (nheaders && (!header_keys || !header_vals)))
75 if (!emit_escaped_str(buf, cap, &pos, command))
86 for (
size_t i = 0; i < nheaders; i++)
88 if (!header_keys[i] || !header_vals[i])
92 if (!emit_escaped_str(buf, cap, &pos, header_keys[i]))
101 if (!emit_escaped_str(buf, cap, &pos, header_vals[i]))
120 if (!body || pos + body_len > cap)
124 memcpy(buf + pos, body, body_len);
137static bool parse_len(
const char *s,
size_t len,
size_t *out)
144 for (
size_t i = 0; i < len; i++)
146 if (s[i] <
'0' || s[i] >
'9')
150 if (v > (SIZE_MAX - 9) / 10)
154 v = v * 10 + (size_t)(s[i] -
'0');
161static size_t line_len(
const char *buf,
size_t start,
size_t nl)
164 if (end > start && buf[end - 1] ==
'\r')
171bool pc_stomp_parse_frame(
const char *buf,
size_t len, StompFrame *out,
size_t *consumed)
173 if (!buf || !out || !consumed)
180 while (i < len && (buf[i] ==
'\r' || buf[i] ==
'\n'))
189 out->command =
nullptr;
190 out->command_len = 0;
191 out->header_count = 0;
197 while (nl < len && buf[nl] !=
'\n')
205 out->command = buf + i;
206 out->command_len = line_len(buf, i, nl);
207 if (out->command_len == 0)
219 size_t content_length = 0;
220 bool have_content_length =
false;
224 while (nl < len && buf[nl] !=
'\n')
232 size_t ll = line_len(buf, cur, nl);
240 size_t line_end = cur + ll;
241 while (colon < line_end && buf[colon] !=
':')
245 if (colon >= line_end)
251 StompHeader *h = &out->headers[out->header_count++];
253 h->key_len = colon - cur;
254 h->val = buf + colon + 1;
255 h->val_len = line_end - (colon + 1);
259 if (!have_content_length && h->key_len == 14 && memcmp(h->key,
"content-length", 14) == 0)
261 if (!parse_len(h->val, h->val_len, &content_length))
265 have_content_length =
true;
277 if (have_content_length)
279 if (cur + content_length >= len)
283 if (buf[cur + content_length] !=
'\0')
287 out->body = buf + cur;
288 out->body_len = content_length;
289 *consumed = cur + content_length + 1;
294 while (b < len && buf[b] !=
'\0')
302 out->body = buf + cur;
303 out->body_len = b - cur;
308bool pc_stomp_header(
const StompFrame *f,
const char *name,
const char **val,
size_t *val_len)
314#define PC_name_max 128
315 size_t nlen = strnlen(name, PC_name_max);
316 for (
size_t i = 0; i < f->header_count; i++)
318 if (f->headers[i].key_len == nlen && memcmp(f->headers[i].key, name, nlen) == 0)
322 *val = f->headers[i].val;
326 *val_len = f->headers[i].val_len;
334size_t pc_stomp_unescape(
char *dst,
size_t cap,
const char *src,
size_t src_len)
341 for (
size_t i = 0; i < src_len; i++)
346 if (i + 1 >= src_len)
#define PC_STOMP_MAX_HEADERS
Max header lines parsed per STOMP frame (extras beyond this are ignored).
STOMP 1.2 frame codec (PC_ENABLE_STOMP) - zero-heap frame builder + parser, so a device can talk to a...