14static char *mem_find(
char *hay,
size_t hlen,
const char *needle,
size_t nlen)
16 if (nlen == 0 || nlen > hlen)
20 for (
size_t i = 0; i + nlen <= hlen; i++)
22 if (memcmp(hay + i, needle, nlen) == 0)
33static char *extract_quoted_param(
char *src,
const char *key)
35 char *p = strstr(src, key);
47 char *end = strchr(p,
'"');
67 const char *bsearch = strstr(ct,
"boundary=");
83 while (*bsearch && *bsearch !=
'"' && *bsearch !=
';' && *bsearch !=
' ' &&
86 bval[blen++] = *bsearch++;
99 memcpy(delim + 2, bval, blen + 1);
100 size_t dlen = blen + 2;
102 char *body = (
char *)req->
body;
110 memcpy(ddelim + 2, delim, dlen);
111 size_t ddlen = dlen + 2;
114 char *pos = mem_find(body, (
size_t)(end - body), delim, dlen);
120 if (pos + 2 <= end && pos[0] ==
'\r' && pos[1] ==
'\n')
128 if (pos + 2 <= end && pos[0] ==
'-' && pos[1] ==
'-')
134 part->
name =
nullptr;
136 part->
type =
nullptr;
137 part->
data =
nullptr;
143 if (pos + 2 <= end && pos[0] ==
'\r' && pos[1] ==
'\n')
149 char *line_end = mem_find(pos, (
size_t)(end - pos),
"\r\n", 2);
157 if (strncasecmp(pos,
"Content-Disposition:", 20) == 0)
167 part->
filename = extract_quoted_param(v,
"filename=");
168 part->
name = extract_quoted_param(v,
"name=");
170 else if (strncasecmp(pos,
"Content-Type:", 13) == 0)
184 char *next = mem_find(pos, (
size_t)(end - pos), ddelim, ddlen);
191 part->
data_len = (size_t)(next - pos);
197 if (pos + 2 <= end && pos[0] ==
'\r' && pos[1] ==
'\n')
const char * http_get_header(const HttpReq *req, const char *key)
Look up a header value by name (case-insensitive).
const char * pc_multipart_get_field(const Multipart *mp, const char *field)
Look up a field value across all parsed parts by name.
bool pc_multipart_parse(HttpReq *req, Multipart *mp)
Parse the body of req as multipart/form-data.
In-place multipart/form-data parser (RFC 7578).
#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.
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[].