test_postprocessor.c (28153B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2013, 2019, 2020 Christian Grothoff 4 Copyright (C) 2021 Evgeny Grin (Karlson2k) 5 6 libmicrohttpd is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published 8 by the Free Software Foundation; either version 3, or (at your 9 option) any later version. 10 11 libmicrohttpd is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with libmicrohttpd; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 */ 21 /** 22 * @file test_postprocessor.c 23 * @brief Testcase for postprocessor 24 * @author Christian Grothoff 25 * @author Karlson2k (Evgeny Grin) 26 */ 27 #include "platform.h" 28 #include "microhttpd.h" 29 #include "internal.h" 30 #include <stdlib.h> 31 #include <string.h> 32 #include <stdio.h> 33 #include "mhd_compat.h" 34 35 #ifndef WINDOWS 36 #include <unistd.h> 37 #endif 38 39 #ifndef MHD_DEBUG_PP 40 #define MHD_DEBUG_PP 0 41 #endif /* MHD_DEBUG_PP */ 42 43 struct expResult 44 { 45 const char *key; 46 const char *fname; 47 const char *cnt_type; 48 const char *tr_enc; 49 const char *data; 50 }; 51 52 /** 53 * Array of values that the value checker "wants". 54 * Each series of checks should be terminated by 55 * five NULL-entries. 56 */ 57 static struct expResult exp_results[] = { 58 #define URL_NOVALUE1_DATA "abc&x=5" 59 #define URL_NOVALUE1_START 0 60 {"abc", NULL, NULL, NULL, /* NULL */ ""}, /* change after API update */ 61 {"x", NULL, NULL, NULL, "5"}, 62 #define URL_NOVALUE1_END (URL_NOVALUE1_START + 2) 63 #define URL_NOVALUE2_DATA "abc=&x=5" 64 #define URL_NOVALUE2_START URL_NOVALUE1_END 65 {"abc", NULL, NULL, NULL, ""}, 66 {"x", NULL, NULL, NULL, "5"}, 67 #define URL_NOVALUE2_END (URL_NOVALUE2_START + 2) 68 #define URL_NOVALUE3_DATA "xyz=" 69 #define URL_NOVALUE3_START URL_NOVALUE2_END 70 {"xyz", NULL, NULL, NULL, ""}, 71 #define URL_NOVALUE3_END (URL_NOVALUE3_START + 1) 72 #define URL_NOVALUE4_DATA "xyz" 73 #define URL_NOVALUE4_START URL_NOVALUE3_END 74 {"xyz", NULL, NULL, NULL, /* NULL */ ""}, /* change after API update */ 75 #define URL_NOVALUE4_END (URL_NOVALUE4_START + 1) 76 #define URL_DATA "abc=def&x=5" 77 #define URL_START URL_NOVALUE4_END 78 {"abc", NULL, NULL, NULL, "def"}, 79 {"x", NULL, NULL, NULL, "5"}, 80 #define URL_END (URL_START + 2) 81 #define URL_ENC_DATA "space=%20&key%201=&crlf=%0D%0a&mix%09ed=%2001%0d%0A" 82 #define URL_ENC_START URL_END 83 {"space", NULL, NULL, NULL, " "}, 84 {"key 1", NULL, NULL, NULL, ""}, 85 {"crlf", NULL, NULL, NULL, "\r\n"}, 86 {"mix\ted", NULL, NULL, NULL, " 01\r\n"}, 87 #define URL_ENC_END (URL_ENC_START + 4) 88 {NULL, NULL, NULL, NULL, NULL}, 89 #define FORM_DATA \ 90 "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\n" \ 91 "Joe Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\";" \ 92 " filename=\"file1.txt\"\r\nContent-Type: text/plain\r\n" \ 93 "Content-Transfer-Encoding: binary\r\n\r\nfiledata\r\n--AaB03x--\r\n" 94 #define FORM_START (URL_ENC_END + 1) 95 {"field1", NULL, NULL, NULL, "Joe Blow"}, 96 {"pics", "file1.txt", "text/plain", "binary", "filedata"}, 97 #define FORM_END (FORM_START + 2) 98 {NULL, NULL, NULL, NULL, NULL}, 99 #define FORM_NESTED_DATA \ 100 "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\n" \ 101 "Jane Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\"\r\n" \ 102 "Content-type: multipart/mixed, boundary=BbC04y\r\n\r\n--BbC04y\r\n" \ 103 "Content-disposition: attachment; filename=\"file1.txt\"\r\n" \ 104 "Content-Type: text/plain\r\n\r\nfiledata1\r\n--BbC04y\r\n" \ 105 "Content-disposition: attachment; filename=\"file2.gif\"\r\n" \ 106 "Content-type: image/gif\r\nContent-Transfer-Encoding: binary\r\n\r\n" \ 107 "filedata2\r\n--BbC04y--\r\n--AaB03x--" 108 #define FORM_NESTED_START (FORM_END + 1) 109 {"field1", NULL, NULL, NULL, "Jane Blow"}, 110 {"pics", "file1.txt", "text/plain", NULL, "filedata1"}, 111 {"pics", "file2.gif", "image/gif", "binary", "filedata2"}, 112 #define FORM_NESTED_END (FORM_NESTED_START + 3) 113 {NULL, NULL, NULL, NULL, NULL}, 114 #define URL_EMPTY_VALUE_DATA "key1=value1&key2=&key3=" 115 #define URL_EMPTY_VALUE_START (FORM_NESTED_END + 1) 116 {"key1", NULL, NULL, NULL, "value1"}, 117 {"key2", NULL, NULL, NULL, ""}, 118 {"key3", NULL, NULL, NULL, ""}, 119 #define URL_EMPTY_VALUE_END (URL_EMPTY_VALUE_START + 3) 120 {NULL, NULL, NULL, NULL, NULL} 121 }; 122 123 124 static int 125 mismatch (const char *a, const char *b) 126 { 127 if (a == b) 128 return 0; 129 if ((a == NULL) || (b == NULL)) 130 return 1; 131 return 0 != strcmp (a, b); 132 } 133 134 135 static int 136 mismatch2 (const char *data, const char *expected, size_t offset, size_t size) 137 { 138 if (data == expected) 139 return 0; 140 if ((data == NULL) || (expected == NULL)) 141 return 1; 142 return 0 != memcmp (data, expected + offset, size); 143 } 144 145 146 static enum MHD_Result 147 value_checker (void *cls, 148 enum MHD_ValueKind kind, 149 const char *key, 150 const char *filename, 151 const char *content_type, 152 const char *transfer_encoding, 153 const char *data, 154 uint64_t off, 155 size_t size) 156 { 157 unsigned int *idxp = cls; 158 struct expResult *expect = exp_results + *idxp; 159 (void) kind; /* Unused. Silent compiler warning. */ 160 161 #if MHD_DEBUG_PP 162 fprintf (stderr, 163 "VC: `%s' `%s' `%s' `%s' (+%u)`%.*s' (%d)\n", 164 key ? key : "(NULL)", 165 filename ? filename : "(NULL)", 166 content_type ? content_type : "(NULL)", 167 transfer_encoding ? transfer_encoding : "(NULL)", 168 (unsigned int) off, 169 (int) (data ? size : 6), 170 data ? data : "(NULL)", 171 (int) size); 172 #endif 173 if (*idxp == (unsigned int) -1) 174 exit (99); 175 if ( (0 != off) && (0 == size) ) 176 { 177 if (NULL == expect->data) 178 *idxp += 1; 179 return MHD_YES; 180 } 181 if ((expect->key == NULL) || 182 (0 != strcmp (key, expect->key)) || 183 (mismatch (filename, expect->fname)) || 184 (mismatch (content_type, expect->cnt_type)) || 185 (mismatch (transfer_encoding, expect->tr_enc)) || 186 (strlen (expect->data) < off) || 187 (mismatch2 (data, expect->data, (size_t) off, size))) 188 { 189 *idxp = (unsigned int) -1; 190 fprintf (stderr, 191 "Failed with: `%s' `%s' `%s' `%s' `%.*s'\n", 192 key ? key : "(NULL)", 193 filename ? filename : "(NULL)", 194 content_type ? content_type : "(NULL)", 195 transfer_encoding ? transfer_encoding : "(NULL)", 196 (int) (data ? size : 6), 197 data ? data : "(NULL)"); 198 fprintf (stderr, 199 "Wanted: `%s' `%s' `%s' `%s' `%s'\n", 200 expect->key ? expect->key : "(NULL)", 201 expect->fname ? expect->fname : "(NULL)", 202 expect->cnt_type ? expect->cnt_type : "(NULL)", 203 expect->tr_enc ? expect->tr_enc : "(NULL)", 204 expect->data ? expect->data : "(NULL)"); 205 fprintf (stderr, 206 "Unexpected result: %d/%d/%d/%d/%d/%d\n", 207 (expect->key == NULL), 208 (NULL != expect->key) && (0 != strcmp (key, expect->key)), 209 (mismatch (filename, expect->fname)), 210 (mismatch (content_type, expect->cnt_type)), 211 (mismatch (transfer_encoding, expect->tr_enc)), 212 (strlen (expect->data) < off) 213 || (mismatch2 (data, expect->data, (size_t) off, size))); 214 return MHD_NO; 215 } 216 if ( ( (NULL == expect->data) && 217 (0 == off + size) ) || 218 ( (NULL != expect->data) && 219 (off + size == strlen (expect->data)) ) ) 220 *idxp += 1; 221 return MHD_YES; 222 } 223 224 225 static unsigned int 226 test_urlencoding_case (unsigned int want_start, 227 unsigned int want_end, 228 const char *url_data) 229 { 230 size_t step; 231 unsigned int errors = 0; 232 const size_t size = strlen (url_data); 233 234 for (step = 1; size >= step; ++step) 235 { 236 struct MHD_Connection connection; 237 struct MHD_HTTP_Req_Header header; 238 struct MHD_PostProcessor *pp; 239 unsigned int want_off = want_start; 240 size_t i; 241 242 memset (&connection, 0, sizeof (struct MHD_Connection)); 243 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 244 connection.rq.headers_received = &header; 245 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 246 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; 247 header.header_size = MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_TYPE); 248 header.value_size = 249 MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED); 250 header.kind = MHD_HEADER_KIND; 251 pp = MHD_create_post_processor (&connection, 252 1024, 253 &value_checker, 254 &want_off); 255 if (NULL == pp) 256 { 257 fprintf (stderr, "Failed to create post processor.\n" 258 "Line: %u\n", (unsigned int) __LINE__); 259 exit (50); 260 } 261 for (i = 0; size > i; i += step) 262 { 263 size_t left = size - i; 264 if (MHD_YES != MHD_post_process (pp, 265 &url_data[i], 266 (left > step) ? step : left)) 267 { 268 fprintf (stderr, "Failed to process the data.\n" 269 "i: %u. step: %u.\n" 270 "Line: %u\n", (unsigned) i, (unsigned) step, 271 (unsigned int) __LINE__); 272 exit (49); 273 } 274 } 275 MHD_destroy_post_processor (pp); 276 if (want_off != want_end) 277 { 278 fprintf (stderr, 279 "Test failed in line %u.\tStep: %u.\tData: \"%s\"\n" \ 280 " Got: %u\tExpected: %u\n", 281 (unsigned int) __LINE__, 282 (unsigned int) step, 283 url_data, 284 want_off, 285 want_end); 286 errors++; 287 } 288 } 289 return errors; 290 } 291 292 293 static unsigned int 294 test_urlencoding (void) 295 { 296 unsigned int errorCount = 0; 297 298 errorCount += test_urlencoding_case (URL_START, 299 URL_END, 300 URL_DATA); 301 errorCount += test_urlencoding_case (URL_ENC_START, 302 URL_ENC_END, 303 URL_ENC_DATA); 304 errorCount += test_urlencoding_case (URL_NOVALUE1_START, 305 URL_NOVALUE1_END, 306 URL_NOVALUE1_DATA); 307 errorCount += test_urlencoding_case (URL_NOVALUE2_START, 308 URL_NOVALUE2_END, 309 URL_NOVALUE2_DATA); 310 errorCount += test_urlencoding_case (URL_NOVALUE3_START, 311 URL_NOVALUE3_END, 312 URL_NOVALUE3_DATA); 313 errorCount += test_urlencoding_case (URL_NOVALUE4_START, 314 URL_NOVALUE4_START, /* No advance */ 315 URL_NOVALUE4_DATA); 316 errorCount += test_urlencoding_case (URL_EMPTY_VALUE_START, 317 URL_EMPTY_VALUE_END, 318 URL_EMPTY_VALUE_DATA); 319 320 errorCount += test_urlencoding_case (URL_START, 321 URL_END, 322 URL_DATA "\n"); 323 errorCount += test_urlencoding_case (URL_ENC_START, 324 URL_ENC_END, 325 URL_ENC_DATA "\n"); 326 errorCount += test_urlencoding_case (URL_NOVALUE1_START, 327 URL_NOVALUE1_END, 328 URL_NOVALUE1_DATA "\n"); 329 errorCount += test_urlencoding_case (URL_NOVALUE2_START, 330 URL_NOVALUE2_END, 331 URL_NOVALUE2_DATA "\n"); 332 errorCount += test_urlencoding_case (URL_NOVALUE3_START, 333 URL_NOVALUE3_END, 334 URL_NOVALUE3_DATA "\n"); 335 errorCount += test_urlencoding_case (URL_NOVALUE4_START, 336 URL_NOVALUE4_END, /* With advance */ 337 URL_NOVALUE4_DATA "\n"); 338 errorCount += test_urlencoding_case (URL_EMPTY_VALUE_START, 339 URL_EMPTY_VALUE_END, 340 URL_EMPTY_VALUE_DATA "\n"); 341 342 errorCount += test_urlencoding_case (URL_START, 343 URL_END, 344 "&&" URL_DATA); 345 errorCount += test_urlencoding_case (URL_ENC_START, 346 URL_ENC_END, 347 "&&" URL_ENC_DATA); 348 errorCount += test_urlencoding_case (URL_NOVALUE1_START, 349 URL_NOVALUE1_END, 350 "&&" URL_NOVALUE1_DATA); 351 errorCount += test_urlencoding_case (URL_NOVALUE2_START, 352 URL_NOVALUE2_END, 353 "&&" URL_NOVALUE2_DATA); 354 errorCount += test_urlencoding_case (URL_NOVALUE3_START, 355 URL_NOVALUE3_END, 356 "&&" URL_NOVALUE3_DATA); 357 errorCount += test_urlencoding_case (URL_NOVALUE4_START, 358 URL_NOVALUE4_START, /* No advance */ 359 "&&" URL_NOVALUE4_DATA); 360 errorCount += test_urlencoding_case (URL_EMPTY_VALUE_START, 361 URL_EMPTY_VALUE_END, 362 "&&" URL_EMPTY_VALUE_DATA); 363 if (0 != errorCount) 364 fprintf (stderr, 365 "Test failed in line %u with %u errors\n", 366 (unsigned int) __LINE__, 367 errorCount); 368 return errorCount; 369 } 370 371 372 static unsigned int 373 test_multipart_garbage (void) 374 { 375 struct MHD_Connection connection; 376 struct MHD_HTTP_Req_Header header; 377 struct MHD_PostProcessor *pp; 378 unsigned int want_off; 379 size_t size = MHD_STATICSTR_LEN_ (FORM_DATA); 380 size_t splitpoint; 381 char xdata[MHD_STATICSTR_LEN_ (FORM_DATA) + 3]; 382 383 /* fill in evil garbage at the beginning */ 384 xdata[0] = '-'; 385 xdata[1] = 'x'; 386 xdata[2] = '\r'; 387 memcpy (&xdata[3], FORM_DATA, size); 388 size += 3; 389 for (splitpoint = 1; splitpoint < size; splitpoint++) 390 { 391 want_off = FORM_START; 392 memset (&connection, 0, sizeof (struct MHD_Connection)); 393 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 394 connection.rq.headers_received = &header; 395 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 396 header.value = 397 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; 398 header.header_size = MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_TYPE); 399 header.value_size = 400 MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA \ 401 ", boundary=AaB03x"); 402 header.kind = MHD_HEADER_KIND; 403 pp = MHD_create_post_processor (&connection, 404 1024, &value_checker, &want_off); 405 if (NULL == pp) 406 { 407 fprintf (stderr, "Failed to create post processor.\n" 408 "Line: %u\n", (unsigned int) __LINE__); 409 exit (50); 410 } 411 if (MHD_YES != MHD_post_process (pp, xdata, splitpoint)) 412 { 413 fprintf (stderr, 414 "Test failed in line %u at point %d\n", 415 (unsigned int) __LINE__, 416 (int) splitpoint); 417 exit (49); 418 } 419 if (MHD_YES != MHD_post_process (pp, &xdata[splitpoint], size - splitpoint)) 420 { 421 fprintf (stderr, 422 "Test failed in line %u at point %u\n", 423 (unsigned int) __LINE__, 424 (unsigned int) splitpoint); 425 exit (49); 426 } 427 MHD_destroy_post_processor (pp); 428 if (want_off != FORM_END) 429 { 430 fprintf (stderr, 431 "Test failed in line %u at point %u\n", 432 (unsigned int) __LINE__, 433 (unsigned int) splitpoint); 434 return (unsigned int) splitpoint; 435 } 436 } 437 return 0; 438 } 439 440 441 static unsigned int 442 test_multipart_splits (void) 443 { 444 struct MHD_Connection connection; 445 struct MHD_HTTP_Req_Header header; 446 struct MHD_PostProcessor *pp; 447 unsigned int want_off; 448 size_t size; 449 size_t splitpoint; 450 451 size = strlen (FORM_DATA); 452 for (splitpoint = 1; splitpoint < size; splitpoint++) 453 { 454 want_off = FORM_START; 455 memset (&connection, 0, sizeof (struct MHD_Connection)); 456 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 457 connection.rq.headers_received = &header; 458 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 459 header.value = 460 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; 461 header.header_size = strlen (header.header); 462 header.value_size = strlen (header.value); 463 header.kind = MHD_HEADER_KIND; 464 pp = MHD_create_post_processor (&connection, 465 1024, &value_checker, &want_off); 466 if (NULL == pp) 467 { 468 fprintf (stderr, "Failed to create post processor.\n" 469 "Line: %u\n", (unsigned int) __LINE__); 470 exit (50); 471 } 472 if (MHD_YES != MHD_post_process (pp, FORM_DATA, splitpoint)) 473 { 474 fprintf (stderr, 475 "Test failed in line %u at point %d\n", 476 (unsigned int) __LINE__, 477 (int) splitpoint); 478 exit (49); 479 } 480 if (MHD_YES != MHD_post_process (pp, &FORM_DATA[splitpoint], 481 size - splitpoint)) 482 { 483 fprintf (stderr, 484 "Test failed in line %u at point %u\n", 485 (unsigned int) __LINE__, 486 (unsigned int) splitpoint); 487 exit (49); 488 } 489 MHD_destroy_post_processor (pp); 490 if (want_off != FORM_END) 491 { 492 fprintf (stderr, 493 "Test failed in line %u at point %u\n", 494 (unsigned int) __LINE__, 495 (unsigned int) splitpoint); 496 return (unsigned int) splitpoint; 497 } 498 } 499 return 0; 500 } 501 502 503 static unsigned int 504 test_multipart (void) 505 { 506 struct MHD_Connection connection; 507 struct MHD_HTTP_Req_Header header; 508 struct MHD_PostProcessor *pp; 509 unsigned int want_off = FORM_START; 510 size_t i; 511 size_t delta; 512 size_t size; 513 514 memset (&connection, 0, sizeof (struct MHD_Connection)); 515 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 516 connection.rq.headers_received = &header; 517 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 518 header.value = 519 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; 520 header.kind = MHD_HEADER_KIND; 521 header.header_size = strlen (header.header); 522 header.value_size = strlen (header.value); 523 pp = MHD_create_post_processor (&connection, 524 1024, &value_checker, &want_off); 525 if (NULL == pp) 526 { 527 fprintf (stderr, "Failed to create post processor.\n" 528 "Line: %u\n", (unsigned int) __LINE__); 529 exit (50); 530 } 531 i = 0; 532 size = strlen (FORM_DATA); 533 while (i < size) 534 { 535 delta = 1 + ((size_t) MHD_random_ ()) % (size - i); 536 if (MHD_YES != MHD_post_process (pp, 537 &FORM_DATA[i], 538 delta)) 539 { 540 fprintf (stderr, "Failed to process the data.\n" 541 "i: %u. delta: %u.\n" 542 "Line: %u\n", (unsigned) i, (unsigned) delta, 543 (unsigned int) __LINE__); 544 exit (49); 545 } 546 i += delta; 547 } 548 MHD_destroy_post_processor (pp); 549 if (want_off != FORM_END) 550 { 551 fprintf (stderr, 552 "Test failed in line %u\n", 553 (unsigned int) __LINE__); 554 return 2; 555 } 556 return 0; 557 } 558 559 560 static unsigned int 561 test_nested_multipart (void) 562 { 563 struct MHD_Connection connection; 564 struct MHD_HTTP_Req_Header header; 565 struct MHD_PostProcessor *pp; 566 unsigned int want_off = FORM_NESTED_START; 567 size_t i; 568 size_t delta; 569 size_t size; 570 571 memset (&connection, 0, sizeof (struct MHD_Connection)); 572 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 573 connection.rq.headers_received = &header; 574 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 575 header.value = 576 MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; 577 header.kind = MHD_HEADER_KIND; 578 header.header_size = strlen (header.header); 579 header.value_size = strlen (header.value); 580 pp = MHD_create_post_processor (&connection, 581 1024, &value_checker, &want_off); 582 if (NULL == pp) 583 { 584 fprintf (stderr, "Failed to create post processor.\n" 585 "Line: %u\n", (unsigned int) __LINE__); 586 exit (50); 587 } 588 i = 0; 589 size = strlen (FORM_NESTED_DATA); 590 while (i < size) 591 { 592 delta = 1 + ((size_t) MHD_random_ ()) % (size - i); 593 if (MHD_YES != MHD_post_process (pp, 594 &FORM_NESTED_DATA[i], 595 delta)) 596 { 597 fprintf (stderr, "Failed to process the data.\n" 598 "i: %u. delta: %u.\n" 599 "Line: %u\n", (unsigned) i, (unsigned) delta, 600 (unsigned int) __LINE__); 601 exit (49); 602 } 603 i += delta; 604 } 605 MHD_destroy_post_processor (pp); 606 if (want_off != FORM_NESTED_END) 607 { 608 fprintf (stderr, 609 "Test failed in line %u\n", 610 (unsigned int) __LINE__); 611 return 4; 612 } 613 return 0; 614 } 615 616 617 static enum MHD_Result 618 value_checker2 (void *cls, 619 enum MHD_ValueKind kind, 620 const char *key, 621 const char *filename, 622 const char *content_type, 623 const char *transfer_encoding, 624 const char *data, 625 uint64_t off, 626 size_t size) 627 { 628 (void) cls; (void) kind; (void) key; /* Mute compiler warnings */ 629 (void) filename; (void) content_type; (void) transfer_encoding; 630 (void) data; (void) off; (void) size; 631 return MHD_YES; 632 } 633 634 635 static unsigned int 636 test_overflow (void) 637 { 638 struct MHD_Connection connection; 639 struct MHD_HTTP_Req_Header header; 640 struct MHD_PostProcessor *pp; 641 size_t i; 642 size_t j; 643 size_t delta; 644 char *buf; 645 646 memset (&connection, 0, sizeof (struct MHD_Connection)); 647 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 648 connection.rq.headers_received = &header; 649 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 650 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; 651 header.header_size = strlen (header.header); 652 header.value_size = strlen (header.value); 653 header.kind = MHD_HEADER_KIND; 654 for (i = 128; i < 1024 * 1024; i += 1024) 655 { 656 pp = MHD_create_post_processor (&connection, 657 1024, 658 &value_checker2, 659 NULL); 660 if (NULL == pp) 661 { 662 fprintf (stderr, "Failed to create post processor.\n" 663 "Line: %u\n", (unsigned int) __LINE__); 664 exit (50); 665 } 666 buf = malloc (i); 667 if (NULL == buf) 668 return 1; 669 memset (buf, 'A', i); 670 buf[i / 2] = '='; 671 delta = 1 + (((size_t) MHD_random_ ()) % (i - 1)); 672 j = 0; 673 while (j < i) 674 { 675 if (j + delta > i) 676 delta = i - j; 677 if (MHD_NO == 678 MHD_post_process (pp, 679 &buf[j], 680 delta)) 681 break; 682 j += delta; 683 } 684 free (buf); 685 MHD_destroy_post_processor (pp); 686 } 687 return 0; 688 } 689 690 691 static unsigned int 692 test_empty_key (void) 693 { 694 const char form_data[] = "=abcdef"; 695 size_t step; 696 const size_t size = MHD_STATICSTR_LEN_ (form_data); 697 698 for (step = 1; size >= step; ++step) 699 { 700 size_t i; 701 struct MHD_Connection connection; 702 struct MHD_HTTP_Req_Header header; 703 struct MHD_PostProcessor *pp; 704 memset (&connection, 0, sizeof (struct MHD_Connection)); 705 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 706 707 connection.rq.headers_received = &header; 708 connection.rq.headers_received_tail = &header; 709 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 710 header.header_size = MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_TYPE); 711 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; 712 header.value_size = 713 MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED); 714 header.kind = MHD_HEADER_KIND; 715 pp = MHD_create_post_processor (&connection, 716 1024, &value_checker2, NULL); 717 if (NULL == pp) 718 { 719 fprintf (stderr, "Failed to create post processor.\n" 720 "Line: %u\n", (unsigned int) __LINE__); 721 exit (50); 722 } 723 for (i = 0; size > i; i += step) 724 { 725 if (MHD_NO != MHD_post_process (pp, 726 form_data + i, 727 (step > size - i) ? (size - i) : step)) 728 { 729 fprintf (stderr, "Succeed to process the broken data.\n" 730 "i: %u. step: %u.\n" 731 "Line: %u\n", (unsigned) i, (unsigned) step, 732 (unsigned int) __LINE__); 733 exit (49); 734 } 735 } 736 MHD_destroy_post_processor (pp); 737 } 738 return 0; 739 } 740 741 742 static unsigned int 743 test_double_value (void) 744 { 745 const char form_data[] = URL_DATA "=abcdef"; 746 size_t step; 747 const size_t size = MHD_STATICSTR_LEN_ (form_data); 748 const size_t safe_size = MHD_STATICSTR_LEN_ (URL_DATA); 749 750 for (step = 1; size >= step; ++step) 751 { 752 size_t i; 753 struct MHD_Connection connection; 754 struct MHD_HTTP_Req_Header header; 755 struct MHD_PostProcessor *pp; 756 unsigned int results_off = URL_START; 757 unsigned int results_final = results_off + 1; /* First value is correct */ 758 memset (&connection, 0, sizeof (struct MHD_Connection)); 759 memset (&header, 0, sizeof (struct MHD_HTTP_Res_Header)); 760 761 connection.rq.headers_received = &header; 762 connection.rq.headers_received_tail = &header; 763 header.header = MHD_HTTP_HEADER_CONTENT_TYPE; 764 header.header_size = MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_TYPE); 765 header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; 766 header.value_size = 767 MHD_STATICSTR_LEN_ (MHD_HTTP_POST_ENCODING_FORM_URLENCODED); 768 header.kind = MHD_HEADER_KIND; 769 pp = MHD_create_post_processor (&connection, 770 1024, &value_checker, &results_off); 771 if (NULL == pp) 772 { 773 fprintf (stderr, "Failed to create post processor.\n" 774 "Line: %u\n", (unsigned int) __LINE__); 775 exit (50); 776 } 777 for (i = 0; size > i; i += step) 778 { 779 if (MHD_NO != MHD_post_process (pp, 780 form_data + i, 781 (step > size - i) ? (size - i) : step)) 782 { 783 if (safe_size == i + step) 784 results_final = URL_END; 785 if (safe_size < i + step) 786 { 787 fprintf (stderr, "Succeed to process the broken data.\n" 788 "i: %u. step: %u.\n" 789 "Line: %u\n", (unsigned) i, (unsigned) step, 790 (unsigned int) __LINE__); 791 exit (49); 792 } 793 } 794 else 795 { 796 if (safe_size >= i + step) 797 { 798 fprintf (stderr, "Failed to process the data.\n" 799 "i: %u. step: %u.\n" 800 "Line: %u\n", (unsigned) i, (unsigned) step, 801 (unsigned int) __LINE__); 802 exit (49); 803 } 804 } 805 } 806 MHD_destroy_post_processor (pp); 807 if (results_final != results_off) 808 { 809 fprintf (stderr, 810 "Test failed in line %u.\tStep:%u\n Got: %u\tExpected: %u\n", 811 (unsigned int) __LINE__, 812 (unsigned int) step, 813 results_off, 814 results_final); 815 return 1; 816 } 817 } 818 return 0; 819 } 820 821 822 int 823 main (int argc, char *const *argv) 824 { 825 unsigned int errorCount = 0; 826 (void) argc; (void) argv; /* Unused. Silent compiler warning. */ 827 828 errorCount += test_multipart_splits (); 829 errorCount += test_multipart_garbage (); 830 errorCount += test_urlencoding (); 831 errorCount += test_multipart (); 832 errorCount += test_nested_multipart (); 833 errorCount += test_empty_key (); 834 errorCount += test_double_value (); 835 errorCount += test_overflow (); 836 if (errorCount != 0) 837 fprintf (stderr, "Error (code: %u)\n", errorCount); 838 return (errorCount == 0) ? 0 : 1; /* 0 == pass */ 839 }