1 /* Based on node-formidable by Felix Geisendörfer
2 * Igor Afonov - afonov@gmail.com - 2012
3 * MIT License - http://www.opensource.org/licenses/mit-license.php
6 #include "multipart_parser.h"
12 static void multipart_log(const char * format, ...)
14 #ifdef DEBUG_MULTIPART
16 va_start(args, format);
18 fprintf(stderr, "[HTTP_MULTIPART_PARSER] %s:%d: ", __FILE__, __LINE__);
19 vfprintf(stderr, format, args);
20 fprintf(stderr, "\n");
24 #define NOTIFY_CB(FOR) \
26 if (p->settings->on_##FOR) { \
27 if (p->settings->on_##FOR(p) != 0) { \
33 #define EMIT_DATA_CB(FOR, ptr, len) \
35 if (p->settings->on_##FOR) { \
36 if (p->settings->on_##FOR(p, ptr, len) != 0) { \
46 struct multipart_parser {
50 size_t boundary_length;
54 const multipart_parser_settings* settings;
57 char multipart_boundary[1];
66 s_headers_almost_done,
69 s_header_value_almost_done,
72 s_part_data_almost_boundary,
74 s_part_data_almost_end,
76 s_part_data_final_hyphen,
80 multipart_parser* multipart_parser_init
81 (const char *boundary, const multipart_parser_settings* settings) {
83 multipart_parser* p = malloc(sizeof(multipart_parser) +
85 strlen(boundary) + 9);
87 strcpy(p->multipart_boundary, boundary);
88 p->boundary_length = strlen(boundary);
90 p->lookbehind = (p->multipart_boundary + p->boundary_length + 1);
94 p->settings = settings;
99 void multipart_parser_free(multipart_parser* p) {
103 void multipart_parser_set_data(multipart_parser *p, void *data) {
107 void *multipart_parser_get_data(multipart_parser *p) {
111 size_t multipart_parser_execute(multipart_parser* p, const char *buf, size_t len) {
119 is_last = (i == (len - 1));
122 multipart_log("s_start");
124 p->state = s_start_boundary;
127 case s_start_boundary:
128 multipart_log("s_start_boundary");
129 if (p->index == p->boundary_length) {
135 } else if (p->index == (p->boundary_length + 1)) {
140 NOTIFY_CB(part_data_begin);
141 p->state = s_header_field_start;
144 if (c != p->multipart_boundary[p->index]) {
150 case s_header_field_start:
151 multipart_log("s_header_field_start");
153 p->state = s_header_field;
157 multipart_log("s_header_field");
159 p->state = s_headers_almost_done;
168 EMIT_DATA_CB(header_field, buf + mark, i - mark);
169 p->state = s_header_value_start;
174 if (cl < 'a' || cl > 'z') {
175 multipart_log("invalid character in header name");
179 EMIT_DATA_CB(header_field, buf + mark, (i - mark) + 1);
182 case s_headers_almost_done:
183 multipart_log("s_headers_almost_done");
188 p->state = s_part_data_start;
191 case s_header_value_start:
192 multipart_log("s_header_value_start");
198 p->state = s_header_value;
202 multipart_log("s_header_value");
204 EMIT_DATA_CB(header_value, buf + mark, i - mark);
205 p->state = s_header_value_almost_done;
208 EMIT_DATA_CB(header_value, buf + mark, (i - mark) + 1);
211 case s_header_value_almost_done:
212 multipart_log("s_header_value_almost_done");
216 p->state = s_header_field_start;
219 case s_part_data_start:
220 multipart_log("s_part_data_start");
221 NOTIFY_CB(headers_complete);
223 p->state = s_part_data;
227 multipart_log("s_part_data");
229 EMIT_DATA_CB(part_data, buf + mark, i - mark);
231 p->state = s_part_data_almost_boundary;
232 p->lookbehind[0] = CR;
236 EMIT_DATA_CB(part_data, buf + mark, (i - mark) + 1);
239 case s_part_data_almost_boundary:
240 multipart_log("s_part_data_almost_boundary");
242 p->state = s_part_data_boundary;
243 p->lookbehind[1] = LF;
247 EMIT_DATA_CB(part_data, p->lookbehind, 1);
248 p->state = s_part_data;
252 case s_part_data_boundary:
253 multipart_log("s_part_data_boundary");
254 if (p->multipart_boundary[p->index] != c) {
255 EMIT_DATA_CB(part_data, p->lookbehind, 2 + p->index);
256 p->state = s_part_data;
260 p->lookbehind[2 + p->index] = c;
261 if ((++ p->index) == p->boundary_length) {
262 NOTIFY_CB(part_data_end);
263 p->state = s_part_data_almost_end;
267 case s_part_data_almost_end:
268 multipart_log("s_part_data_almost_end");
270 p->state = s_part_data_final_hyphen;
274 p->state = s_part_data_end;
279 case s_part_data_final_hyphen:
280 multipart_log("s_part_data_final_hyphen");
288 case s_part_data_end:
289 multipart_log("s_part_data_end");
291 p->state = s_header_field_start;
292 NOTIFY_CB(part_data_begin);
298 multipart_log("s_end: %02X", (int) c);
302 multipart_log("Multipart parser unrecoverable error");