14static char *mem_find(
char *hay,
size_t hlen,
const char *needle,
size_t nlen)
16 if (nlen == 0 || nlen > hlen)
18 for (
size_t i = 0; i + nlen <= hlen; i++)
19 if (memcmp(hay + i, needle, nlen) == 0)
27static char *extract_quoted_param(
char *src,
const char *key)
29 char *p = strstr(src, key);
32 constexpr size_t key_max = 32;
33 p += strnlen(key, key_max);
37 char *end = strchr(p,
'"');
53 const char *bsearch = strstr(ct,
"boundary=");
62 while (*bsearch && *bsearch !=
'"' && *bsearch !=
';' && *bsearch !=
' ' && blen <
MAX_BOUNDARY_LEN)
63 bval[blen++] = *bsearch++;
73 memcpy(delim + 2, bval, blen + 1);
74 size_t dlen = blen + 2;
76 char *body = (
char *)req->
body;
84 memcpy(ddelim + 2, delim, dlen);
85 size_t ddlen = dlen + 2;
88 char *pos = mem_find(body, (
size_t)(end - body), delim, dlen);
92 if (pos + 2 <= end && pos[0] ==
'\r' && pos[1] ==
'\n')
98 if (pos + 2 <= end && pos[0] ==
'-' && pos[1] ==
'-')
102 part->
name =
nullptr;
104 part->
type =
nullptr;
105 part->
data =
nullptr;
111 if (pos + 2 <= end && pos[0] ==
'\r' && pos[1] ==
'\n')
117 char *line_end = mem_find(pos, (
size_t)(end - pos),
"\r\n", 2);
123 if (strncasecmp(pos,
"Content-Disposition:", 20) == 0)
131 part->
filename = extract_quoted_param(v,
"filename=");
132 part->
name = extract_quoted_param(v,
"name=");
134 else if (strncasecmp(pos,
"Content-Type:", 13) == 0)
146 char *next = mem_find(pos, (
size_t)(end - pos), ddelim, ddlen);
151 part->
data_len = (size_t)(next - pos);
157 if (pos + 2 <= end && pos[0] ==
'\r' && pos[1] ==
'\n')
#define MAX_BOUNDARY_LEN
Maximum MIME boundary length (RFC 2046 allows up to 70 characters).
#define MAX_MULTIPART_PARTS
Maximum simultaneously parsed multipart parts per request.
const char * http_get_header(const HttpReq *req, const char *key)
Look up a header value by name (case-insensitive).
const char * multipart_get_field(const Multipart *mp, const char *field)
Look up a field value across all parsed parts by name.
bool multipart_parse(HttpReq *req, Multipart *mp)
Parse the body of req as multipart/form-data.
In-place multipart/form-data parser (RFC 7578).
Fully-parsed HTTP/1.1 request.
uint8_t body[BODY_BUF_SIZE+1]
Stored body bytes, always null-terminated.
size_t body_len
Bytes stored in body[] (≤ BODY_BUF_SIZE).
One parsed part from a multipart body.
const char * data
Part body (null-terminated in-place).
const char * type
Content-Type of this part, or nullptr.
size_t data_len
Part body length in bytes (not counting the null).
const char * name
Form field name from Content-Disposition, or nullptr.
const char * filename
Upload filename from Content-Disposition, or nullptr.
Container for all parsed parts of a multipart body.
MultipartPart parts[MAX_MULTIPART_PARTS]
Parsed parts.
int part_count
Number of valid entries in parts[].