32 return (c >=
'A' && c <=
'Z') ? c -
'A' +
'a' : c;
37static int name_eq(
const char* s,
size_t n,
const char* lit) {
39 for (i = 0; i < n; i++)
40 if (lit[i] ==
'\0' ||
lc((
unsigned char)s[i]) != lit[i])
42 return lit[n] ==
'\0';
52 for (i = 0; i < n; i++)
53 if ((
unsigned char)s[i] <= 0x20 || (
unsigned char)s[i] == 0x7f)
62 unsigned long long v = 0;
66 for (i = 0; i < n; i++) {
67 if (s[i] <
'0' || s[i] >
'9')
69 v = v * 10u + (unsigned)(s[i] -
'0');
80 return c > 0x20 && c < 0x7f && c !=
'#';
84 size_t scan, i, sl, p, tstart, tend, line_start, nheaders = 0;
89 memset(out, 0,
sizeof(*out));
102 for (i = 0; i + 3 < scan; i++)
103 if (buf[i] ==
'\r' && buf[i + 1] ==
'\n' && buf[i + 2] ==
'\r' &&
104 buf[i + 3] ==
'\n') {
114 while (sl + 1 < out->
head_len && !(buf[sl] ==
'\r' && buf[sl + 1] ==
'\n'))
116 if (sl >= 4 && buf[0] ==
'G' && buf[1] ==
'E' && buf[2] ==
'T' &&
120 }
else if (sl >= 5 && buf[0] ==
'P' && buf[1] ==
'O' && buf[2] ==
'S' &&
121 buf[3] ==
'T' && buf[4] ==
' ') {
129 while (p < sl && buf[p] !=
' ') {
135 if (tend == tstart || buf[tstart] !=
'/' ||
139 if (p >= sl || buf[p] !=
' ')
142 if (sl - p != 8 || memcmp(buf + p,
"HTTP/1.", 7) != 0 ||
143 (buf[p + 7] !=
'0' && buf[p + 7] !=
'1'))
145 memcpy(out->
path, buf + tstart, tend - tstart);
146 out->
path[tend - tstart] =
'\0';
150 while (line_start + 1 < out->
head_len) {
151 size_t le = line_start, colon, vs, vlen, nlen;
152 const char *name, *val;
154 !(buf[
le] ==
'\r' && buf[
le + 1] ==
'\n'))
156 if (
le == line_start)
161 while (colon <
le && buf[colon] !=
':')
165 name = buf + line_start;
166 nlen = colon - line_start;
170 while (vs <
le && (buf[vs] ==
' ' || buf[vs] ==
'\t'))
174 while (vlen > 0 && (val[vlen - 1] ==
' ' || val[vlen - 1] ==
'\t'))
176 if (
name_eq(name, nlen,
"transfer-encoding"))
178 if (
name_eq(name, nlen,
"content-length")) {
186 }
else if (
name_eq(name, nlen,
"authorization")) {
static int parse_body_len(const char *s, size_t n, long long *out)
n_http_req_status n_http_request_parse(const char *buf, size_t len, n_http_request *out)
parse an HTTP/1.1 request head from [buf, buf+len)
static int target_ok(unsigned char c)
static int name_eq(const char *s, size_t n, const char *lit)
static int name_token_ok(const char *s, size_t n)
Pure, strict, bounded parser for an HTTP/1.1 request head.
#define N_HTTP_REQ_HEAD_MAX
Largest request head (request line + headers, through CRLFCRLF) accepted.
n_http_req_status
Result of n_http_request_parse.
@ N_HTTP_REQ_INCOMPLETE
no CRLFCRLF yet, still under the cap
@ N_HTTP_REQ_ERROR
malformed / oversized / unsupported
@ N_HTTP_REQ_OK
a complete, valid head was parsed
char authorization[256u+1]
#define N_HTTP_REQ_AUTH_MAX
Longest captured Authorization header value.
#define N_HTTP_REQ_BODY_MAX
Maximum declared Content-Length (body size), in bytes.
#define N_HTTP_REQ_HEADERS_MAX
Maximum number of header lines.
#define N_HTTP_REQ_PATH_MAX
Longest origin-form request target ('/'-prefixed, query included).
static uint64_t le(const unsigned char *p, int n)
read a little endian unsigned value