test_large_put.c (28069B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2008 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 /** 23 * @file test_large_put.c 24 * @brief Testcase for libmicrohttpd PUT operations 25 * @author Christian Grothoff 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 29 #include "MHD_config.h" 30 #include "platform.h" 31 #include <curl/curl.h> 32 #include <microhttpd.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <errno.h> 37 38 #ifndef WINDOWS 39 #include <unistd.h> 40 #endif 41 42 #include "mhd_has_in_name.h" 43 #include "mhd_has_param.h" 44 45 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2 46 #undef MHD_CPU_COUNT 47 #endif 48 #if ! defined(MHD_CPU_COUNT) 49 #define MHD_CPU_COUNT 2 50 #endif 51 52 53 #if defined(HAVE___FUNC__) 54 #define externalErrorExit(ignore) \ 55 _externalErrorExit_func(NULL, __func__, __LINE__) 56 #define externalErrorExitDesc(errDesc) \ 57 _externalErrorExit_func(errDesc, __func__, __LINE__) 58 #define libcurlErrorExit(ignore) \ 59 _libcurlErrorExit_func(NULL, __func__, __LINE__) 60 #define libcurlErrorExitDesc(errDesc) \ 61 _libcurlErrorExit_func(errDesc, __func__, __LINE__) 62 #define mhdErrorExit(ignore) \ 63 _mhdErrorExit_func(NULL, __func__, __LINE__) 64 #define mhdErrorExitDesc(errDesc) \ 65 _mhdErrorExit_func(errDesc, __func__, __LINE__) 66 #elif defined(HAVE___FUNCTION__) 67 #define externalErrorExit(ignore) \ 68 _externalErrorExit_func(NULL, __FUNCTION__, __LINE__) 69 #define externalErrorExitDesc(errDesc) \ 70 _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__) 71 #define libcurlErrorExit(ignore) \ 72 _libcurlErrorExit_func(NULL, __FUNCTION__, __LINE__) 73 #define libcurlErrorExitDesc(errDesc) \ 74 _libcurlErrorExit_func(errDesc, __FUNCTION__, __LINE__) 75 #define mhdErrorExit(ignore) \ 76 _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__) 77 #define mhdErrorExitDesc(errDesc) \ 78 _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__) 79 #else 80 #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__) 81 #define externalErrorExitDesc(errDesc) \ 82 _externalErrorExit_func(errDesc, NULL, __LINE__) 83 #define libcurlErrorExit(ignore) _libcurlErrorExit_func(NULL, NULL, __LINE__) 84 #define libcurlErrorExitDesc(errDesc) \ 85 _libcurlErrorExit_func(errDesc, NULL, __LINE__) 86 #define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__) 87 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__) 88 #endif 89 90 91 _MHD_NORETURN static void 92 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 93 { 94 if ((NULL != errDesc) && (0 != errDesc[0])) 95 fprintf (stderr, "%s", errDesc); 96 else 97 fprintf (stderr, "System or external library call failed"); 98 if ((NULL != funcName) && (0 != funcName[0])) 99 fprintf (stderr, " in %s", funcName); 100 if (0 < lineNum) 101 fprintf (stderr, " at line %d", lineNum); 102 103 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 104 strerror (errno)); 105 #ifdef MHD_WINSOCK_SOCKETS 106 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 107 #endif /* MHD_WINSOCK_SOCKETS */ 108 fflush (stderr); 109 exit (99); 110 } 111 112 113 static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; 114 115 _MHD_NORETURN static void 116 _libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 117 { 118 if ((NULL != errDesc) && (0 != errDesc[0])) 119 fprintf (stderr, "%s", errDesc); 120 else 121 fprintf (stderr, "CURL library call failed"); 122 if ((NULL != funcName) && (0 != funcName[0])) 123 fprintf (stderr, " in %s", funcName); 124 if (0 < lineNum) 125 fprintf (stderr, " at line %d", lineNum); 126 127 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 128 strerror (errno)); 129 if (0 != libcurl_errbuf[0]) 130 fprintf (stderr, "Last libcurl error details: %s\n", libcurl_errbuf); 131 132 fflush (stderr); 133 exit (99); 134 } 135 136 137 _MHD_NORETURN static void 138 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 139 { 140 if ((NULL != errDesc) && (0 != errDesc[0])) 141 fprintf (stderr, "%s", errDesc); 142 else 143 fprintf (stderr, "MHD unexpected error"); 144 if ((NULL != funcName) && (0 != funcName[0])) 145 fprintf (stderr, " in %s", funcName); 146 if (0 < lineNum) 147 fprintf (stderr, " at line %d", lineNum); 148 149 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 150 strerror (errno)); 151 152 fflush (stderr); 153 exit (8); 154 } 155 156 157 static int oneone; 158 static int incr_read; /* Use incremental read */ 159 static int verbose; /* Be verbose */ 160 161 #define PUT_SIZE (256 * 1024) 162 163 static char *put_buffer; 164 165 struct CBC 166 { 167 char *buf; 168 size_t pos; 169 size_t size; 170 }; 171 172 static char * 173 alloc_init (size_t buf_size) 174 { 175 static const char template[] = 176 "ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz"; 177 static const size_t templ_size = sizeof(template) / sizeof(char) - 1; 178 char *buf; 179 char *fill_ptr; 180 size_t to_fill; 181 182 buf = malloc (buf_size); 183 if (NULL == buf) 184 externalErrorExit (); 185 186 fill_ptr = buf; 187 to_fill = buf_size; 188 while (to_fill > 0) 189 { 190 const size_t to_copy = to_fill > templ_size ? templ_size : to_fill; 191 memcpy (fill_ptr, template, to_copy); 192 fill_ptr += to_copy; 193 to_fill -= to_copy; 194 } 195 return buf; 196 } 197 198 199 static size_t 200 putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) 201 { 202 size_t *pos = (size_t *) ptr; 203 size_t wrt; 204 205 wrt = size * nmemb; 206 /* Check for overflow. */ 207 if (wrt / size != nmemb) 208 libcurlErrorExitDesc ("Too large buffer size"); 209 if (wrt > PUT_SIZE - (*pos)) 210 wrt = PUT_SIZE - (*pos); 211 memcpy (stream, &put_buffer[*pos], wrt); 212 (*pos) += wrt; 213 return wrt; 214 } 215 216 217 static size_t 218 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 219 { 220 struct CBC *cbc = ctx; 221 222 if (cbc->pos + size * nmemb > cbc->size) 223 libcurlErrorExitDesc ("Too large buffer size"); 224 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 225 cbc->pos += size * nmemb; 226 return size * nmemb; 227 } 228 229 230 static enum MHD_Result 231 ahc_echo (void *cls, 232 struct MHD_Connection *connection, 233 const char *url, 234 const char *method, 235 const char *version, 236 const char *upload_data, size_t *upload_data_size, 237 void **req_cls) 238 { 239 int *done = cls; 240 struct MHD_Response *response; 241 enum MHD_Result ret; 242 static size_t processed; 243 244 if (NULL == cls) 245 mhdErrorExitDesc ("cls parameter is NULL"); 246 247 if (0 != strcmp (version, oneone ? 248 MHD_HTTP_VERSION_1_1 : MHD_HTTP_VERSION_1_0)) 249 mhdErrorExitDesc ("Unexpected HTTP version"); 250 251 if (NULL == url) 252 mhdErrorExitDesc ("url parameter is NULL"); 253 254 if (NULL == upload_data_size) 255 mhdErrorExitDesc ("'upload_data_size' pointer is NULL"); 256 257 if (0 != strcmp ("PUT", method)) 258 mhdErrorExitDesc ("Unexpected request method"); /* unexpected method */ 259 260 if ((*done) == 0) 261 { 262 size_t *pproc; 263 if (NULL == *req_cls) 264 { 265 processed = 0; 266 /* Safe as long as only one parallel request served. */ 267 *req_cls = &processed; 268 } 269 pproc = (size_t *) *req_cls; 270 271 if (0 == *upload_data_size) 272 return MHD_YES; /* No data to process. */ 273 274 if (*pproc + *upload_data_size > PUT_SIZE) 275 mhdErrorExitDesc ("Incoming data larger than expected"); 276 277 if ( (! incr_read) && (*upload_data_size != PUT_SIZE) ) 278 return MHD_YES; /* Wait until whole request is received. */ 279 280 if (0 != memcmp (upload_data, put_buffer + (*pproc), *upload_data_size)) 281 mhdErrorExitDesc ("Incoming data does not match sent data"); 282 283 *pproc += *upload_data_size; 284 *upload_data_size = 0; /* Current block of data is fully processed. */ 285 286 if (PUT_SIZE == *pproc) 287 *done = 1; /* Whole request is processed. */ 288 return MHD_YES; 289 } 290 response = 291 MHD_create_response_from_buffer_copy (strlen (url), 292 (const void *) url); 293 if (NULL == response) 294 mhdErrorExitDesc ("Failed to create response"); 295 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 296 MHD_destroy_response (response); 297 return ret; 298 } 299 300 301 static unsigned int 302 testPutInternalThread (unsigned int add_flag) 303 { 304 struct MHD_Daemon *d; 305 CURL *c; 306 struct CBC cbc; 307 size_t pos = 0; 308 int done_flag = 0; 309 CURLcode errornum; 310 char buf[2048]; 311 uint16_t port; 312 313 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 314 port = 0; 315 else 316 { 317 port = 1270; 318 if (oneone) 319 port += 10; 320 if (incr_read) 321 port += 20; 322 } 323 324 cbc.buf = buf; 325 cbc.size = 2048; 326 cbc.pos = 0; 327 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 328 | add_flag, 329 port, 330 NULL, NULL, &ahc_echo, &done_flag, 331 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 332 (size_t) (incr_read ? 1024 : (PUT_SIZE * 4 / 3)), 333 MHD_OPTION_END); 334 if (d == NULL) 335 mhdErrorExit (); 336 if (0 == port) 337 { 338 const union MHD_DaemonInfo *dinfo; 339 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 340 if ((NULL == dinfo) || (0 == dinfo->port) ) 341 mhdErrorExit (); 342 port = dinfo->port; 343 } 344 345 c = curl_easy_init (); 346 if (NULL == c) 347 { 348 fprintf (stderr, "curl_easy_init() failed.\n"); 349 externalErrorExit (); 350 } 351 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 352 (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, 353 "http://127.0.0.1/hello_world")) || 354 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) port)) || 355 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 356 ©Buffer)) || 357 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc)) || 358 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READFUNCTION, 359 &putBuffer)) || 360 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READDATA, &pos)) || 361 (CURLE_OK != curl_easy_setopt (c, CURLOPT_UPLOAD, 1L)) || 362 (CURLE_OK != curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE)) || 363 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || 364 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, libcurl_errbuf)) || 365 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 366 (long) 150)) || 367 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 368 (long) 150)) || 369 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 370 (oneone) ? 371 CURL_HTTP_VERSION_1_1 : 372 CURL_HTTP_VERSION_1_0))) 373 374 { 375 fprintf (stderr, "curl_easy_setopt() failed.\n"); 376 externalErrorExit (); 377 } 378 379 if (CURLE_OK != (errornum = curl_easy_perform (c))) 380 { 381 fprintf (stderr, 382 "curl_easy_perform failed: `%s'\n", 383 curl_easy_strerror (errornum)); 384 curl_easy_cleanup (c); 385 MHD_stop_daemon (d); 386 return 2; 387 } 388 curl_easy_cleanup (c); 389 MHD_stop_daemon (d); 390 if (cbc.pos != strlen ("/hello_world")) 391 { 392 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", 393 (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, 394 (unsigned) strlen ("/hello_world")); 395 mhdErrorExitDesc ("Wrong returned data length"); 396 } 397 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 398 { 399 fprintf (stderr, "Got invalid response '%.*s'. ", (int) cbc.pos, cbc.buf); 400 mhdErrorExitDesc ("Wrong returned data length"); 401 } 402 return 0; 403 } 404 405 406 static unsigned int 407 testPutThreadPerConn (unsigned int add_flag) 408 { 409 struct MHD_Daemon *d; 410 CURL *c; 411 struct CBC cbc; 412 size_t pos = 0; 413 int done_flag = 0; 414 CURLcode errornum; 415 char buf[2048]; 416 uint16_t port; 417 418 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 419 port = 0; 420 else 421 { 422 port = 1271; 423 if (oneone) 424 port += 10; 425 if (incr_read) 426 port += 20; 427 } 428 429 cbc.buf = buf; 430 cbc.size = 2048; 431 cbc.pos = 0; 432 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 433 | MHD_USE_INTERNAL_POLLING_THREAD 434 | MHD_USE_ERROR_LOG | add_flag, 435 port, 436 NULL, NULL, &ahc_echo, &done_flag, 437 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 438 (size_t) (incr_read ? 1024 : (PUT_SIZE * 4)), 439 MHD_OPTION_END); 440 if (d == NULL) 441 mhdErrorExit (); 442 if (0 == port) 443 { 444 const union MHD_DaemonInfo *dinfo; 445 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 446 if ((NULL == dinfo) || (0 == dinfo->port) ) 447 mhdErrorExit (); 448 port = dinfo->port; 449 } 450 451 c = curl_easy_init (); 452 if (NULL == c) 453 { 454 fprintf (stderr, "curl_easy_init() failed.\n"); 455 externalErrorExit (); 456 } 457 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 458 (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, 459 "http://127.0.0.1/hello_world")) || 460 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) port)) || 461 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 462 ©Buffer)) || 463 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc)) || 464 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READFUNCTION, 465 &putBuffer)) || 466 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READDATA, &pos)) || 467 (CURLE_OK != curl_easy_setopt (c, CURLOPT_UPLOAD, 1L)) || 468 (CURLE_OK != curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE)) || 469 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || 470 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, libcurl_errbuf)) || 471 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 472 (long) 150)) || 473 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 474 (long) 150)) || 475 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 476 (oneone) ? 477 CURL_HTTP_VERSION_1_1 : 478 CURL_HTTP_VERSION_1_0))) 479 { 480 fprintf (stderr, "curl_easy_setopt() failed.\n"); 481 externalErrorExit (); 482 } 483 484 if (CURLE_OK != (errornum = curl_easy_perform (c))) 485 { 486 fprintf (stderr, 487 "curl_easy_perform failed: `%s'\n", 488 curl_easy_strerror (errornum)); 489 curl_easy_cleanup (c); 490 MHD_stop_daemon (d); 491 return 32; 492 } 493 curl_easy_cleanup (c); 494 MHD_stop_daemon (d); 495 if (cbc.pos != strlen ("/hello_world")) 496 { 497 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", 498 (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, 499 (unsigned) strlen ("/hello_world")); 500 mhdErrorExitDesc ("Wrong returned data length"); 501 } 502 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 503 { 504 fprintf (stderr, "Got invalid response '%.*s'. ", (int) cbc.pos, cbc.buf); 505 mhdErrorExitDesc ("Wrong returned data length"); 506 } 507 return 0; 508 } 509 510 511 static unsigned int 512 testPutThreadPool (unsigned int add_flag) 513 { 514 struct MHD_Daemon *d; 515 CURL *c; 516 struct CBC cbc; 517 size_t pos = 0; 518 int done_flag = 0; 519 CURLcode errornum; 520 char buf[2048]; 521 uint16_t port; 522 523 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 524 port = 0; 525 else 526 { 527 port = 1272; 528 if (oneone) 529 port += 10; 530 if (incr_read) 531 port += 20; 532 } 533 534 cbc.buf = buf; 535 cbc.size = 2048; 536 cbc.pos = 0; 537 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 538 | add_flag, 539 port, 540 NULL, NULL, &ahc_echo, &done_flag, 541 MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT, 542 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 543 (size_t) (incr_read ? 1024 : (PUT_SIZE * 4)), 544 MHD_OPTION_END); 545 if (d == NULL) 546 mhdErrorExit (); 547 if (0 == port) 548 { 549 const union MHD_DaemonInfo *dinfo; 550 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 551 if ((NULL == dinfo) || (0 == dinfo->port) ) 552 mhdErrorExit (); 553 port = dinfo->port; 554 } 555 556 c = curl_easy_init (); 557 if (NULL == c) 558 { 559 fprintf (stderr, "curl_easy_init() failed.\n"); 560 externalErrorExit (); 561 } 562 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 563 (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, 564 "http://127.0.0.1/hello_world")) || 565 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) port)) || 566 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 567 ©Buffer)) || 568 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc)) || 569 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READFUNCTION, 570 &putBuffer)) || 571 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READDATA, &pos)) || 572 (CURLE_OK != curl_easy_setopt (c, CURLOPT_UPLOAD, 1L)) || 573 (CURLE_OK != curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE)) || 574 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || 575 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, libcurl_errbuf)) || 576 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 577 (long) 150)) || 578 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 579 (long) 150)) || 580 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 581 (oneone) ? 582 CURL_HTTP_VERSION_1_1 : 583 CURL_HTTP_VERSION_1_0))) 584 { 585 fprintf (stderr, "curl_easy_setopt() failed.\n"); 586 externalErrorExit (); 587 } 588 if (CURLE_OK != (errornum = curl_easy_perform (c))) 589 { 590 fprintf (stderr, 591 "curl_easy_perform failed: `%s'\n", 592 curl_easy_strerror (errornum)); 593 curl_easy_cleanup (c); 594 MHD_stop_daemon (d); 595 return 32; 596 } 597 curl_easy_cleanup (c); 598 MHD_stop_daemon (d); 599 if (cbc.pos != strlen ("/hello_world")) 600 { 601 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", 602 (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, 603 (unsigned) strlen ("/hello_world")); 604 mhdErrorExitDesc ("Wrong returned data length"); 605 } 606 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 607 { 608 fprintf (stderr, "Got invalid response '%.*s'. ", (int) cbc.pos, cbc.buf); 609 mhdErrorExitDesc ("Wrong returned data length"); 610 } 611 return 0; 612 } 613 614 615 static unsigned int 616 testPutExternal (void) 617 { 618 struct MHD_Daemon *d; 619 CURL *c; 620 struct CBC cbc; 621 CURLM *multi; 622 CURLMcode mret; 623 fd_set rs; 624 fd_set ws; 625 fd_set es; 626 int running; 627 struct CURLMsg *msg; 628 time_t start; 629 struct timeval tv; 630 size_t pos = 0; 631 int done_flag = 0; 632 char buf[2048]; 633 uint16_t port; 634 635 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 636 port = 0; 637 else 638 { 639 port = 1273; 640 if (oneone) 641 port += 10; 642 if (incr_read) 643 port += 20; 644 } 645 646 cbc.buf = buf; 647 cbc.size = 2048; 648 cbc.pos = 0; 649 multi = NULL; 650 d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY, 651 port, 652 NULL, NULL, &ahc_echo, &done_flag, 653 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 654 (size_t) (incr_read ? 1024 : (PUT_SIZE * 4)), 655 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 656 MHD_OPTION_END); 657 if (d == NULL) 658 mhdErrorExit (); 659 if (0 == 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 mhdErrorExit (); 665 port = dinfo->port; 666 } 667 668 c = curl_easy_init (); 669 if (NULL == c) 670 { 671 fprintf (stderr, "curl_easy_init() failed.\n"); 672 externalErrorExit (); 673 } 674 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 675 (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, 676 "http://127.0.0.1/hello_world")) || 677 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) port)) || 678 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 679 ©Buffer)) || 680 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc)) || 681 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READFUNCTION, 682 &putBuffer)) || 683 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READDATA, &pos)) || 684 (CURLE_OK != curl_easy_setopt (c, CURLOPT_UPLOAD, 1L)) || 685 (CURLE_OK != curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE)) || 686 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || 687 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, libcurl_errbuf)) || 688 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 689 (long) 150)) || 690 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 691 (long) 150)) || 692 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 693 (oneone) ? 694 CURL_HTTP_VERSION_1_1 : 695 CURL_HTTP_VERSION_1_0))) 696 { 697 fprintf (stderr, "curl_easy_setopt() failed.\n"); 698 externalErrorExit (); 699 } 700 701 multi = curl_multi_init (); 702 if (multi == NULL) 703 libcurlErrorExit (); 704 mret = curl_multi_add_handle (multi, c); 705 if (mret != CURLM_OK) 706 libcurlErrorExit (); 707 708 start = time (NULL); 709 while ((time (NULL) - start < 45) && (multi != NULL)) 710 { 711 MHD_socket maxMHDsock; 712 int maxcurlsock; 713 maxMHDsock = MHD_INVALID_SOCKET; 714 maxcurlsock = -1; 715 FD_ZERO (&rs); 716 FD_ZERO (&ws); 717 FD_ZERO (&es); 718 mret = curl_multi_perform (multi, &running); 719 if ((CURLM_OK != mret) && (CURLM_CALL_MULTI_PERFORM != mret)) 720 { 721 fprintf (stderr, "curl_multi_perform() failed. Error: '%s'. ", 722 curl_multi_strerror (mret)); 723 libcurlErrorExit (); 724 } 725 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxcurlsock)) 726 libcurlErrorExitDesc ("curl_multi_fdset() failed"); 727 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMHDsock)) 728 mhdErrorExit (); 729 730 tv.tv_sec = 0; 731 tv.tv_usec = 1000; 732 #ifndef MHD_WINSOCK_SOCKETS 733 if (maxMHDsock > maxcurlsock) 734 maxcurlsock = maxMHDsock; 735 #endif /* MHD_WINSOCK_SOCKETS */ 736 if (-1 == select (maxcurlsock + 1, &rs, &ws, &es, &tv)) 737 { 738 #ifdef MHD_POSIX_SOCKETS 739 if (EINTR != errno) 740 externalErrorExitDesc ("Unexpected select() error"); 741 #else 742 if ((WSAEINVAL != WSAGetLastError ()) || 743 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 744 externalErrorExitDesc ("Unexpected select() error"); 745 Sleep ((DWORD) (tv.tv_sec * 1000 + tv.tv_usec / 1000)); 746 #endif 747 } 748 749 mret = curl_multi_perform (multi, &running); 750 if ((CURLM_OK != mret) && (CURLM_CALL_MULTI_PERFORM != mret)) 751 { 752 fprintf (stderr, "curl_multi_perform() failed. Error: '%s'. ", 753 curl_multi_strerror (mret)); 754 libcurlErrorExit (); 755 } 756 if (0 == running) 757 { 758 int pending; 759 int curl_fine = 0; 760 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 761 { 762 if (msg->msg == CURLMSG_DONE) 763 { 764 if (msg->data.result == CURLE_OK) 765 curl_fine = 1; 766 else 767 { 768 fprintf (stderr, 769 "curl_multi_perform() failed: '%s' ", 770 curl_easy_strerror (msg->data.result)); 771 libcurlErrorExit (); 772 } 773 } 774 } 775 if (! curl_fine) 776 { 777 fprintf (stderr, "libcurl haven't returned OK code "); 778 mhdErrorExit (); 779 } 780 curl_multi_remove_handle (multi, c); 781 curl_multi_cleanup (multi); 782 curl_easy_cleanup (c); 783 c = NULL; 784 multi = NULL; 785 } 786 MHD_run (d); 787 } 788 if (multi != NULL) 789 mhdErrorExitDesc ("Request has been aborted by timeout"); 790 791 MHD_stop_daemon (d); 792 if (cbc.pos != strlen ("/hello_world")) 793 { 794 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", 795 (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, 796 (unsigned) strlen ("/hello_world")); 797 mhdErrorExitDesc ("Wrong returned data length"); 798 } 799 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 800 { 801 fprintf (stderr, "Got invalid response '%.*s'. ", (int) cbc.pos, cbc.buf); 802 mhdErrorExitDesc ("Wrong returned data length"); 803 } 804 return 0; 805 } 806 807 808 int 809 main (int argc, char *const *argv) 810 { 811 unsigned int errorCount = 0; 812 unsigned int lastErr; 813 814 oneone = has_in_name (argv[0], "11"); 815 incr_read = has_in_name (argv[0], "_inc"); 816 verbose = has_param (argc, argv, "-v"); 817 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 818 return 99; 819 put_buffer = alloc_init (PUT_SIZE); 820 if (NULL == put_buffer) 821 return 99; 822 lastErr = testPutExternal (); 823 if (verbose && (0 != lastErr)) 824 fprintf (stderr, "Error during testing with external select().\n"); 825 errorCount += lastErr; 826 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 827 { 828 lastErr = testPutInternalThread (0); 829 if (verbose && (0 != lastErr) ) 830 fprintf (stderr, 831 "Error during testing with internal thread with select().\n"); 832 errorCount += lastErr; 833 lastErr = testPutThreadPerConn (0); 834 if (verbose && (0 != lastErr) ) 835 fprintf (stderr, 836 "Error during testing with internal thread per connection with select().\n"); 837 errorCount += lastErr; 838 lastErr = testPutThreadPool (0); 839 if (verbose && (0 != lastErr) ) 840 fprintf (stderr, 841 "Error during testing with thread pool per connection with select().\n"); 842 errorCount += lastErr; 843 if (MHD_is_feature_supported (MHD_FEATURE_POLL)) 844 { 845 lastErr = testPutInternalThread (MHD_USE_POLL); 846 if (verbose && (0 != lastErr) ) 847 fprintf (stderr, 848 "Error during testing with internal thread with poll().\n"); 849 errorCount += lastErr; 850 lastErr = testPutThreadPerConn (MHD_USE_POLL); 851 if (verbose && (0 != lastErr) ) 852 fprintf (stderr, 853 "Error during testing with internal thread per connection with poll().\n"); 854 errorCount += lastErr; 855 lastErr = testPutThreadPool (MHD_USE_POLL); 856 if (verbose && (0 != lastErr) ) 857 fprintf (stderr, 858 "Error during testing with thread pool per connection with poll().\n"); 859 errorCount += lastErr; 860 } 861 if (MHD_is_feature_supported (MHD_FEATURE_EPOLL)) 862 { 863 lastErr = testPutInternalThread (MHD_USE_EPOLL); 864 if (verbose && (0 != lastErr) ) 865 fprintf (stderr, 866 "Error during testing with internal thread with epoll.\n"); 867 errorCount += lastErr; 868 lastErr = testPutThreadPool (MHD_USE_EPOLL); 869 if (verbose && (0 != lastErr) ) 870 fprintf (stderr, 871 "Error during testing with thread pool per connection with epoll.\n"); 872 errorCount += lastErr; 873 } 874 } 875 free (put_buffer); 876 if (errorCount != 0) 877 fprintf (stderr, "Error (code: %u)\n", errorCount); 878 else if (verbose) 879 printf ("All checks passed successfully.\n"); 880 curl_global_cleanup (); 881 return (errorCount == 0) ? 0 : 1; 882 }