test_put_header_fold.c (39582B)
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_put_header_fold.c 24 * @brief Testcase for requests with header fold 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 #endif 41 42 #include "internal.h" 43 #include "mhd_has_param.h" 44 #include "mhd_has_in_name.h" 45 46 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 47 test into a marked, classifiable test error (TESTING.md, P5). */ 48 #include "mhd_panic_tripwire.h" 49 50 /* The next macros are borrowed from memorypool.c 51 Keep them in sync! */ 52 53 /** 54 * Align to 2x word size (as GNU libc does). 55 */ 56 #define ALIGN_SIZE (2 * sizeof(void*)) 57 /** 58 * Round up 'n' to a multiple of ALIGN_SIZE. 59 */ 60 #define ROUND_TO_ALIGN(n) (((n) + (ALIGN_SIZE - 1)) \ 61 / (ALIGN_SIZE) *(ALIGN_SIZE)) 62 #ifndef MHD_ASAN_POISON_ACTIVE 63 #define _MHD_RED_ZONE_SIZE (0) 64 #else /* MHD_ASAN_POISON_ACTIVE */ 65 #define _MHD_RED_ZONE_SIZE (ALIGN_SIZE) 66 #endif /* MHD_ASAN_POISON_ACTIVE */ 67 68 #define ROUND_TO_ALIGN_PLUS_RED_ZONE(n) (ROUND_TO_ALIGN(n) + _MHD_RED_ZONE_SIZE) 69 70 /* The previous macros are borrowed from memorypool.c 71 Keep them in sync! */ 72 73 #ifndef MHD_STATICSTR_LEN_ 74 /** 75 * Determine length of static string / macro strings at compile time. 76 */ 77 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) 78 #endif /* ! MHD_STATICSTR_LEN_ */ 79 80 #ifndef CURL_VERSION_BITS 81 #define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z)) 82 #endif /* ! CURL_VERSION_BITS */ 83 #ifndef CURL_AT_LEAST_VERSION 84 #define CURL_AT_LEAST_VERSION(x,y,z) \ 85 (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z)) 86 #endif /* ! CURL_AT_LEAST_VERSION */ 87 88 #ifndef _MHD_INSTRMACRO 89 /* Quoted macro parameter */ 90 #define _MHD_INSTRMACRO(a) #a 91 #endif /* ! _MHD_INSTRMACRO */ 92 #ifndef _MHD_STRMACRO 93 /* Quoted expanded macro parameter */ 94 #define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a) 95 #endif /* ! _MHD_STRMACRO */ 96 97 #if defined(HAVE___FUNC__) 98 #define externalErrorExit(ignore) \ 99 _externalErrorExit_func (NULL, __func__, __LINE__) 100 #define externalErrorExitDesc(errDesc) \ 101 _externalErrorExit_func (errDesc, __func__, __LINE__) 102 #define libcurlErrorExit(ignore) \ 103 _libcurlErrorExit_func (NULL, __func__, __LINE__) 104 #define libcurlErrorExitDesc(errDesc) \ 105 _libcurlErrorExit_func (errDesc, __func__, __LINE__) 106 #define mhdErrorExit(ignore) \ 107 _mhdErrorExit_func (NULL, __func__, __LINE__) 108 #define mhdErrorExitDesc(errDesc) \ 109 _mhdErrorExit_func (errDesc, __func__, __LINE__) 110 #define checkCURLE_OK(libcurlcall) \ 111 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ 112 __func__, __LINE__) 113 #elif defined(HAVE___FUNCTION__) 114 #define externalErrorExit(ignore) \ 115 _externalErrorExit_func (NULL, __FUNCTION__, __LINE__) 116 #define externalErrorExitDesc(errDesc) \ 117 _externalErrorExit_func (errDesc, __FUNCTION__, __LINE__) 118 #define libcurlErrorExit(ignore) \ 119 _libcurlErrorExit_func (NULL, __FUNCTION__, __LINE__) 120 #define libcurlErrorExitDesc(errDesc) \ 121 _libcurlErrorExit_func (errDesc, __FUNCTION__, __LINE__) 122 #define mhdErrorExit(ignore) \ 123 _mhdErrorExit_func (NULL, __FUNCTION__, __LINE__) 124 #define mhdErrorExitDesc(errDesc) \ 125 _mhdErrorExit_func (errDesc, __FUNCTION__, __LINE__) 126 #define checkCURLE_OK(libcurlcall) \ 127 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \ 128 __FUNCTION__, __LINE__) 129 #else 130 #define externalErrorExit(ignore) _externalErrorExit_func (NULL, NULL, __LINE__) 131 #define externalErrorExitDesc(errDesc) \ 132 _externalErrorExit_func (errDesc, NULL, __LINE__) 133 #define libcurlErrorExit(ignore) _libcurlErrorExit_func (NULL, NULL, __LINE__) 134 #define libcurlErrorExitDesc(errDesc) \ 135 _libcurlErrorExit_func (errDesc, NULL, __LINE__) 136 #define mhdErrorExit(ignore) _mhdErrorExit_func (NULL, NULL, __LINE__) 137 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func (errDesc, NULL, __LINE__) 138 #define checkCURLE_OK(libcurlcall) \ 139 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), NULL, \ 140 __LINE__) 141 #endif 142 143 144 _MHD_NORETURN static void 145 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 146 { 147 fflush (stdout); 148 if ((NULL != errDesc) && (0 != errDesc[0])) 149 fprintf (stderr, "%s", errDesc); 150 else 151 fprintf (stderr, "System or external library call failed"); 152 if ((NULL != funcName) && (0 != funcName[0])) 153 fprintf (stderr, " in %s", funcName); 154 if (0 < lineNum) 155 fprintf (stderr, " at line %d", lineNum); 156 157 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 158 strerror (errno)); 159 #ifdef MHD_WINSOCK_SOCKETS 160 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 161 #endif /* MHD_WINSOCK_SOCKETS */ 162 fflush (stderr); 163 exit (99); 164 } 165 166 167 static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; 168 169 _MHD_NORETURN static void 170 _libcurlErrorExit_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, "CURL library call failed"); 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 if (0 != libcurl_errbuf[0]) 188 fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf); 189 190 fflush (stderr); 191 exit (99); 192 } 193 194 195 _MHD_NORETURN static void 196 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 197 { 198 fflush (stdout); 199 if ((NULL != errDesc) && (0 != errDesc[0])) 200 fprintf (stderr, "%s", errDesc); 201 else 202 fprintf (stderr, "MHD unexpected error"); 203 if ((NULL != funcName) && (0 != funcName[0])) 204 fprintf (stderr, " in %s", funcName); 205 if (0 < lineNum) 206 fprintf (stderr, " at line %d", lineNum); 207 208 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 209 strerror (errno)); 210 #ifdef MHD_WINSOCK_SOCKETS 211 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 212 #endif /* MHD_WINSOCK_SOCKETS */ 213 214 fflush (stderr); 215 exit (8); 216 } 217 218 219 /* Could be increased to facilitate debugging */ 220 #define TIMEOUTS_VAL 5 221 222 #define TEST_UPLOAD_DATA_SIZE 2048U 223 224 #define EXPECTED_URI_BASE_PATH "/" 225 226 #define URL_SCHEME "http:/" "/" 227 228 #define URL_HOST "127.0.0.1" 229 230 #define URL_SCHEME_HOST_PATH URL_SCHEME URL_HOST EXPECTED_URI_BASE_PATH 231 232 #define RP_HEADER1_NAME "First" 233 #define RP_HEADER1_VALUE "1st" 234 #define RP_HEADER1 RP_HEADER1_NAME ": " RP_HEADER1_VALUE 235 #define RP_HEADER1_CRLF RP_HEADER1 "\r\n" 236 #define RP_HEADER2_NAME "Normal" 237 #define RP_HEADER2_VALUE "it's fine" 238 #define RP_HEADER2 RP_HEADER2_NAME ": " RP_HEADER2_VALUE 239 #define RP_HEADER2_CRLF RP_HEADER2 "\r\n" 240 241 #define HDR_FOLD "\r\n " 242 #define RQ_HEADER1_NAME RP_HEADER1_NAME 243 #define RQ_HEADER1_VALUE RP_HEADER1_VALUE 244 #define RQ_HEADER1 RQ_HEADER1_NAME ": " RQ_HEADER1_VALUE 245 #define RQ_HEADER2_NAME "Folded" 246 #define RQ_HEADER2_VALUE_S "start" 247 #define RQ_HEADER2_VALUE_E "end" 248 #define RQ_HEADER2_VALUE \ 249 RQ_HEADER2_VALUE_S HDR_FOLD RQ_HEADER2_VALUE_E 250 #define RQ_HEADER2_VALUE_DF \ 251 RQ_HEADER2_VALUE_S HDR_FOLD HDR_FOLD RQ_HEADER2_VALUE_E 252 #define RQ_HEADER2 RQ_HEADER2_NAME ": " RQ_HEADER2_VALUE 253 #define RQ_HEADER2_DF RQ_HEADER2_NAME ": " RQ_HEADER2_VALUE_DF 254 #define RQ_HEADER3_NAME RP_HEADER2_NAME 255 #define RQ_HEADER3_VALUE RP_HEADER2_VALUE 256 #define RQ_HEADER3 RQ_HEADER3_NAME ": " RQ_HEADER3_VALUE 257 258 /** 259 * The number of request headers: 3 custom headers + 2 automatic headers 260 */ 261 #define RQ_NUM_HEADERS (3 + 2) 262 /** 263 * The extra size in the memory pool for pointers to the headers 264 */ 265 #define HEADERS_POINTERS_SIZE \ 266 RQ_NUM_HEADERS * \ 267 ROUND_TO_ALIGN_PLUS_RED_ZONE(sizeof(struct MHD_HTTP_Req_Header)) 268 269 #define PAGE \ 270 "<html><head><title>libmicrohttpd demo page</title></head>" \ 271 "<body>Success!</body></html>" 272 273 /* Global parameters */ 274 static int verbose; 275 static int oneone; /**< If false use HTTP/1.0 for requests*/ 276 static int use_get; 277 static int use_put; 278 static int use_put_large; 279 static int use_double_fold; 280 static int use_hdr_last; /**< If non-zero, folded header is placed last */ 281 static int use_hdr_large; /**< If non-zero, folded header is large */ 282 283 /* Static data */ 284 static struct curl_slist *libcurl_headers = NULL; 285 286 static char *put_data = NULL; 287 288 /** 289 * Initialise headers for libcurl 290 * 291 * @return non-zero if succeed, 292 * zero if failed 293 */ 294 static void 295 libcurl_headers_init (void) 296 { 297 libcurl_headers = curl_slist_append (NULL, RQ_HEADER1); 298 if (NULL == libcurl_headers) 299 libcurlErrorExitDesc ("curl_slist_append() failed"); 300 301 if (use_hdr_last) 302 { 303 libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER3); 304 if (NULL == libcurl_headers) 305 libcurlErrorExitDesc ("curl_slist_append() failed"); 306 } 307 308 if (! use_hdr_large) 309 { 310 if (! use_double_fold) 311 libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER2); 312 else 313 libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER2_DF); 314 if (NULL == libcurl_headers) 315 libcurlErrorExitDesc ("curl_slist_append() failed"); 316 } 317 else 318 { 319 char *buf; 320 size_t pos; 321 buf = malloc (TEST_UPLOAD_DATA_SIZE + 1); 322 if (NULL == buf) 323 externalErrorExitDesc ("malloc() failed"); 324 pos = 0; 325 memcpy (buf, RQ_HEADER2_NAME, MHD_STATICSTR_LEN_ (RQ_HEADER2_NAME)); 326 pos += MHD_STATICSTR_LEN_ (RQ_HEADER2_NAME); 327 buf[pos++] = ':'; 328 buf[pos++] = ' '; 329 memcpy (buf + pos, 330 RQ_HEADER2_VALUE_S, MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S)); 331 pos += MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S); 332 memcpy (buf + pos, HDR_FOLD, MHD_STATICSTR_LEN_ (HDR_FOLD)); 333 pos += MHD_STATICSTR_LEN_ (HDR_FOLD); 334 if (use_double_fold) 335 { 336 memcpy (buf + pos, HDR_FOLD, MHD_STATICSTR_LEN_ (HDR_FOLD)); 337 pos += MHD_STATICSTR_LEN_ (HDR_FOLD); 338 } 339 memset (buf + pos, 'a', 340 TEST_UPLOAD_DATA_SIZE - pos 341 - MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E) - 1); 342 pos += TEST_UPLOAD_DATA_SIZE - pos 343 - MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E) - 1; 344 buf[pos++] = ' '; 345 memcpy (buf + pos, 346 RQ_HEADER2_VALUE_E, MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E)); 347 pos += MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E); 348 if (TEST_UPLOAD_DATA_SIZE != pos) 349 externalErrorExitDesc ("Position miscalculation"); 350 buf[pos] = 0; 351 352 libcurl_headers = curl_slist_append (libcurl_headers, buf); 353 if (NULL == libcurl_headers) 354 libcurlErrorExitDesc ("curl_slist_append() failed"); 355 356 free (buf); 357 } 358 359 if (! use_hdr_last) 360 { 361 libcurl_headers = curl_slist_append (libcurl_headers, RQ_HEADER3); 362 if (NULL == libcurl_headers) 363 libcurlErrorExitDesc ("curl_slist_append() failed"); 364 } 365 } 366 367 368 static void 369 init_put_data (void) 370 { 371 size_t i; 372 put_data = malloc (TEST_UPLOAD_DATA_SIZE + 1); 373 if (NULL == put_data) 374 externalErrorExit (); 375 376 for (i = 0; i < (TEST_UPLOAD_DATA_SIZE - 1); ++i) 377 { 378 if (0 == (i % 7)) 379 put_data[i] = ' '; 380 else if (0 == (i % 47)) 381 put_data[i] = '\n'; 382 else if (0 == (i % 11)) 383 put_data[i] = (char) ('A' + i % ('Z' - 'A' + 1)); 384 else 385 put_data[i] = (char) ('a' + i % ('z' - 'a' + 1)); 386 } 387 put_data[TEST_UPLOAD_DATA_SIZE - 1] = '\n'; 388 put_data[TEST_UPLOAD_DATA_SIZE] = 0; 389 } 390 391 392 static void 393 test_global_init (void) 394 { 395 libcurl_errbuf[0] = 0; 396 397 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 398 externalErrorExit (); 399 400 init_put_data (); 401 libcurl_headers_init (); 402 } 403 404 405 static void 406 test_global_cleanup (void) 407 { 408 curl_slist_free_all (libcurl_headers); 409 curl_global_cleanup (); 410 if (NULL != put_data) 411 free (put_data); 412 put_data = NULL; 413 } 414 415 416 struct headers_check_result 417 { 418 unsigned int expected_size; 419 int header1_found; 420 int header2_found; 421 unsigned int size_found; 422 unsigned int size_broken_found; 423 }; 424 425 static size_t 426 lcurl_hdr_callback (char *buffer, size_t size, size_t nitems, 427 void *userdata) 428 { 429 const size_t data_size = size * nitems; 430 struct headers_check_result *check_res = 431 (struct headers_check_result *) userdata; 432 433 if ((MHD_STATICSTR_LEN_ (RP_HEADER1_CRLF) == data_size) && 434 (0 == memcmp (RP_HEADER1_CRLF, buffer, data_size))) 435 check_res->header1_found++; 436 else if ((MHD_STATICSTR_LEN_ (RP_HEADER2_CRLF) == data_size) && 437 (0 == memcmp (RP_HEADER2_CRLF, buffer, data_size))) 438 check_res->header2_found++; 439 else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": ") 440 < data_size) && 441 (0 == 442 memcmp (MHD_HTTP_HEADER_CONTENT_LENGTH ": ", buffer, 443 MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": ")))) 444 { 445 char cmpbuf[256]; 446 int res; 447 const unsigned int numbers_pos = 448 MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH ": "); 449 res = snprintf (cmpbuf, sizeof(cmpbuf), "%u", check_res->expected_size); 450 if ((res <= 0) || (res > ((int) (sizeof(cmpbuf) - 1)))) 451 externalErrorExit (); 452 if (data_size - numbers_pos <= 2) 453 { 454 fprintf (stderr, "Broken Content-Length.\n"); 455 check_res->size_broken_found++; 456 } 457 else if ((((size_t) res + 2) != data_size - numbers_pos) || 458 (0 != memcmp (buffer + numbers_pos, cmpbuf, (size_t) res))) 459 { 460 fprintf (stderr, "Wrong Content-Length. " 461 "Expected: %u. " 462 "Received: %.*s.\n", 463 check_res->expected_size, 464 (int) (data_size - numbers_pos - 2), 465 buffer + numbers_pos); 466 check_res->size_broken_found++; 467 } 468 else if (0 != memcmp ("\r\n", buffer + data_size - 2, 2)) 469 { 470 fprintf (stderr, "The Content-Length header is not " 471 "terminated by CRLF.\n"); 472 check_res->size_broken_found++; 473 } 474 else 475 check_res->size_found++; 476 } 477 478 return data_size; 479 } 480 481 482 struct CBC 483 { 484 /* Upload members */ 485 size_t up_pos; 486 size_t up_size; 487 /* Download members */ 488 char *dn_buf; 489 size_t dn_pos; 490 size_t dn_buf_size; 491 }; 492 493 494 static size_t 495 copyBuffer (void *ptr, 496 size_t size, 497 size_t nmemb, 498 void *ctx) 499 { 500 struct CBC *cbc = ctx; 501 502 if (cbc->dn_pos + size * nmemb > cbc->dn_buf_size) 503 return 0; /* overflow */ 504 memcpy (&cbc->dn_buf[cbc->dn_pos], ptr, size * nmemb); 505 cbc->dn_pos += size * nmemb; 506 return size * nmemb; 507 } 508 509 510 static size_t 511 libcurlUploadDataCB (void *stream, size_t item_size, size_t nitems, void *ctx) 512 { 513 size_t to_fill; 514 struct CBC *cbc = ctx; 515 516 to_fill = cbc->up_size - cbc->up_pos; 517 if (to_fill > item_size * nitems) 518 to_fill = item_size * nitems; 519 520 /* Avoid libcurl magic numbers */ 521 #ifdef CURL_READFUNC_PAUSE 522 if (CURL_READFUNC_PAUSE == to_fill) 523 to_fill = (CURL_READFUNC_PAUSE - 2); 524 #endif /* CURL_READFUNC_PAUSE */ 525 #ifdef CURL_READFUNC_ABORT 526 if (CURL_READFUNC_ABORT == to_fill) 527 to_fill = (CURL_READFUNC_ABORT - 1); 528 #endif /* CURL_READFUNC_ABORT */ 529 530 memcpy (stream, put_data + cbc->up_pos, to_fill); 531 cbc->up_pos += to_fill; 532 return to_fill; 533 } 534 535 536 static int 537 libcurl_debug_cb (CURL *handle, 538 curl_infotype type, 539 char *data, 540 size_t size, 541 void *userptr) 542 { 543 static const char excess_mark[] = "Excess found"; 544 static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark); 545 546 (void) handle; 547 (void) userptr; 548 549 #ifdef _DEBUG 550 switch (type) 551 { 552 case CURLINFO_TEXT: 553 fprintf (stderr, "* %.*s", (int) size, data); 554 break; 555 case CURLINFO_HEADER_IN: 556 fprintf (stderr, "< %.*s", (int) size, data); 557 break; 558 case CURLINFO_HEADER_OUT: 559 fprintf (stderr, "> %.*s", (int) size, data); 560 break; 561 case CURLINFO_DATA_IN: 562 #if 0 563 fprintf (stderr, "<| %.*s\n", (int) size, data); 564 #endif 565 break; 566 case CURLINFO_DATA_OUT: 567 case CURLINFO_SSL_DATA_IN: 568 case CURLINFO_SSL_DATA_OUT: 569 case CURLINFO_END: 570 default: 571 break; 572 } 573 #endif /* _DEBUG */ 574 if (CURLINFO_TEXT == type) 575 { 576 if ((size >= excess_mark_len) && 577 (0 == memcmp (data, excess_mark, excess_mark_len))) 578 mhdErrorExitDesc ("Extra data has been detected in MHD reply"); 579 } 580 return 0; 581 } 582 583 584 static CURL * 585 setupCURL (void *cbc, uint16_t port, 586 struct headers_check_result *hdr_chk_result) 587 { 588 CURL *c; 589 590 c = curl_easy_init (); 591 if (NULL == c) 592 libcurlErrorExitDesc ("curl_easy_init() failed"); 593 594 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || 595 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, 596 ©Buffer)) || 597 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) || 598 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 599 ((long) TIMEOUTS_VAL))) || 600 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 601 (oneone) ? 602 CURL_HTTP_VERSION_1_1 : 603 CURL_HTTP_VERSION_1_0)) || 604 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, 605 ((long) TIMEOUTS_VAL))) || 606 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERFUNCTION, 607 lcurl_hdr_callback)) || 608 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERDATA, 609 hdr_chk_result)) || 610 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, 611 libcurl_errbuf)) || 612 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) || 613 #ifdef _DEBUG 614 (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) || 615 #endif /* _DEBUG */ 616 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, 617 &libcurl_debug_cb)) || 618 #if CURL_AT_LEAST_VERSION (7, 45, 0) 619 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) || 620 #endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */ 621 #if CURL_AT_LEAST_VERSION (7, 85, 0) 622 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS_STR, "http")) || 623 #elif CURL_AT_LEAST_VERSION (7, 19, 4) 624 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) || 625 #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */ 626 (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, 627 URL_SCHEME_HOST_PATH)) || 628 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port)))) 629 libcurlErrorExitDesc ("curl_easy_setopt() failed"); 630 631 if (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPHEADER, libcurl_headers)) 632 libcurlErrorExitDesc ("Failed to set request headers"); 633 634 if (use_put) 635 { 636 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_UPLOAD, 1L)) || 637 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READFUNCTION, 638 libcurlUploadDataCB)) || 639 (CURLE_OK != curl_easy_setopt (c, CURLOPT_READDATA, 640 cbc))) 641 libcurlErrorExitDesc ("Failed to configure the PUT upload"); 642 } 643 644 return c; 645 } 646 647 648 struct ahc_cls_type 649 { 650 const char *rq_method; 651 const char *rq_url; 652 653 unsigned int num_req; 654 /* Position in the upload data, not compatible with parallel requests */ 655 size_t up_pos; 656 size_t expected_upload_size; 657 unsigned int req_check_error; 658 }; 659 660 661 static enum MHD_Result 662 ahcCheck (void *cls, 663 struct MHD_Connection *connection, 664 const char *url, 665 const char *method, 666 const char *version, 667 const char *upload_data, size_t *upload_data_size, 668 void **req_cls) 669 { 670 static int marker; 671 struct MHD_Response *response; 672 enum MHD_Result ret; 673 struct ahc_cls_type *const param = (struct ahc_cls_type *) cls; 674 675 if (NULL == param) 676 mhdErrorExitDesc ("cls parameter is NULL"); 677 678 if (oneone) 679 { 680 if (0 != strcmp (version, MHD_HTTP_VERSION_1_1)) 681 mhdErrorExitDesc ("Unexpected HTTP version"); 682 } 683 else 684 { 685 if (0 != strcmp (version, MHD_HTTP_VERSION_1_0)) 686 mhdErrorExitDesc ("Unexpected HTTP version"); 687 } 688 689 if (0 != strcmp (url, param->rq_url)) 690 mhdErrorExitDesc ("Unexpected URI"); 691 692 if (0 != strcmp (param->rq_method, method)) 693 mhdErrorExitDesc ("Unexpected request method"); 694 695 if (NULL == upload_data_size) 696 mhdErrorExitDesc ("'upload_data_size' pointer is NULL"); 697 698 if (NULL != upload_data) 699 { 700 size_t report_processed_size; 701 if (0 == *upload_data_size) 702 mhdErrorExitDesc ("'*upload_data_size' value is zero"); 703 report_processed_size = *upload_data_size; 704 /* The next checks are not compatible with parallel requests */ 705 if (*upload_data_size > param->expected_upload_size - param->up_pos) 706 { 707 fprintf (stderr, "Unexpected *upload_data_size value: %lu. " 708 "Already processed data size: %lu. " 709 "Total expected upload size: %lu. " 710 "Expected unprocessed upload size: %lu. " 711 "The upload data cannot be checked.\n", 712 (unsigned long) *upload_data_size, 713 (unsigned long) param->up_pos, 714 (unsigned long) param->expected_upload_size, 715 (unsigned long) (param->expected_upload_size - param->up_pos)); 716 param->req_check_error++; 717 } 718 else 719 { 720 if (0 != memcmp (upload_data, put_data + param->up_pos, 721 *upload_data_size)) 722 { 723 fprintf (stderr, "Wrong upload data.\n" 724 "Expected: '%.*s'\n" 725 "Received: '%.*s'.\n", 726 (int) *upload_data_size, upload_data, 727 (int) *upload_data_size, put_data + param->up_pos); 728 param->req_check_error++; 729 } 730 if (use_put_large && 731 (report_processed_size > param->expected_upload_size / 10)) 732 report_processed_size = param->expected_upload_size / 10; 733 734 param->up_pos += report_processed_size; 735 } 736 *upload_data_size -= report_processed_size; 737 return MHD_YES; 738 } 739 else 740 { 741 if (0 != *upload_data_size) 742 mhdErrorExitDesc ("'*upload_data_size' value is not zero"); 743 } 744 745 if (1) 746 { 747 /* Check headers */ 748 const char *value; 749 size_t value_len; 750 unsigned int header_check_error; 751 752 header_check_error = 0; 753 754 value = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 755 RQ_HEADER1_NAME); 756 if (NULL == value) 757 { 758 fprintf (stderr, "Request header '" RQ_HEADER1_NAME "' not found.\n"); 759 header_check_error++; 760 } 761 else 762 { 763 if (0 != strcmp (value, RQ_HEADER1_VALUE)) 764 { 765 fprintf (stderr, "Wrong header '" RQ_HEADER1_NAME "'value. " 766 "Expected: '%s'. Received: '%s'.\n", 767 RQ_HEADER1_VALUE, value); 768 header_check_error++; 769 } 770 } 771 772 if (MHD_YES != 773 MHD_lookup_connection_value_n (connection, MHD_HEADER_KIND, 774 RQ_HEADER2_NAME, 775 MHD_STATICSTR_LEN_ (RQ_HEADER2_NAME), 776 &value, &value_len)) 777 { 778 fprintf (stderr, "Request header '" RQ_HEADER2_NAME "' not found.\n"); 779 header_check_error++; 780 } 781 else 782 { 783 if (NULL == value) 784 mhdErrorExitDesc ("The 'value' pointer is NULL"); 785 if (strlen (value) != value_len) 786 mhdErrorExitDesc ("The 'value' length does not match strlen(value)"); 787 788 if (value_len < MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S) 789 + MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E)) 790 { 791 fprintf (stderr, "The value_len is too short. The value: '%s'.\n", 792 value); 793 header_check_error++; 794 } 795 if (0 != memcmp (value, RQ_HEADER2_VALUE_S, 796 MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_S))) 797 { 798 fprintf (stderr, "The 'value' does not start with '" 799 RQ_HEADER2_VALUE_S "'. The 'value' is '%s'. ", 800 value); 801 header_check_error++; 802 } 803 if (0 != memcmp (value 804 + value_len - MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E), 805 RQ_HEADER2_VALUE_E, 806 MHD_STATICSTR_LEN_ (RQ_HEADER2_VALUE_E))) 807 { 808 fprintf (stderr, "The 'value' does not end with '" 809 RQ_HEADER2_VALUE_E "'. The 'value' is '%s'. ", 810 value); 811 header_check_error++; 812 } 813 } 814 815 value = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 816 RQ_HEADER3_NAME); 817 if (NULL == value) 818 { 819 fprintf (stderr, "Request header '" RQ_HEADER3_NAME "' not found.\n"); 820 header_check_error++; 821 } 822 else 823 { 824 if (0 != strcmp (value, RQ_HEADER3_VALUE)) 825 { 826 fprintf (stderr, "Wrong header '" RQ_HEADER3_NAME "'value. " 827 "Expected: '%s'. Received: '%s'.\n", 828 RQ_HEADER3_VALUE, value); 829 header_check_error++; 830 } 831 } 832 param->req_check_error += header_check_error; 833 } 834 835 if (&marker != *req_cls) 836 { 837 *req_cls = ▮ 838 if (param->num_req) 839 mhdErrorExitDesc ("Got unexpected second request"); 840 param->num_req++; 841 return MHD_YES; 842 } 843 *req_cls = NULL; 844 845 if (0 != strcmp (url, EXPECTED_URI_BASE_PATH)) 846 { 847 fprintf (stderr, "Unexpected URI: '%s'. ", url); 848 mhdErrorExitDesc ("Unexpected URI found"); 849 } 850 851 response = 852 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE), 853 PAGE); 854 if (NULL == response) 855 mhdErrorExitDesc ("Failed to create response"); 856 857 if (MHD_YES != MHD_add_response_header (response, 858 RP_HEADER1_NAME, 859 RP_HEADER1_VALUE)) 860 mhdErrorExitDesc ("Cannot add header1"); 861 if (MHD_YES != MHD_add_response_header (response, 862 RP_HEADER2_NAME, 863 RP_HEADER2_VALUE)) 864 mhdErrorExitDesc ("Cannot add header2"); 865 866 ret = MHD_queue_response (connection, 867 MHD_HTTP_OK, 868 response); 869 MHD_destroy_response (response); 870 if (MHD_YES != ret) 871 mhdErrorExitDesc ("Failed to queue response"); 872 873 return ret; 874 } 875 876 877 static CURLcode 878 performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse) 879 { 880 CURLM *multi; 881 time_t start; 882 struct timeval tv; 883 CURLcode ret; 884 int libcurl_finished; 885 886 ret = CURLE_FAILED_INIT; /* will be replaced with real result */ 887 if (NULL != *multi_reuse) 888 multi = *multi_reuse; 889 else 890 { 891 multi = curl_multi_init (); 892 if (multi == NULL) 893 libcurlErrorExitDesc ("curl_multi_init() failed"); 894 *multi_reuse = multi; 895 } 896 if (CURLM_OK != curl_multi_add_handle (multi, c)) 897 libcurlErrorExitDesc ("curl_multi_add_handle() failed"); 898 libcurl_finished = 0; 899 900 start = time (NULL); 901 while (time (NULL) - start <= TIMEOUTS_VAL) 902 { 903 fd_set rs; 904 fd_set ws; 905 fd_set es; 906 MHD_socket maxMhdSk; 907 int maxCurlSk; 908 909 maxMhdSk = MHD_INVALID_SOCKET; 910 maxCurlSk = -1; 911 FD_ZERO (&rs); 912 FD_ZERO (&ws); 913 FD_ZERO (&es); 914 if (! libcurl_finished) 915 { 916 int running; 917 curl_multi_perform (multi, &running); 918 if (0 == running) 919 { 920 struct CURLMsg *msg; 921 int msgLeft; 922 int totalMsgs = 0; 923 do 924 { 925 msg = curl_multi_info_read (multi, &msgLeft); 926 if (NULL == msg) 927 libcurlErrorExitDesc ("curl_multi_info_read() failed"); 928 totalMsgs++; 929 if (CURLMSG_DONE == msg->msg) 930 ret = msg->data.result; 931 } while (msgLeft > 0); 932 if (1 != totalMsgs) 933 { 934 fprintf (stderr, 935 "curl_multi_info_read returned wrong " 936 "number of results (%d).\n", 937 totalMsgs); 938 externalErrorExit (); 939 } 940 curl_multi_remove_handle (multi, c); 941 libcurl_finished = ! 0; 942 } 943 else 944 { 945 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) 946 libcurlErrorExitDesc ("curl_multi_fdset() failed"); 947 } 948 } 949 if (libcurl_finished) 950 { /* libcurl has finished, check whether MHD still needs to perform cleanup */ 951 if (0 != MHD_get_timeout64s (d)) 952 break; /* MHD finished as well */ 953 } 954 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) 955 mhdErrorExitDesc ("MHD_get_fdset() failed"); 956 tv.tv_sec = 0; 957 tv.tv_usec = 200000; 958 if (0 == MHD_get_timeout64s (d)) 959 tv.tv_usec = 0; 960 else 961 { 962 long curl_to = -1; 963 curl_multi_timeout (multi, &curl_to); 964 if (0 == curl_to) 965 tv.tv_usec = 0; 966 } 967 #ifdef MHD_POSIX_SOCKETS 968 if (maxMhdSk > maxCurlSk) 969 maxCurlSk = maxMhdSk; 970 #endif /* MHD_POSIX_SOCKETS */ 971 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) 972 { 973 #ifdef MHD_POSIX_SOCKETS 974 if (EINTR != errno) 975 externalErrorExitDesc ("Unexpected select() error"); 976 #else 977 if ((WSAEINVAL != WSAGetLastError ()) || 978 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 979 externalErrorExitDesc ("Unexpected select() error"); 980 Sleep ((unsigned long) tv.tv_usec / 1000); 981 #endif 982 } 983 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) 984 mhdErrorExitDesc ("MHD_run_from_select() failed"); 985 } 986 987 return ret; 988 } 989 990 991 /** 992 * Check request result 993 * @param curl_code the CURL easy return code 994 * @param pcbc the pointer struct CBC 995 * @return non-zero if success, zero if failed 996 */ 997 static unsigned int 998 check_result (CURLcode curl_code, CURL *c, long expected_code, 999 struct CBC *pcbc, struct headers_check_result *hdr_res, 1000 struct ahc_cls_type *ahc_cls) 1001 { 1002 long code; 1003 unsigned int ret; 1004 1005 fflush (stderr); 1006 fflush (stdout); 1007 if (CURLE_OK != curl_code) 1008 { 1009 fflush (stdout); 1010 if (0 != libcurl_errbuf[0]) 1011 fprintf (stderr, "Request failed. " 1012 "libcurl error: '%s'.\n" 1013 "libcurl error description: '%s'.\n", 1014 curl_easy_strerror (curl_code), 1015 libcurl_errbuf); 1016 else 1017 fprintf (stderr, "Request failed. " 1018 "libcurl error: '%s'.\n", 1019 curl_easy_strerror (curl_code)); 1020 return 0; 1021 } 1022 1023 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) 1024 libcurlErrorExit (); 1025 1026 if (expected_code != code) 1027 { 1028 fprintf (stderr, "The response has wrong HTTP code: %ld\tExpected: %ld.\n", 1029 code, expected_code); 1030 return 0; 1031 } 1032 else if (verbose) 1033 printf ("The response has expected HTTP code: %ld\n", expected_code); 1034 1035 ret = 1; 1036 1037 if (ahc_cls->req_check_error) 1038 { 1039 fprintf (stderr, "One or more errors have been detected by access " 1040 "handler callback.\n"); 1041 ret = 0; 1042 } 1043 if (ahc_cls->expected_upload_size != ahc_cls->up_pos) 1044 { 1045 fprintf (stderr, "Upload size does not match expected. " 1046 "Expected: %lu. " 1047 "Received: %lu.\n", 1048 (unsigned long) ahc_cls->expected_upload_size, 1049 (unsigned long) ahc_cls->up_pos); 1050 ret = 0; 1051 } 1052 1053 if (1 != hdr_res->header1_found) 1054 { 1055 if (0 == hdr_res->header1_found) 1056 fprintf (stderr, "Response header1 was not found.\n"); 1057 else 1058 fprintf (stderr, "Response header1 was found %d times " 1059 "instead of one time only.\n", hdr_res->header1_found); 1060 ret = 0; 1061 } 1062 else if (verbose) 1063 printf ("Header1 is present in the response.\n"); 1064 if (1 != hdr_res->header2_found) 1065 { 1066 if (0 == hdr_res->header2_found) 1067 fprintf (stderr, "Response header2 was not found.\n"); 1068 else 1069 fprintf (stderr, "Response header2 was found %d times " 1070 "instead of one time only.\n", hdr_res->header2_found); 1071 ret = 0; 1072 } 1073 else if (verbose) 1074 printf ("Header2 is present in the response.\n"); 1075 if (1 != hdr_res->size_found) 1076 { 1077 if (0 == hdr_res->size_found) 1078 fprintf (stderr, "Correct response 'Content-Length' header " 1079 "was not found.\n"); 1080 else 1081 fprintf (stderr, "Correct response 'Content-Length' header " 1082 "was found %u times instead of one time only.\n", 1083 hdr_res->size_found); 1084 ret = 0; 1085 } 1086 else if (verbose) 1087 printf ("'Content-Length' header with correct value " 1088 "is present in the response.\n"); 1089 if (0 != hdr_res->size_broken_found) 1090 { 1091 fprintf (stderr, "Wrong response 'Content-Length' header was found " 1092 "%u times.\n", hdr_res->size_broken_found); 1093 ret = 0; 1094 } 1095 1096 if (pcbc->dn_pos != MHD_STATICSTR_LEN_ (PAGE)) 1097 { 1098 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", 1099 (unsigned) pcbc->dn_pos, (int) pcbc->dn_pos, pcbc->dn_buf, 1100 (unsigned) MHD_STATICSTR_LEN_ (PAGE)); 1101 mhdErrorExitDesc ("Wrong returned data length"); 1102 } 1103 if (0 != memcmp (PAGE, pcbc->dn_buf, pcbc->dn_pos)) 1104 { 1105 fprintf (stderr, "Got invalid response '%.*s'. ", 1106 (int) pcbc->dn_pos, pcbc->dn_buf); 1107 mhdErrorExitDesc ("Wrong returned data"); 1108 } 1109 fflush (stderr); 1110 fflush (stdout); 1111 return ret; 1112 } 1113 1114 1115 static unsigned int 1116 performCheck (void) 1117 { 1118 struct MHD_Daemon *d; 1119 uint16_t port; 1120 struct CBC cbc; 1121 struct ahc_cls_type ahc_param; 1122 struct headers_check_result rp_headers_check; 1123 char buf[2048]; 1124 CURL *c; 1125 CURLM *multi_reuse; 1126 int failed = 0; 1127 1128 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 1129 port = 0; 1130 else 1131 { 1132 port = UINT16_C (4220); 1133 if (! oneone) 1134 port += UINT16_C (1); 1135 if (use_put) 1136 port += UINT16_C (2); 1137 if (use_put_large) 1138 port += UINT16_C (4); 1139 if (use_hdr_last) 1140 port += UINT16_C (8); 1141 if (use_hdr_large) 1142 port += UINT16_C (16); 1143 } 1144 1145 if (1) 1146 { 1147 size_t mem_limit; 1148 if (use_put_large) 1149 mem_limit = (size_t) (TEST_UPLOAD_DATA_SIZE / 2 + HEADERS_POINTERS_SIZE); 1150 else 1151 mem_limit = (size_t) ((TEST_UPLOAD_DATA_SIZE * 4) / 3 + 2 1152 + HEADERS_POINTERS_SIZE); 1153 1154 d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY, 1155 port, NULL, NULL, 1156 &ahcCheck, &ahc_param, 1157 MHD_OPTION_CONNECTION_MEMORY_LIMIT, mem_limit, 1158 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 1159 MHD_OPTION_END); 1160 } 1161 if (d == NULL) 1162 return 1; 1163 if (0 == port) 1164 { 1165 const union MHD_DaemonInfo *dinfo; 1166 1167 dinfo = MHD_get_daemon_info (d, 1168 MHD_DAEMON_INFO_BIND_PORT); 1169 if ( (NULL == dinfo) || 1170 (0 == dinfo->port) ) 1171 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 1172 port = dinfo->port; 1173 } 1174 1175 /* First request */ 1176 ahc_param.rq_method = use_put ? MHD_HTTP_METHOD_PUT : MHD_HTTP_METHOD_GET; 1177 ahc_param.rq_url = EXPECTED_URI_BASE_PATH; 1178 ahc_param.expected_upload_size = use_put ? TEST_UPLOAD_DATA_SIZE : 0; 1179 ahc_param.req_check_error = 0; 1180 ahc_param.num_req = 0; 1181 ahc_param.up_pos = 0; 1182 rp_headers_check.expected_size = MHD_STATICSTR_LEN_ (PAGE); 1183 rp_headers_check.header1_found = 0; 1184 rp_headers_check.header2_found = 0; 1185 rp_headers_check.size_found = 0; 1186 rp_headers_check.size_broken_found = 0; 1187 cbc.dn_buf = buf; 1188 cbc.dn_buf_size = sizeof (buf); 1189 cbc.dn_pos = 0; 1190 memset (cbc.dn_buf, 0, cbc.dn_buf_size); 1191 cbc.up_size = TEST_UPLOAD_DATA_SIZE; 1192 cbc.up_pos = 0; 1193 c = setupCURL (&cbc, port, &rp_headers_check); 1194 multi_reuse = NULL; 1195 /* First request */ 1196 if (check_result (performQueryExternal (d, c, &multi_reuse), c, 1197 MHD_HTTP_OK, &cbc, &rp_headers_check, &ahc_param)) 1198 { 1199 fflush (stderr); 1200 if (verbose) 1201 printf ("Got first expected response.\n"); 1202 fflush (stdout); 1203 } 1204 else 1205 { 1206 fprintf (stderr, "First request FAILED.\n"); 1207 fflush (stderr); 1208 failed = 1; 1209 } 1210 /* Second request */ 1211 ahc_param.req_check_error = 0; 1212 ahc_param.num_req = 0; 1213 ahc_param.up_pos = 0; 1214 rp_headers_check.header1_found = 0; 1215 rp_headers_check.header2_found = 0; 1216 rp_headers_check.size_found = 0; 1217 rp_headers_check.size_broken_found = 0; 1218 /* Reset buffer position */ 1219 cbc.dn_pos = 0; 1220 memset (cbc.dn_buf, 0, cbc.dn_buf_size); 1221 cbc.up_pos = 0; 1222 if (check_result (performQueryExternal (d, c, &multi_reuse), c, 1223 MHD_HTTP_OK, &cbc, &rp_headers_check, &ahc_param)) 1224 { 1225 fflush (stderr); 1226 if (verbose) 1227 printf ("Got second expected response.\n"); 1228 fflush (stdout); 1229 } 1230 else 1231 { 1232 fprintf (stderr, "Second request FAILED.\n"); 1233 fflush (stderr); 1234 failed = 1; 1235 } 1236 /* Third request */ 1237 ahc_param.req_check_error = 0; 1238 ahc_param.num_req = 0; 1239 ahc_param.up_pos = 0; 1240 rp_headers_check.header1_found = 0; 1241 rp_headers_check.header2_found = 0; 1242 rp_headers_check.size_found = 0; 1243 rp_headers_check.size_broken_found = 0; 1244 /* Reset buffer position */ 1245 cbc.dn_pos = 0; 1246 memset (cbc.dn_buf, 0, cbc.dn_buf_size); 1247 cbc.up_pos = 0; 1248 if (NULL != multi_reuse) 1249 curl_multi_cleanup (multi_reuse); 1250 multi_reuse = NULL; /* Force new connection */ 1251 if (check_result (performQueryExternal (d, c, &multi_reuse), c, 1252 MHD_HTTP_OK, &cbc, &rp_headers_check, &ahc_param)) 1253 { 1254 fflush (stderr); 1255 if (verbose) 1256 printf ("Got third expected response.\n"); 1257 fflush (stdout); 1258 } 1259 else 1260 { 1261 fprintf (stderr, "Third request FAILED.\n"); 1262 fflush (stderr); 1263 failed = 1; 1264 } 1265 1266 curl_easy_cleanup (c); 1267 if (NULL != multi_reuse) 1268 curl_multi_cleanup (multi_reuse); 1269 1270 MHD_stop_daemon (d); 1271 return failed ? 1 : 0; 1272 } 1273 1274 1275 int 1276 main (int argc, char *const *argv) 1277 { 1278 unsigned int errorCount = 0; 1279 1280 /* Test type and test parameters */ 1281 verbose = ! (has_param (argc, argv, "-q") || 1282 has_param (argc, argv, "--quiet") || 1283 has_param (argc, argv, "-s") || 1284 has_param (argc, argv, "--silent")); 1285 oneone = ! has_in_name (argv[0], "10"); 1286 1287 use_get = has_in_name (argv[0], "_get"); 1288 use_put = has_in_name (argv[0], "_put"); 1289 1290 use_double_fold = has_in_name (argv[0], "_double_fold"); 1291 use_put_large = has_in_name (argv[0], "_put_large"); 1292 use_hdr_last = has_in_name (argv[0], "_last"); 1293 use_hdr_large = has_in_name (argv[0], "_fold_large"); 1294 1295 if (1 != 1296 ((use_get ? 1 : 0) + (use_put ? 1 : 0))) 1297 { 1298 fprintf (stderr, "Wrong test name '%s': no or multiple indications " 1299 "for the test type.\n", argv[0] ? argv[0] : "(NULL)"); 1300 return 99; 1301 } 1302 1303 test_global_init (); 1304 1305 errorCount += performCheck (); 1306 if (errorCount != 0) 1307 fprintf (stderr, "Error (code: %u)\n", errorCount); 1308 test_global_cleanup (); 1309 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 1310 }