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