postprocessor.c (38296B)
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 { 537 pp->state = PP_Error; 538 return MHD_NO; 539 } 540 memcpy (&kbuf[pp->buffer_pos], 541 start_key, 542 key_len); 543 pp->buffer_pos += key_len; 544 pp->must_unescape_key = true; 545 start_key = NULL; 546 end_key = NULL; 547 } 548 if ( (NULL != start_value) && 549 (PP_ProcessValue == pp->state) ) 550 { 551 /* compute key, if we have not already */ 552 if (pp->must_unescape_key) 553 { 554 kbuf[pp->buffer_pos] = '\0'; /* 0-terminate key */ 555 MHD_unescape_plus (kbuf); 556 MHD_http_unescape (kbuf); 557 pp->must_unescape_key = false; 558 } 559 if (NULL == end_value) 560 end_value = &post_data[poff]; 561 if ( (NULL != last_escape) && 562 (2 < (end_value - last_escape)) ) 563 last_escape = NULL; 564 process_value (pp, 565 start_value, 566 end_value, 567 last_escape); 568 pp->must_ikvi = false; 569 } 570 if (PP_Error == pp->state) 571 { 572 /* State in error, returning failure */ 573 return MHD_NO; 574 } 575 return MHD_YES; 576 } 577 578 579 /** 580 * If the given line matches the prefix, strdup the 581 * rest of the line into the suffix ptr. 582 * 583 * @param prefix prefix to match 584 * @param prefix_len length of @a prefix 585 * @param line line to match prefix in 586 * @param suffix set to a copy of the rest of the line, starting at the end of the match 587 * @return #MHD_YES if there was a match, #MHD_NO if not 588 */ 589 static int 590 try_match_header (const char *prefix, 591 size_t prefix_len, 592 char *line, 593 char **suffix) 594 { 595 if (NULL != *suffix) 596 return MHD_NO; 597 while (0 != *line) 598 { 599 if (MHD_str_equal_caseless_n_ (prefix, 600 line, 601 prefix_len)) 602 { 603 *suffix = strdup (&line[prefix_len]); 604 return MHD_YES; 605 } 606 ++line; 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 pp->nested_boundary = strstr (pp->content_type, 1115 "boundary="); 1116 if (NULL == pp->nested_boundary) 1117 { 1118 pp->state = PP_Error; 1119 return MHD_NO; 1120 } 1121 pp->nested_boundary = 1122 strdup (&pp->nested_boundary[MHD_STATICSTR_LEN_ ("boundary=")]); 1123 if (NULL == pp->nested_boundary) 1124 { 1125 /* out of memory */ 1126 pp->state = PP_Error; 1127 return MHD_NO; 1128 } 1129 /* free old content type, we will need that field 1130 for the content type of the nested elements */ 1131 free (pp->content_type); 1132 pp->content_type = NULL; 1133 pp->nlen = strlen (pp->nested_boundary); 1134 pp->state = PP_Nested_Init; 1135 state_changed = 1; 1136 break; 1137 } 1138 pp->state = PP_ProcessValueToBoundary; 1139 pp->value_offset = 0; 1140 state_changed = 1; 1141 break; 1142 case PP_ProcessValueToBoundary: 1143 if (MHD_NO == process_value_to_boundary (pp, 1144 &ioff, 1145 pp->boundary, 1146 pp->blen, 1147 PP_PerformCleanup, 1148 PP_Done)) 1149 { 1150 if (pp->state == PP_Error) 1151 return MHD_NO; 1152 break; 1153 } 1154 break; 1155 case PP_PerformCleanup: 1156 /* clean up state of one multipart form-data element! */ 1157 pp->have = NE_none; 1158 free_unmarked (pp); 1159 if (NULL != pp->nested_boundary) 1160 { 1161 free (pp->nested_boundary); 1162 pp->nested_boundary = NULL; 1163 } 1164 pp->state = PP_ProcessEntryHeaders; 1165 state_changed = 1; 1166 break; 1167 case PP_Nested_Init: 1168 if (NULL == pp->nested_boundary) 1169 { 1170 pp->state = PP_Error; 1171 return MHD_NO; 1172 } 1173 if (MHD_NO == find_boundary (pp, 1174 pp->nested_boundary, 1175 pp->nlen, 1176 &ioff, 1177 PP_Nested_PerformMarking, 1178 PP_NextBoundary /* or PP_Error? */)) 1179 { 1180 if (pp->state == PP_Error) 1181 return MHD_NO; 1182 goto END; 1183 } 1184 break; 1185 case PP_Nested_PerformMarking: 1186 /* remember what headers were given 1187 globally */ 1188 pp->have = NE_none; 1189 if (NULL != pp->content_name) 1190 pp->have |= NE_content_name; 1191 if (NULL != pp->content_type) 1192 pp->have |= NE_content_type; 1193 if (NULL != pp->content_filename) 1194 pp->have |= NE_content_filename; 1195 if (NULL != pp->content_transfer_encoding) 1196 pp->have |= NE_content_transfer_encoding; 1197 pp->state = PP_Nested_ProcessEntryHeaders; 1198 state_changed = 1; 1199 break; 1200 case PP_Nested_ProcessEntryHeaders: 1201 pp->value_offset = 0; 1202 if (MHD_NO == 1203 process_multipart_headers (pp, 1204 &ioff, 1205 PP_Nested_ProcessValueToBoundary)) 1206 { 1207 if (pp->state == PP_Error) 1208 return MHD_NO; 1209 else 1210 goto END; 1211 } 1212 state_changed = 1; 1213 break; 1214 case PP_Nested_ProcessValueToBoundary: 1215 if (MHD_NO == process_value_to_boundary (pp, 1216 &ioff, 1217 pp->nested_boundary, 1218 pp->nlen, 1219 PP_Nested_PerformCleanup, 1220 PP_NextBoundary)) 1221 { 1222 if (pp->state == PP_Error) 1223 return MHD_NO; 1224 break; 1225 } 1226 break; 1227 case PP_Nested_PerformCleanup: 1228 free_unmarked (pp); 1229 pp->state = PP_Nested_ProcessEntryHeaders; 1230 state_changed = 1; 1231 break; 1232 case PP_ProcessKey: 1233 case PP_ProcessValue: 1234 case PP_Callback: 1235 default: 1236 MHD_PANIC (_ ("internal error.\n")); /* should never happen! */ 1237 } 1238 AGAIN: 1239 if (ioff > 0) 1240 { 1241 memmove (buf, 1242 &buf[ioff], 1243 pp->buffer_pos - ioff); 1244 pp->buffer_pos -= ioff; 1245 ioff = 0; 1246 state_changed = 1; 1247 } 1248 } 1249 END: 1250 if (0 != ioff) 1251 { 1252 memmove (buf, 1253 &buf[ioff], 1254 pp->buffer_pos - ioff); 1255 pp->buffer_pos -= ioff; 1256 } 1257 if (poff < post_data_len) 1258 { 1259 pp->state = PP_Error; 1260 return MHD_NO; /* serious error */ 1261 } 1262 return MHD_YES; 1263 } 1264 1265 1266 _MHD_EXTERN enum MHD_Result 1267 MHD_post_process (struct MHD_PostProcessor *pp, 1268 const char *post_data, 1269 size_t post_data_len) 1270 { 1271 if (0 == post_data_len) 1272 return MHD_YES; 1273 if (NULL == pp) 1274 return MHD_NO; 1275 if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, 1276 pp->encoding, 1277 MHD_STATICSTR_LEN_ ( 1278 MHD_HTTP_POST_ENCODING_FORM_URLENCODED))) 1279 return post_process_urlencoded (pp, 1280 post_data, 1281 post_data_len); 1282 if (MHD_str_equal_caseless_n_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, 1283 pp->encoding, 1284 MHD_STATICSTR_LEN_ ( 1285 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) 1286 return post_process_multipart (pp, 1287 post_data, 1288 post_data_len); 1289 /* this should never be reached */ 1290 return MHD_NO; 1291 } 1292 1293 1294 _MHD_EXTERN enum MHD_Result 1295 MHD_destroy_post_processor (struct MHD_PostProcessor *pp) 1296 { 1297 enum MHD_Result ret; 1298 1299 if (NULL == pp) 1300 return MHD_YES; 1301 if (PP_ProcessValue == pp->state) 1302 { 1303 /* key without terminated value left at the end of the 1304 buffer; fake receiving a termination character to 1305 ensure it is also processed */ 1306 post_process_urlencoded (pp, 1307 "\n", 1308 1); 1309 } 1310 /* These internal strings need cleaning up since 1311 the post-processing may have been interrupted 1312 at any stage */ 1313 if ( (pp->xbuf_pos > 0) || 1314 ( (pp->state != PP_Done) && 1315 (pp->state != PP_Init) ) ) 1316 ret = MHD_NO; 1317 else 1318 ret = MHD_YES; 1319 pp->have = NE_none; 1320 free_unmarked (pp); 1321 if (NULL != pp->nested_boundary) 1322 free (pp->nested_boundary); 1323 free (pp); 1324 return ret; 1325 } 1326 1327 1328 /* end of postprocessor.c */