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);
90 strcpy(p
->multipart_boundary
, boundary
);
91 p
->boundary_length
= strlen(boundary
);
93 p
->lookbehind
= (p
->multipart_boundary
+ p
->boundary_length
+ 1);
97 p
->settings
= settings
;
102 void multipart_parser_free(multipart_parser
* p
) {
106 void multipart_parser_set_data(multipart_parser
*p
, void *data
) {
110 void *multipart_parser_get_data(multipart_parser
*p
) {
114 size_t multipart_parser_execute(multipart_parser
* p
, const char *buf
, size_t len
) {
122 is_last
= (i
== (len
- 1));
125 multipart_log("s_start");
127 p
->state
= s_start_boundary
;
130 case s_start_boundary
:
131 multipart_log("s_start_boundary");
132 if (p
->index
== p
->boundary_length
) {
138 } else if (p
->index
== (p
->boundary_length
+ 1)) {
143 NOTIFY_CB(part_data_begin
);
144 p
->state
= s_header_field_start
;
147 if (c
!= p
->multipart_boundary
[p
->index
]) {
153 case s_header_field_start
:
154 multipart_log("s_header_field_start");
156 p
->state
= s_header_field
;
160 multipart_log("s_header_field");
162 p
->state
= s_headers_almost_done
;
171 EMIT_DATA_CB(header_field
, buf
+ mark
, i
- mark
);
172 p
->state
= s_header_value_start
;
177 if (cl
< 'a' || cl
> 'z') {
178 multipart_log("invalid character in header name");
182 EMIT_DATA_CB(header_field
, buf
+ mark
, (i
- mark
) + 1);
185 case s_headers_almost_done
:
186 multipart_log("s_headers_almost_done");
191 p
->state
= s_part_data_start
;
194 case s_header_value_start
:
195 multipart_log("s_header_value_start");
201 p
->state
= s_header_value
;
205 multipart_log("s_header_value");
207 EMIT_DATA_CB(header_value
, buf
+ mark
, i
- mark
);
208 p
->state
= s_header_value_almost_done
;
211 EMIT_DATA_CB(header_value
, buf
+ mark
, (i
- mark
) + 1);
214 case s_header_value_almost_done
:
215 multipart_log("s_header_value_almost_done");
219 p
->state
= s_header_field_start
;
222 case s_part_data_start
:
223 multipart_log("s_part_data_start");
224 NOTIFY_CB(headers_complete
);
226 p
->state
= s_part_data
;
230 multipart_log("s_part_data");
232 EMIT_DATA_CB(part_data
, buf
+ mark
, i
- mark
);
234 p
->state
= s_part_data_almost_boundary
;
235 p
->lookbehind
[0] = CR
;
239 EMIT_DATA_CB(part_data
, buf
+ mark
, (i
- mark
) + 1);
242 case s_part_data_almost_boundary
:
243 multipart_log("s_part_data_almost_boundary");
245 p
->state
= s_part_data_boundary
;
246 p
->lookbehind
[1] = LF
;
250 EMIT_DATA_CB(part_data
, p
->lookbehind
, 1);
251 p
->state
= s_part_data
;
255 case s_part_data_boundary
:
256 multipart_log("s_part_data_boundary");
257 if (p
->multipart_boundary
[p
->index
] != c
) {
258 EMIT_DATA_CB(part_data
, p
->lookbehind
, 2 + p
->index
);
259 p
->state
= s_part_data
;
263 p
->lookbehind
[2 + p
->index
] = c
;
264 if ((++ p
->index
) == p
->boundary_length
) {
265 NOTIFY_CB(part_data_end
);
266 p
->state
= s_part_data_almost_end
;
270 case s_part_data_almost_end
:
271 multipart_log("s_part_data_almost_end");
273 p
->state
= s_part_data_final_hyphen
;
277 p
->state
= s_part_data_end
;
282 case s_part_data_final_hyphen
:
283 multipart_log("s_part_data_final_hyphen");
291 case s_part_data_end
:
292 multipart_log("s_part_data_end");
294 p
->state
= s_header_field_start
;
295 NOTIFY_CB(part_data_begin
);
301 multipart_log("s_end: %02X", (int) c
);
305 multipart_log("Multipart parser unrecoverable error");