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");