postprocessor.c (38301B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007-2021 Daniel Pittman and Christian Grothoff 4 Copyright (C) 2014-2022 Karlson2k (Evgeny Grin) 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 /** 22 * @file postprocessor.c 23 * @brief Methods for parsing POST data 24 * @author Christian Grothoff 25 * @author Karlson2k (Evgeny Grin) 26 */ 27 28 #include "postprocessor.h" 29 #include "internal.h" 30 #include "mhd_str.h" 31 #include "mhd_compat.h" 32 #include "mhd_assert.h" 33 34 /** 35 * Size of on-stack buffer that we use for un-escaping of the value. 36 * We use a pretty small value to be nice to the stack on embedded 37 * systems. 38 */ 39 #define XBUF_SIZE 512 40 41 42 _MHD_EXTERN struct MHD_PostProcessor * 43 MHD_create_post_processor (struct MHD_Connection *connection, 44 size_t buffer_size, 45 MHD_PostDataIterator iter, 46 void *iter_cls) 47 { 48 struct MHD_PostProcessor *ret; 49 const char *encoding; 50 const char *boundary; 51 size_t blen; 52 53 if ( (buffer_size < 256) || 54 (NULL == connection) || 55 (NULL == iter)) 56 MHD_PANIC (_ ("libmicrohttpd API violation.\n")); 57 encoding = NULL; 58 if (MHD_NO == 59 MHD_lookup_connection_value_n (connection, 60 MHD_HEADER_KIND, 61 MHD_HTTP_HEADER_CONTENT_TYPE, 62 MHD_STATICSTR_LEN_ ( 63 MHD_HTTP_HEADER_CONTENT_TYPE), 64 &encoding, 65 NULL)) 66 return NULL; 67 mhd_assert (NULL != encoding); 68 boundary = NULL; 69 if (! MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, 70 encoding, 71 MHD_STATICSTR_LEN_ ( 72 MHD_HTTP_POST_ENCODING_FORM_URLENCODED))) 73 { 74 if (! MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, 75 encoding, 76 MHD_STATICSTR_LEN_ ( 77 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) 78 return NULL; 79 boundary = 80 &encoding[MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)]; 81 /* Q: should this be "strcasestr"? */ 82 boundary = strstr (boundary, "boundary="); 83 if (NULL == boundary) 84 return NULL; /* failed to determine boundary */ 85 boundary += MHD_STATICSTR_LEN_ ("boundary="); 86 blen = strlen (boundary); 87 if ( (blen < 2) || 88 (blen * 2 + 2 > buffer_size) ) 89 return NULL; /* (will be) out of memory or invalid boundary */ 90 if ( (boundary[0] == '"') && 91 (boundary[blen - 1] == '"') ) 92 { 93 /* remove enclosing quotes */ 94 ++boundary; 95 blen -= 2; 96 } 97 } 98 else 99 blen = 0; 100 buffer_size += 4; /* round up to get nice block sizes despite boundary search */ 101 102 /* add +1 to ensure we ALWAYS have a zero-termination at the end */ 103 if (NULL == (ret = MHD_calloc_ (1, sizeof (struct MHD_PostProcessor) 104 + buffer_size + 1))) 105 return NULL; 106 ret->connection = connection; 107 ret->ikvi = iter; 108 ret->cls = iter_cls; 109 ret->encoding = encoding; 110 ret->buffer_size = buffer_size; 111 ret->state = PP_Init; 112 ret->blen = blen; 113 ret->boundary = boundary; 114 ret->skip_rn = RN_Inactive; 115 return ret; 116 } 117 118 119 /** 120 * Give a (possibly partial) value to the application callback. We have some 121 * part of the value in the 'pp->xbuf', the rest is between @a value_start and 122 * @a value_end. If @a last_escape is non-NULL, there may be an incomplete 123 * escape sequence at at @a value_escape between @a value_start and @a 124 * value_end which we should preserve in 'pp->xbuf' for the future. 125 * 126 * Unescapes the value and calls the iterator together with the key. The key 127 * must already be in the key buffer allocated and 0-terminated at the end of 128 * @a pp at the time of the call. 129 * 130 * @param[in,out] pp post processor to act upon 131 * @param value_start where in memory is the value 132 * @param value_end where does the value end 133 * @param last_escape last '%'-sign in value range, 134 * if relevant, or NULL 135 */ 136 static void 137 process_value (struct MHD_PostProcessor *pp, 138 const char *value_start, 139 const char *value_end, 140 const char *last_escape) 141 { 142 char xbuf[XBUF_SIZE + 1]; 143 size_t xoff; 144 145 mhd_assert (pp->xbuf_pos < sizeof (xbuf)); 146 /* 'value_start' and 'value_end' must be either both non-NULL or both NULL */ 147 mhd_assert ( (NULL == value_start) || (NULL != value_end) ); 148 mhd_assert ( (NULL != value_start) || (NULL == value_end) ); 149 mhd_assert ( (NULL == last_escape) || (NULL != value_start) ); 150 /* move remaining input from previous round into processing buffer */ 151 if (0 != pp->xbuf_pos) 152 memcpy (xbuf, 153 pp->xbuf, 154 pp->xbuf_pos); 155 xoff = pp->xbuf_pos; 156 pp->xbuf_pos = 0; 157 if ( (NULL != last_escape) && 158 (((size_t) (value_end - last_escape)) < sizeof (pp->xbuf)) ) 159 { 160 mhd_assert (value_end >= last_escape); 161 pp->xbuf_pos = (size_t) (value_end - last_escape); 162 memcpy (pp->xbuf, 163 last_escape, 164 (size_t) (value_end - last_escape)); 165 value_end = last_escape; 166 } 167 while ( (value_start != value_end) || 168 (pp->must_ikvi) || 169 (xoff > 0) ) 170 { 171 size_t delta = (size_t) (value_end - value_start); 172 bool cut = false; 173 size_t clen = 0; 174 175 mhd_assert (value_end >= value_start); 176 177 if (delta > XBUF_SIZE - xoff) 178 delta = XBUF_SIZE - xoff; 179 /* move (additional) input into processing buffer */ 180 if (0 != delta) 181 { 182 memcpy (&xbuf[xoff], 183 value_start, 184 delta); 185 xoff += delta; 186 value_start += delta; 187 } 188 /* find if escape sequence is at the end of the processing buffer; 189 if so, exclude those from processing (reduce delta to point at 190 end of processed region) */ 191 if ( (xoff > 0) && 192 ('%' == xbuf[xoff - 1]) ) 193 { 194 cut = (xoff != XBUF_SIZE); 195 xoff--; 196 if (cut) 197 { 198 /* move escape sequence into buffer for next function invocation */ 199 pp->xbuf[0] = '%'; 200 pp->xbuf_pos = 1; 201 } 202 else 203 { 204 /* just skip escape sequence for next loop iteration */ 205 delta = xoff; 206 clen = 1; 207 } 208 } 209 else if ( (xoff > 1) && 210 ('%' == xbuf[xoff - 2]) ) 211 { 212 cut = (xoff != XBUF_SIZE); 213 xoff -= 2; 214 if (cut) 215 { 216 /* move escape sequence into buffer for next function invocation */ 217 memcpy (pp->xbuf, 218 &xbuf[xoff], 219 2); 220 pp->xbuf_pos = 2; 221 } 222 else 223 { 224 /* just skip escape sequence for next loop iteration */ 225 delta = xoff; 226 clen = 2; 227 } 228 } 229 mhd_assert (xoff < sizeof (xbuf)); 230 /* unescape */ 231 xbuf[xoff] = '\0'; /* 0-terminate in preparation */ 232 if (0 != xoff) 233 { 234 MHD_unescape_plus (xbuf); 235 xoff = MHD_http_unescape (xbuf); 236 } 237 /* finally: call application! */ 238 if (pp->must_ikvi || (0 != xoff) ) 239 { 240 pp->must_ikvi = false; 241 if (MHD_NO == pp->ikvi (pp->cls, 242 MHD_POSTDATA_KIND, 243 (const char *) &pp[1], /* key */ 244 NULL, 245 NULL, 246 NULL, 247 xbuf, 248 pp->value_offset, 249 xoff)) 250 { 251 pp->state = PP_Error; 252 return; 253 } 254 } 255 pp->value_offset += xoff; 256 if (cut) 257 break; 258 if (0 != clen) 259 { 260 xbuf[delta] = '%'; /* undo 0-termination */ 261 memmove (xbuf, 262 &xbuf[delta], 263 clen); 264 } 265 xoff = clen; 266 } 267 } 268 269 270 /** 271 * Process url-encoded POST data. 272 * 273 * @param pp post processor context 274 * @param post_data upload data 275 * @param post_data_len number of bytes in @a post_data 276 * @return #MHD_YES on success, #MHD_NO if there was an error processing the data 277 */ 278 static enum MHD_Result 279 post_process_urlencoded (struct MHD_PostProcessor *pp, 280 const char *post_data, 281 size_t post_data_len) 282 { 283 char *kbuf = (char *) &pp[1]; 284 size_t poff; 285 const char *start_key = NULL; 286 const char *end_key = NULL; 287 const char *start_value = NULL; 288 const char *end_value = NULL; 289 const char *last_escape = NULL; 290 291 mhd_assert (PP_Callback != pp->state); 292 293 poff = 0; 294 while ( ( (poff < post_data_len) || 295 (pp->state == PP_Callback) ) && 296 (pp->state != PP_Error) ) 297 { 298 switch (pp->state) 299 { 300 case PP_Error: 301 /* clearly impossible as per while loop invariant */ 302 abort (); 303 break; /* Unreachable */ 304 case PP_Init: 305 /* initial phase */ 306 mhd_assert (NULL == start_key); 307 mhd_assert (NULL == end_key); 308 mhd_assert (NULL == start_value); 309 mhd_assert (NULL == end_value); 310 switch (post_data[poff]) 311 { 312 case '=': 313 /* Case: (no key)'=' */ 314 /* Empty key with value */ 315 pp->state = PP_Error; 316 continue; 317 case '&': 318 /* Case: (no key)'&' */ 319 /* Empty key without value */ 320 poff++; 321 continue; 322 case '\n': 323 case '\r': 324 /* Case: (no key)'\n' or (no key)'\r' */ 325 pp->state = PP_Done; 326 poff++; 327 break; 328 default: 329 /* normal character, key start, advance! */ 330 pp->state = PP_ProcessKey; 331 start_key = &post_data[poff]; 332 pp->must_ikvi = true; 333 poff++; 334 continue; 335 } 336 break; /* end PP_Init */ 337 case PP_ProcessKey: 338 /* key phase */ 339 mhd_assert (NULL == start_value); 340 mhd_assert (NULL == end_value); 341 mhd_assert (NULL != start_key || 0 == poff); 342 mhd_assert (0 != poff || NULL == start_key); 343 mhd_assert (NULL == end_key); 344 switch (post_data[poff]) 345 { 346 case '=': 347 /* Case: 'key=' */ 348 if (0 != poff) 349 end_key = &post_data[poff]; 350 poff++; 351 pp->state = PP_ProcessValue; 352 break; 353 case '&': 354 /* Case: 'key&' */ 355 if (0 != poff) 356 end_key = &post_data[poff]; 357 poff++; 358 pp->state = PP_Callback; 359 break; 360 case '\n': 361 case '\r': 362 /* Case: 'key\n' or 'key\r' */ 363 if (0 != poff) 364 end_key = &post_data[poff]; 365 /* No advance here, 'PP_Done' will be selected by next 'PP_Init' phase */ 366 pp->state = PP_Callback; 367 break; 368 default: 369 /* normal character, advance! */ 370 if (0 == poff) 371 start_key = post_data; 372 poff++; 373 break; 374 } 375 mhd_assert (NULL == end_key || NULL != start_key); 376 break; /* end PP_ProcessKey */ 377 case PP_ProcessValue: 378 if (NULL == start_value) 379 start_value = &post_data[poff]; 380 switch (post_data[poff]) 381 { 382 case '=': 383 /* case 'key==' */ 384 pp->state = PP_Error; 385 continue; 386 case '&': 387 /* case 'value&' */ 388 end_value = &post_data[poff]; 389 poff++; 390 if (pp->must_ikvi || 391 (start_value != end_value) ) 392 { 393 pp->state = PP_Callback; 394 } 395 else 396 { 397 pp->buffer_pos = 0; 398 pp->value_offset = 0; 399 pp->state = PP_Init; 400 start_value = NULL; 401 end_value = NULL; 402 } 403 continue; 404 case '\n': 405 case '\r': 406 /* Case: 'value\n' or 'value\r' */ 407 end_value = &post_data[poff]; 408 if (pp->must_ikvi || 409 (start_value != end_value) ) 410 pp->state = PP_Callback; /* No poff advance here to set PP_Done in the next iteration */ 411 else 412 { 413 poff++; 414 pp->state = PP_Done; 415 } 416 break; 417 case '%': 418 last_escape = &post_data[poff]; 419 poff++; 420 break; 421 case '0': 422 case '1': 423 case '2': 424 case '3': 425 case '4': 426 case '5': 427 case '6': 428 case '7': 429 case '8': 430 case '9': 431 /* character, may be part of escaping */ 432 poff++; 433 continue; 434 default: 435 /* normal character, no more escaping! */ 436 last_escape = NULL; 437 poff++; 438 continue; 439 } 440 break; /* end PP_ProcessValue */ 441 case PP_Done: 442 switch (post_data[poff]) 443 { 444 case '\n': 445 case '\r': 446 poff++; 447 continue; 448 } 449 /* unexpected data at the end, fail! */ 450 pp->state = PP_Error; 451 break; 452 case PP_Callback: 453 mhd_assert ((NULL != end_key) || (NULL == start_key)); 454 if (1) 455 { 456 const size_t key_len = (size_t) (end_key - start_key); 457 mhd_assert (end_key >= start_key); 458 if (0 != key_len) 459 { 460 if ( (pp->buffer_pos + key_len >= pp->buffer_size) || 461 (pp->buffer_pos + key_len < pp->buffer_pos) ) 462 { 463 /* key too long, cannot parse! */ 464 pp->state = PP_Error; 465 continue; 466 } 467 /* compute key, if we have not already */ 468 memcpy (&kbuf[pp->buffer_pos], 469 start_key, 470 key_len); 471 pp->buffer_pos += key_len; 472 start_key = NULL; 473 end_key = NULL; 474 pp->must_unescape_key = true; 475 } 476 } 477 #ifdef _DEBUG 478 else 479 mhd_assert (0 != pp->buffer_pos); 480 #endif /* _DEBUG */ 481 if (pp->must_unescape_key) 482 { 483 kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */ 484 MHD_unescape_plus (kbuf); 485 MHD_http_unescape (kbuf); 486 pp->must_unescape_key = false; 487 } 488 process_value (pp, 489 start_value, 490 end_value, 491 NULL); 492 if (PP_Error == pp->state) 493 continue; 494 pp->value_offset = 0; 495 start_value = NULL; 496 end_value = NULL; 497 pp->buffer_pos = 0; 498 pp->state = PP_Init; 499 break; 500 case PP_NextBoundary: 501 case PP_ProcessEntryHeaders: 502 case PP_PerformCheckMultipart: 503 case PP_ProcessValueToBoundary: 504 case PP_PerformCleanup: 505 case PP_Nested_Init: 506 case PP_Nested_PerformMarking: 507 case PP_Nested_ProcessEntryHeaders: 508 case PP_Nested_ProcessValueToBoundary: 509 case PP_Nested_PerformCleanup: 510 default: 511 MHD_PANIC (_ ("internal error.\n")); /* should never happen! */ 512 } 513 mhd_assert ((end_key == NULL) || (start_key != NULL)); 514 mhd_assert ((end_value == NULL) || (start_value != NULL)); 515 } 516 517 mhd_assert (PP_Callback != pp->state); 518 519 if (PP_Error == pp->state) 520 { 521 /* State in error, returning failure */ 522 return MHD_NO; 523 } 524 525 /* save remaining data for next iteration */ 526 if (NULL != start_key) 527 { 528 size_t key_len; 529 mhd_assert ((PP_ProcessKey == pp->state) || (NULL != end_key)); 530 if (NULL == end_key) 531 end_key = &post_data[poff]; 532 mhd_assert (end_key >= start_key); 533 key_len = (size_t) (end_key - start_key); 534 mhd_assert (0 != key_len); /* it must be always non-zero here */ 535 if ( (pp->buffer_pos + key_len >= pp->buffer_size) || 536 (pp->buffer_pos + key_len < pp->buffer_pos) ) 537 { 538 pp->state = PP_Error; 539 return MHD_NO; 540 } 541 memcpy (&kbuf[pp->buffer_pos], 542 start_key, 543 key_len); 544 pp->buffer_pos += key_len; 545 pp->must_unescape_key = true; 546 start_key = NULL; 547 end_key = NULL; 548 } 549 if ( (NULL != start_value) && 550 (PP_ProcessValue == pp->state) ) 551 { 552 /* compute key, if we have not already */ 553 if (pp->must_unescape_key) 554 { 555 kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */ 556 MHD_unescape_plus (kbuf); 557 MHD_http_unescape (kbuf); 558 pp->must_unescape_key = false; 559 } 560 if (NULL == end_value) 561 end_value = &post_data[poff]; 562 if ( (NULL != last_escape) && 563 (2 < (end_value - last_escape)) ) 564 last_escape = NULL; 565 process_value (pp, 566 start_value, 567 end_value, 568 last_escape); 569 pp->must_ikvi = false; 570 } 571 if (PP_Error == pp->state) 572 { 573 /* State in error, returning failure */ 574 return MHD_NO; 575 } 576 return MHD_YES; 577 } 578 579 580 /** 581 * If the given line matches the prefix, strdup the 582 * rest of the line into the suffix ptr. 583 * 584 * @param prefix prefix to match 585 * @param prefix_len length of @a prefix 586 * @param line line to match prefix in 587 * @param suffix set to a copy of the rest of the line, starting at the end of the match 588 * @return #MHD_YES if there was a match, #MHD_NO if not 589 */ 590 static int 591 try_match_header (const char *prefix, 592 size_t prefix_len, 593 char *line, 594 char **suffix) 595 { 596 if (NULL != *suffix) 597 return MHD_NO; 598 if (MHD_str_equal_caseless_n_ (prefix, 599 line, 600 prefix_len)) 601 { 602 *suffix = strdup (&line[prefix_len]); 603 return MHD_YES; 604 } 605 return MHD_NO; 606 } 607 608 609 /** 610 * 611 * @param pp post processor context 612 * @param boundary boundary to look for 613 * @param blen number of bytes in boundary 614 * @param ioffptr set to the end of the boundary if found, 615 * otherwise incremented by one (FIXME: quirky API!) 616 * @param next_state state to which we should advance the post processor 617 * if the boundary is found 618 * @param next_dash_state dash_state to which we should advance the 619 * post processor if the boundary is found 620 * @return #MHD_NO if the boundary is not found, #MHD_YES if we did find it 621 */ 622 static int 623 find_boundary (struct MHD_PostProcessor *pp, 624 const char *boundary, 625 size_t blen, 626 size_t *ioffptr, 627 enum PP_State next_state, 628 enum PP_State next_dash_state) 629 { 630 char *buf = (char *) &pp[1]; 631 const char *dash; 632 633 if (pp->buffer_pos < 2 + blen) 634 { 635 if (pp->buffer_pos == pp->buffer_size) 636 pp->state = PP_Error; /* out of memory */ 637 /* ++(*ioffptr); */ 638 return MHD_NO; /* not enough data */ 639 } 640 if ( (0 != memcmp ("--", 641 buf, 642 2)) || 643 (0 != memcmp (&buf[2], 644 boundary, 645 blen))) 646 { 647 if (pp->state != PP_Init) 648 { 649 /* garbage not allowed */ 650 pp->state = PP_Error; 651 } 652 else 653 { 654 /* skip over garbage (RFC 2046, 5.1.1) */ 655 dash = memchr (buf, 656 '-', 657 pp->buffer_pos); 658 if (NULL == dash) 659 (*ioffptr) += pp->buffer_pos; /* skip entire buffer */ 660 else if (dash == buf) 661 (*ioffptr)++; /* at least skip one byte */ 662 else 663 (*ioffptr) += (size_t) (dash - buf); /* skip to first possible boundary */ 664 } 665 return MHD_NO; /* expected boundary */ 666 } 667 /* remove boundary from buffer */ 668 (*ioffptr) += 2 + blen; 669 /* next: start with headers */ 670 pp->skip_rn = RN_Dash; 671 pp->state = next_state; 672 pp->dash_state = next_dash_state; 673 return MHD_YES; 674 } 675 676 677 /** 678 * In buf, there maybe an expression '$key="$value"'. If that is the 679 * case, copy a copy of $value to destination. 680 * 681 * If destination is already non-NULL, do nothing. 682 */ 683 static void 684 try_get_value (const char *buf, 685 const char *key, 686 char **destination) 687 { 688 const char *spos; 689 const char *bpos; 690 const char *endv; 691 size_t klen; 692 size_t vlen; 693 694 if (NULL != *destination) 695 return; 696 bpos = buf; 697 klen = strlen (key); 698 while (NULL != (spos = strstr (bpos, key))) 699 { 700 if ( (spos[klen] != '=') || 701 ( (spos != buf) && 702 (spos[-1] != ' ') ) ) 703 { 704 /* no match */ 705 bpos = spos + 1; 706 continue; 707 } 708 if (spos[klen + 1] != '"') 709 return; /* not quoted */ 710 if (NULL == (endv = strchr (&spos[klen + 2], 711 '\"'))) 712 return; /* no end-quote */ 713 vlen = (size_t) (endv - spos) - klen - 1; 714 *destination = malloc (vlen); 715 if (NULL == *destination) 716 return; /* out of memory */ 717 (*destination)[vlen - 1] = '\0'; 718 memcpy (*destination, 719 &spos[klen + 2], 720 vlen - 1); 721 return; /* success */ 722 } 723 } 724 725 726 /** 727 * Go over the headers of the part and update 728 * the fields in "pp" according to what we find. 729 * If we are at the end of the headers (as indicated 730 * by an empty line), transition into next_state. 731 * 732 * @param pp post processor context 733 * @param ioffptr set to how many bytes have been 734 * processed 735 * @param next_state state to which the post processor should 736 * be advanced if we find the end of the headers 737 * @return #MHD_YES if we can continue processing, 738 * #MHD_NO on error or if we do not have 739 * enough data yet 740 */ 741 static int 742 process_multipart_headers (struct MHD_PostProcessor *pp, 743 size_t *ioffptr, 744 enum PP_State next_state) 745 { 746 char *buf = (char *) &pp[1]; 747 size_t newline; 748 749 newline = 0; 750 while ( (newline < pp->buffer_pos) && 751 (buf[newline] != '\r') && 752 (buf[newline] != '\n') ) 753 newline++; 754 if (newline == pp->buffer_size) 755 { 756 pp->state = PP_Error; 757 return MHD_NO; /* out of memory */ 758 } 759 if (newline == pp->buffer_pos) 760 return MHD_NO; /* will need more data */ 761 if (0 == newline) 762 { 763 /* empty line - end of headers */ 764 pp->skip_rn = RN_Full; 765 pp->state = next_state; 766 return MHD_YES; 767 } 768 /* got an actual header */ 769 if (buf[newline] == '\r') 770 pp->skip_rn = RN_OptN; 771 buf[newline] = '\0'; 772 if (MHD_str_equal_caseless_n_ ("Content-disposition: ", 773 buf, 774 MHD_STATICSTR_LEN_ ("Content-disposition: "))) 775 { 776 try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")], 777 "name", 778 &pp->content_name); 779 try_get_value (&buf[MHD_STATICSTR_LEN_ ("Content-disposition: ")], 780 "filename", 781 &pp->content_filename); 782 } 783 else 784 { 785 try_match_header ("Content-type: ", 786 MHD_STATICSTR_LEN_ ("Content-type: "), 787 buf, 788 &pp->content_type); 789 try_match_header ("Content-Transfer-Encoding: ", 790 MHD_STATICSTR_LEN_ ("Content-Transfer-Encoding: "), 791 buf, 792 &pp->content_transfer_encoding); 793 } 794 (*ioffptr) += newline + 1; 795 return MHD_YES; 796 } 797 798 799 /** 800 * We have the value until we hit the given boundary; 801 * process accordingly. 802 * 803 * @param pp post processor context 804 * @param ioffptr incremented based on the number of bytes processed 805 * @param boundary the boundary to look for 806 * @param blen strlen(boundary) 807 * @param next_state what state to go into after the 808 * boundary was found 809 * @param next_dash_state state to go into if the next 810 * boundary ends with "--" 811 * @return #MHD_YES if we can continue processing, 812 * #MHD_NO on error or if we do not have 813 * enough data yet 814 */ 815 static int 816 process_value_to_boundary (struct MHD_PostProcessor *pp, 817 size_t *ioffptr, 818 const char *boundary, 819 size_t blen, 820 enum PP_State next_state, 821 enum PP_State next_dash_state) 822 { 823 char *buf = (char *) &pp[1]; 824 size_t newline; 825 const char *r; 826 827 /* all data in buf until the boundary 828 (\r\n--+boundary) is part of the value */ 829 newline = 0; 830 while (1) 831 { 832 while (newline + 4 < pp->buffer_pos) 833 { 834 r = memchr (&buf[newline], 835 '\r', 836 pp->buffer_pos - newline - 4); 837 if (NULL == r) 838 { 839 newline = pp->buffer_pos - 4; 840 break; 841 } 842 newline = (size_t) (r - buf); 843 if (0 == memcmp ("\r\n--", 844 &buf[newline], 845 4)) 846 break; 847 newline++; 848 } 849 if (newline + blen + 4 <= pp->buffer_pos) 850 { 851 /* can check boundary */ 852 if (0 != memcmp (&buf[newline + 4], 853 boundary, 854 blen)) 855 { 856 /* no boundary, "\r\n--" is part of content, skip */ 857 newline += 4; 858 continue; 859 } 860 else 861 { 862 /* boundary found, process until newline then 863 skip boundary and go back to init */ 864 pp->skip_rn = RN_Dash; 865 pp->state = next_state; 866 pp->dash_state = next_dash_state; 867 (*ioffptr) += blen + 4; /* skip boundary as well */ 868 buf[newline] = '\0'; 869 break; 870 } 871 } 872 else 873 { 874 /* cannot check for boundary, process content that 875 we have and check again later; except, if we have 876 no content, abort (out of memory) */ 877 if ( (0 == newline) && 878 (pp->buffer_pos == pp->buffer_size) ) 879 { 880 pp->state = PP_Error; 881 return MHD_NO; 882 } 883 break; 884 } 885 } 886 /* newline is either at beginning of boundary or 887 at least at the last character that we are sure 888 is not part of the boundary */ 889 if ( ( (pp->must_ikvi) || 890 (0 != newline) ) && 891 (MHD_NO == pp->ikvi (pp->cls, 892 MHD_POSTDATA_KIND, 893 pp->content_name, 894 pp->content_filename, 895 pp->content_type, 896 pp->content_transfer_encoding, 897 buf, 898 pp->value_offset, 899 newline)) ) 900 { 901 pp->state = PP_Error; 902 return MHD_NO; 903 } 904 pp->must_ikvi = false; 905 pp->value_offset += newline; 906 (*ioffptr) += newline; 907 return MHD_YES; 908 } 909 910 911 /** 912 * 913 * @param pp post processor context 914 */ 915 static void 916 free_unmarked (struct MHD_PostProcessor *pp) 917 { 918 if ( (NULL != pp->content_name) && 919 (0 == (pp->have & NE_content_name)) ) 920 { 921 free (pp->content_name); 922 pp->content_name = NULL; 923 } 924 if ( (NULL != pp->content_type) && 925 (0 == (pp->have & NE_content_type)) ) 926 { 927 free (pp->content_type); 928 pp->content_type = NULL; 929 } 930 if ( (NULL != pp->content_filename) && 931 (0 == (pp->have & NE_content_filename)) ) 932 { 933 free (pp->content_filename); 934 pp->content_filename = NULL; 935 } 936 if ( (NULL != pp->content_transfer_encoding) && 937 (0 == (pp->have & NE_content_transfer_encoding)) ) 938 { 939 free (pp->content_transfer_encoding); 940 pp->content_transfer_encoding = NULL; 941 } 942 } 943 944 945 /** 946 * Decode multipart POST data. 947 * 948 * @param pp post processor context 949 * @param post_data data to decode 950 * @param post_data_len number of bytes in @a post_data 951 * @return #MHD_NO on error, 952 */ 953 static enum MHD_Result 954 post_process_multipart (struct MHD_PostProcessor *pp, 955 const char *post_data, 956 size_t post_data_len) 957 { 958 char *buf; 959 size_t max; 960 size_t ioff; 961 size_t poff; 962 int state_changed; 963 964 buf = (char *) &pp[1]; 965 ioff = 0; 966 poff = 0; 967 state_changed = 1; 968 while ( (poff < post_data_len) || 969 ( (pp->buffer_pos > 0) && 970 (0 != state_changed) ) ) 971 { 972 /* first, move as much input data 973 as possible to our internal buffer */ 974 max = pp->buffer_size - pp->buffer_pos; 975 if (max > post_data_len - poff) 976 max = post_data_len - poff; 977 memcpy (&buf[pp->buffer_pos], 978 &post_data[poff], 979 max); 980 poff += max; 981 pp->buffer_pos += max; 982 if ( (0 == max) && 983 (0 == state_changed) && 984 (poff < post_data_len) ) 985 { 986 pp->state = PP_Error; 987 return MHD_NO; /* out of memory */ 988 } 989 state_changed = 0; 990 991 /* first state machine for '\r'-'\n' and '--' handling */ 992 switch (pp->skip_rn) 993 { 994 case RN_Inactive: 995 break; 996 case RN_OptN: 997 if (buf[0] == '\n') 998 { 999 ioff++; 1000 pp->skip_rn = RN_Inactive; 1001 goto AGAIN; 1002 } 1003 /* fall-through! */ 1004 case RN_Dash: 1005 if (buf[0] == '-') 1006 { 1007 ioff++; 1008 pp->skip_rn = RN_Dash2; 1009 goto AGAIN; 1010 } 1011 pp->skip_rn = RN_Full; 1012 /* fall-through! */ 1013 case RN_Full: 1014 if (buf[0] == '\r') 1015 { 1016 if ( (pp->buffer_pos > 1) && 1017 ('\n' == buf[1]) ) 1018 { 1019 pp->skip_rn = RN_Inactive; 1020 ioff += 2; 1021 } 1022 else 1023 { 1024 pp->skip_rn = RN_OptN; 1025 ioff++; 1026 } 1027 goto AGAIN; 1028 } 1029 if (buf[0] == '\n') 1030 { 1031 ioff++; 1032 pp->skip_rn = RN_Inactive; 1033 goto AGAIN; 1034 } 1035 pp->skip_rn = RN_Inactive; 1036 pp->state = PP_Error; 1037 return MHD_NO; /* no '\r\n' */ 1038 case RN_Dash2: 1039 if (buf[0] == '-') 1040 { 1041 ioff++; 1042 pp->skip_rn = RN_Full; 1043 pp->state = pp->dash_state; 1044 goto AGAIN; 1045 } 1046 pp->state = PP_Error; 1047 break; 1048 } 1049 1050 /* main state engine */ 1051 switch (pp->state) 1052 { 1053 case PP_Error: 1054 return MHD_NO; 1055 case PP_Done: 1056 /* did not expect to receive more data */ 1057 pp->state = PP_Error; 1058 return MHD_NO; 1059 case PP_Init: 1060 /** 1061 * Per RFC2046 5.1.1 NOTE TO IMPLEMENTORS, consume anything 1062 * prior to the first multipart boundary: 1063 * 1064 * > There appears to be room for additional information prior 1065 * > to the first boundary delimiter line and following the 1066 * > final boundary delimiter line. These areas should 1067 * > generally be left blank, and implementations must ignore 1068 * > anything that appears before the first boundary delimiter 1069 * > line or after the last one. 1070 */ 1071 (void) find_boundary (pp, 1072 pp->boundary, 1073 pp->blen, 1074 &ioff, 1075 PP_ProcessEntryHeaders, 1076 PP_Done); 1077 break; 1078 case PP_NextBoundary: 1079 if (MHD_NO == find_boundary (pp, 1080 pp->boundary, 1081 pp->blen, 1082 &ioff, 1083 PP_ProcessEntryHeaders, 1084 PP_Done)) 1085 { 1086 if (pp->state == PP_Error) 1087 return MHD_NO; 1088 goto END; 1089 } 1090 break; 1091 case PP_ProcessEntryHeaders: 1092 pp->must_ikvi = true; 1093 if (MHD_NO == 1094 process_multipart_headers (pp, 1095 &ioff, 1096 PP_PerformCheckMultipart)) 1097 { 1098 if (pp->state == PP_Error) 1099 return MHD_NO; 1100 else 1101 goto END; 1102 } 1103 state_changed = 1; 1104 break; 1105 case PP_PerformCheckMultipart: 1106 if ( (NULL != pp->content_type) && 1107 (MHD_str_equal_caseless_n_ (pp->content_type, 1108 "multipart/mixed", 1109 MHD_STATICSTR_LEN_ ("multipart/mixed")))) 1110 { 1111 pp->nested_boundary = strstr (pp->content_type, 1112 "boundary="); 1113 if (NULL == pp->nested_boundary) 1114 { 1115 pp->state = PP_Error; 1116 return MHD_NO; 1117 } 1118 pp->nested_boundary = 1119 strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]); 1120 if (NULL == pp->nested_boundary) 1121 { 1122 /* out of memory */ 1123 pp->state = PP_Error; 1124 return MHD_NO; 1125 } 1126 /* free old content type, we will need that field 1127 for the content type of the nested elements */ 1128 free (pp->content_type); 1129 pp->content_type = NULL; 1130 pp->nlen = strlen (pp->nested_boundary); 1131 pp->state = PP_Nested_Init; 1132 state_changed = 1; 1133 break; 1134 } 1135 pp->state = PP_ProcessValueToBoundary; 1136 pp->value_offset = 0; 1137 state_changed = 1; 1138 break; 1139 case PP_ProcessValueToBoundary: 1140 if (MHD_NO == process_value_to_boundary (pp, 1141 &ioff, 1142 pp->boundary, 1143 pp->blen, 1144 PP_PerformCleanup, 1145 PP_Done)) 1146 { 1147 if (pp->state == PP_Error) 1148 return MHD_NO; 1149 break; 1150 } 1151 break; 1152 case PP_PerformCleanup: 1153 /* clean up state of one multipart form-data element! */ 1154 pp->have = NE_none; 1155 free_unmarked (pp); 1156 if (NULL != pp->nested_boundary) 1157 { 1158 free (pp->nested_boundary); 1159 pp->nested_boundary = NULL; 1160 } 1161 pp->state = PP_ProcessEntryHeaders; 1162 state_changed = 1; 1163 break; 1164 case PP_Nested_Init: 1165 if (NULL == pp->nested_boundary) 1166 { 1167 pp->state = PP_Error; 1168 return MHD_NO; 1169 } 1170 if (MHD_NO == find_boundary (pp, 1171 pp->nested_boundary, 1172 pp->nlen, 1173 &ioff, 1174 PP_Nested_PerformMarking, 1175 PP_NextBoundary /* or PP_Error? */)) 1176 { 1177 if (pp->state == PP_Error) 1178 return MHD_NO; 1179 goto END; 1180 } 1181 break; 1182 case PP_Nested_PerformMarking: 1183 /* remember what headers were given 1184 globally */ 1185 pp->have = NE_none; 1186 if (NULL != pp->content_name) 1187 pp->have |= NE_content_name; 1188 if (NULL != pp->content_type) 1189 pp->have |= NE_content_type; 1190 if (NULL != pp->content_filename) 1191 pp->have |= NE_content_filename; 1192 if (NULL != pp->content_transfer_encoding) 1193 pp->have |= NE_content_transfer_encoding; 1194 pp->state = PP_Nested_ProcessEntryHeaders; 1195 state_changed = 1; 1196 break; 1197 case PP_Nested_ProcessEntryHeaders: 1198 pp->value_offset = 0; 1199 if (MHD_NO == 1200 process_multipart_headers (pp, 1201 &ioff, 1202 PP_Nested_ProcessValueToBoundary)) 1203 { 1204 if (pp->state == PP_Error) 1205 return MHD_NO; 1206 else 1207 goto END; 1208 } 1209 state_changed = 1; 1210 break; 1211 case PP_Nested_ProcessValueToBoundary: 1212 if (MHD_NO == process_value_to_boundary (pp, 1213 &ioff, 1214 pp->nested_boundary, 1215 pp->nlen, 1216 PP_Nested_PerformCleanup, 1217 PP_NextBoundary)) 1218 { 1219 if (pp->state == PP_Error) 1220 return MHD_NO; 1221 break; 1222 } 1223 break; 1224 case PP_Nested_PerformCleanup: 1225 free_unmarked (pp); 1226 pp->state = PP_Nested_ProcessEntryHeaders; 1227 state_changed = 1; 1228 break; 1229 case PP_ProcessKey: 1230 case PP_ProcessValue: 1231 case PP_Callback: 1232 default: 1233 MHD_PANIC (_ ("internal error.\n")); /* should never happen! */ 1234 } 1235 AGAIN: 1236 if (ioff > 0) 1237 { 1238 memmove (buf, 1239 &buf[ioff], 1240 pp->buffer_pos - ioff); 1241 pp->buffer_pos -= ioff; 1242 ioff = 0; 1243 state_changed = 1; 1244 } 1245 } 1246 END: 1247 if (0 != ioff) 1248 { 1249 memmove (buf, 1250 &buf[ioff], 1251 pp->buffer_pos - ioff); 1252 pp->buffer_pos -= ioff; 1253 } 1254 if (poff < post_data_len) 1255 { 1256 pp->state = PP_Error; 1257 return MHD_NO; /* serious error */ 1258 } 1259 return MHD_YES; 1260 } 1261 1262 1263 _MHD_EXTERN enum MHD_Result 1264 MHD_post_process (struct MHD_PostProcessor *pp, 1265 const char *post_data, 1266 size_t post_data_len) 1267 { 1268 if (0 == post_data_len) 1269 return MHD_YES; 1270 if (NULL == pp) 1271 return MHD_NO; 1272 if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, 1273 pp->encoding, 1274 MHD_STATICSTR_LEN_ ( 1275 MHD_HTTP_POST_ENCODING_FORM_URLENCODED))) 1276 return post_process_urlencoded (pp, 1277 post_data, 1278 post_data_len); 1279 if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, 1280 pp->encoding, 1281 MHD_STATICSTR_LEN_ ( 1282 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) 1283 return post_process_multipart (pp, 1284 post_data, 1285 post_data_len); 1286 /* this should never be reached */ 1287 return MHD_NO; 1288 } 1289 1290 1291 _MHD_EXTERN enum MHD_Result 1292 MHD_destroy_post_processor (struct MHD_PostProcessor *pp) 1293 { 1294 enum MHD_Result ret; 1295 1296 if (NULL == pp) 1297 return MHD_YES; 1298 if (PP_ProcessValue == pp->state) 1299 { 1300 /* key without terminated value left at the end of the 1301 buffer; fake receiving a termination character to 1302 ensure it is also processed */ 1303 post_process_urlencoded (pp, 1304 "\n", 1305 1); 1306 } 1307 /* These internal strings need cleaning up since 1308 the post-processing may have been interrupted 1309 at any stage */ 1310 if ( (pp->xbuf_pos > 0) || 1311 ( (pp->state != PP_Done) && 1312 (pp->state != PP_Init) ) ) 1313 ret = MHD_NO; 1314 else 1315 ret = MHD_YES; 1316 pp->have = NE_none; 1317 free_unmarked (pp); 1318 if (NULL != pp->nested_boundary) 1319 free (pp->nested_boundary); 1320 free (pp); 1321 return ret; 1322 } 1323 1324 1325 /* end of postprocessor.c */