test_get_sendfile.c (18190B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2009 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_sendfile.c 23 * @brief Testcase for libmicrohttpd response from FD 24 * @author Christian Grothoff 25 * @author Karlson2k (Evgeny Grin) 26 */ 27 28 #include "MHD_config.h" 29 #include "platform.h" 30 #include <curl/curl.h> 31 #include <microhttpd.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <time.h> 35 #include <sys/types.h> 36 #include <fcntl.h> 37 #include <errno.h> 38 #include "mhd_sockets.h" 39 #include "mhd_has_in_name.h" 40 41 #ifndef WINDOWS 42 #include <sys/socket.h> 43 #include <unistd.h> 44 #endif 45 46 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2 47 #undef MHD_CPU_COUNT 48 #endif 49 #if ! defined(MHD_CPU_COUNT) 50 #define MHD_CPU_COUNT 2 51 #endif 52 53 #define TESTSTR \ 54 "This is the content of the test file we are sending using sendfile (if available)" 55 56 static char *sourcefile; 57 58 static int oneone; 59 60 struct CBC 61 { 62 char *buf; 63 size_t pos; 64 size_t size; 65 }; 66 67 68 static size_t 69 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 70 { 71 struct CBC *cbc = ctx; 72 73 if (cbc->pos + size * nmemb > cbc->size) 74 return 0; /* overflow */ 75 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 76 cbc->pos += size * nmemb; 77 return size * nmemb; 78 } 79 80 81 static enum MHD_Result 82 ahc_echo (void *cls, 83 struct MHD_Connection *connection, 84 const char *url, 85 const char *method, 86 const char *version, 87 const char *upload_data, size_t *upload_data_size, 88 void **req_cls) 89 { 90 static int ptr; 91 struct MHD_Response *response; 92 enum MHD_Result ret; 93 int fd; 94 (void) cls; 95 (void) url; (void) version; /* Unused. Silent compiler warning. */ 96 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 97 98 if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) 99 return MHD_NO; /* unexpected method */ 100 if (&ptr != *req_cls) 101 { 102 *req_cls = &ptr; 103 return MHD_YES; 104 } 105 *req_cls = NULL; 106 fd = open (sourcefile, O_RDONLY); 107 if (fd == -1) 108 { 109 fprintf (stderr, "Failed to open `%s': %s\n", 110 sourcefile, 111 strerror (errno)); 112 exit (1); 113 } 114 response = MHD_create_response_from_fd (strlen (TESTSTR), fd); 115 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 116 MHD_destroy_response (response); 117 if (ret == MHD_NO) 118 abort (); 119 return ret; 120 } 121 122 123 static unsigned int 124 testInternalGet (void) 125 { 126 struct MHD_Daemon *d; 127 CURL *c; 128 char buf[2048]; 129 struct CBC cbc; 130 CURLcode errornum; 131 uint16_t port; 132 133 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 134 port = 0; 135 else 136 { 137 port = 1200; 138 if (oneone) 139 port += 10; 140 } 141 142 cbc.buf = buf; 143 cbc.size = 2048; 144 cbc.pos = 0; 145 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 146 port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); 147 if (d == NULL) 148 return 1; 149 if (0 == port) 150 { 151 const union MHD_DaemonInfo *dinfo; 152 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 153 if ((NULL == dinfo) || (0 == dinfo->port) ) 154 { 155 MHD_stop_daemon (d); return 32; 156 } 157 port = dinfo->port; 158 } 159 c = curl_easy_init (); 160 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 161 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 162 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 163 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 164 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 165 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 166 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 167 if (oneone) 168 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 169 else 170 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 171 /* NOTE: use of CONNECTTIMEOUT without also 172 setting NOSIGNAL results in really weird 173 crashes on my system!*/ 174 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 175 if (CURLE_OK != (errornum = curl_easy_perform (c))) 176 { 177 fprintf (stderr, 178 "curl_easy_perform failed: `%s'\n", 179 curl_easy_strerror (errornum)); 180 curl_easy_cleanup (c); 181 MHD_stop_daemon (d); 182 return 2; 183 } 184 curl_easy_cleanup (c); 185 MHD_stop_daemon (d); 186 if (cbc.pos != strlen (TESTSTR)) 187 return 4; 188 if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR))) 189 return 8; 190 return 0; 191 } 192 193 194 static unsigned int 195 testMultithreadedGet (void) 196 { 197 struct MHD_Daemon *d; 198 CURL *c; 199 char buf[2048]; 200 struct CBC cbc; 201 CURLcode errornum; 202 uint16_t port; 203 204 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 205 port = 0; 206 else 207 { 208 port = 1201; 209 if (oneone) 210 port += 10; 211 } 212 213 cbc.buf = buf; 214 cbc.size = 2048; 215 cbc.pos = 0; 216 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 217 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 218 port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); 219 if (d == NULL) 220 return 16; 221 if (0 == port) 222 { 223 const union MHD_DaemonInfo *dinfo; 224 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 225 if ((NULL == dinfo) || (0 == dinfo->port) ) 226 { 227 MHD_stop_daemon (d); return 32; 228 } 229 port = dinfo->port; 230 } 231 c = curl_easy_init (); 232 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 233 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 234 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 235 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 236 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 237 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 238 if (oneone) 239 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 240 else 241 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 242 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 243 /* NOTE: use of CONNECTTIMEOUT without also 244 setting NOSIGNAL results in really weird 245 crashes on my system! */ 246 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 247 if (CURLE_OK != (errornum = curl_easy_perform (c))) 248 { 249 fprintf (stderr, 250 "curl_easy_perform failed: `%s'\n", 251 curl_easy_strerror (errornum)); 252 curl_easy_cleanup (c); 253 MHD_stop_daemon (d); 254 return 32; 255 } 256 curl_easy_cleanup (c); 257 MHD_stop_daemon (d); 258 if (cbc.pos != strlen (TESTSTR)) 259 return 64; 260 if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR))) 261 return 128; 262 return 0; 263 } 264 265 266 static unsigned int 267 testMultithreadedPoolGet (void) 268 { 269 struct MHD_Daemon *d; 270 CURL *c; 271 char buf[2048]; 272 struct CBC cbc; 273 CURLcode errornum; 274 uint16_t port; 275 276 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 277 port = 0; 278 else 279 { 280 port = 1202; 281 if (oneone) 282 port += 10; 283 } 284 285 cbc.buf = buf; 286 cbc.size = 2048; 287 cbc.pos = 0; 288 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 289 port, NULL, NULL, &ahc_echo, NULL, 290 MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT, 291 MHD_OPTION_END); 292 if (d == NULL) 293 return 16; 294 if (0 == port) 295 { 296 const union MHD_DaemonInfo *dinfo; 297 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 298 if ((NULL == dinfo) || (0 == dinfo->port) ) 299 { 300 MHD_stop_daemon (d); return 32; 301 } 302 port = dinfo->port; 303 } 304 c = curl_easy_init (); 305 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 306 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 307 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 308 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 309 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 310 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 311 if (oneone) 312 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 313 else 314 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 315 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 316 /* NOTE: use of CONNECTTIMEOUT without also 317 setting NOSIGNAL results in really weird 318 crashes on my system!*/ 319 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 320 if (CURLE_OK != (errornum = curl_easy_perform (c))) 321 { 322 fprintf (stderr, 323 "curl_easy_perform failed: `%s'\n", 324 curl_easy_strerror (errornum)); 325 curl_easy_cleanup (c); 326 MHD_stop_daemon (d); 327 return 32; 328 } 329 curl_easy_cleanup (c); 330 MHD_stop_daemon (d); 331 if (cbc.pos != strlen (TESTSTR)) 332 return 64; 333 if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR))) 334 return 128; 335 return 0; 336 } 337 338 339 static unsigned int 340 testExternalGet (int thread_unsafe) 341 { 342 struct MHD_Daemon *d; 343 CURL *c; 344 char buf[2048]; 345 struct CBC cbc; 346 CURLM *multi; 347 CURLMcode mret; 348 fd_set rs; 349 fd_set ws; 350 fd_set es; 351 MHD_socket maxsock; 352 #ifdef MHD_WINSOCK_SOCKETS 353 int maxposixs; /* Max socket number unused on W32 */ 354 #else /* MHD_POSIX_SOCKETS */ 355 #define maxposixs maxsock 356 #endif /* MHD_POSIX_SOCKETS */ 357 int running; 358 struct CURLMsg *msg; 359 time_t start; 360 struct timeval tv; 361 uint16_t port; 362 363 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 364 port = 0; 365 else 366 { 367 port = 1203; 368 if (oneone) 369 port += 10; 370 } 371 372 multi = NULL; 373 cbc.buf = buf; 374 cbc.size = 2048; 375 cbc.pos = 0; 376 d = MHD_start_daemon (MHD_USE_ERROR_LOG 377 | (thread_unsafe ? MHD_USE_NO_THREAD_SAFETY : 0), 378 port, NULL, NULL, &ahc_echo, NULL, 379 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 380 MHD_OPTION_END); 381 if (d == NULL) 382 return 256; 383 if (0 == port) 384 { 385 const union MHD_DaemonInfo *dinfo; 386 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 387 if ((NULL == dinfo) || (0 == dinfo->port) ) 388 { 389 MHD_stop_daemon (d); return 32; 390 } 391 port = dinfo->port; 392 } 393 c = curl_easy_init (); 394 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 395 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 396 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 397 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 398 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 399 if (oneone) 400 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 401 else 402 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 403 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 404 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 405 /* NOTE: use of CONNECTTIMEOUT without also 406 setting NOSIGNAL results in really weird 407 crashes on my system! */ 408 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 409 410 411 multi = curl_multi_init (); 412 if (multi == NULL) 413 { 414 curl_easy_cleanup (c); 415 MHD_stop_daemon (d); 416 return 512; 417 } 418 mret = curl_multi_add_handle (multi, c); 419 if (mret != CURLM_OK) 420 { 421 curl_multi_cleanup (multi); 422 curl_easy_cleanup (c); 423 MHD_stop_daemon (d); 424 return 1024; 425 } 426 start = time (NULL); 427 while ((time (NULL) - start < 5) && (multi != NULL)) 428 { 429 maxsock = MHD_INVALID_SOCKET; 430 maxposixs = -1; 431 FD_ZERO (&rs); 432 FD_ZERO (&ws); 433 FD_ZERO (&es); 434 curl_multi_perform (multi, &running); 435 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); 436 if (mret != CURLM_OK) 437 { 438 curl_multi_remove_handle (multi, c); 439 curl_multi_cleanup (multi); 440 curl_easy_cleanup (c); 441 MHD_stop_daemon (d); 442 return 2048; 443 } 444 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) 445 { 446 curl_multi_remove_handle (multi, c); 447 curl_multi_cleanup (multi); 448 curl_easy_cleanup (c); 449 MHD_stop_daemon (d); 450 return 4096; 451 } 452 tv.tv_sec = 0; 453 tv.tv_usec = 1000; 454 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) 455 { 456 #ifdef MHD_POSIX_SOCKETS 457 if (EINTR != errno) 458 { 459 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 460 (int) errno, __LINE__); 461 fflush (stderr); 462 exit (99); 463 } 464 #else 465 if ((WSAEINVAL != WSAGetLastError ()) || 466 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 467 { 468 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 469 (int) WSAGetLastError (), __LINE__); 470 fflush (stderr); 471 exit (99); 472 } 473 Sleep (1); 474 #endif 475 } 476 curl_multi_perform (multi, &running); 477 if (0 == running) 478 { 479 int pending; 480 int curl_fine = 0; 481 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 482 { 483 if (msg->msg == CURLMSG_DONE) 484 { 485 if (msg->data.result == CURLE_OK) 486 curl_fine = 1; 487 else 488 { 489 fprintf (stderr, 490 "%s failed at %s:%d: `%s'\n", 491 "curl_multi_perform", 492 __FILE__, 493 __LINE__, curl_easy_strerror (msg->data.result)); 494 abort (); 495 } 496 } 497 } 498 if (! curl_fine) 499 { 500 fprintf (stderr, "libcurl haven't returned OK code\n"); 501 abort (); 502 } 503 curl_multi_remove_handle (multi, c); 504 curl_multi_cleanup (multi); 505 curl_easy_cleanup (c); 506 c = NULL; 507 multi = NULL; 508 } 509 MHD_run (d); 510 } 511 if (multi != NULL) 512 { 513 curl_multi_remove_handle (multi, c); 514 curl_easy_cleanup (c); 515 curl_multi_cleanup (multi); 516 } 517 MHD_stop_daemon (d); 518 if (cbc.pos != strlen (TESTSTR)) 519 { 520 fprintf (stderr, 521 "Got %.*s instead of %s!\n", 522 (int) cbc.pos, 523 cbc.buf, 524 TESTSTR); 525 return 8192; 526 } 527 if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR))) 528 return 16384; 529 return 0; 530 } 531 532 533 static unsigned int 534 testUnknownPortGet (void) 535 { 536 struct MHD_Daemon *d; 537 const union MHD_DaemonInfo *di; 538 CURL *c; 539 char buf[2048]; 540 struct CBC cbc; 541 CURLcode errornum; 542 uint16_t port; 543 544 struct sockaddr_in addr; 545 socklen_t addr_len = sizeof(addr); 546 memset (&addr, 0, sizeof(addr)); 547 addr.sin_family = AF_INET; 548 addr.sin_port = 0; 549 addr.sin_addr.s_addr = INADDR_ANY; 550 551 cbc.buf = buf; 552 cbc.size = 2048; 553 cbc.pos = 0; 554 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 555 0, NULL, NULL, &ahc_echo, NULL, 556 MHD_OPTION_SOCK_ADDR, &addr, 557 MHD_OPTION_END); 558 if (d == NULL) 559 return 32768; 560 561 if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 562 { 563 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD); 564 if (di == NULL) 565 return 65536; 566 567 if (0 != getsockname (di->listen_fd, (struct sockaddr *) &addr, &addr_len)) 568 return 131072; 569 570 if (addr.sin_family != AF_INET) 571 return 26214; 572 port = (uint16_t) ntohs (addr.sin_port); 573 } 574 else 575 { 576 const union MHD_DaemonInfo *dinfo; 577 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 578 if ((NULL == dinfo) || (0 == dinfo->port) ) 579 { 580 MHD_stop_daemon (d); return 32; 581 } 582 port = dinfo->port; 583 } 584 585 snprintf (buf, sizeof(buf), "http://127.0.0.1:%u/", 586 (unsigned int) port); 587 588 c = curl_easy_init (); 589 curl_easy_setopt (c, CURLOPT_URL, buf); 590 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 591 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 592 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 593 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 594 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 595 if (oneone) 596 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 597 else 598 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 599 /* NOTE: use of CONNECTTIMEOUT without also 600 setting NOSIGNAL results in really weird 601 crashes on my system! */ 602 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 603 if (CURLE_OK != (errornum = curl_easy_perform (c))) 604 { 605 fprintf (stderr, 606 "curl_easy_perform failed: `%s'\n", 607 curl_easy_strerror (errornum)); 608 curl_easy_cleanup (c); 609 MHD_stop_daemon (d); 610 return 524288; 611 } 612 curl_easy_cleanup (c); 613 MHD_stop_daemon (d); 614 if (cbc.pos != strlen (TESTSTR)) 615 return 1048576; 616 if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR))) 617 return 2097152; 618 return 0; 619 } 620 621 622 int 623 main (int argc, char *const *argv) 624 { 625 unsigned int errorCount = 0; 626 const char *tmp; 627 FILE *f; 628 (void) argc; /* Unused. Silent compiler warning. */ 629 630 if ((NULL == argv) || (0 == argv[0])) 631 return 99; 632 oneone = has_in_name (argv[0], "11"); 633 634 if ( (NULL == (tmp = getenv ("TMPDIR"))) && 635 (NULL == (tmp = getenv ("TMP"))) && 636 (NULL == (tmp = getenv ("TEMP"))) ) 637 tmp = "/tmp"; 638 sourcefile = malloc (strlen (tmp) + 32); 639 snprintf (sourcefile, 640 strlen (tmp) + 32, 641 "%s/%s%s", 642 tmp, 643 "test-mhd-sendfile", 644 oneone ? "11" : ""); 645 f = fopen (sourcefile, "w"); 646 if (NULL == f) 647 { 648 fprintf (stderr, "failed to write test file\n"); 649 free (sourcefile); 650 return 1; 651 } 652 if (1 != 653 fwrite (TESTSTR, strlen (TESTSTR), 1, f)) 654 abort (); 655 fclose (f); 656 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 657 return 2; 658 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 659 { 660 errorCount += testInternalGet (); 661 errorCount += testMultithreadedGet (); 662 errorCount += testMultithreadedPoolGet (); 663 errorCount += testUnknownPortGet (); 664 errorCount += testExternalGet (0); 665 } 666 errorCount += testExternalGet (! 0); 667 if (errorCount != 0) 668 fprintf (stderr, "Error (code: %u)\n", errorCount); 669 curl_global_cleanup (); 670 unlink (sourcefile); 671 free (sourcefile); 672 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 673 }