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