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