libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

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                                      &copyBuffer)) ||
    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 = &marker;
    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 }