test_toolarge.c (57584B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2014-2022 Evgeny Grin (Karlson2k) 4 Copyright (C) 2007, 2009, 2011 Christian Grothoff 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 * @file test_toolarge.c 23 * @brief Testcase for handling of data larger then buffers. 24 * @details Testcases for handling of various situations when data cannot fit 25 * the buffers. Address sanitizers and debug asserts should increase 26 * number of problems detected by this test (detect actual overrun). 27 * Tests start with valid sizes to ensure that normal data is processed 28 * correctly and then sizes are monotonically increased to ensure that 29 * overflow is handled correctly at all stages in all codepaths. 30 * Tests with valid sizes are repeated several times to ensure that 31 * tests are failed because of overflow, but because of second run. 32 * @author Karlson2k (Evgeny Grin) 33 * @author Christian Grothoff 34 */ 35 #include "mhd_options.h" 36 #include "platform.h" 37 #include <curl/curl.h> 38 #include <microhttpd.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <time.h> 42 #include <errno.h> 43 #include "mhd_has_in_name.h" 44 #include "mhd_has_param.h" 45 #include "mhd_sockets.h" /* only macros used */ 46 47 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 48 test into a marked, classifiable test error (TESTING.md, P5). */ 49 #include "mhd_panic_tripwire.h" 50 51 #ifdef HAVE_STRINGS_H 52 #include <strings.h> 53 #endif /* HAVE_STRINGS_H */ 54 55 #ifdef _WIN32 56 #ifndef WIN32_LEAN_AND_MEAN 57 #define WIN32_LEAN_AND_MEAN 1 58 #endif /* !WIN32_LEAN_AND_MEAN */ 59 #include <windows.h> 60 #endif 61 62 #ifndef WINDOWS 63 #include <unistd.h> 64 #include <sys/socket.h> 65 #endif 66 67 #ifdef HAVE_LIMITS_H 68 #include <limits.h> 69 #endif /* HAVE_LIMITS_H */ 70 71 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2 72 #undef MHD_CPU_COUNT 73 #endif 74 #if ! defined(MHD_CPU_COUNT) 75 #define MHD_CPU_COUNT 2 76 #endif 77 #if MHD_CPU_COUNT > 32 78 #undef MHD_CPU_COUNT 79 /* Limit to reasonable value */ 80 #define MHD_CPU_COUNT 32 81 #endif /* MHD_CPU_COUNT > 32 */ 82 83 84 #if defined(HAVE___FUNC__) 85 #define externalErrorExit(ignore) \ 86 _externalErrorExit_func(NULL, __func__, __LINE__) 87 #define externalErrorExitDesc(errDesc) \ 88 _externalErrorExit_func(errDesc, __func__, __LINE__) 89 #define libcurlErrorExit(ignore) \ 90 _libcurlErrorExit_func(NULL, __func__, __LINE__) 91 #define libcurlErrorExitDesc(errDesc) \ 92 _libcurlErrorExit_func(errDesc, __func__, __LINE__) 93 #define mhdErrorExit(ignore) \ 94 _mhdErrorExit_func(NULL, __func__, __LINE__) 95 #define mhdErrorExitDesc(errDesc) \ 96 _mhdErrorExit_func(errDesc, __func__, __LINE__) 97 #elif defined(HAVE___FUNCTION__) 98 #define externalErrorExit(ignore) \ 99 _externalErrorExit_func(NULL, __FUNCTION__, __LINE__) 100 #define externalErrorExitDesc(errDesc) \ 101 _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__) 102 #define libcurlErrorExit(ignore) \ 103 _libcurlErrorExit_func(NULL, __FUNCTION__, __LINE__) 104 #define libcurlErrorExitDesc(errDesc) \ 105 _libcurlErrorExit_func(errDesc, __FUNCTION__, __LINE__) 106 #define mhdErrorExit(ignore) \ 107 _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__) 108 #define mhdErrorExitDesc(errDesc) \ 109 _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__) 110 #else 111 #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__) 112 #define externalErrorExitDesc(errDesc) \ 113 _externalErrorExit_func(errDesc, NULL, __LINE__) 114 #define libcurlErrorExit(ignore) _libcurlErrorExit_func(NULL, NULL, __LINE__) 115 #define libcurlErrorExitDesc(errDesc) \ 116 _libcurlErrorExit_func(errDesc, NULL, __LINE__) 117 #define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__) 118 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__) 119 #endif 120 121 122 _MHD_NORETURN static void 123 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 124 { 125 if ((NULL != errDesc) && (0 != errDesc[0])) 126 fprintf (stderr, "%s", errDesc); 127 else 128 fprintf (stderr, "System or external library call failed"); 129 if ((NULL != funcName) && (0 != funcName[0])) 130 fprintf (stderr, " in %s", funcName); 131 if (0 < lineNum) 132 fprintf (stderr, " at line %d", lineNum); 133 134 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 135 strerror (errno)); 136 #ifdef MHD_WINSOCK_SOCKETS 137 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 138 #endif /* MHD_WINSOCK_SOCKETS */ 139 fflush (stderr); 140 exit (99); 141 } 142 143 144 static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; 145 146 _MHD_NORETURN static void 147 _libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 148 { 149 if ((NULL != errDesc) && (0 != errDesc[0])) 150 fprintf (stderr, "%s", errDesc); 151 else 152 fprintf (stderr, "CURL library call failed"); 153 if ((NULL != funcName) && (0 != funcName[0])) 154 fprintf (stderr, " in %s", funcName); 155 if (0 < lineNum) 156 fprintf (stderr, " at line %d", lineNum); 157 158 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 159 strerror (errno)); 160 if (0 != libcurl_errbuf[0]) 161 fprintf (stderr, "Last libcurl error details: %s\n", libcurl_errbuf); 162 163 fflush (stderr); 164 exit (99); 165 } 166 167 168 _MHD_NORETURN static void 169 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 170 { 171 if ((NULL != errDesc) && (0 != errDesc[0])) 172 fprintf (stderr, "%s", errDesc); 173 else 174 fprintf (stderr, "MHD unexpected error"); 175 if ((NULL != funcName) && (0 != funcName[0])) 176 fprintf (stderr, " in %s", funcName); 177 if (0 < lineNum) 178 fprintf (stderr, " at line %d", lineNum); 179 180 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 181 strerror (errno)); 182 183 fflush (stderr); 184 exit (8); 185 } 186 187 188 /* Could be increased to facilitate debugging */ 189 #define TIMEOUTS_VAL 5 190 191 #define EXPECTED_URI_BASE_PATH "/a" 192 193 #define URL_SCHEME_HOST "http:/" "/127.0.0.1" 194 195 #define N1_HEADER_NAME "n" 196 #define N1_HEADER_VALUE "1" 197 #define N1_HEADER N1_HEADER_NAME ": " N1_HEADER_VALUE 198 #define N1_HEADER_CRLF N1_HEADER "\r\n" 199 200 #define BUFFER_SIZE 1024 201 202 /* The size of the test element that must pass the test */ 203 #ifndef MHD_ASAN_POISON_ACTIVE 204 #define TEST_OK_SIZE (BUFFER_SIZE - 384) 205 #else /* MHD_ASAN_POISON_ACTIVE */ 206 #define TEST_OK_SIZE (BUFFER_SIZE - 384 - 80) 207 #endif /* MHD_ASAN_POISON_ACTIVE */ 208 209 /* The size of the test element where tests are started */ 210 #define TEST_START_SIZE (TEST_OK_SIZE - 16) 211 212 /* The size of the test element that must definitely fail */ 213 #define TEST_FAIL_SIZE (BUFFER_SIZE + 32) 214 215 /* Special value for request many headers test. 216 * MHD uses the same buffer to store headers strings and pointers to the strings 217 * so allocation is multiplied for small request header. */ 218 /* The size of the test element that must pass the test */ 219 #define TEST_RQ_N1_OK_SIZE 50 220 221 /* The size of the test element where tests are started */ 222 #define TEST_RQ_N1_START_SIZE (TEST_RQ_N1_OK_SIZE - 32) 223 224 /* Global parameters */ 225 static int verbose; /**< Be verbose */ 226 static int oneone; /**< If false use HTTP/1.0 for requests*/ 227 static uint16_t global_port; /**< MHD daemons listen port number */ 228 static int large_req_method; /**< Large request method */ 229 static int large_req_url; /**< Large request URL */ 230 static int large_req_header_name; /**< Large request single header name */ 231 static int large_req_header_value; /**< Large request single header value */ 232 static int large_req_headers; /**< Large request headers */ 233 static int large_rsp_header_name; /**< Large response single header name */ 234 static int large_rsp_header_value; /**< Large response single header value */ 235 static int large_rsp_headers; /**< Large response headers */ 236 static int response_timeout_val = TIMEOUTS_VAL; 237 238 /* Current test parameters */ 239 /* * Moved to local variables * */ 240 241 /* Static helper variables */ 242 /* * None for this test * */ 243 244 static void 245 test_global_init (void) 246 { 247 libcurl_errbuf[0] = 0; 248 249 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 250 externalErrorExit (); 251 } 252 253 254 static void 255 test_global_cleanup (void) 256 { 257 curl_global_cleanup (); 258 } 259 260 261 struct headers_check_result 262 { 263 unsigned int num_n1_headers; 264 size_t large_header_name_size; 265 size_t large_header_value_size; 266 int large_header_valid; 267 }; 268 269 static size_t 270 lcurl_hdr_callback (char *buffer, size_t size, size_t nitems, 271 void *userdata) 272 { 273 const size_t data_size = size * nitems; 274 struct headers_check_result *check_res = 275 (struct headers_check_result *) userdata; 276 277 if ((6 == data_size) && (0 == memcmp (N1_HEADER_CRLF, buffer, 6))) 278 check_res->num_n1_headers++; 279 else if ((5 <= data_size) && ('0' == buffer[0])) 280 { 281 const char *const col_ptr = memchr (buffer, ':', data_size); 282 if (0 != check_res->large_header_value_size) 283 mhdErrorExitDesc ("Expected only one large header, " \ 284 "but found two large headers in the reply"); 285 if (NULL == col_ptr) 286 check_res->large_header_valid = 0; 287 else if ((size_t) (col_ptr - buffer) >= data_size - 2) 288 check_res->large_header_valid = 0; 289 else if (*(col_ptr + 1) != ' ') 290 check_res->large_header_valid = 0; 291 else 292 { 293 const char *const name = buffer; 294 const size_t name_len = (size_t) (col_ptr - buffer); 295 const size_t val_pos = name_len + 2; 296 const size_t val_len = data_size - val_pos - 2; /* 2 = strlen("\r\n") */ 297 const char *const value = buffer + val_pos; 298 size_t i; 299 check_res->large_header_name_size = name_len; 300 check_res->large_header_value_size = val_len; 301 check_res->large_header_valid = 1; /* To be reset if any problem found */ 302 for (i = 1; i < name_len; i++) 303 if ('a' + (char) (i % ('z' - 'a' + 1)) != name[i]) 304 { 305 fprintf (stderr, "Wrong sequence in reply header name " \ 306 "at position %u. Expected '%c', got '%c'\n", 307 (unsigned int) i, 308 'a' + (char) (i % ('z' - 'a' + 1)), 309 name[i]); 310 check_res->large_header_valid = 0; 311 break; 312 } 313 for (i = 0; i < val_len; i++) 314 if ('Z' - (char) (i % ('Z' - 'A' + 1)) != value[i]) 315 { 316 fprintf (stderr, "Wrong sequence in reply header value " \ 317 "at position %u. Expected '%c', got '%c'\n", 318 (unsigned int) i, 319 'Z' - (char) (i % ('Z' - 'A' + 1)), 320 value[i]); 321 check_res->large_header_valid = 0; 322 break; 323 } 324 } 325 } 326 327 return data_size; 328 } 329 330 331 struct lcurl_data_cb_param 332 { 333 char *buf; 334 size_t pos; 335 size_t size; 336 }; 337 338 339 static size_t 340 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 341 { 342 struct lcurl_data_cb_param *cbc = ctx; 343 344 if (cbc->pos + size * nmemb > cbc->size) 345 externalErrorExit (); /* overflow */ 346 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 347 cbc->pos += size * nmemb; 348 return size * nmemb; 349 } 350 351 352 struct check_uri_cls 353 { 354 const char *volatile uri; 355 }; 356 357 static void * 358 check_uri_cb (void *cls, 359 const char *uri, 360 struct MHD_Connection *con) 361 { 362 struct check_uri_cls *param = (struct check_uri_cls *) cls; 363 (void) con; 364 365 if (0 != strcmp (param->uri, 366 uri)) 367 { 368 fprintf (stderr, 369 "Wrong URI: `%s', line: %d\n", 370 uri, __LINE__); 371 exit (22); 372 } 373 return NULL; 374 } 375 376 377 struct mhd_header_checker_param 378 { 379 unsigned int num_n1_headers; 380 size_t large_header_name_size; 381 size_t large_header_value_size; 382 int large_header_valid; 383 }; 384 385 static enum MHD_Result 386 headerCheckerInterator (void *cls, 387 enum MHD_ValueKind kind, 388 const char *key, 389 size_t key_size, 390 const char *value, 391 size_t value_size) 392 { 393 struct mhd_header_checker_param *const param = 394 (struct mhd_header_checker_param *) cls; 395 396 if (NULL == param) 397 mhdErrorExitDesc ("cls parameter is NULL"); 398 399 if (MHD_HEADER_KIND != kind) 400 return MHD_YES; /* Continue iteration */ 401 402 if (0 == key_size) 403 mhdErrorExitDesc ("Zero key length"); 404 405 if ((1 == key_size) && (1 == value_size) && 406 ('n' == key[0]) && ('1' == value[0])) 407 param->num_n1_headers++; 408 else if ('0' == key[0]) 409 { /* Found 'large' header */ 410 size_t i; 411 param->large_header_name_size = key_size; 412 param->large_header_value_size = value_size; 413 param->large_header_valid = 1; 414 for (i = 1; i < key_size; i++) 415 if ('a' + (char) (i % ('z' - 'a' + 1)) != key[i]) 416 { 417 fprintf (stderr, "Wrong sequence in request header name " \ 418 "at position %u. Expected '%c', got '%c'\n", 419 (unsigned int) i, 420 'a' + (char) (i % ('z' - 'a' + 1)), 421 key[i]); 422 param->large_header_valid = 0; 423 break; 424 } 425 for (i = 0; i < value_size; i++) 426 if ('Z' - (char) (i % ('Z' - 'A' + 1)) != value[i]) 427 { 428 fprintf (stderr, "Wrong sequence in request header value " \ 429 "at position %u. Expected '%c', got '%c'\n", 430 (unsigned int) i, 431 'Z' - (char) (i % ('Z' - 'A' + 1)), 432 value[i]); 433 param->large_header_valid = 0; 434 break; 435 } 436 } 437 return MHD_YES; 438 } 439 440 441 struct ahc_cls_type 442 { 443 const char *volatile rp_data; 444 volatile size_t rp_data_size; 445 volatile size_t rp_num_n1_hdrs; 446 volatile size_t rp_large_hdr_name_size; 447 volatile size_t rp_large_hdr_value_size; 448 struct mhd_header_checker_param header_check_param; 449 const char *volatile rq_method; 450 const char *volatile rq_url; 451 }; 452 453 454 static enum MHD_Result 455 ahcCheck (void *cls, 456 struct MHD_Connection *connection, 457 const char *url, 458 const char *method, 459 const char *version, 460 const char *upload_data, size_t *upload_data_size, 461 void **req_cls) 462 { 463 static int ptr; 464 struct MHD_Response *response; 465 enum MHD_Result ret; 466 struct ahc_cls_type *const param = (struct ahc_cls_type *) cls; 467 size_t i; 468 469 if (NULL == param) 470 mhdErrorExitDesc ("cls parameter is NULL"); 471 472 if (0 != strcmp (version, MHD_HTTP_VERSION_1_1)) 473 mhdErrorExitDesc ("Unexpected HTTP version"); 474 475 if (0 != strcmp (url, param->rq_url)) 476 mhdErrorExitDesc ("Unexpected URI"); 477 478 if (NULL != upload_data) 479 mhdErrorExitDesc ("'upload_data' is not NULL"); 480 481 if (NULL == upload_data_size) 482 mhdErrorExitDesc ("'upload_data_size' pointer is NULL"); 483 484 if (0 != *upload_data_size) 485 mhdErrorExitDesc ("'*upload_data_size' value is not zero"); 486 487 if (0 != strcmp (param->rq_method, method)) 488 mhdErrorExitDesc ("Unexpected request method"); 489 490 if (&ptr != *req_cls) 491 { 492 *req_cls = &ptr; 493 return MHD_YES; 494 } 495 *req_cls = NULL; 496 497 if (1 > MHD_get_connection_values_n (connection, MHD_HEADER_KIND, 498 &headerCheckerInterator, 499 ¶m->header_check_param)) 500 mhdErrorExitDesc ("Wrong number of headers in the request"); 501 502 response = 503 MHD_create_response_from_buffer_copy (param->rp_data_size, 504 (const void *) param->rp_data); 505 if (NULL == response) 506 mhdErrorExitDesc ("Failed to create response"); 507 508 for (i = 0; i < param->rp_num_n1_hdrs; i++) 509 if (MHD_YES != MHD_add_response_header (response, 510 N1_HEADER_NAME, 511 N1_HEADER_VALUE)) 512 mhdErrorExitDesc ("Cannot add header"); 513 514 if (0 != param->rp_large_hdr_name_size) 515 { 516 const size_t large_hdr_name_size = param->rp_large_hdr_name_size; 517 char *large_hrd_name; 518 const size_t large_hdr_value_size = param->rp_large_hdr_value_size; 519 char *large_hrd_value; 520 521 large_hrd_name = malloc (large_hdr_name_size + 1); 522 if (NULL == large_hrd_name) 523 externalErrorExit (); 524 if (0 != large_hdr_value_size) 525 large_hrd_value = malloc (large_hdr_value_size + 1); 526 else 527 large_hrd_value = NULL; 528 529 if ((0 != large_hdr_value_size) && (NULL == large_hrd_value)) 530 externalErrorExit (); 531 large_hrd_name[0] = '0'; /* Name starts with zero for unique identification */ 532 for (i = 1; i < large_hdr_name_size; i++) 533 large_hrd_name[i] = 'a' + (char) (unsigned char) (i % ('z' - 'a' + 1)); 534 large_hrd_name[large_hdr_name_size] = 0; 535 for (i = 0; i < large_hdr_value_size; i++) 536 large_hrd_value[i] = 'Z' - (char) (unsigned char) (i % ('Z' - 'A' + 1)); 537 if (NULL != large_hrd_value) 538 large_hrd_value[large_hdr_value_size] = 0; 539 if (MHD_YES != MHD_add_response_header (response, 540 large_hrd_name, 541 large_hrd_value)) 542 mhdErrorExitDesc ("Cannot add large header"); 543 544 if (NULL != large_hrd_value) 545 free (large_hrd_value); 546 free (large_hrd_name); 547 } 548 549 ret = MHD_queue_response (connection, 550 MHD_HTTP_OK, 551 response); 552 MHD_destroy_response (response); 553 if (MHD_YES != ret) 554 mhdErrorExitDesc ("Failed to queue response"); 555 556 return ret; 557 } 558 559 560 static CURL * 561 curlEasyInitForTest (const char *queryPath, const char *method, 562 uint16_t port, 563 struct lcurl_data_cb_param *dcbp, 564 struct headers_check_result *hdr_chk_result, 565 struct curl_slist *headers) 566 { 567 CURL *c; 568 569 c = curl_easy_init (); 570 if (NULL == c) 571 libcurlErrorExitDesc ("curl_easy_init() failed"); 572 573 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 574 (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, queryPath)) || 575 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) port)) || 576 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 577 ©Buffer)) || 578 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, dcbp)) || 579 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 580 (long) response_timeout_val)) || 581 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 582 (long) response_timeout_val)) || 583 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, 584 libcurl_errbuf)) || 585 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERFUNCTION, 586 lcurl_hdr_callback)) || 587 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERDATA, 588 hdr_chk_result)) || 589 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || 590 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 591 (oneone) ? 592 CURL_HTTP_VERSION_1_1 : 593 CURL_HTTP_VERSION_1_0))) 594 libcurlErrorExitDesc ("curl_easy_setopt() failed"); 595 596 if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, method)) 597 libcurlErrorExitDesc ("curl_easy_setopt() failed"); 598 599 if (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPHEADER, headers)) 600 libcurlErrorExitDesc ("curl_easy_setopt() failed"); 601 602 return c; 603 } 604 605 606 static CURLcode 607 performQueryExternal (struct MHD_Daemon *d, CURL *c) 608 { 609 CURLM *multi; 610 time_t start; 611 struct timeval tv; 612 CURLcode ret; 613 614 ret = CURLE_FAILED_INIT; /* will be replaced with real result */ 615 multi = NULL; 616 multi = curl_multi_init (); 617 if (multi == NULL) 618 libcurlErrorExitDesc ("curl_multi_init() failed"); 619 if (CURLM_OK != curl_multi_add_handle (multi, c)) 620 libcurlErrorExitDesc ("curl_multi_add_handle() failed"); 621 622 start = time (NULL); 623 while (time (NULL) - start <= TIMEOUTS_VAL) 624 { 625 fd_set rs; 626 fd_set ws; 627 fd_set es; 628 MHD_socket maxMhdSk; 629 int maxCurlSk; 630 int running; 631 632 maxMhdSk = MHD_INVALID_SOCKET; 633 maxCurlSk = -1; 634 FD_ZERO (&rs); 635 FD_ZERO (&ws); 636 FD_ZERO (&es); 637 if (NULL != multi) 638 { 639 curl_multi_perform (multi, &running); 640 if (0 == running) 641 { 642 struct CURLMsg *msg; 643 int msgLeft; 644 int totalMsgs = 0; 645 do 646 { 647 msg = curl_multi_info_read (multi, &msgLeft); 648 if (NULL == msg) 649 libcurlErrorExitDesc ("curl_multi_info_read() failed"); 650 totalMsgs++; 651 if (CURLMSG_DONE == msg->msg) 652 ret = msg->data.result; 653 } while (msgLeft > 0); 654 if (1 != totalMsgs) 655 { 656 fprintf (stderr, 657 "curl_multi_info_read returned wrong " 658 "number of results (%d).\n", 659 totalMsgs); 660 externalErrorExit (); 661 } 662 curl_multi_remove_handle (multi, c); 663 curl_multi_cleanup (multi); 664 multi = NULL; 665 } 666 else 667 { 668 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) 669 libcurlErrorExitDesc ("curl_multi_fdset() failed"); 670 } 671 } 672 if (NULL == multi) 673 { /* libcurl has finished, check whether MHD still needs to perform cleanup */ 674 if (0 != MHD_get_timeout64s (d)) 675 break; /* MHD finished as well */ 676 } 677 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) 678 mhdErrorExitDesc ("MHD_get_fdset() failed"); 679 tv.tv_sec = 0; 680 tv.tv_usec = 1000; 681 #ifdef MHD_POSIX_SOCKETS 682 if (maxMhdSk > maxCurlSk) 683 maxCurlSk = maxMhdSk; 684 #endif /* MHD_POSIX_SOCKETS */ 685 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) 686 { 687 #ifdef MHD_POSIX_SOCKETS 688 if (EINTR != errno) 689 externalErrorExitDesc ("Unexpected select() error"); 690 #else 691 if ((WSAEINVAL != WSAGetLastError ()) || 692 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 693 externalErrorExitDesc ("Unexpected select() error"); 694 Sleep (1); 695 #endif 696 } 697 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) 698 mhdErrorExitDesc ("MHD_run_from_select() failed"); 699 } 700 701 return ret; 702 } 703 704 705 struct curlQueryParams 706 { 707 /* Destination path for CURL query */ 708 const char *queryPath; 709 710 /* Custom query method, NULL for default */ 711 const char *method; 712 713 /* Destination port for CURL query */ 714 uint16_t queryPort; 715 716 /* List of additional request headers */ 717 struct curl_slist *headers; 718 719 /* CURL query result error flag */ 720 volatile unsigned int queryError; 721 722 /* Response HTTP code, zero if no response */ 723 volatile int responseCode; 724 }; 725 726 727 /* Returns zero for successful response and non-zero for failed response */ 728 static unsigned int 729 doCurlQueryInThread (struct MHD_Daemon *d, 730 struct curlQueryParams *p, 731 struct headers_check_result *hdr_res, 732 const char *expected_data, 733 size_t expected_data_size) 734 { 735 const union MHD_DaemonInfo *dinfo; 736 CURL *c; 737 struct lcurl_data_cb_param dcbp; 738 CURLcode errornum; 739 int use_external_poll; 740 long resp_code; 741 742 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_FLAGS); 743 if (NULL == dinfo) 744 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 745 use_external_poll = (0 == (dinfo->flags 746 & MHD_USE_INTERNAL_POLLING_THREAD)); 747 748 if (NULL == p->queryPath) 749 abort (); 750 751 if (0 == p->queryPort) 752 abort (); 753 754 /* Test must not fail due to test's internal buffer shortage */ 755 dcbp.size = TEST_FAIL_SIZE * 2 + 1; 756 dcbp.buf = malloc (dcbp.size); 757 if (NULL == dcbp.buf) 758 externalErrorExit (); 759 dcbp.pos = 0; 760 761 memset (hdr_res, 0, sizeof(*hdr_res)); 762 763 c = curlEasyInitForTest (p->queryPath, p->method, p->queryPort, 764 &dcbp, hdr_res, p->headers); 765 766 if (! use_external_poll) 767 errornum = curl_easy_perform (c); 768 else 769 errornum = performQueryExternal (d, c); 770 771 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &resp_code)) 772 libcurlErrorExitDesc ("curl_easy_getinfo() failed"); 773 774 p->responseCode = (int) resp_code; 775 if ((CURLE_OK == errornum) && (200 != resp_code)) 776 { 777 fprintf (stderr, 778 "Got reply with unexpected status code: %d\n", 779 p->responseCode); 780 mhdErrorExit (); 781 } 782 783 if (CURLE_OK != errornum) 784 { 785 if ((CURLE_GOT_NOTHING != errornum) && (CURLE_RECV_ERROR != errornum) 786 && (CURLE_HTTP_RETURNED_ERROR != errornum)) 787 { 788 if (CURLE_OPERATION_TIMEDOUT == errornum) 789 mhdErrorExitDesc ("Request was aborted due to timeout"); 790 fprintf (stderr, "libcurl returned unexpected error: %s\n", 791 curl_easy_strerror (errornum)); 792 mhdErrorExitDesc ("Request failed due to unexpected error"); 793 } 794 p->queryError = 1; 795 switch (resp_code) 796 { 797 case 0: /* No parsed response */ 798 case 413: /* "Content Too Large" */ 799 case 414: /* "URI Too Long" */ 800 case 431: /* "Request Header Fields Too Large" */ 801 case 501: /* "Not Implemented" */ 802 /* Expected error codes */ 803 break; 804 default: 805 fprintf (stderr, 806 "Got reply with unexpected status code: %ld\n", 807 resp_code); 808 mhdErrorExit (); 809 } 810 } 811 else 812 { 813 if (dcbp.pos != expected_data_size) 814 mhdErrorExit ("libcurl reports wrong size of MHD reply body data"); 815 else if (0 != memcmp (expected_data, dcbp.buf, 816 expected_data_size)) 817 mhdErrorExit ("libcurl reports wrong MHD reply body data"); 818 else 819 p->queryError = 0; 820 } 821 822 curl_easy_cleanup (c); 823 free (dcbp.buf); 824 825 return p->queryError; 826 } 827 828 829 /* Perform test queries, shut down MHD daemon, and free parameters */ 830 static unsigned int 831 performTestQueries (struct MHD_Daemon *d, uint16_t d_port, 832 struct ahc_cls_type *ahc_param, 833 struct check_uri_cls *uri_cb_param) 834 { 835 struct curlQueryParams qParam; 836 unsigned int ret = 0; /* Return value */ 837 struct headers_check_result rp_headers_check; 838 char *buf; 839 size_t i; 840 size_t first_failed_at = 0; 841 842 843 buf = malloc (TEST_FAIL_SIZE + 1 + strlen (URL_SCHEME_HOST)); 844 if (NULL == buf) 845 externalErrorExit (); 846 847 /* Common parameters, to be individually overridden by specific test cases */ 848 qParam.queryPort = d_port; 849 qParam.method = NULL; /* Use libcurl default: GET */ 850 qParam.queryPath = URL_SCHEME_HOST EXPECTED_URI_BASE_PATH; 851 qParam.headers = NULL; /* No additional headers */ 852 uri_cb_param->uri = EXPECTED_URI_BASE_PATH; 853 ahc_param->rq_url = EXPECTED_URI_BASE_PATH; 854 ahc_param->rq_method = "GET"; /* Default expected method */ 855 856 ahc_param->rp_data = "~"; 857 ahc_param->rp_data_size = 1; 858 ahc_param->rp_large_hdr_name_size = 0; 859 ahc_param->rp_large_hdr_value_size = 0; 860 ahc_param->rp_num_n1_hdrs = 0; 861 862 if (large_req_method) 863 { 864 for (i = 0; i < TEST_START_SIZE; i++) 865 buf[i] = 'A' + (char) (unsigned char) (i % ('Z' - 'A' + 1)); 866 for (; i <= TEST_FAIL_SIZE; i++) 867 { 868 buf[i] = 0; 869 870 qParam.method = buf; 871 ahc_param->rq_method = buf; 872 873 memset (&ahc_param->header_check_param, 0, 874 sizeof (ahc_param->header_check_param)); 875 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 876 ahc_param->rp_data, 877 ahc_param->rp_data_size)) 878 { 879 if ((0 != qParam.responseCode) && (501 != qParam.responseCode)) 880 { 881 fprintf (stderr, 882 "Got reply with status code %d, " 883 "while code 501 (\"Not Implemented\") is expected.\n", 884 qParam.responseCode); 885 mhdErrorExit (); 886 } 887 if (TEST_OK_SIZE >= i) 888 { 889 fprintf (stderr, 890 "Request failed when running with the valid value size.\n"); 891 ret = 1; /* Failed too early */ 892 } 893 if (0 == first_failed_at) 894 { 895 if (verbose) 896 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 897 first_failed_at = i; 898 } 899 } 900 else 901 { 902 if (TEST_FAIL_SIZE == i) 903 { 904 fprintf (stderr, "Request succeed with the largest size.\n"); 905 ret = 1; /* Succeed with largest value */ 906 } 907 } 908 if (0 != ahc_param->header_check_param.num_n1_headers) 909 mhdErrorExitDesc ("Detected unexpected request headers"); 910 if (0 != ahc_param->header_check_param.large_header_name_size) 911 mhdErrorExitDesc ("Detected unexpected large request header"); 912 if (0 != rp_headers_check.num_n1_headers) 913 mhdErrorExitDesc ("Detected unexpected reply headers"); 914 if (0 != rp_headers_check.large_header_name_size) 915 mhdErrorExitDesc ("Detected unexpected large reply header"); 916 917 buf[i] = 'A' + (char) (unsigned char) (i % ('Z' - 'A' + 1)); 918 } 919 } 920 else if (large_req_url) 921 { 922 const size_t base_size = strlen (URL_SCHEME_HOST); 923 char *const url = buf + base_size; 924 925 memcpy (buf, URL_SCHEME_HOST, base_size); 926 url[0] = '/'; 927 for (i = 1; i < TEST_START_SIZE; i++) 928 url[i] = 'a' + (char) (unsigned char) (i % ('z' - 'a' + 1)); 929 for (; i <= TEST_FAIL_SIZE; i++) 930 { 931 url[i] = 0; 932 933 qParam.queryPath = buf; 934 uri_cb_param->uri = url; 935 ahc_param->rq_url = url; 936 937 memset (&ahc_param->header_check_param, 0, 938 sizeof (ahc_param->header_check_param)); 939 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 940 ahc_param->rp_data, 941 ahc_param->rp_data_size)) 942 { 943 if ((0 != qParam.responseCode) && (414 != qParam.responseCode)) 944 { 945 fprintf (stderr, 946 "Got reply with status code %d, " 947 "while code 414 (\"URI Too Long\") is expected.\n", 948 qParam.responseCode); 949 mhdErrorExit (); 950 } 951 if (TEST_OK_SIZE >= i) 952 { 953 fprintf (stderr, 954 "Request failed when running with the valid value size.\n"); 955 ret = 1; /* Failed too early */ 956 } 957 if (0 == first_failed_at) 958 { 959 if (verbose) 960 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 961 first_failed_at = i; 962 } 963 } 964 else 965 { 966 if (TEST_FAIL_SIZE == i) 967 { 968 fprintf (stderr, "Request succeed with the largest size.\n"); 969 ret = 1; /* Succeed with largest value */ 970 } 971 } 972 if (0 != ahc_param->header_check_param.num_n1_headers) 973 mhdErrorExitDesc ("Detected unexpected request headers"); 974 if (0 != ahc_param->header_check_param.large_header_name_size) 975 mhdErrorExitDesc ("Detected unexpected large request header"); 976 if (0 != rp_headers_check.num_n1_headers) 977 mhdErrorExitDesc ("Detected unexpected reply headers"); 978 if (0 != rp_headers_check.large_header_name_size) 979 mhdErrorExitDesc ("Detected unexpected large reply header"); 980 981 url[i] = 'a' + (char) (unsigned char) (i % ('z' - 'a' + 1)); 982 } 983 } 984 else if (large_req_header_name) 985 { 986 buf[0] = '0'; /* Name starts with zero for unique identification */ 987 for (i = 1; i < TEST_START_SIZE; i++) 988 buf[i] = 'a' + (char) (unsigned char) (i % ('z' - 'a' + 1)); 989 for (; i <= TEST_FAIL_SIZE; i++) 990 { 991 struct curl_slist *curl_headers; 992 curl_headers = NULL; 993 994 memcpy (buf + i, ": Z", 3); /* Note: strlen(": Z") is less than strlen(URL_SCHEME_HOST) */ 995 buf[i + 3] = 0; 996 997 curl_headers = curl_slist_append (curl_headers, buf); 998 if (NULL == curl_headers) 999 externalErrorExit (); 1000 1001 qParam.headers = curl_headers; 1002 1003 memset (&ahc_param->header_check_param, 0, 1004 sizeof (ahc_param->header_check_param)); 1005 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 1006 ahc_param->rp_data, 1007 ahc_param->rp_data_size)) 1008 { 1009 if ((0 != qParam.responseCode) && (431 != qParam.responseCode)) 1010 { 1011 fprintf (stderr, 1012 "Got reply with status code %d, while code 431 " 1013 "(\"Request Header Fields Too Large\") is expected.\n", 1014 qParam.responseCode); 1015 mhdErrorExit (); 1016 } 1017 if (0 != ahc_param->header_check_param.large_header_name_size) 1018 { /* If large header was processed, it must be valid */ 1019 if (i != ahc_param->header_check_param.large_header_name_size) 1020 mhdErrorExitDesc ("Detected wrong large request header name size"); 1021 if (1 != ahc_param->header_check_param.large_header_value_size) 1022 mhdErrorExitDesc ("Detected wrong large request header value size"); 1023 if (0 == ahc_param->header_check_param.large_header_valid) 1024 mhdErrorExitDesc ("Detected wrong large request header"); 1025 } 1026 if (TEST_OK_SIZE >= i) 1027 { 1028 fprintf (stderr, 1029 "Request failed when running with the valid value size.\n"); 1030 ret = 1; /* Failed too early */ 1031 } 1032 if (0 == first_failed_at) 1033 { 1034 if (verbose) 1035 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 1036 first_failed_at = i; 1037 } 1038 } 1039 else 1040 { 1041 if (i != ahc_param->header_check_param.large_header_name_size) 1042 mhdErrorExitDesc ("Detected wrong large request header name size"); 1043 if (1 != ahc_param->header_check_param.large_header_value_size) 1044 mhdErrorExitDesc ("Detected wrong large request header value size"); 1045 if (0 == ahc_param->header_check_param.large_header_valid) 1046 mhdErrorExitDesc ("Detected wrong large request header"); 1047 if (TEST_FAIL_SIZE == i) 1048 { 1049 fprintf (stderr, "Request succeed with the largest size.\n"); 1050 ret = 1; /* Succeed with largest value */ 1051 } 1052 } 1053 if (0 != ahc_param->header_check_param.num_n1_headers) 1054 mhdErrorExitDesc ("Detected unexpected request headers"); 1055 if (0 != rp_headers_check.num_n1_headers) 1056 mhdErrorExitDesc ("Detected unexpected reply headers"); 1057 if (0 != rp_headers_check.large_header_name_size) 1058 mhdErrorExitDesc ("Detected unexpected large reply header"); 1059 1060 curl_slist_free_all (curl_headers); 1061 buf[i] = 'a' + (char) (unsigned char) (i % ('z' - 'a' + 1)); 1062 } 1063 } 1064 else if (large_req_header_value) 1065 { 1066 char *const hdr_value = buf + 3; 1067 /* Name starts with zero for unique identification */ 1068 memcpy (buf, "0: ", 3); /* Note: strlen(": Z") is less than strlen(URL_SCHEME_HOST) */ 1069 for (i = 0; i < TEST_START_SIZE; i++) 1070 hdr_value[i] = 'Z' - (char) (unsigned char) (i % ('Z' - 'A' + 1)); 1071 for (; i <= TEST_FAIL_SIZE; i++) 1072 { 1073 struct curl_slist *curl_headers; 1074 curl_headers = NULL; 1075 1076 hdr_value[i] = 0; 1077 1078 curl_headers = curl_slist_append (curl_headers, buf); 1079 if (NULL == curl_headers) 1080 externalErrorExit (); 1081 1082 qParam.headers = curl_headers; 1083 1084 memset (&ahc_param->header_check_param, 0, 1085 sizeof (ahc_param->header_check_param)); 1086 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 1087 ahc_param->rp_data, 1088 ahc_param->rp_data_size)) 1089 { 1090 if ((0 != qParam.responseCode) && (431 != qParam.responseCode)) 1091 { 1092 fprintf (stderr, 1093 "Got reply with status code %d, while code 431 " 1094 "(\"Request Header Fields Too Large\") is expected.\n", 1095 qParam.responseCode); 1096 mhdErrorExit (); 1097 } 1098 if (0 != ahc_param->header_check_param.large_header_name_size) 1099 { /* If large header was processed, it must be valid */ 1100 if (1 != ahc_param->header_check_param.large_header_name_size) 1101 mhdErrorExitDesc ("Detected wrong large request header name size"); 1102 if (i != ahc_param->header_check_param.large_header_value_size) 1103 mhdErrorExitDesc ("Detected wrong large request header value size"); 1104 if (0 == ahc_param->header_check_param.large_header_valid) 1105 mhdErrorExitDesc ("Detected wrong large request header"); 1106 } 1107 if (TEST_OK_SIZE >= i) 1108 { 1109 fprintf (stderr, 1110 "Request failed when running with the valid value size.\n"); 1111 ret = 1; /* Failed too early */ 1112 } 1113 if (0 == first_failed_at) 1114 { 1115 if (verbose) 1116 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 1117 first_failed_at = i; 1118 } 1119 } 1120 else 1121 { 1122 if (1 != ahc_param->header_check_param.large_header_name_size) 1123 mhdErrorExitDesc ("Detected wrong large request header name size"); 1124 if (i != ahc_param->header_check_param.large_header_value_size) 1125 mhdErrorExitDesc ("Detected wrong large request header value size"); 1126 if (0 == ahc_param->header_check_param.large_header_valid) 1127 mhdErrorExitDesc ("Detected wrong large request header"); 1128 if (TEST_FAIL_SIZE == i) 1129 { 1130 fprintf (stderr, "Request succeed with the largest size.\n"); 1131 ret = 1; /* Succeed with largest value */ 1132 } 1133 } 1134 if (0 != ahc_param->header_check_param.num_n1_headers) 1135 mhdErrorExitDesc ("Detected unexpected request headers"); 1136 if (0 != rp_headers_check.num_n1_headers) 1137 mhdErrorExitDesc ("Detected unexpected reply headers"); 1138 if (0 != rp_headers_check.large_header_name_size) 1139 mhdErrorExitDesc ("Detected unexpected large reply header"); 1140 1141 curl_slist_free_all (curl_headers); 1142 hdr_value[i] = 'Z' - (char) (unsigned char) (i % ('Z' - 'A' + 1)); 1143 } 1144 } 1145 else if (large_req_headers) 1146 { 1147 unsigned int num_hdrs = 0; 1148 struct curl_slist *curl_headers; 1149 const size_t hdr_size = strlen (N1_HEADER_CRLF); 1150 1151 curl_headers = NULL; 1152 1153 for (i = 0; i < TEST_RQ_N1_START_SIZE; i += hdr_size) 1154 { 1155 curl_headers = curl_slist_append (curl_headers, N1_HEADER); 1156 if (NULL == curl_headers) 1157 externalErrorExit (); 1158 num_hdrs++; 1159 } 1160 for (; i <= TEST_FAIL_SIZE; i += hdr_size) 1161 { 1162 qParam.headers = curl_headers; 1163 ahc_param->header_check_param.num_n1_headers = num_hdrs; 1164 1165 memset (&ahc_param->header_check_param, 0, 1166 sizeof (ahc_param->header_check_param)); 1167 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 1168 ahc_param->rp_data, 1169 ahc_param->rp_data_size)) 1170 { 1171 if ((0 != qParam.responseCode) && (431 != qParam.responseCode)) 1172 { 1173 fprintf (stderr, 1174 "Got reply with status code %d, while code 431 " 1175 "(\"Request Header Fields Too Large\") is expected.\n", 1176 qParam.responseCode); 1177 mhdErrorExit (); 1178 } 1179 if (0 != ahc_param->header_check_param.num_n1_headers) 1180 { /* If headers were processed, they must be valid */ 1181 if (num_hdrs != ahc_param->header_check_param.num_n1_headers) 1182 mhdErrorExitDesc ("Detected wrong number of request headers"); 1183 } 1184 if (TEST_RQ_N1_OK_SIZE >= i) 1185 { 1186 fprintf (stderr, 1187 "Request failed when running with the valid value size.\n"); 1188 ret = 1; /* Failed too early */ 1189 } 1190 if (0 == first_failed_at) 1191 { 1192 if (verbose) 1193 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 1194 first_failed_at = i; 1195 } 1196 } 1197 else 1198 { 1199 if (num_hdrs != ahc_param->header_check_param.num_n1_headers) 1200 mhdErrorExitDesc ("Detected wrong number of request headers"); 1201 if (TEST_FAIL_SIZE == i) 1202 { 1203 fprintf (stderr, "Request succeed with the largest size.\n"); 1204 ret = 1; /* Succeed with largest value */ 1205 } 1206 } 1207 if (0 != ahc_param->header_check_param.large_header_name_size) 1208 mhdErrorExitDesc ("Detected unexpected large request header"); 1209 if (0 != rp_headers_check.num_n1_headers) 1210 mhdErrorExitDesc ("Detected unexpected reply headers"); 1211 if (0 != rp_headers_check.large_header_name_size) 1212 mhdErrorExitDesc ("Detected unexpected large reply header"); 1213 1214 curl_headers = curl_slist_append (curl_headers, N1_HEADER); 1215 if (NULL == curl_headers) 1216 externalErrorExit (); 1217 num_hdrs++; 1218 } 1219 curl_slist_free_all (curl_headers); 1220 } 1221 else if (large_rsp_header_name) 1222 { 1223 for (i = TEST_START_SIZE; i <= TEST_FAIL_SIZE; i++) 1224 { 1225 ahc_param->rp_large_hdr_name_size = i; 1226 ahc_param->rp_large_hdr_value_size = 1; 1227 1228 memset (&ahc_param->header_check_param, 0, 1229 sizeof (ahc_param->header_check_param)); 1230 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 1231 ahc_param->rp_data, 1232 ahc_param->rp_data_size)) 1233 { 1234 (void) qParam.responseCode; /* TODO: check for the right response code */ 1235 if (0 != rp_headers_check.large_header_name_size) 1236 mhdErrorExitDesc ("Detected unexpected large reply header"); 1237 if (TEST_OK_SIZE >= i) 1238 { 1239 fprintf (stderr, 1240 "Request failed when running with the valid value size.\n"); 1241 ret = 1; /* Failed too early */ 1242 } 1243 if (0 == first_failed_at) 1244 { 1245 if (verbose) 1246 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 1247 first_failed_at = i; 1248 } 1249 } 1250 else 1251 { 1252 if (i != rp_headers_check.large_header_name_size) 1253 mhdErrorExitDesc ("Detected wrong large reply header name size"); 1254 if (1 != rp_headers_check.large_header_value_size) 1255 mhdErrorExitDesc ("Detected wrong large reply header value size"); 1256 if (0 == rp_headers_check.large_header_valid) 1257 mhdErrorExitDesc ("Detected wrong large reply header"); 1258 if (TEST_FAIL_SIZE == i) 1259 { 1260 fprintf (stderr, "Request succeed with the largest size.\n"); 1261 ret = 1; /* Succeed with largest value */ 1262 } 1263 } 1264 if (0 != ahc_param->header_check_param.num_n1_headers) 1265 mhdErrorExitDesc ("Detected unexpected request headers"); 1266 if (0 != ahc_param->header_check_param.large_header_name_size) 1267 mhdErrorExitDesc ("Detected unexpected large request header"); 1268 if (0 != rp_headers_check.num_n1_headers) 1269 mhdErrorExitDesc ("Detected unexpected reply headers"); 1270 } 1271 } 1272 else if (large_rsp_header_value) 1273 { 1274 for (i = TEST_START_SIZE; i <= TEST_FAIL_SIZE; i++) 1275 { 1276 ahc_param->rp_large_hdr_name_size = 1; 1277 ahc_param->rp_large_hdr_value_size = i; 1278 1279 memset (&ahc_param->header_check_param, 0, 1280 sizeof (ahc_param->header_check_param)); 1281 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 1282 ahc_param->rp_data, 1283 ahc_param->rp_data_size)) 1284 { 1285 (void) qParam.responseCode; /* TODO: check for the right response code */ 1286 if (0 != rp_headers_check.large_header_name_size) 1287 mhdErrorExitDesc ("Detected unexpected large reply header"); 1288 if (TEST_OK_SIZE >= i) 1289 { 1290 fprintf (stderr, 1291 "Request failed when running with the valid value size.\n"); 1292 ret = 1; /* Failed too early */ 1293 } 1294 if (0 == first_failed_at) 1295 { 1296 if (verbose) 1297 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 1298 first_failed_at = i; 1299 } 1300 } 1301 else 1302 { 1303 if (1 != rp_headers_check.large_header_name_size) 1304 mhdErrorExitDesc ("Detected wrong large reply header name size"); 1305 if (i != rp_headers_check.large_header_value_size) 1306 mhdErrorExitDesc ("Detected wrong large reply header value size"); 1307 if (0 == rp_headers_check.large_header_valid) 1308 mhdErrorExitDesc ("Detected wrong large reply header"); 1309 if (TEST_FAIL_SIZE == i) 1310 { 1311 fprintf (stderr, "Request succeed with the largest size.\n"); 1312 ret = 1; /* Succeed with largest value */ 1313 } 1314 } 1315 if (0 != ahc_param->header_check_param.num_n1_headers) 1316 mhdErrorExitDesc ("Detected unexpected request headers"); 1317 if (0 != ahc_param->header_check_param.large_header_name_size) 1318 mhdErrorExitDesc ("Detected unexpected large request header"); 1319 if (0 != rp_headers_check.num_n1_headers) 1320 mhdErrorExitDesc ("Detected unexpected reply headers"); 1321 } 1322 } 1323 else if (large_rsp_headers) 1324 { 1325 size_t num_hrds; 1326 const size_t hdr_size = strlen (N1_HEADER_CRLF); 1327 1328 for (num_hrds = TEST_START_SIZE / hdr_size; 1329 num_hrds * hdr_size <= TEST_FAIL_SIZE; num_hrds++) 1330 { 1331 i = num_hrds * hdr_size; 1332 ahc_param->rp_num_n1_hdrs = num_hrds; 1333 1334 memset (&ahc_param->header_check_param, 0, 1335 sizeof (ahc_param->header_check_param)); 1336 if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check, 1337 ahc_param->rp_data, 1338 ahc_param->rp_data_size)) 1339 { 1340 (void) qParam.responseCode; /* TODO: check for the right response code */ 1341 if (0 != rp_headers_check.num_n1_headers) 1342 mhdErrorExitDesc ("Detected unexpected reply headers"); 1343 if (TEST_OK_SIZE >= i) 1344 { 1345 fprintf (stderr, 1346 "Request failed when running with the valid value size.\n"); 1347 ret = 1; /* Failed too early */ 1348 } 1349 if (0 == first_failed_at) 1350 { 1351 if (verbose) 1352 fprintf (stderr, "First failed size is %u.\n", (unsigned int) i); 1353 first_failed_at = i; 1354 } 1355 } 1356 else 1357 { 1358 if (num_hrds != rp_headers_check.num_n1_headers) 1359 mhdErrorExitDesc ("Detected wrong number of reply headers"); 1360 if (TEST_FAIL_SIZE == i) 1361 { 1362 fprintf (stderr, "Request succeed with the largest size.\n"); 1363 ret = 1; /* Succeed with largest value */ 1364 } 1365 } 1366 if (0 != ahc_param->header_check_param.num_n1_headers) 1367 mhdErrorExitDesc ("Detected unexpected request headers"); 1368 if (0 != ahc_param->header_check_param.large_header_name_size) 1369 mhdErrorExitDesc ("Detected unexpected large request header"); 1370 if (0 != rp_headers_check.large_header_name_size) 1371 mhdErrorExitDesc ("Detected unexpected large reply header"); 1372 } 1373 } 1374 else 1375 externalErrorExitDesc ("No valid test test was selected"); 1376 1377 MHD_stop_daemon (d); 1378 free (buf); 1379 free (uri_cb_param); 1380 free (ahc_param); 1381 1382 return ret; 1383 } 1384 1385 1386 enum testMhdThreadsType 1387 { 1388 testMhdThreadExternal = 0, 1389 testMhdThreadInternal = MHD_USE_INTERNAL_POLLING_THREAD, 1390 testMhdThreadInternalPerConnection = MHD_USE_THREAD_PER_CONNECTION 1391 | MHD_USE_INTERNAL_POLLING_THREAD, 1392 testMhdThreadInternalPool 1393 }; 1394 1395 enum testMhdPollType 1396 { 1397 testMhdPollBySelect = 0, 1398 testMhdPollByPoll = MHD_USE_POLL, 1399 testMhdPollByEpoll = MHD_USE_EPOLL, 1400 testMhdPollAuto = MHD_USE_AUTO 1401 }; 1402 1403 /* Get number of threads for thread pool depending 1404 * on used poll function and test type. */ 1405 static unsigned int 1406 testNumThreadsForPool (enum testMhdPollType pollType) 1407 { 1408 unsigned int numThreads = MHD_CPU_COUNT; 1409 (void) pollType; /* Don't care about pollType for this test */ 1410 return numThreads; /* No practical limit for non-cleanup test */ 1411 } 1412 1413 1414 static struct MHD_Daemon * 1415 startTestMhdDaemon (enum testMhdThreadsType thrType, 1416 enum testMhdPollType pollType, uint16_t *pport, 1417 struct ahc_cls_type **ahc_param, 1418 struct check_uri_cls **uri_cb_param) 1419 { 1420 struct MHD_Daemon *d; 1421 const union MHD_DaemonInfo *dinfo; 1422 1423 if ((NULL == ahc_param) || (NULL == uri_cb_param)) 1424 abort (); 1425 1426 *ahc_param = (struct ahc_cls_type *) malloc (sizeof(struct ahc_cls_type)); 1427 if (NULL == *ahc_param) 1428 externalErrorExit (); 1429 *uri_cb_param = 1430 (struct check_uri_cls *) malloc (sizeof(struct check_uri_cls)); 1431 if (NULL == *uri_cb_param) 1432 externalErrorExit (); 1433 1434 if ( (0 == *pport) && 1435 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) 1436 { 1437 *pport = 4100; 1438 if (large_req_method) 1439 *pport += 1; 1440 if (large_req_url) 1441 *pport += 2; 1442 if (large_req_header_name) 1443 *pport += 3; 1444 if (large_req_header_value) 1445 *pport += 4; 1446 if (large_req_headers) 1447 *pport += 5; 1448 if (large_rsp_header_name) 1449 *pport += 6; 1450 if (large_rsp_header_value) 1451 *pport += 7; 1452 if (large_rsp_headers) 1453 *pport += 8; 1454 if (! oneone) 1455 *pport += 16; 1456 } 1457 1458 if (testMhdThreadExternal == thrType) 1459 d = MHD_start_daemon (((unsigned int) thrType) | ((unsigned int) pollType) 1460 | (verbose ? MHD_USE_ERROR_LOG : 0) 1461 | MHD_USE_NO_THREAD_SAFETY, 1462 *pport, NULL, NULL, 1463 &ahcCheck, *ahc_param, 1464 MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb, 1465 *uri_cb_param, 1466 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 1467 (size_t) BUFFER_SIZE, 1468 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 1469 MHD_OPTION_END); 1470 else if (testMhdThreadInternalPool != thrType) 1471 d = MHD_start_daemon (((unsigned int) thrType) | ((unsigned int) pollType) 1472 | (verbose ? MHD_USE_ERROR_LOG : 0), 1473 *pport, NULL, NULL, 1474 &ahcCheck, *ahc_param, 1475 MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb, 1476 *uri_cb_param, 1477 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 1478 (size_t) BUFFER_SIZE, 1479 MHD_OPTION_END); 1480 else 1481 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD 1482 | ((unsigned int) pollType) 1483 | (verbose ? MHD_USE_ERROR_LOG : 0), 1484 *pport, NULL, NULL, 1485 &ahcCheck, *ahc_param, 1486 MHD_OPTION_THREAD_POOL_SIZE, 1487 testNumThreadsForPool (pollType), 1488 MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb, 1489 *uri_cb_param, 1490 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 1491 (size_t) BUFFER_SIZE, 1492 MHD_OPTION_END); 1493 1494 if (NULL == d) 1495 { 1496 fprintf (stderr, "Failed to start MHD daemon, errno=%d.\n", errno); 1497 abort (); 1498 } 1499 1500 if (0 == *pport) 1501 { 1502 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 1503 if ((NULL == dinfo) || (0 == dinfo->port) ) 1504 { 1505 fprintf (stderr, "MHD_get_daemon_info() failed.\n"); 1506 abort (); 1507 } 1508 *pport = dinfo->port; 1509 if (0 == global_port) 1510 global_port = *pport; /* Reuse the same port for all tests */ 1511 } 1512 1513 return d; 1514 } 1515 1516 1517 /* Test runners */ 1518 1519 1520 static unsigned int 1521 testExternalGet (void) 1522 { 1523 struct MHD_Daemon *d; 1524 uint16_t d_port = global_port; /* Daemon's port */ 1525 struct ahc_cls_type *ahc_param; 1526 struct check_uri_cls *uri_cb_param; 1527 1528 d = startTestMhdDaemon (testMhdThreadExternal, testMhdPollBySelect, &d_port, 1529 &ahc_param, &uri_cb_param); 1530 1531 return performTestQueries (d, d_port, ahc_param, uri_cb_param); 1532 } 1533 1534 1535 static unsigned int 1536 testInternalGet (enum testMhdPollType pollType) 1537 { 1538 struct MHD_Daemon *d; 1539 uint16_t d_port = global_port; /* Daemon's port */ 1540 struct ahc_cls_type *ahc_param; 1541 struct check_uri_cls *uri_cb_param; 1542 1543 d = startTestMhdDaemon (testMhdThreadInternal, pollType, &d_port, 1544 &ahc_param, &uri_cb_param); 1545 1546 return performTestQueries (d, d_port, ahc_param, uri_cb_param); 1547 } 1548 1549 1550 static unsigned int 1551 testMultithreadedGet (enum testMhdPollType pollType) 1552 { 1553 struct MHD_Daemon *d; 1554 uint16_t d_port = global_port; /* Daemon's port */ 1555 struct ahc_cls_type *ahc_param; 1556 struct check_uri_cls *uri_cb_param; 1557 1558 d = startTestMhdDaemon (testMhdThreadInternalPerConnection, pollType, &d_port, 1559 &ahc_param, &uri_cb_param); 1560 return performTestQueries (d, d_port, ahc_param, uri_cb_param); 1561 } 1562 1563 1564 static unsigned int 1565 testMultithreadedPoolGet (enum testMhdPollType pollType) 1566 { 1567 struct MHD_Daemon *d; 1568 uint16_t d_port = global_port; /* Daemon's port */ 1569 struct ahc_cls_type *ahc_param; 1570 struct check_uri_cls *uri_cb_param; 1571 1572 d = startTestMhdDaemon (testMhdThreadInternalPool, pollType, &d_port, 1573 &ahc_param, &uri_cb_param); 1574 return performTestQueries (d, d_port, ahc_param, uri_cb_param); 1575 } 1576 1577 1578 int 1579 main (int argc, char *const *argv) 1580 { 1581 unsigned int errorCount = 0; 1582 unsigned int test_result = 0; 1583 verbose = 0; 1584 1585 if ((NULL == argv) || (0 == argv[0])) 1586 return 99; 1587 oneone = ! has_in_name (argv[0], "10"); 1588 large_req_method = has_in_name (argv[0], "_method") ? 1 : 0; 1589 large_req_url = has_in_name (argv[0], "_url") ? 1 : 0; 1590 large_req_header_name = has_in_name (argv[0], "_request_header_name") ? 1591 1 : 0; 1592 large_req_header_value = has_in_name (argv[0], "_request_header_value") ? 1593 1 : 0; 1594 large_req_headers = has_in_name (argv[0], "_request_headers") ? 1 : 0; 1595 large_rsp_header_name = has_in_name (argv[0], "_reply_header_name") ? 1596 1 : 0; 1597 large_rsp_header_value = has_in_name (argv[0], "_reply_header_value") ? 1598 1 : 0; 1599 large_rsp_headers = has_in_name (argv[0], "_reply_headers") ? 1 : 0; 1600 if (large_req_method + large_req_url + large_req_header_name 1601 + large_req_header_value + large_req_headers + large_rsp_header_name 1602 + large_rsp_header_value + large_rsp_headers != 1) 1603 return 99; 1604 verbose = ! (has_param (argc, argv, "-q") || 1605 has_param (argc, argv, "--quiet") || 1606 has_param (argc, argv, "-s") || 1607 has_param (argc, argv, "--silent")); 1608 1609 test_global_init (); 1610 1611 /* Could be set to non-zero value to enforce using specific port 1612 * in the test */ 1613 global_port = 0; 1614 test_result = testExternalGet (); 1615 if (test_result) 1616 fprintf (stderr, "FAILED: testExternalGet () - %u.\n", test_result); 1617 else if (verbose) 1618 printf ("PASSED: testExternalGet ().\n"); 1619 errorCount += test_result; 1620 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 1621 { 1622 test_result = testInternalGet (testMhdPollAuto); 1623 if (test_result) 1624 fprintf (stderr, "FAILED: testInternalGet (testMhdPollAuto) - %u.\n", 1625 test_result); 1626 else if (verbose) 1627 printf ("PASSED: testInternalGet (testMhdPollBySelect).\n"); 1628 errorCount += test_result; 1629 #ifdef _MHD_HEAVY_TESTS 1630 /* Actually tests are not heavy, but took too long to complete while 1631 * not really provide any additional results. */ 1632 test_result = testInternalGet (testMhdPollBySelect); 1633 if (test_result) 1634 fprintf (stderr, "FAILED: testInternalGet (testMhdPollBySelect) - %u.\n", 1635 test_result); 1636 else if (verbose) 1637 printf ("PASSED: testInternalGet (testMhdPollBySelect).\n"); 1638 errorCount += test_result; 1639 test_result = testMultithreadedPoolGet (testMhdPollBySelect); 1640 if (test_result) 1641 fprintf (stderr, 1642 "FAILED: testMultithreadedPoolGet (testMhdPollBySelect) - %u.\n", 1643 test_result); 1644 else if (verbose) 1645 printf ("PASSED: testMultithreadedPoolGet (testMhdPollBySelect).\n"); 1646 errorCount += test_result; 1647 test_result = testMultithreadedGet (testMhdPollBySelect); 1648 if (test_result) 1649 fprintf (stderr, 1650 "FAILED: testMultithreadedGet (testMhdPollBySelect) - %u.\n", 1651 test_result); 1652 else if (verbose) 1653 printf ("PASSED: testMultithreadedGet (testMhdPollBySelect).\n"); 1654 errorCount += test_result; 1655 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL)) 1656 { 1657 test_result = testInternalGet (testMhdPollByPoll); 1658 if (test_result) 1659 fprintf (stderr, "FAILED: testInternalGet (testMhdPollByPoll) - %u.\n", 1660 test_result); 1661 else if (verbose) 1662 printf ("PASSED: testInternalGet (testMhdPollByPoll).\n"); 1663 errorCount += test_result; 1664 } 1665 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL)) 1666 { 1667 test_result = testInternalGet (testMhdPollByEpoll); 1668 if (test_result) 1669 fprintf (stderr, "FAILED: testInternalGet (testMhdPollByEpoll) - %u.\n", 1670 test_result); 1671 else if (verbose) 1672 printf ("PASSED: testInternalGet (testMhdPollByEpoll).\n"); 1673 errorCount += test_result; 1674 } 1675 #else 1676 /* Mute compiler warnings */ 1677 (void) testMultithreadedGet; 1678 (void) testMultithreadedPoolGet; 1679 #endif /* _MHD_HEAVY_TESTS */ 1680 } 1681 if (0 != errorCount) 1682 fprintf (stderr, 1683 "Error (code: %u)\n", 1684 errorCount); 1685 else if (verbose) 1686 printf ("All tests passed.\n"); 1687 1688 test_global_cleanup (); 1689 1690 return (errorCount == 0) ? 0 : 1; /* 0 == pass */ 1691 }