cybersecurity · intermediate · ~25 min
Careful protocol parsing with strict line discipline.
Implement int unfold_header(const char *input, char *out, size_t cap) that takes a possibly-folded header line group and unfolds it into a single line.
Input format:
\r\n.X-Foo: bar).\r\n + leading whitespace with a single space.The function:
out, NUL-terminated, capped at cap-1.0 on failure (insufficient cap, empty input)."X-Foo: bar\r\n other\r\n"
-> consumes 2 lines, out = "X-Foo: bar other"
"Content-Type: text/html\r\nHost: x\r\n"
-> consumes 1 line, out = "Content-Type: text/html"
"X-Long: one\r\n\ttwo\r\n three\r\nNext: 1\r\n"
-> consumes 3 lines, out = "X-Long: one two three"
A bug where the proxy joins the lines differently from the back-end is a request-smuggling primitive: the proxy sees one request, the back-end sees two.
HTTP/1.1 'header folding' lets a header value span multiple lines using a continuation line that begins with whitespace. RFC 7230 has since deprecated this — but parsers still encounter it, and mishandling it is a known request-smuggling vector. Writing a careful unfold helps you understand why proxies are so paranoid.
Buffer with CRLF-separated lines.
Unfolded single line + line count consumed.
Cap-aware. No allocations.
#include <stddef.h>
int unfold_header(const char *input, char *out, size_t cap) { /* TODO */ return 0; }
Joining lines with \r\n left in. Treating LF without preceding CR as end of line — strict HTTP wants CRLF only. Forgetting the leading-WS rule for continuations.
Header with no continuation; empty input; continuation lines with only whitespace; cap too small.
O(strlen(input)).
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.