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