test_get_empty.c (27987B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2009, 2011, 2019 Christian Grothoff 4 Copyright (C) 2014-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 * @file test_get_empty.c 23 * @brief Testcase for libmicrohttpd GET operations returning an empty body 24 * @author Christian Grothoff 25 * @author Karlson2k (Evgeny Grin) 26 */ 27 #include "MHD_config.h" 28 #include "platform.h" 29 #include <curl/curl.h> 30 #include <microhttpd.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <time.h> 34 #include <errno.h> 35 #include "mhd_has_in_name.h" 36 #include "mhd_has_param.h" 37 #include "mhd_sockets.h" /* only macros used */ 38 39 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 40 test into a marked, classifiable test error (TESTING.md, P5). */ 41 #include "mhd_panic_tripwire.h" 42 43 44 #define EXPECTED_URI_PATH "/hello_world?a=%26&b=c" 45 46 #ifdef _WIN32 47 #ifndef WIN32_LEAN_AND_MEAN 48 #define WIN32_LEAN_AND_MEAN 1 49 #endif /* !WIN32_LEAN_AND_MEAN */ 50 #include <windows.h> 51 #endif 52 53 #ifndef WINDOWS 54 #include <unistd.h> 55 #include <sys/socket.h> 56 #endif 57 58 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2 59 #undef MHD_CPU_COUNT 60 #endif 61 #if ! defined(MHD_CPU_COUNT) 62 #define MHD_CPU_COUNT 2 63 #endif 64 65 static int oneone; 66 static uint16_t global_port; 67 68 struct CBC 69 { 70 char *buf; 71 size_t pos; 72 size_t size; 73 }; 74 75 76 static size_t 77 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 78 { 79 struct CBC *cbc = ctx; 80 81 if (cbc->pos + size * nmemb > cbc->size) 82 return 0; /* overflow */ 83 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 84 cbc->pos += size * nmemb; 85 return size * nmemb; 86 } 87 88 89 static void * 90 log_cb (void *cls, 91 const char *uri, 92 struct MHD_Connection *con) 93 { 94 (void) cls; 95 (void) con; 96 if (0 != strcmp (uri, 97 EXPECTED_URI_PATH)) 98 { 99 fprintf (stderr, 100 "Wrong URI: `%s'\n", 101 uri); 102 _exit (22); 103 } 104 return NULL; 105 } 106 107 108 static int 109 ahc_echo (void *cls, 110 struct MHD_Connection *connection, 111 const char *url, 112 const char *method, 113 const char *version, 114 const char *upload_data, size_t *upload_data_size, 115 void **req_cls) 116 { 117 static int ptr; 118 const char *me = cls; 119 struct MHD_Response *response; 120 int ret; 121 (void) version; 122 (void) upload_data; 123 (void) upload_data_size; /* Unused. Silence compiler warning. */ 124 125 if (0 != strcmp (me, method)) 126 return MHD_NO; /* unexpected method */ 127 if (&ptr != *req_cls) 128 { 129 *req_cls = &ptr; 130 return MHD_YES; 131 } 132 *req_cls = NULL; 133 response = MHD_create_response_empty (MHD_RF_NONE); 134 ret = MHD_queue_response (connection, 135 MHD_HTTP_NO_CONTENT, 136 response); 137 MHD_destroy_response (response); 138 if (ret == MHD_NO) 139 { 140 fprintf (stderr, "Failed to queue response.\n"); 141 _exit (19); 142 } 143 return ret; 144 } 145 146 147 static unsigned int 148 testInternalGet (uint32_t poll_flag) 149 { 150 struct MHD_Daemon *d; 151 CURL *c; 152 char buf[2048]; 153 struct CBC cbc; 154 CURLcode errornum; 155 156 if ( (0 == global_port) && 157 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) 158 { 159 global_port = 1220; 160 if (oneone) 161 global_port += 20; 162 } 163 164 cbc.buf = buf; 165 cbc.size = 2048; 166 cbc.pos = 0; 167 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 168 | (enum MHD_FLAG) poll_flag, 169 global_port, NULL, NULL, 170 &ahc_echo, "GET", 171 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 172 MHD_OPTION_END); 173 if (d == NULL) 174 return 1; 175 if (0 == global_port) 176 { 177 const union MHD_DaemonInfo *dinfo; 178 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 179 if ((NULL == dinfo) || (0 == dinfo->port) ) 180 { 181 MHD_stop_daemon (d); return 32; 182 } 183 global_port = dinfo->port; 184 } 185 c = curl_easy_init (); 186 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH); 187 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port); 188 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 189 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 190 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 191 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 192 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 193 if (oneone) 194 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 195 else 196 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 197 /* NOTE: use of CONNECTTIMEOUT without also 198 setting NOSIGNAL results in really weird 199 crashes on my system!*/ 200 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 201 if (CURLE_OK != (errornum = curl_easy_perform (c))) 202 { 203 fprintf (stderr, 204 "curl_easy_perform failed: `%s'\n", 205 curl_easy_strerror (errornum)); 206 curl_easy_cleanup (c); 207 MHD_stop_daemon (d); 208 return 2; 209 } 210 curl_easy_cleanup (c); 211 MHD_stop_daemon (d); 212 if (cbc.pos != 0) 213 return 4; 214 return 0; 215 } 216 217 218 static unsigned int 219 testMultithreadedGet (uint32_t poll_flag) 220 { 221 struct MHD_Daemon *d; 222 CURL *c; 223 char buf[2048]; 224 struct CBC cbc; 225 CURLcode errornum; 226 227 if ( (0 == global_port) && 228 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) 229 { 230 global_port = 1221; 231 if (oneone) 232 global_port += 20; 233 } 234 235 cbc.buf = buf; 236 cbc.size = 2048; 237 cbc.pos = 0; 238 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 239 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 240 | (enum MHD_FLAG) poll_flag, 241 global_port, NULL, NULL, 242 &ahc_echo, "GET", 243 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 244 MHD_OPTION_END); 245 if (d == NULL) 246 return 16; 247 if (0 == global_port) 248 { 249 const union MHD_DaemonInfo *dinfo; 250 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 251 if ((NULL == dinfo) || (0 == dinfo->port) ) 252 { 253 MHD_stop_daemon (d); return 32; 254 } 255 global_port = dinfo->port; 256 } 257 c = curl_easy_init (); 258 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH); 259 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port); 260 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 261 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 262 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 263 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 264 if (oneone) 265 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 266 else 267 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 268 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 269 /* NOTE: use of CONNECTTIMEOUT without also 270 setting NOSIGNAL results in really weird 271 crashes on my system! */ 272 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 273 if (CURLE_OK != (errornum = curl_easy_perform (c))) 274 { 275 fprintf (stderr, 276 "curl_easy_perform failed: `%s'\n", 277 curl_easy_strerror (errornum)); 278 curl_easy_cleanup (c); 279 MHD_stop_daemon (d); 280 return 32; 281 } 282 curl_easy_cleanup (c); 283 MHD_stop_daemon (d); 284 if (cbc.pos != 0) 285 return 64; 286 return 0; 287 } 288 289 290 static unsigned int 291 testMultithreadedPoolGet (uint32_t poll_flag) 292 { 293 struct MHD_Daemon *d; 294 CURL *c; 295 char buf[2048]; 296 struct CBC cbc; 297 CURLcode errornum; 298 299 if ( (0 == global_port) && 300 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) 301 { 302 global_port = 1222; 303 if (oneone) 304 global_port += 20; 305 } 306 307 cbc.buf = buf; 308 cbc.size = 2048; 309 cbc.pos = 0; 310 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 311 | (enum MHD_FLAG) poll_flag, 312 global_port, NULL, NULL, 313 &ahc_echo, "GET", 314 MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT, 315 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 316 MHD_OPTION_END); 317 if (d == NULL) 318 return 16; 319 if (0 == global_port) 320 { 321 const union MHD_DaemonInfo *dinfo; 322 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 323 if ((NULL == dinfo) || (0 == dinfo->port) ) 324 { 325 MHD_stop_daemon (d); return 32; 326 } 327 global_port = dinfo->port; 328 } 329 c = curl_easy_init (); 330 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH); 331 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port); 332 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 333 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 334 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 335 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 336 if (oneone) 337 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 338 else 339 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 340 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 341 /* NOTE: use of CONNECTTIMEOUT without also 342 setting NOSIGNAL results in really weird 343 crashes on my system!*/ 344 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 345 if (CURLE_OK != (errornum = curl_easy_perform (c))) 346 { 347 fprintf (stderr, 348 "curl_easy_perform failed: `%s'\n", 349 curl_easy_strerror (errornum)); 350 curl_easy_cleanup (c); 351 MHD_stop_daemon (d); 352 return 32; 353 } 354 curl_easy_cleanup (c); 355 MHD_stop_daemon (d); 356 if (cbc.pos != 0) 357 return 64; 358 return 0; 359 } 360 361 362 static unsigned int 363 testExternalGet () 364 { 365 struct MHD_Daemon *d; 366 CURL *c; 367 char buf[2048]; 368 struct CBC cbc; 369 CURLM *multi; 370 CURLMcode mret; 371 fd_set rs; 372 fd_set ws; 373 fd_set es; 374 MHD_socket maxsock; 375 int maxposixs; 376 int running; 377 struct CURLMsg *msg; 378 time_t start; 379 struct timeval tv; 380 381 if ( (0 == global_port) && 382 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) 383 { 384 global_port = 1223; 385 if (oneone) 386 global_port += 20; 387 } 388 389 multi = NULL; 390 cbc.buf = buf; 391 cbc.size = 2048; 392 cbc.pos = 0; 393 d = MHD_start_daemon (MHD_USE_ERROR_LOG, 394 global_port, NULL, NULL, 395 &ahc_echo, "GET", 396 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 397 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 398 MHD_OPTION_END); 399 if (d == NULL) 400 return 256; 401 if (0 == global_port) 402 { 403 const union MHD_DaemonInfo *dinfo; 404 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 405 if ((NULL == dinfo) || (0 == dinfo->port) ) 406 { 407 MHD_stop_daemon (d); return 32; 408 } 409 global_port = dinfo->port; 410 } 411 c = curl_easy_init (); 412 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH); 413 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port); 414 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 415 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 416 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 417 if (oneone) 418 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 419 else 420 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 421 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 422 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 423 /* NOTE: use of CONNECTTIMEOUT without also 424 setting NOSIGNAL results in really weird 425 crashes on my system! */ 426 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 427 428 429 multi = curl_multi_init (); 430 if (multi == NULL) 431 { 432 curl_easy_cleanup (c); 433 MHD_stop_daemon (d); 434 return 512; 435 } 436 mret = curl_multi_add_handle (multi, c); 437 if (mret != CURLM_OK) 438 { 439 curl_multi_cleanup (multi); 440 curl_easy_cleanup (c); 441 MHD_stop_daemon (d); 442 return 1024; 443 } 444 start = time (NULL); 445 while ((time (NULL) - start < 5) && (multi != NULL)) 446 { 447 maxsock = MHD_INVALID_SOCKET; 448 maxposixs = -1; 449 FD_ZERO (&rs); 450 FD_ZERO (&ws); 451 FD_ZERO (&es); 452 curl_multi_perform (multi, &running); 453 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); 454 if (mret != CURLM_OK) 455 { 456 curl_multi_remove_handle (multi, c); 457 curl_multi_cleanup (multi); 458 curl_easy_cleanup (c); 459 MHD_stop_daemon (d); 460 return 2048; 461 } 462 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) 463 { 464 curl_multi_remove_handle (multi, c); 465 curl_multi_cleanup (multi); 466 curl_easy_cleanup (c); 467 MHD_stop_daemon (d); 468 return 4096; 469 } 470 tv.tv_sec = 0; 471 tv.tv_usec = 1000; 472 #ifdef MHD_POSIX_SOCKETS 473 if (maxsock > maxposixs) 474 maxposixs = maxsock; 475 #endif /* MHD_POSIX_SOCKETS */ 476 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) 477 { 478 #ifdef MHD_POSIX_SOCKETS 479 if (EINTR != errno) 480 { 481 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 482 (int) errno, __LINE__); 483 fflush (stderr); 484 exit (99); 485 } 486 #else 487 if ((WSAEINVAL != WSAGetLastError ()) || 488 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 489 { 490 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 491 (int) WSAGetLastError (), __LINE__); 492 fflush (stderr); 493 exit (99); 494 } 495 Sleep (1); 496 #endif 497 } 498 curl_multi_perform (multi, &running); 499 if (0 == running) 500 { 501 int pending; 502 int curl_fine = 0; 503 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 504 { 505 if (msg->msg == CURLMSG_DONE) 506 { 507 if (msg->data.result == CURLE_OK) 508 curl_fine = 1; 509 else 510 { 511 fprintf (stderr, 512 "%s failed at %s:%d: `%s'\n", 513 "curl_multi_perform", 514 __FILE__, 515 __LINE__, curl_easy_strerror (msg->data.result)); 516 abort (); 517 } 518 } 519 } 520 if (! curl_fine) 521 { 522 fprintf (stderr, "libcurl haven't returned OK code\n"); 523 abort (); 524 } 525 curl_multi_remove_handle (multi, c); 526 curl_multi_cleanup (multi); 527 curl_easy_cleanup (c); 528 c = NULL; 529 multi = NULL; 530 } 531 MHD_run (d); 532 } 533 if (multi != NULL) 534 { 535 curl_multi_remove_handle (multi, c); 536 curl_easy_cleanup (c); 537 curl_multi_cleanup (multi); 538 } 539 MHD_stop_daemon (d); 540 if (cbc.pos != 0) 541 return 8192; 542 return 0; 543 } 544 545 546 static unsigned int 547 testUnknownPortGet (uint32_t poll_flag) 548 { 549 struct MHD_Daemon *d; 550 const union MHD_DaemonInfo *di; 551 CURL *c; 552 char buf[2048]; 553 struct CBC cbc; 554 CURLcode errornum; 555 uint16_t port; 556 557 struct sockaddr_in addr; 558 socklen_t addr_len = sizeof(addr); 559 memset (&addr, 0, sizeof(addr)); 560 addr.sin_family = AF_INET; 561 addr.sin_port = 0; 562 addr.sin_addr.s_addr = INADDR_ANY; 563 564 cbc.buf = buf; 565 cbc.size = 2048; 566 cbc.pos = 0; 567 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 568 | (enum MHD_FLAG) poll_flag, 569 0, NULL, NULL, &ahc_echo, "GET", 570 MHD_OPTION_SOCK_ADDR, &addr, 571 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 572 MHD_OPTION_END); 573 if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 574 { 575 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD); 576 if (di == NULL) 577 return 65536; 578 579 if (0 != getsockname (di->listen_fd, (struct sockaddr *) &addr, &addr_len)) 580 return 131072; 581 582 if (addr.sin_family != AF_INET) 583 return 26214; 584 port = ntohs (addr.sin_port); 585 } 586 else 587 { 588 const union MHD_DaemonInfo *dinfo; 589 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 590 if ((NULL == dinfo) || (0 == dinfo->port) ) 591 { 592 MHD_stop_daemon (d); return 32; 593 } 594 port = dinfo->port; 595 } 596 597 snprintf (buf, 598 sizeof(buf), 599 "http://127.0.0.1:%u%s", 600 (unsigned int) port, 601 EXPECTED_URI_PATH); 602 603 c = curl_easy_init (); 604 curl_easy_setopt (c, CURLOPT_URL, buf); 605 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 606 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 607 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 608 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 609 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 610 if (oneone) 611 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 612 else 613 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 614 /* NOTE: use of CONNECTTIMEOUT without also 615 setting NOSIGNAL results in really weird 616 crashes on my system! */ 617 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 618 if (CURLE_OK != (errornum = curl_easy_perform (c))) 619 { 620 fprintf (stderr, 621 "curl_easy_perform failed: `%s'\n", 622 curl_easy_strerror (errornum)); 623 curl_easy_cleanup (c); 624 MHD_stop_daemon (d); 625 return 524288; 626 } 627 curl_easy_cleanup (c); 628 MHD_stop_daemon (d); 629 if (cbc.pos != 0) 630 return 1048576; 631 return 0; 632 } 633 634 635 static unsigned int 636 testStopRace (uint32_t poll_flag) 637 { 638 struct sockaddr_in sin; 639 MHD_socket fd; 640 struct MHD_Daemon *d; 641 642 if ( (0 == global_port) && 643 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) 644 { 645 global_port = 1224; 646 if (oneone) 647 global_port += 20; 648 } 649 650 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 651 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 652 | (enum MHD_FLAG) poll_flag, 653 global_port, NULL, NULL, 654 &ahc_echo, "GET", 655 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 656 MHD_OPTION_END); 657 if (d == NULL) 658 return 16; 659 if (0 == global_port) 660 { 661 const union MHD_DaemonInfo *dinfo; 662 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 663 if ((NULL == dinfo) || (0 == dinfo->port) ) 664 { 665 MHD_stop_daemon (d); return 32; 666 } 667 global_port = dinfo->port; 668 } 669 670 fd = socket (PF_INET, SOCK_STREAM, 0); 671 if (fd == MHD_INVALID_SOCKET) 672 { 673 fprintf (stderr, "socket error\n"); 674 return 256; 675 } 676 677 memset (&sin, 0, sizeof(sin)); 678 sin.sin_family = AF_INET; 679 sin.sin_port = htons (global_port); 680 sin.sin_addr.s_addr = htonl (0x7f000001); 681 682 if (connect (fd, (struct sockaddr *) (&sin), sizeof(sin)) < 0) 683 { 684 fprintf (stderr, "connect error\n"); 685 MHD_socket_close_chk_ (fd); 686 return 512; 687 } 688 689 /* printf("Waiting\n"); */ 690 /* Let the thread get going. */ 691 usleep (500000); 692 693 /* printf("Stopping daemon\n"); */ 694 MHD_stop_daemon (d); 695 696 MHD_socket_close_chk_ (fd); 697 698 /* printf("good\n"); */ 699 return 0; 700 } 701 702 703 static int 704 ahc_empty (void *cls, 705 struct MHD_Connection *connection, 706 const char *url, 707 const char *method, 708 const char *version, 709 const char *upload_data, size_t *upload_data_size, 710 void **req_cls) 711 { 712 static int ptr; 713 struct MHD_Response *response; 714 int ret; 715 (void) cls; 716 (void) url; 717 (void) url; 718 (void) version; /* Unused. Silence compiler warning. */ 719 (void) upload_data; 720 (void) upload_data_size; /* Unused. Silent compiler warning. */ 721 722 if (0 != strcmp ("GET", method)) 723 return MHD_NO; /* unexpected method */ 724 if (&ptr != *req_cls) 725 { 726 *req_cls = &ptr; 727 return MHD_YES; 728 } 729 *req_cls = NULL; 730 response = MHD_create_response_empty (MHD_RF_NONE); 731 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 732 MHD_destroy_response (response); 733 if (ret == MHD_NO) 734 { 735 fprintf (stderr, "Failed to queue response.\n"); 736 _exit (20); 737 } 738 return ret; 739 } 740 741 742 static int 743 curlExcessFound (CURL *c, curl_infotype type, char *data, size_t size, 744 void *cls) 745 { 746 static const char *excess_found = "Excess found"; 747 const size_t str_size = strlen (excess_found); 748 (void) c; /* Unused. Silent compiler warning. */ 749 750 if ((CURLINFO_TEXT == type) 751 && (size >= str_size) 752 && (0 == strncmp (excess_found, data, str_size))) 753 *(int *) cls = 1; 754 return 0; 755 } 756 757 758 static unsigned int 759 testEmptyGet (uint32_t poll_flag) 760 { 761 struct MHD_Daemon *d; 762 CURL *c; 763 char buf[2048]; 764 struct CBC cbc; 765 CURLcode errornum; 766 int excess_found = 0; 767 768 if ( (0 == global_port) && 769 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) 770 { 771 global_port = 1225; 772 if (oneone) 773 global_port += 20; 774 } 775 776 cbc.buf = buf; 777 cbc.size = 2048; 778 cbc.pos = 0; 779 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 780 | (enum MHD_FLAG) poll_flag, 781 global_port, NULL, NULL, 782 &ahc_empty, NULL, 783 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 784 MHD_OPTION_END); 785 if (d == NULL) 786 return 4194304; 787 if (0 == global_port) 788 { 789 const union MHD_DaemonInfo *dinfo; 790 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 791 if ((NULL == dinfo) || (0 == dinfo->port) ) 792 { 793 MHD_stop_daemon (d); return 32; 794 } 795 global_port = dinfo->port; 796 } 797 c = curl_easy_init (); 798 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH); 799 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port); 800 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 801 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 802 curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, &curlExcessFound); 803 curl_easy_setopt (c, CURLOPT_DEBUGDATA, &excess_found); 804 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); 805 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 806 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 807 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 808 if (oneone) 809 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 810 else 811 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 812 /* NOTE: use of CONNECTTIMEOUT without also 813 setting NOSIGNAL results in really weird 814 crashes on my system!*/ 815 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 816 if (CURLE_OK != (errornum = curl_easy_perform (c))) 817 { 818 fprintf (stderr, 819 "curl_easy_perform failed: `%s'\n", 820 curl_easy_strerror (errornum)); 821 curl_easy_cleanup (c); 822 MHD_stop_daemon (d); 823 return 8388608; 824 } 825 curl_easy_cleanup (c); 826 MHD_stop_daemon (d); 827 if (cbc.pos != 0) 828 return 16777216; 829 if (excess_found) 830 return 33554432; 831 return 0; 832 } 833 834 835 int 836 main (int argc, char *const *argv) 837 { 838 unsigned int errorCount = 0; 839 unsigned int test_result = 0; 840 int verbose = 0; 841 842 if ((NULL == argv) || (0 == argv[0])) 843 return 99; 844 oneone = has_in_name (argv[0], "11"); 845 verbose = has_param (argc, argv, "-v") || has_param (argc, argv, "--verbose"); 846 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 847 return 2; 848 global_port = 0; 849 test_result = testExternalGet (); 850 if (test_result) 851 fprintf (stderr, "FAILED: testExternalGet () - %u.\n", test_result); 852 else if (verbose) 853 printf ("PASSED: testExternalGet ().\n"); 854 errorCount += test_result; 855 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 856 { 857 test_result += testInternalGet (0); 858 if (test_result) 859 fprintf (stderr, "FAILED: testInternalGet (0) - %u.\n", test_result); 860 else if (verbose) 861 printf ("PASSED: testInternalGet (0).\n"); 862 errorCount += test_result; 863 test_result += testMultithreadedGet (0); 864 if (test_result) 865 fprintf (stderr, "FAILED: testMultithreadedGet (0) - %u.\n", test_result); 866 else if (verbose) 867 printf ("PASSED: testMultithreadedGet (0).\n"); 868 errorCount += test_result; 869 test_result += testMultithreadedPoolGet (0); 870 if (test_result) 871 fprintf (stderr, "FAILED: testMultithreadedPoolGet (0) - %u.\n", 872 test_result); 873 else if (verbose) 874 printf ("PASSED: testMultithreadedPoolGet (0).\n"); 875 errorCount += test_result; 876 test_result += testUnknownPortGet (0); 877 if (test_result) 878 fprintf (stderr, "FAILED: testUnknownPortGet (0) - %u.\n", test_result); 879 else if (verbose) 880 printf ("PASSED: testUnknownPortGet (0).\n"); 881 errorCount += test_result; 882 test_result += testEmptyGet (0); 883 if (test_result) 884 fprintf (stderr, "FAILED: testEmptyGet (0) - %u.\n", test_result); 885 else if (verbose) 886 printf ("PASSED: testEmptyGet (0).\n"); 887 errorCount += test_result; 888 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL)) 889 { 890 test_result += testInternalGet (MHD_USE_POLL); 891 if (test_result) 892 fprintf (stderr, "FAILED: testInternalGet (MHD_USE_POLL) - %u.\n", 893 test_result); 894 else if (verbose) 895 printf ("PASSED: testInternalGet (MHD_USE_POLL).\n"); 896 errorCount += test_result; 897 test_result += testMultithreadedGet (MHD_USE_POLL); 898 if (test_result) 899 fprintf (stderr, "FAILED: testMultithreadedGet (MHD_USE_POLL) - %u.\n", 900 test_result); 901 else if (verbose) 902 printf ("PASSED: testMultithreadedGet (MHD_USE_POLL).\n"); 903 errorCount += test_result; 904 test_result += testMultithreadedPoolGet (MHD_USE_POLL); 905 if (test_result) 906 fprintf (stderr, 907 "FAILED: testMultithreadedPoolGet (MHD_USE_POLL) - %u.\n", 908 test_result); 909 else if (verbose) 910 printf ("PASSED: testMultithreadedPoolGet (MHD_USE_POLL).\n"); 911 errorCount += test_result; 912 test_result += testUnknownPortGet (MHD_USE_POLL); 913 if (test_result) 914 fprintf (stderr, "FAILED: testUnknownPortGet (MHD_USE_POLL) - %u.\n", 915 test_result); 916 else if (verbose) 917 printf ("PASSED: testUnknownPortGet (MHD_USE_POLL).\n"); 918 errorCount += test_result; 919 test_result += testEmptyGet (MHD_USE_POLL); 920 if (test_result) 921 fprintf (stderr, "FAILED: testEmptyGet (MHD_USE_POLL) - %u.\n", 922 test_result); 923 else if (verbose) 924 printf ("PASSED: testEmptyGet (MHD_USE_POLL).\n"); 925 errorCount += test_result; 926 } 927 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL)) 928 { 929 test_result += testInternalGet (MHD_USE_EPOLL); 930 if (test_result) 931 fprintf (stderr, "FAILED: testInternalGet (MHD_USE_EPOLL) - %u.\n", 932 test_result); 933 else if (verbose) 934 printf ("PASSED: testInternalGet (MHD_USE_EPOLL).\n"); 935 errorCount += test_result; 936 test_result += testMultithreadedPoolGet (MHD_USE_EPOLL); 937 if (test_result) 938 fprintf (stderr, 939 "FAILED: testMultithreadedPoolGet (MHD_USE_EPOLL) - %u.\n", 940 test_result); 941 else if (verbose) 942 printf ("PASSED: testMultithreadedPoolGet (MHD_USE_EPOLL).\n"); 943 errorCount += test_result; 944 test_result += testUnknownPortGet (MHD_USE_EPOLL); 945 if (test_result) 946 fprintf (stderr, "FAILED: testUnknownPortGet (MHD_USE_EPOLL) - %u.\n", 947 test_result); 948 else if (verbose) 949 printf ("PASSED: testUnknownPortGet (MHD_USE_EPOLL).\n"); 950 errorCount += test_result; 951 test_result += testEmptyGet (MHD_USE_EPOLL); 952 if (test_result) 953 fprintf (stderr, "FAILED: testEmptyGet (MHD_USE_EPOLL) - %u.\n", 954 test_result); 955 else if (verbose) 956 printf ("PASSED: testEmptyGet (MHD_USE_EPOLL).\n"); 957 errorCount += test_result; 958 } 959 } 960 if (0 != errorCount) 961 fprintf (stderr, 962 "Error (code: %u)\n", 963 errorCount); 964 else if (verbose) 965 printf ("All tests passed.\n"); 966 curl_global_cleanup (); 967 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 968 }