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 4 */ 5 6 #include "multipart_parser.h" 7 8 #include <stdio.h> 9 #include <stdarg.h> 10 #include <string.h> 11 12 static void multipart_log(const char * format, ...) 13 { 14 #ifdef DEBUG_MULTIPART 15 va_list args; 16 va_start(args, format); 17 18 fprintf(stderr, "[HTTP_MULTIPART_PARSER] %s:%d: ", __FILE__, __LINE__); 19 vfprintf(stderr, format, args); 20 fprintf(stderr, "\n"); 21 #endif 22 } 23 24 #define NOTIFY_CB(FOR) \ 25 do { \ 26 if (p->settings->on_##FOR) { \ 27 if (p->settings->on_##FOR(p) != 0) { \ 28 return i; \ 29 } \ 30 } \ 31 } while (0) 32 33 #define EMIT_DATA_CB(FOR, ptr, len) \ 34 do { \ 35 if (p->settings->on_##FOR) { \ 36 if (p->settings->on_##FOR(p, ptr, len) != 0) { \ 37 return i; \ 38 } \ 39 } \ 40 } while (0) 41 42 43 #define LF 10 44 #define CR 13 45 46 struct multipart_parser { 47 void * data; 48 49 size_t index; 50 size_t boundary_length; 51 52 unsigned char state; 53 54 const multipart_parser_settings* settings; 55 56 char* lookbehind; 57 char multipart_boundary[1]; 58 }; 59 60 enum state { 61 s_uninitialized = 1, 62 s_start, 63 s_start_boundary, 64 s_header_field_start, 65 s_header_field, 66 s_headers_almost_done, 67 s_header_value_start, 68 s_header_value, 69 s_header_value_almost_done, 70 s_part_data_start, 71 s_part_data, 72 s_part_data_almost_boundary, 73 s_part_data_boundary, 74 s_part_data_almost_end, 75 s_part_data_end, 76 s_part_data_final_hyphen, 77 s_end 78 }; 79 80 multipart_parser* multipart_parser_init 81 (const char *boundary, const multipart_parser_settings* settings) { 82 83 multipart_parser* p = malloc(sizeof(multipart_parser) + 84 strlen(boundary) + 85 strlen(boundary) + 9); 86 87 strcpy(p->multipart_boundary, boundary); 88 p->boundary_length = strlen(boundary); 89 90 p->lookbehind = (p->multipart_boundary + p->boundary_length + 1); 91 92 p->index = 0; 93 p->state = s_start; 94 p->settings = settings; 95 96 return p; 97 } 98 99 void multipart_parser_free(multipart_parser* p) { 100 free(p); 101 } 102 103 void multipart_parser_set_data(multipart_parser *p, void *data) { 104 p->data = data; 105 } 106 107 void *multipart_parser_get_data(multipart_parser *p) { 108 return p->data; 109 } 110 111 size_t multipart_parser_execute(multipart_parser* p, const char *buf, size_t len) { 112 size_t i = 0; 113 size_t mark = 0; 114 char c, cl; 115 int is_last = 0; 116 117 while(i < len) { 118 c = buf[i]; 119 is_last = (i == (len - 1)); 120 switch (p->state) { 121 case s_start: 122 multipart_log("s_start"); 123 p->index = 0; 124 p->state = s_start_boundary; 125 126 /* fallthrough */ 127 case s_start_boundary: 128 multipart_log("s_start_boundary"); 129 if (p->index == p->boundary_length) { 130 if (c != CR) { 131 return i; 132 } 133 p->index++; 134 break; 135 } else if (p->index == (p->boundary_length + 1)) { 136 if (c != LF) { 137 return i; 138 } 139 p->index = 0; 140 NOTIFY_CB(part_data_begin); 141 p->state = s_header_field_start; 142 break; 143 } 144 if (c != p->multipart_boundary[p->index]) { 145 return i; 146 } 147 p->index++; 148 break; 149 150 case s_header_field_start: 151 multipart_log("s_header_field_start"); 152 mark = i; 153 p->state = s_header_field; 154 155 /* fallthrough */ 156 case s_header_field: 157 multipart_log("s_header_field"); 158 if (c == CR) { 159 p->state = s_headers_almost_done; 160 break; 161 } 162 163 if (c == '-') { 164 break; 165 } 166 167 if (c == ':') { 168 EMIT_DATA_CB(header_field, buf + mark, i - mark); 169 p->state = s_header_value_start; 170 break; 171 } 172 173 cl = tolower(c); 174 if (cl < 'a' || cl > 'z') { 175 multipart_log("invalid character in header name"); 176 return i; 177 } 178 if (is_last) 179 EMIT_DATA_CB(header_field, buf + mark, (i - mark) + 1); 180 break; 181 182 case s_headers_almost_done: 183 multipart_log("s_headers_almost_done"); 184 if (c != LF) { 185 return i; 186 } 187 188 p->state = s_part_data_start; 189 break; 190 191 case s_header_value_start: 192 multipart_log("s_header_value_start"); 193 if (c == ' ') { 194 break; 195 } 196 197 mark = i; 198 p->state = s_header_value; 199 200 /* fallthrough */ 201 case s_header_value: 202 multipart_log("s_header_value"); 203 if (c == CR) { 204 EMIT_DATA_CB(header_value, buf + mark, i - mark); 205 p->state = s_header_value_almost_done; 206 } 207 if (is_last) 208 EMIT_DATA_CB(header_value, buf + mark, (i - mark) + 1); 209 break; 210 211 case s_header_value_almost_done: 212 multipart_log("s_header_value_almost_done"); 213 if (c != LF) { 214 return i; 215 } 216 p->state = s_header_field_start; 217 break; 218 219 case s_part_data_start: 220 multipart_log("s_part_data_start"); 221 NOTIFY_CB(headers_complete); 222 mark = i; 223 p->state = s_part_data; 224 225 /* fallthrough */ 226 case s_part_data: 227 multipart_log("s_part_data"); 228 if (c == CR) { 229 EMIT_DATA_CB(part_data, buf + mark, i - mark); 230 mark = i; 231 p->state = s_part_data_almost_boundary; 232 p->lookbehind[0] = CR; 233 break; 234 } 235 if (is_last) 236 EMIT_DATA_CB(part_data, buf + mark, (i - mark) + 1); 237 break; 238 239 case s_part_data_almost_boundary: 240 multipart_log("s_part_data_almost_boundary"); 241 if (c == LF) { 242 p->state = s_part_data_boundary; 243 p->lookbehind[1] = LF; 244 p->index = 0; 245 break; 246 } 247 EMIT_DATA_CB(part_data, p->lookbehind, 1); 248 p->state = s_part_data; 249 mark = i --; 250 break; 251 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; 257 mark = i --; 258 break; 259 } 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; 264 } 265 break; 266 267 case s_part_data_almost_end: 268 multipart_log("s_part_data_almost_end"); 269 if (c == '-') { 270 p->state = s_part_data_final_hyphen; 271 break; 272 } 273 if (c == CR) { 274 p->state = s_part_data_end; 275 break; 276 } 277 return i; 278 279 case s_part_data_final_hyphen: 280 multipart_log("s_part_data_final_hyphen"); 281 if (c == '-') { 282 NOTIFY_CB(body_end); 283 p->state = s_end; 284 break; 285 } 286 return i; 287 288 case s_part_data_end: 289 multipart_log("s_part_data_end"); 290 if (c == LF) { 291 p->state = s_header_field_start; 292 NOTIFY_CB(part_data_begin); 293 break; 294 } 295 return i; 296 297 case s_end: 298 multipart_log("s_end: %02X", (int) c); 299 break; 300 301 default: 302 multipart_log("Multipart parser unrecoverable error"); 303 return 0; 304 } 305 ++ i; 306 } 307 308 return len; 309 } 310
This page was automatically generated by LXR 0.3.1. • OpenWrt