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