test_get.c (51023B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2008 Christian Grothoff 4 Copyright (C) 2016-2022 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 2, 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 /** 23 * @file testzzuf/test_get.c 24 * @brief Several testcases for libmicrohttpd with input fuzzing 25 * @author Christian Grothoff 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 29 #include "platform.h" 30 #include <curl/curl.h> 31 #include <microhttpd.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <time.h> 35 #include <errno.h> 36 37 #ifndef WINDOWS 38 #include <unistd.h> 39 #endif 40 41 #include "mhd_debug_funcs.h" 42 #include "test_helpers.h" 43 44 #ifndef MHD_STATICSTR_LEN_ 45 /** 46 * Determine length of static string / macro strings at compile time. 47 */ 48 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) 49 #endif /* ! MHD_STATICSTR_LEN_ */ 50 51 #ifndef CURL_VERSION_BITS 52 #define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z)) 53 #endif /* ! CURL_VERSION_BITS */ 54 #ifndef CURL_AT_LEAST_VERSION 55 #define CURL_AT_LEAST_VERSION(x,y,z) \ 56 (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z)) 57 #endif /* ! CURL_AT_LEAST_VERSION */ 58 59 /** 60 * A larger loop count will run more random tests -- 61 * which would be good, except that it may take too 62 * long for most user's patience. So this small 63 * value is the default. 64 * Can be redefined by CPPFLAGS=-DLOOP_COUNT=123 65 */ 66 #ifndef LOOP_COUNT 67 #ifndef _MHD_VHEAVY_TESTS 68 #define LOOP_COUNT 10 69 #else /* ! _MHD_HEAVY_TESTS */ 70 #define LOOP_COUNT 200 71 #endif /* ! _MHD_HEAVY_TESTS */ 72 #endif /* LOOP_COUNT */ 73 74 #ifdef _DEBUG 75 /* Uncomment the next line (or use CPPFLAGS) to see all request and response bodies in log */ 76 /* #define TEST_PRINT_BODY */ 77 /* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they are sent by libcurl */ 78 /* #define TEST_PRINT_BODY_RQ 1 */ 79 /* Uncomment the next line (or use CPPFLAGS) to see all request bodies as they are received by libcurl */ 80 /* #define TEST_PRINT_BODY_RP 1 */ 81 #endif /* _DEBUG */ 82 83 #define MHD_TIMEOUT 2 84 85 #define CURL_TIMEOUT 5 86 87 /* Global test parameters */ 88 static int oneone; 89 static int dry_run; 90 static int use_get; 91 static int use_get_chunked; 92 static int use_put; 93 static int use_put_large; 94 static int use_put_chunked; 95 static int use_post; 96 static int use_post_form; 97 static int use_long_header; 98 static int use_long_uri; 99 static int use_close; 100 static int run_with_socat; 101 102 #define TEST_BASE_URI "http:/" "/127.0.0.1/test_uri" 103 #define TEST_BASE_URI_SOCAT "http:/" "/127.0.0.121/test_uri" 104 105 #define SOCAT_PORT 10121 106 107 #define TEST_BASE_PORT 4010 108 109 #define EMPTY_PAGE "Empty page." 110 #define EMPTY_PAGE_ALT "Alternative empty page." 111 #define METHOD_NOT_SUPPORTED "HTTP method is not supported." 112 #define POST_DATA_BROKEN "The POST request is ill-formed." 113 114 #define POST_KEY1 "test" 115 #define POST_VALUE1 "test_post" 116 #define POST_KEY2 "library" 117 #define POST_VALUE2 "GNU libmicrohttpd" 118 #define POST_URLENC_DATA \ 119 POST_KEY1 "=" POST_VALUE1 "&" POST_KEY2 "=" "GNU%20libmicrohttpd" 120 121 #define PUT_NORMAL_SIZE 11 122 /* Does not need to be very large as MHD buffer will be made smaller anyway */ 123 #define PUT_LARGE_SIZE (4 * 1024) 124 /* The length of "very long" URI and header strings. MHD uses smaller buffer. */ 125 #define TEST_STRING_VLONG_LEN 8 * 1024 126 127 128 #if ! CURL_AT_LEAST_VERSION (7,56,0) 129 #define TEST_USE_STATIC_POST_DATA 1 130 static struct curl_httppost *post_first; 131 static struct curl_httppost *post_last; 132 #endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */ 133 134 static struct curl_slist *libcurl_long_header; 135 136 /** 137 * Initialise long header for libcurl 138 * 139 * @return non-zero if succeed, 140 * zero if failed 141 */ 142 static int 143 long_header_init (void) 144 { 145 char *buf; 146 147 buf = malloc (TEST_STRING_VLONG_LEN + 1); 148 if (NULL == buf) 149 { 150 fprintf (stderr, "malloc() failed " 151 "at line %d.\n", (int) __LINE__); 152 return 0; 153 } 154 buf[TEST_STRING_VLONG_LEN] = 0; 155 buf[0] = 'A'; 156 memset (buf + 1, 'a', TEST_STRING_VLONG_LEN / 2 - 2); 157 buf[TEST_STRING_VLONG_LEN / 2 - 1] = ':'; 158 buf[TEST_STRING_VLONG_LEN / 2] = ' '; 159 memset (buf + TEST_STRING_VLONG_LEN / 2 + 1, 'c', 160 TEST_STRING_VLONG_LEN / 2 - 1); 161 libcurl_long_header = curl_slist_append (NULL, buf); 162 free (buf); 163 if (NULL != libcurl_long_header) 164 return ! 0; /* Success exit point */ 165 166 fprintf (stderr, "curl_slist_append() failed " 167 "at line %d.\n", (int) __LINE__); 168 return 0; /* Failure exit point */ 169 } 170 171 172 /** 173 * Globally initialise test environment 174 * @return non-zero if succeed, 175 * zero if failed 176 */ 177 static int 178 test_global_init (void) 179 { 180 libcurl_long_header = NULL; 181 if (CURLE_OK != curl_global_init (CURL_GLOBAL_WIN32)) 182 { 183 fprintf (stderr, "curl_global_init() failed " 184 "at line %d.\n", (int) __LINE__); 185 return 0; 186 } 187 188 if (long_header_init ()) 189 { 190 #ifndef TEST_USE_STATIC_POST_DATA 191 return 1; /* Success exit point */ 192 #else /* ! TEST_USE_STATIC_POST_DATA */ 193 post_first = NULL; 194 post_last = NULL; 195 if ((CURL_FORMADD_OK != 196 curl_formadd (&post_first, &post_last, 197 CURLFORM_PTRNAME, POST_KEY1, 198 CURLFORM_NAMELENGTH, 199 (long) MHD_STATICSTR_LEN_ (POST_KEY1), 200 CURLFORM_PTRCONTENTS, POST_VALUE1, 201 #if CURL_AT_LEAST_VERSION (7,46,0) 202 CURLFORM_CONTENTLEN, 203 (curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE1), 204 #else /* ! CURL_AT_LEAST_VERSION(7,46,0) */ 205 CURLFORM_CONTENTSLENGTH, 206 (long) MHD_STATICSTR_LEN_ (POST_VALUE1), 207 #endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */ 208 CURLFORM_END)) || 209 (CURL_FORMADD_OK != 210 curl_formadd (&post_first, &post_last, 211 CURLFORM_PTRNAME, POST_KEY2, 212 CURLFORM_NAMELENGTH, 213 (long) MHD_STATICSTR_LEN_ (POST_KEY2), 214 CURLFORM_PTRCONTENTS, POST_VALUE2, 215 #if CURL_AT_LEAST_VERSION (7,46,0) 216 CURLFORM_CONTENTLEN, 217 (curl_off_t) MHD_STATICSTR_LEN_ (POST_VALUE2), 218 #else /* ! CURL_AT_LEAST_VERSION(7,46,0) */ 219 CURLFORM_CONTENTSLENGTH, 220 (long) MHD_STATICSTR_LEN_ (POST_VALUE2), 221 #endif /* ! CURL_AT_LEAST_VERSION(7,46,0) */ 222 CURLFORM_END))) 223 fprintf (stderr, "curl_formadd() failed " 224 "at line %d.\n", (int) __LINE__); 225 else 226 return 1; /* Success exit point */ 227 228 if (NULL != post_first) 229 curl_formfree (post_first); 230 curl_slist_free_all (libcurl_long_header); 231 #endif /* ! CURL_AT_LEAST_VERSION(7,56,0) */ 232 } 233 curl_global_cleanup (); 234 return 0; /* Failure exit point */ 235 } 236 237 238 /** 239 * Globally de-initialise test environment 240 */ 241 static void 242 test_global_deinit (void) 243 { 244 #ifdef TEST_USE_STATIC_POST_DATA 245 curl_formfree (post_first); 246 #endif /* TEST_USE_STATIC_POST_DATA */ 247 curl_global_cleanup (); 248 if (NULL != libcurl_long_header) 249 curl_slist_free_all (libcurl_long_header); 250 } 251 252 253 /** 254 * libcurl callback parameters for uploads, downloads and debug callbacks 255 */ 256 struct CBC 257 { 258 /* Upload members */ 259 size_t up_pos; 260 size_t up_size; 261 /* Download members */ 262 char *dn_buf; 263 size_t dn_pos; 264 size_t dn_buf_size; 265 /* Debug callback members */ 266 unsigned int excess_found; 267 }; 268 269 static void 270 initCBC (struct CBC *libcurlcbc, char *dn_buf, size_t dn_buf_size) 271 { 272 libcurlcbc->up_pos = 0; 273 if (use_put_large) 274 libcurlcbc->up_size = PUT_LARGE_SIZE; 275 else if (use_put) 276 libcurlcbc->up_size = PUT_NORMAL_SIZE; 277 else 278 libcurlcbc->up_size = 0; 279 libcurlcbc->dn_buf = dn_buf; 280 libcurlcbc->dn_pos = 0; 281 libcurlcbc->dn_buf_size = dn_buf_size; 282 libcurlcbc->excess_found = 0; 283 } 284 285 286 static void 287 resetCBC (struct CBC *libcurlcbc) 288 { 289 libcurlcbc->up_pos = 0; 290 libcurlcbc->dn_pos = 0; 291 } 292 293 294 static size_t 295 putBuffer (void *stream, size_t item_size, size_t nitems, void *ctx) 296 { 297 size_t to_fill; 298 size_t i; 299 struct CBC *cbc = ctx; 300 301 to_fill = cbc->up_size - cbc->up_pos; 302 /* Skip overflow check as the return value is valid anyway */ 303 if (use_put_chunked) 304 { 305 /* Send data as several chunks */ 306 if (to_fill > cbc->up_size / 3) 307 to_fill = cbc->up_size / 3; 308 } 309 if (to_fill > item_size * nitems) 310 to_fill = item_size * nitems; 311 312 /* Avoid libcurl magic numbers */ 313 #ifdef CURL_READFUNC_PAUSE 314 if (CURL_READFUNC_ABORT == to_fill) 315 to_fill -= 2; 316 #endif /* CURL_READFUNC_PAUSE */ 317 #ifdef CURL_READFUNC_ABORT 318 if (CURL_READFUNC_ABORT == to_fill) 319 --to_fill; 320 #endif /* CURL_READFUNC_ABORT */ 321 for (i = 0; i < to_fill; ++i) 322 ((char *) stream)[i] = 'a' + (char) ((cbc->up_pos + i) 323 % (unsigned char) ('z' - 'a' + 1)); 324 325 cbc->up_pos += to_fill; 326 return to_fill; 327 } 328 329 330 static size_t 331 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 332 { 333 struct CBC *cbc = ctx; 334 335 if (cbc->dn_pos + size * nmemb > cbc->dn_buf_size) 336 return 0; /* overflow */ 337 memcpy (&cbc->dn_buf[cbc->dn_pos], ptr, size * nmemb); 338 cbc->dn_pos += size * nmemb; 339 return size * nmemb; 340 } 341 342 343 #define TEST_MAGIC_MARKER0 0xFEE1C0DE 344 #define TEST_MAGIC_MARKER1 (TEST_MAGIC_MARKER0 + 1) 345 #define TEST_MAGIC_MARKER2 (TEST_MAGIC_MARKER0 + 2) 346 347 struct content_cb_param_strct 348 { 349 unsigned int magic0; /**< Must have TEST_MAGIC_MARKER0 value */ 350 struct MHD_Response *response; /**< The pointer to the response structure */ 351 }; 352 353 /** 354 * MHD content reader callback that returns 355 * data in chunks. 356 */ 357 static ssize_t 358 content_cb (void *cls, uint64_t pos, char *buf, size_t max) 359 { 360 struct content_cb_param_strct *param = (struct content_cb_param_strct *) cls; 361 size_t fill_size; 362 363 if ((unsigned int) TEST_MAGIC_MARKER0 != param->magic0) 364 { 365 fprintf (stderr, "Wrong cls pointer " 366 "at line %d.\n", (int) __LINE__); 367 fflush (stderr); 368 abort (); 369 } 370 371 if (pos >= 128 * 10) 372 { 373 if (MHD_YES != 374 MHD_add_response_footer (param->response, "Footer", "working")) 375 { 376 fprintf (stderr, "MHD_add_response_footer() failed " 377 "at line %d.\n", (int) __LINE__); 378 fflush (stderr); 379 abort (); 380 } 381 return MHD_CONTENT_READER_END_OF_STREAM; 382 } 383 384 if (128 > max) 385 fill_size = 128; 386 else 387 fill_size = max; 388 memset (buf, 'A' + (char) (unsigned int) (pos / 128), fill_size); 389 390 return (ssize_t) fill_size; 391 } 392 393 394 /** 395 * Deallocate memory for callback cls. 396 */ 397 static void 398 crcf (void *ptr) 399 { 400 free (ptr); 401 } 402 403 404 struct req_process_strct 405 { 406 unsigned int magic2; /**< Must have TEST_MAGIC_MARKER2 value */ 407 int is_static; /**< Non-zero if statically allocated, zero if malloc()'ed */ 408 struct MHD_PostProcessor *postprocsr; 409 unsigned int post_data_sum; 410 }; 411 412 static enum MHD_Result 413 post_iterator (void *cls, 414 enum MHD_ValueKind kind, 415 const char *key, 416 const char *filename, 417 const char *content_type, 418 const char *transfer_encoding, 419 const char *value, uint64_t off, size_t size) 420 { 421 struct req_process_strct *param = (struct req_process_strct *) cls; 422 size_t i; 423 424 (void) filename; (void) content_type; (void) transfer_encoding; 425 (void) off; /* Unused. Mute compiler warnings. */ 426 427 if (TEST_MAGIC_MARKER2 != param->magic2) 428 { 429 fprintf (stderr, "The 'param->magic2' has wrong value " 430 "at line %d.\n", (int) __LINE__); 431 abort (); 432 } 433 434 if (MHD_POSTDATA_KIND != kind) 435 { 436 fprintf (stderr, "The 'kind' parameter has wrong value " 437 "at line %d.\n", (int) __LINE__); 438 abort (); 439 } 440 441 if (NULL != key) 442 param->post_data_sum += (unsigned int) strlen (key); 443 444 for (i = 0; size > i; ++i) 445 param->post_data_sum += (unsigned int) (unsigned char) value[i]; 446 447 return MHD_YES; 448 } 449 450 451 static void 452 free_req_pr_data (struct req_process_strct *pr_data) 453 { 454 if (NULL == pr_data) 455 return; 456 if (TEST_MAGIC_MARKER2 != pr_data->magic2) 457 { 458 fprintf (stderr, "The 'pr_data->magic2' has wrong value " 459 "at line %d.\n", (int) __LINE__); 460 abort (); 461 } 462 if (pr_data->is_static) 463 { 464 if (NULL != pr_data->postprocsr) 465 { 466 fprintf (stderr, "The 'pr_data->postprocsr' has wrong value " 467 "at line %d.\n", (int) __LINE__); 468 abort (); 469 } 470 return; 471 } 472 if (NULL != pr_data->postprocsr) 473 MHD_destroy_post_processor (pr_data->postprocsr); 474 pr_data->postprocsr = NULL; 475 free (pr_data); 476 } 477 478 479 struct ahc_param_strct 480 { 481 unsigned int magic1; /**< Must have TEST_MAGIC_MARKER1 value */ 482 unsigned int err_flag; /**< Non-zero if any error is encountered */ 483 unsigned int num_replies; /**< The number of replies sent for the current request */ 484 }; 485 486 static enum MHD_Result 487 send_error_response (struct MHD_Connection *connection, 488 struct ahc_param_strct *param, 489 unsigned int status_code, 490 const char *static_text, 491 const size_t static_text_len) 492 { 493 struct MHD_Response *response; 494 response = 495 MHD_create_response_from_buffer_static (static_text_len, 496 static_text); 497 if (NULL != response) 498 { 499 if (MHD_YES == MHD_add_response_header (response, 500 MHD_HTTP_HEADER_CONNECTION, 501 "close")) 502 { 503 if (MHD_YES == MHD_queue_response (connection, status_code, response)) 504 { 505 MHD_destroy_response (response); 506 return MHD_YES; /* Success exit point */ 507 } 508 else 509 fprintf (stderr, "MHD_queue_response() failed " 510 "at line %d.\n", (int) __LINE__); 511 } 512 else 513 fprintf (stderr, "MHD_add_response_header() failed " 514 "at line %d.\n", (int) __LINE__); 515 MHD_destroy_response (response); 516 } 517 else 518 fprintf (stderr, "MHD_create_response_from_callback() failed " 519 "at line %d.\n", (int) __LINE__); 520 521 param->err_flag = 1; 522 return MHD_NO; /* Failure exit point */ 523 } 524 525 526 static enum MHD_Result 527 ahc_check (void *cls, 528 struct MHD_Connection *connection, 529 const char *url, 530 const char *method, 531 const char *version, 532 const char *upload_data, size_t *upload_data_size, 533 void **req_cls) 534 { 535 static struct req_process_strct static_req_pr_data = { 536 TEST_MAGIC_MARKER2, ! 0, NULL, 0 537 }; 538 struct req_process_strct *req_pr_data; 539 struct ahc_param_strct *param = (struct ahc_param_strct *) cls; 540 struct MHD_Response *response; 541 enum MHD_Result ret; 542 unsigned char data_sum; 543 int is_post_req; 544 545 if (NULL == cls) 546 { 547 fprintf (stderr, "The 'cls' parameter is NULL " 548 "at line %d.\n", (int) __LINE__); 549 fflush (stderr); 550 abort (); 551 } 552 if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1) 553 { 554 fprintf (stderr, "The 'param->magic1' has wrong value " 555 "at line %d.\n", (int) __LINE__); 556 fflush (stderr); 557 abort (); 558 } 559 if (NULL == connection) 560 { 561 fprintf (stderr, "The 'connection' parameter is NULL " 562 "at line %d.\n", (int) __LINE__); 563 param->err_flag = 1; 564 return MHD_NO; /* Should not reply */ 565 } 566 if (1) 567 { /* Simple check for 'connection' parameter validity */ 568 const union MHD_ConnectionInfo *conn_info; 569 conn_info = 570 MHD_get_connection_info (connection, 571 MHD_CONNECTION_INFO_CONNECTION_TIMEOUT); 572 if (NULL == conn_info) 573 { 574 fprintf (stderr, "The 'MHD_get_connection_info' has returned NULL " 575 "at line %d.\n", (int) __LINE__); 576 param->err_flag = 1; 577 } 578 else if (MHD_TIMEOUT != conn_info->connection_timeout) 579 { 580 fprintf (stderr, "The 'MHD_get_connection_info' has returned " 581 "unexpected timeout value " 582 "at line %d.\n", (int) __LINE__); 583 param->err_flag = 1; 584 } 585 } 586 if (NULL == url) 587 { 588 fprintf (stderr, "The 'url' parameter is NULL " 589 "at line %d.\n", (int) __LINE__); 590 param->err_flag = 1; 591 } 592 if (NULL == method) 593 { 594 fprintf (stderr, "The 'method' parameter is NULL " 595 "at line %d.\n", (int) __LINE__); 596 param->err_flag = 1; 597 return MHD_NO; /* Should not reply */ 598 } 599 if (NULL == version) 600 { 601 fprintf (stderr, "The 'version' parameter is NULL " 602 "at line %d.\n", (int) __LINE__); 603 param->err_flag = 1; 604 return MHD_NO; /* Should not reply */ 605 } 606 if (NULL == upload_data_size) 607 { 608 fprintf (stderr, "The 'upload_data_size' parameter is NULL " 609 "at line %d.\n", (int) __LINE__); 610 param->err_flag = 1; 611 return MHD_NO; /* Should not reply */ 612 } 613 if ((0 != *upload_data_size) && (NULL == upload_data)) 614 { 615 fprintf (stderr, "The 'upload_data' parameter is NULL " 616 "while '*upload_data_size' is not zero " 617 "at line %d.\n", (int) __LINE__); 618 param->err_flag = 1; 619 return MHD_NO; /* Should not reply */ 620 } 621 if ((NULL != upload_data) && (0 == *upload_data_size)) 622 { 623 fprintf (stderr, "The 'upload_data' parameter is NOT NULL " 624 "while '*upload_data_size' is zero " 625 "at line %d.\n", (int) __LINE__); 626 param->err_flag = 1; 627 return MHD_NO; /* Should not reply */ 628 } 629 630 if (0 != param->num_replies) 631 { 632 /* Phantom "second" request due to the fuzzing of the input. Refuse. */ 633 return MHD_NO; 634 } 635 636 is_post_req = (0 == strcmp (method, MHD_HTTP_METHOD_POST)); 637 if ((0 != strcmp (method, MHD_HTTP_METHOD_GET)) 638 && (0 != strcmp (method, MHD_HTTP_METHOD_HEAD)) 639 && (0 != strcmp (method, MHD_HTTP_METHOD_PUT)) 640 && (! is_post_req)) 641 { 642 /* Unsupported method for this callback */ 643 return send_error_response (connection, param, MHD_HTTP_NOT_IMPLEMENTED, 644 METHOD_NOT_SUPPORTED, 645 MHD_STATICSTR_LEN_ (METHOD_NOT_SUPPORTED)); 646 } 647 648 if (NULL == *req_cls) 649 { 650 if (! is_post_req) 651 { /* Use static memory */ 652 *req_cls = &static_req_pr_data; 653 } 654 else 655 { /* POST request, use PostProcessor */ 656 req_pr_data = 657 (struct req_process_strct *) malloc (sizeof (struct req_process_strct)); 658 if (NULL == req_pr_data) 659 { 660 fprintf (stderr, "malloc() failed " 661 "at line %d.\n", (int) __LINE__); 662 return MHD_NO; 663 } 664 req_pr_data->magic2 = TEST_MAGIC_MARKER2; 665 req_pr_data->is_static = 0; 666 req_pr_data->post_data_sum = 0; 667 req_pr_data->postprocsr = MHD_create_post_processor (connection, 1024, 668 &post_iterator, 669 req_pr_data); 670 if (NULL == req_pr_data->postprocsr) 671 { 672 free (req_pr_data); 673 if (NULL == upload_data) 674 return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST, 675 POST_DATA_BROKEN, 676 MHD_STATICSTR_LEN_ (POST_DATA_BROKEN)); 677 else 678 return MHD_NO; /* Cannot handle request, broken POST */ 679 } 680 *req_cls = req_pr_data; 681 } 682 if (NULL == upload_data) 683 return MHD_YES; 684 } 685 req_pr_data = (struct req_process_strct *) *req_cls; 686 687 data_sum = 0; 688 if (NULL != upload_data) 689 { 690 if (is_post_req) 691 { 692 if (MHD_YES != MHD_post_process (req_pr_data->postprocsr, 693 upload_data, *upload_data_size)) 694 { 695 free_req_pr_data (req_pr_data); 696 *req_cls = NULL; 697 /* Processing upload body (context), error reply cannot be queued here */ 698 return MHD_NO; 699 } 700 *upload_data_size = 0; /* All data have been processed */ 701 } 702 else 703 { 704 /* Check that all 'upload_data' is addressable */ 705 size_t pos; 706 for (pos = 0; pos < *upload_data_size; ++pos) 707 data_sum = 708 (unsigned char) (data_sum + (unsigned char) upload_data[pos]); 709 if (0 != *upload_data_size) 710 { 711 if (3 >= *upload_data_size) 712 *upload_data_size = 0; /* Consume all incoming data */ 713 else 714 *upload_data_size = data_sum % *upload_data_size; /* Pseudo-random */ 715 } 716 } 717 return MHD_YES; 718 } 719 if (is_post_req) 720 { 721 if (MHD_YES != MHD_destroy_post_processor (req_pr_data->postprocsr)) 722 { 723 free (req_pr_data); 724 *req_cls = NULL; 725 return send_error_response (connection, param, MHD_HTTP_BAD_REQUEST, 726 POST_DATA_BROKEN, 727 MHD_STATICSTR_LEN_ (POST_DATA_BROKEN)); 728 } 729 req_pr_data->postprocsr = NULL; 730 } 731 data_sum += (unsigned char) req_pr_data->post_data_sum; 732 free_req_pr_data (req_pr_data); 733 *req_cls = NULL; 734 735 ret = MHD_YES; 736 if (use_get_chunked) 737 { 738 struct content_cb_param_strct *cnt_cb_param; 739 cnt_cb_param = malloc (sizeof (struct content_cb_param_strct)); 740 if (NULL == cnt_cb_param) 741 { 742 fprintf (stderr, "malloc() failed " 743 "at line %d.\n", (int) __LINE__); 744 /* External error, do not rise the error flag */ 745 return MHD_NO; 746 } 747 cnt_cb_param->magic0 = (unsigned int) TEST_MAGIC_MARKER0; 748 response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 749 1024, 750 &content_cb, cnt_cb_param, 751 &crcf); 752 if (NULL == response) 753 { 754 fprintf (stderr, "MHD_create_response_from_callback() failed " 755 "at line %d.\n", (int) __LINE__); 756 free (cnt_cb_param); 757 param->err_flag = 1; 758 ret = MHD_NO; 759 } 760 else 761 cnt_cb_param->response = response; 762 } 763 else if (use_get || use_put || use_post) 764 { 765 /* Randomly choose the response page for the POST requests */ 766 if (0 == data_sum % 2) 767 response = 768 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (EMPTY_PAGE), 769 EMPTY_PAGE); 770 else 771 response = 772 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ ( \ 773 EMPTY_PAGE_ALT), 774 EMPTY_PAGE_ALT); 775 776 if (NULL == response) 777 { 778 fprintf (stderr, "MHD_create_response_from_buffer_static() failed " 779 "at line %d.\n", (int) __LINE__); 780 param->err_flag = 1; 781 ret = MHD_NO; 782 } 783 } 784 else 785 { 786 fprintf (stderr, "Response is not implemented for this test. " 787 "Internal logic is broken. " 788 "At line %d.\n", (int) __LINE__); 789 abort (); 790 } 791 792 if (NULL != response) 793 { 794 if ((MHD_YES == ret) && 795 (use_close || (! oneone && (0 != strcmp (version, 796 MHD_HTTP_VERSION_1_0))))) 797 { 798 ret = MHD_add_response_header (response, 799 MHD_HTTP_HEADER_CONNECTION, 800 "close"); 801 if (MHD_YES != ret) 802 { 803 fprintf (stderr, "MHD_add_response_header() failed " 804 "at line %d.\n", (int) __LINE__); 805 param->err_flag = 1; 806 } 807 } 808 if (MHD_YES == ret) 809 { 810 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 811 if (MHD_YES != ret) 812 { 813 fprintf (stderr, "MHD_queue_response() failed " 814 "at line %d.\n", (int) __LINE__); 815 param->err_flag = 1; 816 } 817 } 818 else 819 param->num_replies++; 820 821 MHD_destroy_response (response); 822 } 823 else 824 { 825 fprintf (stderr, "MHD_create_response_from_buffer_static() failed " 826 "at line %d.\n", (int) __LINE__); 827 ret = MHD_NO; 828 } 829 return ret; 830 } 831 832 833 static void 834 req_completed_cleanup (void *cls, 835 struct MHD_Connection *connection, 836 void **req_cls, 837 enum MHD_RequestTerminationCode toe) 838 { 839 struct ahc_param_strct *param = (struct ahc_param_strct *) cls; 840 struct req_process_strct *req_pr_data = (struct req_process_strct *) *req_cls; 841 (void) connection; /* Unused. Mute compiler warning. */ 842 843 if (NULL == param) 844 { 845 fprintf (stderr, "The 'cls' parameter is NULL at line %d.\n", 846 (int) __LINE__); 847 fflush (stderr); 848 abort (); 849 } 850 if ((unsigned int) TEST_MAGIC_MARKER1 != param->magic1) 851 { 852 fprintf (stderr, "The 'param->magic1' has wrong value at line %d.\n", 853 (int) __LINE__); 854 fflush (stderr); 855 abort (); 856 } 857 if (NULL == req_pr_data) 858 return; /* The data have been freed */ 859 if ((unsigned int) TEST_MAGIC_MARKER2 != req_pr_data->magic2) 860 { 861 fprintf (stderr, "The 'req_pr_data->magic2' has wrong value at line %d.\n", 862 (int) __LINE__); 863 fflush (stderr); 864 abort (); 865 } 866 if (MHD_REQUEST_TERMINATED_COMPLETED_OK == toe) 867 { 868 fprintf (stderr, "The request completed successful, but request cls has" 869 "not been cleared. " 870 "At line %d.\n", (int) __LINE__); 871 param->err_flag = 1; 872 } 873 if (req_pr_data->is_static) 874 return; 875 if (NULL != req_pr_data->postprocsr) 876 MHD_destroy_post_processor (req_pr_data->postprocsr); 877 req_pr_data->postprocsr = NULL; 878 free (req_pr_data); 879 *req_cls = NULL; 880 } 881 882 883 /* Un-comment the next line (or use CPPFLAGS) to avoid 884 logging of the traffic with debug builds */ 885 /* #define TEST_NO_PRINT_TRAFFIC 1 */ 886 887 #ifdef _DEBUG 888 #ifdef TEST_PRINT_BODY 889 #ifndef TEST_PRINT_BODY_RQ 890 #define TEST_PRINT_BODY_RQ 1 891 #endif /* TEST_PRINT_BODY_RQ */ 892 #ifndef TEST_PRINT_BODY_RP 893 #define TEST_PRINT_BODY_RP 1 894 #endif /* TEST_PRINT_BODY_RP */ 895 #endif /* TEST_PRINT_BODY */ 896 #endif /* _DEBUG */ 897 898 static int 899 libcurl_debug_cb (CURL *handle, 900 curl_infotype type, 901 char *data, 902 size_t size, 903 void *ctx) 904 { 905 static const char excess_mark[] = "Excess found"; 906 static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark); 907 struct CBC *cbc = ctx; 908 (void) handle; 909 910 #if defined(_DEBUG) && ! defined(TEST_NO_PRINT_TRAFFIC) 911 switch (type) 912 { 913 case CURLINFO_TEXT: 914 fprintf (stderr, "* %.*s", (int) size, data); 915 break; 916 case CURLINFO_HEADER_IN: 917 fprintf (stderr, "< %.*s", (int) size, data); 918 break; 919 case CURLINFO_HEADER_OUT: 920 fprintf (stderr, "> %.*s", (int) size, data); 921 break; 922 case CURLINFO_DATA_IN: 923 #ifdef TEST_PRINT_BODY_RP 924 fprintf (stderr, "<| %.*s\n", (int) size, data); 925 #endif /* TEST_PRINT_BODY_RP */ 926 break; 927 case CURLINFO_DATA_OUT: 928 #ifdef TEST_PRINT_BODY_RQ 929 fprintf (stderr, ">| %.*s\n", (int) size, data); 930 #endif /* TEST_PRINT_BODY_RQ */ 931 break; 932 case CURLINFO_SSL_DATA_IN: 933 case CURLINFO_SSL_DATA_OUT: 934 case CURLINFO_END: 935 default: 936 break; 937 } 938 #endif /* _DEBUG && ! TEST_NO_PRINT_TRAFFIC */ 939 if (use_close || ! oneone) 940 { 941 /* Check for extra data only if every connection is terminated by MHD 942 after one request, otherwise MHD may react on garbage after request 943 data. */ 944 if (CURLINFO_TEXT == type) 945 { 946 if ((size >= excess_mark_len) && 947 (0 == memcmp (data, excess_mark, excess_mark_len))) 948 { 949 fprintf (stderr, "Extra data has been detected in MHD reply " 950 "at line %d.\n", (int) __LINE__); 951 cbc->excess_found++; 952 } 953 } 954 } 955 return 0; 956 } 957 958 959 static CURL * 960 setupCURL (struct CBC *cbc, uint16_t port 961 #ifndef TEST_USE_STATIC_POST_DATA 962 , curl_mime **mime 963 #endif /* ! TEST_USE_STATIC_POST_DATA */ 964 ) 965 { 966 CURL *c; 967 CURLcode e; 968 char *buf; 969 const char *uri_to_use; 970 const char *base_uri; 971 972 #ifndef TEST_USE_STATIC_POST_DATA 973 *mime = NULL; 974 #endif /* ! TEST_USE_STATIC_POST_DATA */ 975 976 base_uri = run_with_socat ? TEST_BASE_URI_SOCAT : TEST_BASE_URI; 977 if (! use_long_uri) 978 { 979 uri_to_use = base_uri; 980 buf = NULL; 981 } 982 else 983 { 984 size_t pos; 985 size_t base_uri_len; 986 987 base_uri_len = strlen (base_uri); 988 buf = malloc (TEST_STRING_VLONG_LEN + 1); 989 if (NULL == buf) 990 { 991 fprintf (stderr, "malloc() failed " 992 "at line %d.\n", (int) __LINE__); 993 return NULL; 994 } 995 memcpy (buf, base_uri, base_uri_len); 996 for (pos = base_uri_len; 997 pos < TEST_STRING_VLONG_LEN; 998 ++pos) 999 { 1000 if (0 == pos % 9) 1001 buf[pos] = '/'; 1002 else 1003 buf[pos] = 'a' + (char) (unsigned char) (pos % ((unsigned char) 1004 ('z' - 'a' + 1))); 1005 } 1006 buf[TEST_STRING_VLONG_LEN] = 0; 1007 uri_to_use = buf; 1008 } 1009 if (run_with_socat) 1010 port = SOCAT_PORT; 1011 1012 c = curl_easy_init (); 1013 if (NULL == c) 1014 { 1015 fprintf (stderr, "curl_easy_init() failed " 1016 "at line %d.\n", (int) __LINE__); 1017 return NULL; 1018 } 1019 1020 if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_URL, 1021 uri_to_use))) && 1022 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L))) && 1023 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 1024 ©Buffer))) && 1025 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc))) && 1026 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 1027 ((long) CURL_TIMEOUT)))) && 1028 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_TIMEOUT, 1029 ((long) CURL_TIMEOUT)))) && 1030 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L))) && 1031 #ifdef _DEBUG 1032 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_VERBOSE, 1L))) && 1033 #endif /* _DEBUG */ 1034 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, 1035 &libcurl_debug_cb))) && 1036 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEBUGDATA, 1037 cbc))) && 1038 #if CURL_AT_LEAST_VERSION (7, 45, 0) 1039 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, 1040 "http"))) && 1041 #endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */ 1042 #if CURL_AT_LEAST_VERSION (7, 85, 0) 1043 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PROTOCOLS_STR, 1044 "http"))) && 1045 #elif CURL_AT_LEAST_VERSION (7, 19, 4) 1046 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PROTOCOLS, 1047 CURLPROTO_HTTP))) && 1048 #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */ 1049 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 1050 oneone ? 1051 CURL_HTTP_VERSION_1_1 : 1052 CURL_HTTP_VERSION_1_0))) && 1053 #if CURL_AT_LEAST_VERSION (7, 24, 0) 1054 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE, 1055 "host!127.0.0.101"))) && 1056 #else /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */ 1057 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INTERFACE, 1058 "127.0.0.101"))) && 1059 #endif /* ! CURL_AT_LEAST_VERSION (7, 24, 0) */ 1060 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) && 1061 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_HTTPHEADER, 1062 use_long_header ? 1063 libcurl_long_header : NULL))) 1064 ) 1065 { 1066 if (NULL != buf) 1067 { 1068 free (buf); 1069 buf = NULL; 1070 } 1071 if (use_put) 1072 { 1073 if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READFUNCTION, 1074 &putBuffer))) && 1075 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_READDATA, cbc))) && 1076 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_UPLOAD, (long) 1))) && 1077 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, 1078 use_put_chunked ? 1079 ((curl_off_t) -1) : 1080 ((curl_off_t) cbc->up_size))))) 1081 { 1082 return c; /* Success exit point for 'use_put' */ 1083 } 1084 else 1085 fprintf (stderr, "PUT-related curl_easy_setopt() failed at line %d, " 1086 "error: %s\n", (int) __LINE__, 1087 curl_easy_strerror (e)); 1088 } 1089 else if (use_post) 1090 { 1091 if (! use_post_form) 1092 { 1093 if ((CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POST, (long) 1))) && 1094 (CURLE_OK == (e = curl_easy_setopt (c, CURLOPT_POSTFIELDS, 1095 POST_URLENC_DATA))) && 1096 (CURLE_OK == 1097 (e = curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, 1098 MHD_STATICSTR_LEN_ (POST_URLENC_DATA))))) 1099 { 1100 return c; /* Success exit point for 'use_post' */ 1101 } 1102 else 1103 fprintf (stderr, 1104 "POST-related curl_easy_setopt() failed at line %d, " 1105 "error: %s\n", (int) __LINE__, 1106 curl_easy_strerror (e)); 1107 } 1108 else 1109 { 1110 #ifndef TEST_USE_STATIC_POST_DATA 1111 *mime = curl_mime_init (c); 1112 if (NULL != *mime) 1113 { 1114 curl_mimepart *part; 1115 if ((NULL != (part = curl_mime_addpart (*mime))) && 1116 (CURLE_OK == curl_mime_name (part, POST_KEY1)) && 1117 (CURLE_OK == curl_mime_data (part, POST_VALUE1, 1118 MHD_STATICSTR_LEN_ (POST_VALUE1))) && 1119 (NULL != (part = curl_mime_addpart (*mime))) && 1120 (CURLE_OK == curl_mime_name (part, POST_KEY2)) && 1121 (CURLE_OK == curl_mime_data (part, POST_VALUE2, 1122 MHD_STATICSTR_LEN_ (POST_VALUE2)))) 1123 { 1124 if (CURLE_OK == 1125 (e = curl_easy_setopt (c, CURLOPT_MIMEPOST, *mime))) 1126 return c; /* Success exit point for 'use_post' */ 1127 else 1128 fprintf (stderr, "curl_easy_setopt(c, CURLOPT_MIMEPOST, mime) " 1129 "failed at line %d, error: %s\n", 1130 (int) __LINE__, curl_easy_strerror (e)); 1131 } 1132 else 1133 fprintf (stderr, "curl_mime_addpart(), curl_mime_name() or " 1134 "curl_mime_data() failed.\n"); 1135 } 1136 else 1137 fprintf (stderr, "curl_mime_init() failed.\n"); 1138 1139 #else /* TEST_USE_STATIC_POST_DATA */ 1140 if (CURLE_OK == (e = curl_easy_setopt (c, 1141 CURLOPT_HTTPPOST, post_first))) 1142 { 1143 return c; /* Success exit point for 'use_post' */ 1144 } 1145 else 1146 fprintf (stderr, "POST form-related curl_easy_setopt() failed, " 1147 "error: %s\n", curl_easy_strerror (e)); 1148 #endif /* TEST_USE_STATIC_POST_DATA */ 1149 } 1150 } 1151 else 1152 return c; /* Success exit point */ 1153 } 1154 else 1155 fprintf (stderr, "curl_easy_setopt() failed at line %d, " 1156 "error: %s\n", (int) __LINE__, 1157 curl_easy_strerror (e)); 1158 1159 curl_easy_cleanup (c); 1160 #ifndef TEST_USE_STATIC_POST_DATA 1161 if (NULL != *mime) 1162 curl_mime_free (*mime); 1163 #endif /* ! TEST_USE_STATIC_POST_DATA */ 1164 1165 if (NULL != buf) 1166 free (buf); 1167 1168 return NULL; /* Failure exit point */ 1169 } 1170 1171 1172 static struct MHD_Daemon * 1173 start_daemon_for_test (unsigned int daemon_flags, uint16_t *pport, 1174 struct ahc_param_strct *callback_param) 1175 { 1176 struct MHD_Daemon *d; 1177 struct MHD_OptionItem ops[] = { 1178 { MHD_OPTION_END, 0, NULL }, 1179 { MHD_OPTION_END, 0, NULL }, 1180 { MHD_OPTION_END, 0, NULL } 1181 }; 1182 size_t num_opt; 1183 1184 num_opt = 0; 1185 1186 callback_param->magic1 = (unsigned int) TEST_MAGIC_MARKER1; 1187 callback_param->err_flag = 0; 1188 callback_param->num_replies = 0; 1189 1190 if (use_put_large) 1191 { 1192 ops[num_opt].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT; 1193 ops[num_opt].value = (intptr_t) (PUT_LARGE_SIZE / 4); 1194 ++num_opt; 1195 } 1196 else if (use_long_header || use_long_uri) 1197 { 1198 ops[num_opt].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT; 1199 ops[num_opt].value = (intptr_t) (TEST_STRING_VLONG_LEN / 2); 1200 ++num_opt; 1201 } 1202 if (0 == (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags)) 1203 { 1204 ops[num_opt].option = MHD_OPTION_APP_FD_SETSIZE; 1205 ops[num_opt].value = (intptr_t) (FD_SETSIZE); 1206 ++num_opt; 1207 } 1208 d = MHD_start_daemon (daemon_flags /* | MHD_USE_ERROR_LOG */, 1209 *pport, NULL, NULL, 1210 &ahc_check, callback_param, 1211 MHD_OPTION_CONNECTION_TIMEOUT, 1212 (unsigned int) MHD_TIMEOUT, 1213 MHD_OPTION_NOTIFY_COMPLETED, 1214 &req_completed_cleanup, callback_param, 1215 MHD_OPTION_ARRAY, ops, 1216 MHD_OPTION_END); 1217 if (NULL == d) 1218 { 1219 fprintf (stderr, "MHD_start_daemon() failed " 1220 "at line %d.\n", (int) __LINE__); 1221 return NULL; 1222 } 1223 1224 /* Do not use accept4() as only accept() is intercepted by zzuf */ 1225 if (! run_with_socat) 1226 MHD_avoid_accept4_ (d); 1227 1228 if (0 == *pport) 1229 { 1230 const union MHD_DaemonInfo *dinfo; 1231 1232 dinfo = MHD_get_daemon_info (d, 1233 MHD_DAEMON_INFO_BIND_PORT); 1234 if ( (NULL == dinfo) || 1235 (0 == dinfo->port) ) 1236 { 1237 fprintf (stderr, "MHD_get_daemon_info() failed " 1238 "at line %d.\n", (int) __LINE__); 1239 MHD_stop_daemon (d); 1240 return NULL; 1241 } 1242 *pport = dinfo->port; 1243 } 1244 return d; 1245 } 1246 1247 1248 static void 1249 print_test_starting (unsigned int daemon_flags) 1250 { 1251 fflush (stderr); 1252 if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags)) 1253 { 1254 if (0 != (MHD_USE_THREAD_PER_CONNECTION & daemon_flags)) 1255 { 1256 if (0 != (MHD_USE_POLL & daemon_flags)) 1257 printf ("\nStarting test with internal polling by poll() and " 1258 "thread-per-connection.\n"); 1259 else 1260 printf ("\nStarting test with internal polling by select() and " 1261 "thread-per-connection.\n"); 1262 } 1263 else 1264 { 1265 if (0 != (MHD_USE_POLL & daemon_flags)) 1266 printf ("\nStarting test with internal polling by poll().\n"); 1267 else if (0 != (MHD_USE_EPOLL & daemon_flags)) 1268 printf ("\nStarting test with internal polling by 'epoll'.\n"); 1269 else 1270 printf ("\nStarting test with internal polling by select().\n"); 1271 } 1272 } 1273 else 1274 { 1275 if (0 != (MHD_USE_EPOLL & daemon_flags)) 1276 printf ("\nStarting test with%s thread safety with external polling " 1277 "and internal 'epoll'.\n", 1278 ((0 != (MHD_USE_NO_THREAD_SAFETY & daemon_flags)) ? "out" : "")); 1279 else 1280 printf ("\nStarting test with%s thread safety with external polling.\n", 1281 ((0 != (MHD_USE_NO_THREAD_SAFETY & daemon_flags)) ? "out" : "")); 1282 } 1283 fflush (stdout); 1284 } 1285 1286 1287 static unsigned int 1288 testInternalPolling (uint16_t *pport, unsigned int daemon_flags) 1289 { 1290 struct MHD_Daemon *d; 1291 CURL *c; 1292 char buf[2048]; 1293 struct CBC cbc; 1294 struct ahc_param_strct callback_param; 1295 unsigned int ret; 1296 #ifndef TEST_USE_STATIC_POST_DATA 1297 curl_mime *mime; 1298 #endif /* ! TEST_USE_STATIC_POST_DATA */ 1299 1300 if (0 == (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags)) 1301 { 1302 fprintf (stderr, "Wrong internal flags, the test is broken. " 1303 "At line %d.\n", (int) __LINE__); 1304 abort (); /* Wrong flags, error in code */ 1305 } 1306 1307 print_test_starting (daemon_flags); 1308 initCBC (&cbc, buf, sizeof(buf)); 1309 d = start_daemon_for_test (daemon_flags, pport, &callback_param); 1310 if (d == NULL) 1311 return 1; 1312 1313 ret = 0; 1314 c = setupCURL (&cbc, *pport 1315 #ifndef TEST_USE_STATIC_POST_DATA 1316 , &mime 1317 #endif /* ! TEST_USE_STATIC_POST_DATA */ 1318 ); 1319 if (NULL != c) 1320 { 1321 int i; 1322 1323 for (i = dry_run ? LOOP_COUNT : 0; i < LOOP_COUNT; i++) 1324 { 1325 fprintf (stderr, "."); 1326 callback_param.num_replies = 0; 1327 resetCBC (&cbc); 1328 /* Run libcurl without checking the result */ 1329 curl_easy_perform (c); 1330 fflush (stderr); 1331 } 1332 curl_easy_cleanup (c); 1333 #ifndef TEST_USE_STATIC_POST_DATA 1334 if (NULL != mime) 1335 curl_mime_free (mime); 1336 #endif /* ! TEST_USE_STATIC_POST_DATA */ 1337 } 1338 else 1339 ret = 99; /* Not an MHD error */ 1340 1341 if ((0 == ret) && callback_param.err_flag) 1342 { 1343 fprintf (stderr, "One or more errors have been detected by " 1344 "access handler callback function. " 1345 "At line %d.\n", (int) __LINE__); 1346 ret = 1; 1347 } 1348 else if ((0 == ret) && cbc.excess_found) 1349 { 1350 fprintf (stderr, "The extra reply data have been detected one " 1351 "or more times. " 1352 "At line %d.\n", (int) __LINE__); 1353 ret = 1; 1354 } 1355 1356 fprintf (stderr, "\n"); 1357 MHD_stop_daemon (d); 1358 fflush (stderr); 1359 return ret; 1360 } 1361 1362 1363 static unsigned int 1364 testExternalPolling (uint16_t *pport, unsigned int daemon_flags) 1365 { 1366 struct MHD_Daemon *d; 1367 CURLM *multi; 1368 char buf[2048]; 1369 struct CBC cbc; 1370 struct ahc_param_strct callback_param; 1371 unsigned int ret; 1372 #ifndef TEST_USE_STATIC_POST_DATA 1373 curl_mime *mime; 1374 #endif /* ! TEST_USE_STATIC_POST_DATA */ 1375 1376 if (0 != (MHD_USE_INTERNAL_POLLING_THREAD & daemon_flags)) 1377 { 1378 fprintf (stderr, "Wrong internal flags, the test is broken. " 1379 "At line %d.\n", (int) __LINE__); 1380 abort (); /* Wrong flags, error in code */ 1381 } 1382 1383 print_test_starting (daemon_flags); 1384 initCBC (&cbc, buf, sizeof(buf)); 1385 d = start_daemon_for_test (daemon_flags, pport, &callback_param); 1386 if (d == NULL) 1387 return 1; 1388 1389 ret = 0; 1390 multi = curl_multi_init (); 1391 if (multi == NULL) 1392 { 1393 fprintf (stderr, "curl_multi_init() failed " 1394 "at line %d.\n", (int) __LINE__); 1395 ret = 99; /* Not an MHD error */ 1396 } 1397 else 1398 { 1399 CURL *c; 1400 c = setupCURL (&cbc, *pport 1401 #ifndef TEST_USE_STATIC_POST_DATA 1402 , &mime 1403 #endif /* ! TEST_USE_STATIC_POST_DATA */ 1404 ); 1405 1406 if (NULL == c) 1407 ret = 99; /* Not an MHD error */ 1408 else 1409 { 1410 int i; 1411 1412 for (i = dry_run ? LOOP_COUNT : 0; 1413 (i < LOOP_COUNT) && (0 == ret); i++) 1414 { 1415 CURLMcode mret; 1416 1417 /* The same 'multi' handle will be used in transfers so 1418 connection will be reused. 1419 The same 'easy' handle is added (and removed later) to (re-)start 1420 the same transfer. */ 1421 mret = curl_multi_add_handle (multi, c); 1422 if (CURLM_OK != mret) 1423 { 1424 fprintf (stderr, "curl_multi_add_handle() failed at %d, " 1425 "error: %s\n", (int) __LINE__, 1426 curl_multi_strerror (mret)); 1427 ret = 99; /* Not an MHD error */ 1428 } 1429 else 1430 { 1431 time_t start; 1432 1433 fprintf (stderr, "."); 1434 callback_param.num_replies = 0; 1435 resetCBC (&cbc); 1436 start = time (NULL); 1437 do 1438 { 1439 fd_set rs; 1440 fd_set ws; 1441 fd_set es; 1442 int maxfd_curl; 1443 MHD_socket maxfd_mhd; 1444 int maxfd; 1445 int running; 1446 struct timeval tv; 1447 1448 maxfd_curl = 0; 1449 maxfd_mhd = MHD_INVALID_SOCKET; 1450 FD_ZERO (&rs); 1451 FD_ZERO (&ws); 1452 FD_ZERO (&es); 1453 curl_multi_perform (multi, &running); 1454 if (0 == running) 1455 { 1456 int msgs_left; 1457 do 1458 { 1459 (void) curl_multi_info_read (multi, &msgs_left); 1460 } while (0 != msgs_left); 1461 break; /* The transfer has been finished */ 1462 } 1463 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxfd_curl); 1464 if (CURLM_OK != mret) 1465 { 1466 fprintf (stderr, "curl_multi_fdset() failed at line %d, " 1467 "error: %s\n", (int) __LINE__, 1468 curl_multi_strerror (mret)); 1469 ret = 99; /* Not an MHD error */ 1470 break; 1471 } 1472 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxfd_mhd)) 1473 { 1474 fprintf (stderr, "MHD_get_fdset() failed " 1475 "at line %d.\n", (int) __LINE__); 1476 ret = 1; 1477 break; 1478 } 1479 #ifndef MHD_WINSOCK_SOCKETS 1480 if ((int) maxfd_mhd > maxfd_curl) 1481 maxfd = (int) maxfd_mhd; 1482 else 1483 #endif /* ! MHD_WINSOCK_SOCKETS */ 1484 maxfd = maxfd_curl; 1485 tv.tv_sec = 0; 1486 tv.tv_usec = 100 * 1000; 1487 if (0 == MHD_get_timeout64s (d)) 1488 tv.tv_usec = 0; 1489 else 1490 { 1491 long curl_to = -1; 1492 curl_multi_timeout (multi, &curl_to); 1493 if (0 == curl_to) 1494 tv.tv_usec = 0; 1495 } 1496 if (-1 == select (maxfd + 1, &rs, &ws, &es, &tv)) 1497 { 1498 #ifdef MHD_POSIX_SOCKETS 1499 if (EINTR != errno) 1500 fprintf (stderr, "Unexpected select() error " 1501 "at line %d.\n", (int) __LINE__); 1502 #else /* ! MHD_POSIX_SOCKETS */ 1503 if ((WSAEINVAL != WSAGetLastError ()) || 1504 (0 != rs.fd_count) || (0 != ws.fd_count) || 1505 (0 != es.fd_count)) 1506 fprintf (stderr, "Unexpected select() error " 1507 "at line %d.\n", (int) __LINE__); 1508 Sleep ((unsigned long) tv.tv_usec / 1000); 1509 #endif /* ! MHD_POSIX_SOCKETS */ 1510 } 1511 MHD_run (d); 1512 } while (time (NULL) - start <= MHD_TIMEOUT); 1513 /* Remove 'easy' handle from 'multi' handle to 1514 * restart the transfer or to finish. */ 1515 curl_multi_remove_handle (multi, c); 1516 } 1517 } 1518 curl_easy_cleanup (c); 1519 } 1520 curl_multi_cleanup (multi); 1521 #ifndef TEST_USE_STATIC_POST_DATA 1522 if (NULL != mime) 1523 curl_mime_free (mime); 1524 #endif /* ! TEST_USE_STATIC_POST_DATA */ 1525 } 1526 1527 if ((0 == ret) && callback_param.err_flag) 1528 { 1529 fprintf (stderr, "One or more errors have been detected by " 1530 "access handler callback function. " 1531 "At line %d.\n", (int) __LINE__); 1532 ret = 1; 1533 } 1534 else if ((0 == ret) && cbc.excess_found) 1535 { 1536 fprintf (stderr, "The extra reply data have been detected one " 1537 "or more times. " 1538 "At line %d.\n", (int) __LINE__); 1539 ret = 1; 1540 } 1541 1542 fprintf (stderr, "\n"); 1543 MHD_stop_daemon (d); 1544 return 0; 1545 } 1546 1547 1548 static unsigned int 1549 run_all_checks (void) 1550 { 1551 uint16_t port; 1552 unsigned int testRes; 1553 unsigned int ret = 0; 1554 1555 if (! run_with_socat) 1556 { 1557 if (MHD_are_sanitizers_enabled_ ()) 1558 { 1559 fprintf (stderr, "Direct run with zzuf does not work with sanitizers. " 1560 "At line %d.\n", (int) __LINE__); 1561 return 77; 1562 } 1563 if (! MHD_is_avoid_accept4_possible_ ()) 1564 { 1565 fprintf (stderr, 1566 "Non-debug build of MHD on this platform use accept4() function. " 1567 "Direct run with zzuf is not possible. " 1568 "At line %d.\n", (int) __LINE__); 1569 return 77; 1570 } 1571 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 1572 port = 0; /* Use system automatic assignment */ 1573 else 1574 { 1575 port = TEST_BASE_PORT; /* Use predefined port, may break parallel testing of another MHD build */ 1576 if (oneone) 1577 port += 100; 1578 if (use_long_uri) 1579 port += 30; 1580 else if (use_long_header) 1581 port += 35; 1582 else if (use_get_chunked) 1583 port += 0; 1584 else if (use_get) 1585 port += 5; 1586 else if (use_post_form) 1587 port += 10; 1588 else if (use_post) 1589 port += 15; 1590 else if (use_put_large) 1591 port += 20; 1592 else if (use_put_chunked) 1593 port += 25; 1594 } 1595 } 1596 else 1597 port = TEST_BASE_PORT; /* Use predefined port, may break parallel testing of another MHD build */ 1598 1599 if (! dry_run && (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))) 1600 { 1601 testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY); 1602 if ((77 == testRes) || (99 == testRes)) 1603 return testRes; 1604 ret += testRes; 1605 testRes = testInternalPolling (&port, MHD_USE_SELECT_INTERNALLY 1606 | MHD_USE_THREAD_PER_CONNECTION); 1607 if ((77 == testRes) || (99 == testRes)) 1608 return testRes; 1609 ret += testRes; 1610 1611 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL)) 1612 { 1613 testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY); 1614 if ((77 == testRes) || (99 == testRes)) 1615 return testRes; 1616 ret += testRes; 1617 testRes = testInternalPolling (&port, MHD_USE_POLL_INTERNALLY 1618 | MHD_USE_THREAD_PER_CONNECTION); 1619 if ((77 == testRes) || (99 == testRes)) 1620 return testRes; 1621 ret += testRes; 1622 } 1623 1624 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL)) 1625 { 1626 testRes = testInternalPolling (&port, MHD_USE_EPOLL_INTERNALLY); 1627 if ((77 == testRes) || (99 == testRes)) 1628 return testRes; 1629 } 1630 testRes = testExternalPolling (&port, MHD_NO_FLAG); 1631 } 1632 testRes = testExternalPolling (&port, MHD_USE_NO_THREAD_SAFETY); 1633 if ((77 == testRes) || (99 == testRes)) 1634 return testRes; 1635 ret += testRes; 1636 1637 return ret; 1638 } 1639 1640 1641 int 1642 main (int argc, char *const *argv) 1643 { 1644 unsigned int res; 1645 int use_magic_exit_codes; 1646 1647 oneone = ! has_in_name (argv[0], "10"); 1648 use_get = has_in_name (argv[0], "_get"); 1649 use_get_chunked = has_in_name (argv[0], "_get_chunked"); 1650 use_put = has_in_name (argv[0], "_put"); 1651 use_put_large = has_in_name (argv[0], "_put_large"); 1652 use_put_chunked = has_in_name (argv[0], "_put_chunked"); 1653 use_post = has_in_name (argv[0], "_post"); 1654 use_post_form = has_in_name (argv[0], "_post_form"); 1655 use_long_header = has_in_name (argv[0], "_long_header"); 1656 use_long_uri = has_in_name (argv[0], "_long_uri"); 1657 use_close = has_in_name (argv[0], "_close"); 1658 1659 run_with_socat = has_param (argc, argv, "--with-socat"); 1660 dry_run = has_param (argc, argv, "--dry-run") || 1661 has_param (argc, argv, "-n"); 1662 1663 if (1 != 1664 ((use_get ? 1 : 0) + (use_put ? 1 : 0) + (use_post ? 1 : 0))) 1665 { 1666 fprintf (stderr, "Wrong test name '%s': no or multiple indications " 1667 "for the test type.\n", argv[0] ? argv[0] : "(NULL)"); 1668 return 99; 1669 } 1670 use_magic_exit_codes = run_with_socat || dry_run; 1671 1672 /* zzuf cannot bypass exit values. 1673 Unless 'dry run' is used, do not return errors for external error 1674 conditions (like out-of-memory) as they will be reported as test failures. */ 1675 if (! test_global_init ()) 1676 return use_magic_exit_codes ? 99 : 0; 1677 res = run_all_checks (); 1678 test_global_deinit (); 1679 if (99 == res) 1680 return use_magic_exit_codes ? 99 : 0; 1681 if (77 == res) 1682 return use_magic_exit_codes ? 77 : 0; 1683 return (0 == res) ? 0 : 1; /* 0 == pass */ 1684 }