ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
multipart.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#ifndef PROTOCORE_MULTIPART_H
5#define PROTOCORE_MULTIPART_H
6
7#include "network_drivers/presentation/http/http_parser/http_parser.h" // the complete type a public struct below holds by value
8#include "protocore_config.h" // the entry point: protocore_types.h for the widths
9
11
12/**
13 * @file multipart.h
14 * @brief In-place multipart/form-data parser (RFC 7578).
15 *
16 * Parses the body already stored in `HttpReq::body[]`. The parser modifies
17 * the body buffer in-place by inserting null terminators, so `part->data`
18 * pointers are valid only while the `HttpReq` lives (before `http_reset()`).
19 *
20 * The scan is length-bounded over `HttpReq::body_len` and matches the full
21 * `\r\n--boundary` delimiter (RFC 2046), so a **binary** part is safe: embedded
22 * NUL bytes and even the raw boundary string inside the payload do not truncate it
23 * (only the true `CRLF--boundary` delimiter ends a part). Read a binary part via
24 * `part->data` + `part->data_len` (the in-place NUL terminator is a convenience for
25 * text parts, not a length).
26 *
27 * **Limitations**
28 * - Maximum parts: `MAX_MULTIPART_PARTS` (default 4).
29 * - Maximum total body size: `BODY_BUF_SIZE` bytes.
30 * - Only `name` and `filename` are extracted from Content-Disposition;
31 * other parameters are ignored.
32 * - Boundary value must be ≤ `MAX_BOUNDARY_LEN` bytes (RFC 2046 cap: 70).
33 *
34 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
35 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
36 * a caller drives every namespace the same way.
37 *
38 * @author Douglas Quigg (dstroy0)
39 * @date 2026
40 */
41
42// PROTOCORE_MULTIPART_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
43// it into its arena. Its size and its offset are each a static_assert, so a feature
44// combination that does not fit fails to compile rather than overrunning at run time.
45
46/**
47 * @brief One parsed part from a multipart body.
48 *
49 * All char* fields point into the (modified) `HttpReq::body[]` buffer.
50 * They are null-terminated and valid until `http_reset()` is called.
51 */
52typedef struct
53{
54 const char *name; ///< Form field name from Content-Disposition, or nullptr.
55 const char *filename; ///< Upload filename from Content-Disposition, or nullptr.
56 const char *type; ///< Content-Type of this part, or nullptr.
57 const char *data; ///< Part body (null-terminated in-place).
58 size_t data_len; ///< Part body length in bytes (not counting the null).
60
61/**
62 * @brief Container for all parsed parts of a multipart body.
63 */
64typedef struct
65{
66 MultipartPart parts[MAX_MULTIPART_PARTS]; ///< Parsed parts.
67 int part_count; ///< Number of valid entries in parts[].
69
70#include "network_drivers/presentation/http/http_parser/http_parser.h" // HttpReq: the type a parameter points at
71
72/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
73typedef struct
74{
75 proto_bool (*parse)(uint8_t *, HttpReq *, MultipartBody *);
76 const char *(*get_field)(uint8_t *, const MultipartBody *, const char *);
79
80/**
81 * @brief Scan req's body as multipart/form-data, reading the boundary from.
82 * @param work PROTOCORE_MULTIPART_BORROW bytes the caller took. Not held past the call.
83 * @param req Req
84 * @param mp Mp
85 * @return PROTO_TRUE on success.
86 */
88/**
89 * @brief The data pointer of the first part whose name matches field, or.
90 * @param work PROTOCORE_MULTIPART_BORROW bytes the caller took. Not held past the call.
91 * @param mp Mp
92 * @param field Field
93 * @return The const char *.
94 */
95const char *protocore_multipart_get_field(uint8_t *work, const MultipartBody *mp, const char *field);
96
97/** @brief Module namespace. */
100
102
103#endif // PROTOCORE_MULTIPART_H
#define MAX_MULTIPART_PARTS
Maximum simultaneously parsed multipart parts per request.
HttpParser..
proto_bool protocore_multipart_parse(uint8_t *work, HttpReq *req, MultipartBody *mp)
Scan req's body as multipart/form-data, reading the boundary from.
const char * protocore_multipart_get_field(uint8_t *work, const MultipartBody *mp, const char *field)
The data pointer of the first part whose name matches field, or.
PROTOCORE_NS MultipartNs Multipart PROTOCORE_UNUSED
Module namespace.
Definition multipart.h:98
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
Container for all parsed parts of a multipart body.
Definition multipart.h:65
int part_count
Number of valid entries in parts[].
Definition multipart.h:67
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition multipart.h:74
proto_bool(* parse)(uint8_t *, HttpReq *, MultipartBody *)
Definition multipart.h:75
One parsed part from a multipart body.
Definition multipart.h:53
const char * data
Part body (null-terminated in-place).
Definition multipart.h:57
const char * type
Content-Type of this part, or nullptr.
Definition multipart.h:56
size_t data_len
Part body length in bytes (not counting the null).
Definition multipart.h:58
const char * name
Form field name from Content-Disposition, or nullptr.
Definition multipart.h:54
const char * filename
Upload filename from Content-Disposition, or nullptr.
Definition multipart.h:55
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97