test_put_broken_len.c (21164B)
1 /* 2 This file is part of GNU libmicrohttpd 3 Copyright (C) 2010 Christian Grothoff 4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k) 5 6 GNU 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 GNU 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 testcurl/test_head.c 24 * @brief Testcase for PUT requests with broken Content-Length header 25 * @author Karlson2k (Evgeny Grin) 26 */ 27 28 #include "mhd_options.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 <errno.h> 36 37 #ifndef _WIN32 38 #include <sys/socket.h> 39 #include <unistd.h> 40 #else 41 #include <wincrypt.h> 42 #endif 43 44 #include "mhd_has_param.h" 45 #include "mhd_has_in_name.h" 46 47 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 48 test into a marked, classifiable test error (TESTING.md, P5). */ 49 #include "mhd_panic_tripwire.h" 50 51 #ifndef MHD_STATICSTR_LEN_ 52 /** 53 * Determine length of static string / macro strings at compile time. 54 */ 55 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) 56 #endif /* ! MHD_STATICSTR_LEN_ */ 57 58 #ifndef CURL_VERSION_BITS 59 #define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z)) 60 #endif /* ! CURL_VERSION_BITS */ 61 #ifndef CURL_AT_LEAST_VERSION 62 #define CURL_AT_LEAST_VERSION(x,y,z) \ 63 (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z)) 64 #endif /* ! CURL_AT_LEAST_VERSION */ 65 66 #ifndef _MHD_INSTRMACRO 67 /* Quoted macro parameter */ 68 #define _MHD_INSTRMACRO(a) #a 69 #endif /* ! _MHD_INSTRMACRO */ 70 #ifndef _MHD_STRMACRO 71 /* Quoted expanded macro parameter */ 72 #define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a) 73 #endif /* ! _MHD_STRMACRO */ 74 75 #if defined(HAVE___FUNC__) 76 #define externalErrorExit(ignore) \ 77 _externalErrorExit_func (NULL, __func__, __LINE__) 78 #define externalErrorExitDesc(errDesc) \ 79 _externalErrorExit_func (errDesc, __func__, __LINE__) 80 #define libcurlErrorExit(ignore) \ 81 _libcurlErrorExit_func (NULL, __func__, __LINE__) 82 #define libcurlErrorExitDesc(errDesc) \ 83 _libcurlErrorExit_func (errDesc, __func__, __LINE__) 84 #define mhdErrorExit(ignore) \ 85 _mhdErrorExit_func (NULL, __func__, __LINE__) 86 #define mhdErrorExitDesc(errDesc) \ 87 _mhdErrorExit_func (errDesc, __func__, __LINE__) 88 #define checkCURLE_OK(libcurlcall) \ 89 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ 90 __func__, __LINE__) 91 #elif defined(HAVE___FUNCTION__) 92 #define externalErrorExit(ignore) \ 93 _externalErrorExit_func (NULL, __FUNCTION__, __LINE__) 94 #define externalErrorExitDesc(errDesc) \ 95 _externalErrorExit_func (errDesc, __FUNCTION__, __LINE__) 96 #define libcurlErrorExit(ignore) \ 97 _libcurlErrorExit_func (NULL, __FUNCTION__, __LINE__) 98 #define libcurlErrorExitDesc(errDesc) \ 99 _libcurlErrorExit_func (errDesc, __FUNCTION__, __LINE__) 100 #define mhdErrorExit(ignore) \ 101 _mhdErrorExit_func (NULL, __FUNCTION__, __LINE__) 102 #define mhdErrorExitDesc(errDesc) \ 103 _mhdErrorExit_func (errDesc, __FUNCTION__, __LINE__) 104 #define checkCURLE_OK(libcurlcall) \ 105 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ 106 __FUNCTION__, __LINE__) 107 #else 108 #define externalErrorExit(ignore) _externalErrorExit_func (NULL, NULL, __LINE__) 109 #define externalErrorExitDesc(errDesc) \ 110 _externalErrorExit_func (errDesc, NULL, __LINE__) 111 #define libcurlErrorExit(ignore) _libcurlErrorExit_func (NULL, NULL, __LINE__) 112 #define libcurlErrorExitDesc(errDesc) \ 113 _libcurlErrorExit_func (errDesc, NULL, __LINE__) 114 #define mhdErrorExit(ignore) _mhdErrorExit_func (NULL, NULL, __LINE__) 115 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func (errDesc, NULL, __LINE__) 116 #define checkCURLE_OK(libcurlcall) \ 117 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), NULL, \ 118 __LINE__) 119 #endif 120 121 122 _MHD_NORETURN static void 123 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 124 { 125 fflush (stdout); 126 if ((NULL != errDesc) && (0 != errDesc[0])) 127 fprintf (stderr, "%s", errDesc); 128 else 129 fprintf (stderr, "System or external library call failed"); 130 if ((NULL != funcName) && (0 != funcName[0])) 131 fprintf (stderr, " in %s", funcName); 132 if (0 < lineNum) 133 fprintf (stderr, " at line %d", lineNum); 134 135 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 136 strerror (errno)); 137 #ifdef MHD_WINSOCK_SOCKETS 138 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 139 #endif /* MHD_WINSOCK_SOCKETS */ 140 fflush (stderr); 141 exit (99); 142 } 143 144 145 static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; 146 147 _MHD_NORETURN static void 148 _libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 149 { 150 fflush (stdout); 151 if ((NULL != errDesc) && (0 != errDesc[0])) 152 fprintf (stderr, "%s", errDesc); 153 else 154 fprintf (stderr, "CURL library call failed"); 155 if ((NULL != funcName) && (0 != funcName[0])) 156 fprintf (stderr, " in %s", funcName); 157 if (0 < lineNum) 158 fprintf (stderr, " at line %d", lineNum); 159 160 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 161 strerror (errno)); 162 #ifdef MHD_WINSOCK_SOCKETS 163 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 164 #endif /* MHD_WINSOCK_SOCKETS */ 165 if (0 != libcurl_errbuf[0]) 166 fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf); 167 168 fflush (stderr); 169 exit (99); 170 } 171 172 173 _MHD_NORETURN static void 174 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 175 { 176 fflush (stdout); 177 if ((NULL != errDesc) && (0 != errDesc[0])) 178 fprintf (stderr, "%s", errDesc); 179 else 180 fprintf (stderr, "MHD unexpected error"); 181 if ((NULL != funcName) && (0 != funcName[0])) 182 fprintf (stderr, " in %s", funcName); 183 if (0 < lineNum) 184 fprintf (stderr, " at line %d", lineNum); 185 186 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 187 strerror (errno)); 188 #ifdef MHD_WINSOCK_SOCKETS 189 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 190 #endif /* MHD_WINSOCK_SOCKETS */ 191 192 fflush (stderr); 193 exit (8); 194 } 195 196 197 /* Could be increased to facilitate debugging */ 198 #define TIMEOUTS_VAL 500000 199 200 #define EXPECTED_URI_BASE_PATH "/" 201 202 #define EXISTING_URI EXPECTED_URI_BASE_PATH 203 204 #define EXPECTED_URI_BASE_PATH_MISSING "/wrong_uri" 205 206 #define URL_SCHEME "http:/" "/" 207 208 #define URL_HOST "127.0.0.1" 209 210 #define URL_SCHEME_HOST URL_SCHEME URL_HOST 211 212 #define PAGE \ 213 "<html><head><title>libmicrohttpd demo page</title></head>" \ 214 "<body>Success!</body></html>" 215 216 #define PAGE_404 \ 217 "<html><head><title>404 error</title></head>" \ 218 "<body>Error 404: The requested URI does not exist</body></html>" 219 220 /* Global parameters */ 221 static int verbose; 222 static int oneone; /**< If false use HTTP/1.0 for requests*/ 223 224 static struct curl_slist *hdr_broken_cnt_len = NULL; 225 226 static void 227 test_global_init (void) 228 { 229 libcurl_errbuf[0] = 0; 230 231 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 232 externalErrorExit (); 233 234 hdr_broken_cnt_len = 235 curl_slist_append (hdr_broken_cnt_len, 236 MHD_HTTP_HEADER_CONTENT_LENGTH ": 123bad"); 237 } 238 239 240 static void 241 test_global_cleanup (void) 242 { 243 curl_slist_free_all (hdr_broken_cnt_len); 244 245 curl_global_cleanup (); 246 } 247 248 249 struct CBC 250 { 251 char *buf; 252 size_t pos; 253 size_t size; 254 }; 255 256 257 static size_t 258 copyBuffer (void *ptr, 259 size_t size, 260 size_t nmemb, 261 void *ctx) 262 { 263 (void) ptr; /* Unused, mute compiler warning */ 264 (void) ctx; /* Unused, mute compiler warning */ 265 /* Discard data */ 266 return size * nmemb; 267 } 268 269 270 struct ahc_cls_type 271 { 272 const char *rq_method; 273 const char *rq_url; 274 }; 275 276 277 static enum MHD_Result 278 ahcCheck (void *cls, 279 struct MHD_Connection *connection, 280 const char *url, 281 const char *method, 282 const char *version, 283 const char *upload_data, size_t *upload_data_size, 284 void **req_cls) 285 { 286 static int marker; 287 struct MHD_Response *response; 288 enum MHD_Result ret; 289 struct ahc_cls_type *const param = (struct ahc_cls_type *) cls; 290 unsigned int http_code; 291 292 if (NULL == param) 293 mhdErrorExitDesc ("cls parameter is NULL"); 294 295 if (oneone) 296 { 297 if (0 != strcmp (version, MHD_HTTP_VERSION_1_1)) 298 mhdErrorExitDesc ("Unexpected HTTP version"); 299 } 300 else 301 { 302 if (0 != strcmp (version, MHD_HTTP_VERSION_1_0)) 303 mhdErrorExitDesc ("Unexpected HTTP version"); 304 } 305 306 if (0 != strcmp (url, param->rq_url)) 307 mhdErrorExitDesc ("Unexpected URI"); 308 309 if (NULL != upload_data) 310 mhdErrorExitDesc ("'upload_data' is not NULL"); 311 312 if (NULL == upload_data_size) 313 mhdErrorExitDesc ("'upload_data_size' pointer is NULL"); 314 315 if (0 != *upload_data_size) 316 mhdErrorExitDesc ("'*upload_data_size' value is not zero"); 317 318 if (0 != strcmp (param->rq_method, method)) 319 mhdErrorExitDesc ("Unexpected request method"); 320 321 if (&marker != *req_cls) 322 { 323 *req_cls = ▮ 324 return MHD_YES; 325 } 326 *req_cls = NULL; 327 328 if (0 == strcmp (url, EXISTING_URI)) 329 { 330 response = 331 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE), 332 PAGE); 333 http_code = MHD_HTTP_OK; 334 } 335 else 336 { 337 response = 338 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE_404), 339 PAGE_404); 340 http_code = MHD_HTTP_NOT_FOUND; 341 } 342 if (NULL == response) 343 mhdErrorExitDesc ("Failed to create response"); 344 345 ret = MHD_queue_response (connection, 346 http_code, 347 response); 348 MHD_destroy_response (response); 349 if (MHD_YES != ret) 350 mhdErrorExitDesc ("Failed to queue response"); 351 352 return ret; 353 } 354 355 356 static int 357 libcurl_debug_cb (CURL *handle, 358 curl_infotype type, 359 char *data, 360 size_t size, 361 void *userptr) 362 { 363 static const char excess_mark[] = "Excess found"; 364 static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark); 365 (void) handle; 366 (void) userptr; 367 368 #ifdef _DEBUG 369 switch (type) 370 { 371 case CURLINFO_TEXT: 372 fprintf (stderr, "* %.*s", (int) size, data); 373 break; 374 case CURLINFO_HEADER_IN: 375 fprintf (stderr, "< %.*s", (int) size, data); 376 break; 377 case CURLINFO_HEADER_OUT: 378 fprintf (stderr, "> %.*s", (int) size, data); 379 break; 380 case CURLINFO_DATA_IN: 381 #if 0 382 fprintf (stderr, "<| %.*s\n", (int) size, data); 383 #endif 384 break; 385 case CURLINFO_DATA_OUT: 386 case CURLINFO_SSL_DATA_IN: 387 case CURLINFO_SSL_DATA_OUT: 388 case CURLINFO_END: 389 default: 390 break; 391 } 392 #endif /* _DEBUG */ 393 if (CURLINFO_TEXT == type) 394 { 395 if ((size >= excess_mark_len) && 396 (0 == memcmp (data, excess_mark, excess_mark_len))) 397 mhdErrorExitDesc ("Extra data has been detected in MHD reply"); 398 } 399 return 0; 400 } 401 402 403 static CURL * 404 setupCURL (void *cbc, uint16_t port) 405 { 406 CURL *c; 407 408 c = curl_easy_init (); 409 if (NULL == c) 410 libcurlErrorExitDesc ("curl_easy_init() failed"); 411 412 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 413 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 414 ©Buffer)) || 415 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) || 416 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 417 ((long) TIMEOUTS_VAL))) || 418 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 419 (oneone) ? 420 CURL_HTTP_VERSION_1_1 : 421 CURL_HTTP_VERSION_1_0)) || 422 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 423 ((long) TIMEOUTS_VAL))) || 424 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, 425 libcurl_errbuf)) || 426 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) || 427 #ifdef _DEBUG 428 (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) || 429 #endif /* _DEBUG */ 430 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, 431 &libcurl_debug_cb)) || 432 #if CURL_AT_LEAST_VERSION (7, 85, 0) 433 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS_STR, "http")) || 434 #elif CURL_AT_LEAST_VERSION (7, 19, 4) 435 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) || 436 #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */ 437 #if CURL_AT_LEAST_VERSION (7, 45, 0) 438 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) || 439 #endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */ 440 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) 441 libcurlErrorExitDesc ("curl_easy_setopt() failed"); 442 443 if (CURLE_OK != 444 curl_easy_setopt (c, CURLOPT_URL, 445 URL_SCHEME_HOST EXPECTED_URI_BASE_PATH)) 446 libcurlErrorExitDesc ("Cannot set request URI"); 447 448 /* Set as a "custom" request, because no actual upload data is provided. */ 449 if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, 450 MHD_HTTP_METHOD_PUT)) 451 libcurlErrorExitDesc ("curl_easy_setopt() failed"); 452 453 if (CURLE_OK != 454 curl_easy_setopt (c, CURLOPT_HTTPHEADER, 455 hdr_broken_cnt_len)) 456 libcurlErrorExitDesc ("Cannot set '" MHD_HTTP_HEADER_CONTENT_LENGTH "'.\n"); 457 458 return c; 459 } 460 461 462 static CURLcode 463 performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse) 464 { 465 CURLM *multi; 466 time_t start; 467 struct timeval tv; 468 CURLcode ret; 469 470 ret = CURLE_FAILED_INIT; /* will be replaced with real result */ 471 if (NULL != *multi_reuse) 472 multi = *multi_reuse; 473 else 474 { 475 multi = curl_multi_init (); 476 if (multi == NULL) 477 libcurlErrorExitDesc ("curl_multi_init() failed"); 478 *multi_reuse = multi; 479 } 480 if (CURLM_OK != curl_multi_add_handle (multi, c)) 481 libcurlErrorExitDesc ("curl_multi_add_handle() failed"); 482 483 start = time (NULL); 484 while (time (NULL) - start <= TIMEOUTS_VAL) 485 { 486 fd_set rs; 487 fd_set ws; 488 fd_set es; 489 MHD_socket maxMhdSk; 490 int maxCurlSk; 491 int running; 492 493 maxMhdSk = MHD_INVALID_SOCKET; 494 maxCurlSk = -1; 495 FD_ZERO (&rs); 496 FD_ZERO (&ws); 497 FD_ZERO (&es); 498 if (NULL != multi) 499 { 500 curl_multi_perform (multi, &running); 501 if (0 == running) 502 { 503 struct CURLMsg *msg; 504 int msgLeft; 505 int totalMsgs = 0; 506 do 507 { 508 msg = curl_multi_info_read (multi, &msgLeft); 509 if (NULL == msg) 510 libcurlErrorExitDesc ("curl_multi_info_read() failed"); 511 totalMsgs++; 512 if (CURLMSG_DONE == msg->msg) 513 ret = msg->data.result; 514 } while (msgLeft > 0); 515 if (1 != totalMsgs) 516 { 517 fprintf (stderr, 518 "curl_multi_info_read returned wrong " 519 "number of results (%d).\n", 520 totalMsgs); 521 externalErrorExit (); 522 } 523 curl_multi_remove_handle (multi, c); 524 multi = NULL; 525 } 526 else 527 { 528 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) 529 libcurlErrorExitDesc ("curl_multi_fdset() failed"); 530 } 531 } 532 if (NULL == multi) 533 { /* libcurl has finished, check whether MHD still needs to perform cleanup */ 534 if (0 != MHD_get_timeout64s (d)) 535 break; /* MHD finished as well */ 536 } 537 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) 538 mhdErrorExitDesc ("MHD_get_fdset() failed"); 539 tv.tv_sec = 0; 540 tv.tv_usec = 200000; 541 if (0 == MHD_get_timeout64s (d)) 542 tv.tv_usec = 0; 543 else 544 { 545 long curl_to = -1; 546 curl_multi_timeout (multi, &curl_to); 547 if (0 == curl_to) 548 tv.tv_usec = 0; 549 } 550 #ifdef MHD_POSIX_SOCKETS 551 if (maxMhdSk > maxCurlSk) 552 maxCurlSk = maxMhdSk; 553 #endif /* MHD_POSIX_SOCKETS */ 554 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) 555 { 556 #ifdef MHD_POSIX_SOCKETS 557 if (EINTR != errno) 558 externalErrorExitDesc ("Unexpected select() error"); 559 #else 560 if ((WSAEINVAL != WSAGetLastError ()) || 561 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 562 externalErrorExitDesc ("Unexpected select() error"); 563 Sleep ((unsigned long) tv.tv_usec / 1000); 564 #endif 565 } 566 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) 567 mhdErrorExitDesc ("MHD_run_from_select() failed"); 568 } 569 570 return ret; 571 } 572 573 574 /** 575 * Check request result 576 * @param curl_code the CURL easy return code 577 * @param pcbc the pointer struct CBC 578 * @return non-zero if success, zero if failed 579 */ 580 static unsigned int 581 check_result (CURLcode curl_code, CURL *c, long expected_code) 582 { 583 long code; 584 585 if (CURLE_OK != curl_code) 586 { 587 fflush (stdout); 588 if (0 != libcurl_errbuf[0]) 589 fprintf (stderr, "Request failed. " 590 "libcurl error: '%s'.\n" 591 "libcurl error description: '%s'.\n", 592 curl_easy_strerror (curl_code), 593 libcurl_errbuf); 594 else 595 fprintf (stderr, "Request failed. " 596 "libcurl error: '%s'.\n", 597 curl_easy_strerror (curl_code)); 598 fflush (stderr); 599 return 0; 600 } 601 602 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) 603 libcurlErrorExit (); 604 605 if (expected_code != code) 606 { 607 fprintf (stderr, "The response has wrong HTTP code: %ld\tExpected: %ld.\n", 608 code, expected_code); 609 return 0; 610 } 611 else if (verbose) 612 printf ("The response has expected HTTP code: %ld\n", expected_code); 613 614 return ! 0; 615 } 616 617 618 static unsigned int 619 performTest (void) 620 { 621 struct MHD_Daemon *d; 622 uint16_t port; 623 struct CBC cbc; 624 struct ahc_cls_type ahc_param; 625 char buf[2048]; 626 CURL *c; 627 CURLM *multi_reuse; 628 int failed = 0; 629 630 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 631 port = 0; 632 else 633 port = 4220 + oneone ? 0 : 1; 634 635 d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY, 636 port, NULL, NULL, 637 &ahcCheck, &ahc_param, 638 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 639 MHD_OPTION_END); 640 if (d == NULL) 641 return 1; 642 if (0 == port) 643 { 644 const union MHD_DaemonInfo *dinfo; 645 646 dinfo = MHD_get_daemon_info (d, 647 MHD_DAEMON_INFO_BIND_PORT); 648 if ( (NULL == dinfo) || 649 (0 == dinfo->port) ) 650 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 651 port = dinfo->port; 652 } 653 654 /* First request */ 655 ahc_param.rq_method = MHD_HTTP_METHOD_PUT; 656 ahc_param.rq_url = EXPECTED_URI_BASE_PATH; 657 cbc.buf = buf; 658 cbc.size = sizeof (buf); 659 cbc.pos = 0; 660 memset (cbc.buf, 0, cbc.size); 661 c = setupCURL (&cbc, port); 662 multi_reuse = NULL; 663 /* First request */ 664 if (check_result (performQueryExternal (d, c, &multi_reuse), c, 665 MHD_HTTP_BAD_REQUEST)) 666 { 667 fflush (stderr); 668 if (verbose) 669 printf ("Got first expected response.\n"); 670 fflush (stdout); 671 } 672 else 673 { 674 fprintf (stderr, "First request FAILED.\n"); 675 fflush (stderr); 676 failed = 1; 677 } 678 /* Second request */ 679 cbc.pos = 0; /* Reset buffer position */ 680 if (check_result (performQueryExternal (d, c, &multi_reuse), c, 681 MHD_HTTP_BAD_REQUEST)) 682 { 683 fflush (stderr); 684 if (verbose) 685 printf ("Got second expected response.\n"); 686 fflush (stdout); 687 } 688 else 689 { 690 fprintf (stderr, "Second request FAILED.\n"); 691 fflush (stderr); 692 failed = 1; 693 } 694 /* Third request */ 695 cbc.pos = 0; /* Reset buffer position */ 696 if (NULL != multi_reuse) 697 curl_multi_cleanup (multi_reuse); 698 multi_reuse = NULL; /* Force new connection */ 699 if (check_result (performQueryExternal (d, c, &multi_reuse), c, 700 MHD_HTTP_BAD_REQUEST)) 701 { 702 fflush (stderr); 703 if (verbose) 704 printf ("Got third expected response.\n"); 705 fflush (stdout); 706 } 707 else 708 { 709 fprintf (stderr, "Third request FAILED.\n"); 710 fflush (stderr); 711 failed = 1; 712 } 713 714 curl_easy_cleanup (c); 715 if (NULL != multi_reuse) 716 curl_multi_cleanup (multi_reuse); 717 718 MHD_stop_daemon (d); 719 return failed ? 1 : 0; 720 } 721 722 723 int 724 main (int argc, char *const *argv) 725 { 726 unsigned int errorCount = 0; 727 728 /* Test type and test parameters */ 729 verbose = ! (has_param (argc, argv, "-q") || 730 has_param (argc, argv, "--quiet") || 731 has_param (argc, argv, "-s") || 732 has_param (argc, argv, "--silent")); 733 oneone = ! has_in_name (argv[0], "10"); 734 735 test_global_init (); 736 737 errorCount += performTest (); 738 if (errorCount != 0) 739 fprintf (stderr, "Error (code: %u)\n", errorCount); 740 test_global_cleanup (); 741 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 742 }