libmicrohttpd

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

test_tricky.c (37178B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2014-2025 Evgeny Grin (Karlson2k)
      4      Copyright (C) 2007, 2009, 2011 Christian Grothoff
      5 
      6      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      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  * @file test_toolarge.c
     23  * @brief  Testcase for handling of untypical data.
     24  * @author Karlson2k (Evgeny Grin)
     25  * @author Christian Grothoff
     26  */
     27 #include "MHD_config.h"
     28 #include "platform.h"
     29 #include <curl/curl.h>
     30 #include <microhttpd.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <time.h>
     34 #include <errno.h>
     35 #include "mhd_has_in_name.h"
     36 #include "mhd_has_param.h"
     37 #include "mhd_sockets.h" /* only macros used */
     38 
     39 #ifdef HAVE_STRINGS_H
     40 #include <strings.h>
     41 #endif /* HAVE_STRINGS_H */
     42 
     43 #ifdef _WIN32
     44 #ifndef WIN32_LEAN_AND_MEAN
     45 #define WIN32_LEAN_AND_MEAN 1
     46 #endif /* !WIN32_LEAN_AND_MEAN */
     47 #include <windows.h>
     48 #endif
     49 
     50 #ifndef WINDOWS
     51 #include <unistd.h>
     52 #include <sys/socket.h>
     53 #endif
     54 
     55 #ifdef HAVE_LIMITS_H
     56 #include <limits.h>
     57 #endif /* HAVE_LIMITS_H */
     58 
     59 #ifndef CURL_VERSION_BITS
     60 #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
     61 #endif /* ! CURL_VERSION_BITS */
     62 #ifndef CURL_AT_LEAST_VERSION
     63 #define CURL_AT_LEAST_VERSION(x,y,z) \
     64   (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
     65 #endif /* ! CURL_AT_LEAST_VERSION */
     66 
     67 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
     68 #undef MHD_CPU_COUNT
     69 #endif
     70 #if ! defined(MHD_CPU_COUNT)
     71 #define MHD_CPU_COUNT 2
     72 #endif
     73 #if MHD_CPU_COUNT > 32
     74 #undef MHD_CPU_COUNT
     75 /* Limit to reasonable value */
     76 #define MHD_CPU_COUNT 32
     77 #endif /* MHD_CPU_COUNT > 32 */
     78 
     79 
     80 #if defined(HAVE___FUNC__)
     81 #define externalErrorExit(ignore) \
     82     _externalErrorExit_func(NULL, __func__, __LINE__)
     83 #define externalErrorExitDesc(errDesc) \
     84     _externalErrorExit_func(errDesc, __func__, __LINE__)
     85 #define libcurlErrorExit(ignore) \
     86     _libcurlErrorExit_func(NULL, __func__, __LINE__)
     87 #define libcurlErrorExitDesc(errDesc) \
     88     _libcurlErrorExit_func(errDesc, __func__, __LINE__)
     89 #define mhdErrorExit(ignore) \
     90     _mhdErrorExit_func(NULL, __func__, __LINE__)
     91 #define mhdErrorExitDesc(errDesc) \
     92     _mhdErrorExit_func(errDesc, __func__, __LINE__)
     93 #elif defined(HAVE___FUNCTION__)
     94 #define externalErrorExit(ignore) \
     95     _externalErrorExit_func(NULL, __FUNCTION__, __LINE__)
     96 #define externalErrorExitDesc(errDesc) \
     97     _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__)
     98 #define libcurlErrorExit(ignore) \
     99     _libcurlErrorExit_func(NULL, __FUNCTION__, __LINE__)
    100 #define libcurlErrorExitDesc(errDesc) \
    101     _libcurlErrorExit_func(errDesc, __FUNCTION__, __LINE__)
    102 #define mhdErrorExit(ignore) \
    103     _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__)
    104 #define mhdErrorExitDesc(errDesc) \
    105     _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__)
    106 #else
    107 #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__)
    108 #define externalErrorExitDesc(errDesc) \
    109   _externalErrorExit_func(errDesc, NULL, __LINE__)
    110 #define libcurlErrorExit(ignore) _libcurlErrorExit_func(NULL, NULL, __LINE__)
    111 #define libcurlErrorExitDesc(errDesc) \
    112   _libcurlErrorExit_func(errDesc, NULL, __LINE__)
    113 #define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__)
    114 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__)
    115 #endif
    116 
    117 
    118 _MHD_NORETURN static void
    119 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
    120 {
    121   if ((NULL != errDesc) && (0 != errDesc[0]))
    122     fprintf (stderr, "%s", errDesc);
    123   else
    124     fprintf (stderr, "System or external library call failed");
    125   if ((NULL != funcName) && (0 != funcName[0]))
    126     fprintf (stderr, " in %s", funcName);
    127   if (0 < lineNum)
    128     fprintf (stderr, " at line %d", lineNum);
    129 
    130   fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
    131            strerror (errno));
    132 #ifdef MHD_WINSOCK_SOCKETS
    133   fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
    134 #endif /* MHD_WINSOCK_SOCKETS */
    135   fflush (stderr);
    136   exit (99);
    137 }
    138 
    139 
    140 static char libcurl_errbuf[CURL_ERROR_SIZE] = "";
    141 
    142 _MHD_NORETURN static void
    143 _libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
    144 {
    145   if ((NULL != errDesc) && (0 != errDesc[0]))
    146     fprintf (stderr, "%s", errDesc);
    147   else
    148     fprintf (stderr, "CURL library call failed");
    149   if ((NULL != funcName) && (0 != funcName[0]))
    150     fprintf (stderr, " in %s", funcName);
    151   if (0 < lineNum)
    152     fprintf (stderr, " at line %d", lineNum);
    153 
    154   fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
    155            strerror (errno));
    156   if (0 != libcurl_errbuf[0])
    157     fprintf (stderr, "Last libcurl error details: %s\n", libcurl_errbuf);
    158 
    159   fflush (stderr);
    160   exit (99);
    161 }
    162 
    163 
    164 _MHD_NORETURN static void
    165 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
    166 {
    167   if ((NULL != errDesc) && (0 != errDesc[0]))
    168     fprintf (stderr, "%s", errDesc);
    169   else
    170     fprintf (stderr, "MHD unexpected error");
    171   if ((NULL != funcName) && (0 != funcName[0]))
    172     fprintf (stderr, " in %s", funcName);
    173   if (0 < lineNum)
    174     fprintf (stderr, " at line %d", lineNum);
    175 
    176   fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
    177            strerror (errno));
    178 
    179   fflush (stderr);
    180   exit (8);
    181 }
    182 
    183 
    184 /* Could be increased to facilitate debugging */
    185 #define TIMEOUTS_VAL 5
    186 
    187 #define EXPECTED_URI_BASE_PATH  "/a"
    188 
    189 #define EXPECTED_URI_BASE_PATH_TRICKY  "/one\rtwo"
    190 
    191 #define URL_SCHEME "http:/" "/"
    192 
    193 #define URL_HOST "127.0.0.1"
    194 
    195 #define URL_SCHEME_HOST URL_SCHEME URL_HOST
    196 
    197 #define HEADER1_NAME "First"
    198 #define HEADER1_VALUE "1st"
    199 #define HEADER1 HEADER1_NAME ": " HEADER1_VALUE
    200 #define HEADER2_NAME "Second"
    201 #define HEADER2CR_VALUE "2\rnd"
    202 #define HEADER2CR HEADER2_NAME ": " HEADER2CR_VALUE
    203 /* Use headers when it would be properly supported by MHD
    204 #define HEADER3CR_NAME "Thi\rrd"
    205 #define HEADER3CR_VALUE "3r\rd"
    206 #define HEADER3CR HEADER3CR_NAME ": " HEADER3CR_VALUE
    207 */
    208 #define HEADER4_NAME "Normal"
    209 #define HEADER4_VALUE "it's fine"
    210 #define HEADER4 HEADER4_NAME ": " HEADER4_VALUE
    211 
    212 /* Global parameters */
    213 static int verbose;                 /**< Be verbose */
    214 static int oneone;                  /**< If false use HTTP/1.0 for requests*/
    215 static uint16_t global_port;        /**< MHD daemons listen port number */
    216 static int response_timeout_val = TIMEOUTS_VAL;
    217 
    218 static int tricky_url;              /**< Tricky request URL */
    219 static int tricky_header2;          /**< Tricky request header2 */
    220 
    221 /* Current test parameters */
    222 /* * Moved to local variables * */
    223 
    224 /* Static helper variables */
    225 /* * None for this test * */
    226 
    227 static void
    228 test_global_init (void)
    229 {
    230   libcurl_errbuf[0] = 0;
    231 
    232   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    233     externalErrorExit ();
    234 }
    235 
    236 
    237 static void
    238 test_global_cleanup (void)
    239 {
    240   curl_global_cleanup ();
    241 }
    242 
    243 
    244 struct headers_check_result
    245 {
    246   int dummy; /* no checks in this test */
    247 };
    248 
    249 
    250 static size_t
    251 lcurl_hdr_callback (char *buffer, size_t size, size_t nitems,
    252                     void *userdata)
    253 {
    254   const size_t data_size = size * nitems;
    255   struct headers_check_result *check_res =
    256     (struct headers_check_result *) userdata;
    257 
    258   /* no checks in this test */
    259   (void) check_res; (void) buffer;
    260 
    261   return data_size;
    262 }
    263 
    264 
    265 struct lcurl_data_cb_param
    266 {
    267   char *buf;
    268   size_t pos;
    269   size_t size;
    270 };
    271 
    272 
    273 static size_t
    274 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
    275 {
    276   struct lcurl_data_cb_param *cbc = ctx;
    277 
    278   if (cbc->pos + size * nmemb > cbc->size)
    279     externalErrorExit ();  /* overflow */
    280   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
    281   cbc->pos += size * nmemb;
    282   return size * nmemb;
    283 }
    284 
    285 
    286 struct check_uri_cls
    287 {
    288   const char *volatile uri;
    289 };
    290 
    291 static void *
    292 check_uri_cb (void *cls,
    293               const char *uri,
    294               struct MHD_Connection *con)
    295 {
    296   struct check_uri_cls *param = (struct check_uri_cls *) cls;
    297   (void) con;
    298 
    299   if (0 != strcmp (param->uri,
    300                    uri))
    301   {
    302     fprintf (stderr,
    303              "Wrong URI: '%s', line: %d\n",
    304              uri, __LINE__);
    305     exit (22);
    306   }
    307   return NULL;
    308 }
    309 
    310 
    311 struct mhd_header_checker_param
    312 {
    313   int found_header1;
    314   int found_header2;
    315   int found_header4;
    316 };
    317 
    318 static enum MHD_Result
    319 headerCheckerInterator (void *cls,
    320                         enum MHD_ValueKind kind,
    321                         const char *key,
    322                         size_t key_size,
    323                         const char *value,
    324                         size_t value_size)
    325 {
    326   struct mhd_header_checker_param *const param =
    327     (struct mhd_header_checker_param *) cls;
    328 
    329   if (NULL == param)
    330     mhdErrorExitDesc ("cls parameter is NULL");
    331 
    332   if (MHD_HEADER_KIND != kind)
    333     return MHD_YES; /* Continue iteration */
    334 
    335   if (0 == key_size)
    336     mhdErrorExitDesc ("Zero key length");
    337 
    338   if ((strlen (HEADER1_NAME) == key_size) &&
    339       (0 == memcmp (key, HEADER1_NAME, key_size)))
    340   {
    341     if ((strlen (HEADER1_VALUE) == value_size) &&
    342         (0 == memcmp (value, HEADER1_VALUE, value_size)))
    343       param->found_header1 = 1;
    344     else
    345       fprintf (stderr, "Unexpected header value: '%.*s', expected: '%s'\n",
    346                (int) value_size, value, HEADER1_VALUE);
    347   }
    348   else if ((strlen (HEADER2_NAME) == key_size) &&
    349            (0 == memcmp (key, HEADER2_NAME, key_size)))
    350   {
    351     if ((strlen (HEADER2CR_VALUE) == value_size) &&
    352         (0 == memcmp (value, HEADER2CR_VALUE, value_size)))
    353       param->found_header2 = 1;
    354     else
    355       fprintf (stderr, "Unexpected header value: '%.*s', expected: '%s'\n",
    356                (int) value_size, value, HEADER2CR_VALUE);
    357   }
    358   else if ((strlen (HEADER4_NAME) == key_size) &&
    359            (0 == memcmp (key, HEADER4_NAME, key_size)))
    360   {
    361     if ((strlen (HEADER4_VALUE) == value_size) &&
    362         (0 == memcmp (value, HEADER4_VALUE, value_size)))
    363       param->found_header4 = 1;
    364     else
    365       fprintf (stderr, "Unexpected header value: '%.*s', expected: '%s'\n",
    366                (int) value_size, value, HEADER4_VALUE);
    367   }
    368   return MHD_YES;
    369 }
    370 
    371 
    372 struct ahc_cls_type
    373 {
    374   const char *volatile rp_data;
    375   volatile size_t rp_data_size;
    376   struct mhd_header_checker_param header_check_param;
    377   const char *volatile rq_method;
    378   const char *volatile rq_url;
    379 };
    380 
    381 
    382 static enum MHD_Result
    383 ahcCheck (void *cls,
    384           struct MHD_Connection *connection,
    385           const char *url,
    386           const char *method,
    387           const char *version,
    388           const char *upload_data, size_t *upload_data_size,
    389           void **req_cls)
    390 {
    391   static int ptr;
    392   struct MHD_Response *response;
    393   enum MHD_Result ret;
    394   struct ahc_cls_type *const param = (struct ahc_cls_type *) cls;
    395 
    396   if (NULL == param)
    397     mhdErrorExitDesc ("cls parameter is NULL");
    398 
    399   if (0 != strcmp (version, MHD_HTTP_VERSION_1_1))
    400     mhdErrorExitDesc ("Unexpected HTTP version");
    401 
    402   if (0 != strcmp (url, param->rq_url))
    403     mhdErrorExitDesc ("Unexpected URI");
    404 
    405   if (NULL != upload_data)
    406     mhdErrorExitDesc ("'upload_data' is not NULL");
    407 
    408   if (NULL == upload_data_size)
    409     mhdErrorExitDesc ("'upload_data_size' pointer is NULL");
    410 
    411   if (0 != *upload_data_size)
    412     mhdErrorExitDesc ("'*upload_data_size' value is not zero");
    413 
    414   if (0 != strcmp (param->rq_method, method))
    415     mhdErrorExitDesc ("Unexpected request method");
    416 
    417   if (&ptr != *req_cls)
    418   {
    419     *req_cls = &ptr;
    420     return MHD_YES;
    421   }
    422   *req_cls = NULL;
    423 
    424   if (1 > MHD_get_connection_values_n (connection, MHD_HEADER_KIND,
    425                                        &headerCheckerInterator,
    426                                        &param->header_check_param))
    427     mhdErrorExitDesc ("Wrong number of headers in the request");
    428 
    429   response =
    430     MHD_create_response_from_buffer_copy (param->rp_data_size,
    431                                           (const void *) param->rp_data);
    432   if (NULL == response)
    433     mhdErrorExitDesc ("Failed to create response");
    434 
    435   ret = MHD_queue_response (connection,
    436                             MHD_HTTP_OK,
    437                             response);
    438   MHD_destroy_response (response);
    439   if (MHD_YES != ret)
    440     mhdErrorExitDesc ("Failed to queue response");
    441 
    442   return ret;
    443 }
    444 
    445 
    446 struct curlQueryParams
    447 {
    448   /* Destination path for CURL query */
    449   const char *queryPath;
    450 
    451 #if CURL_AT_LEAST_VERSION (7, 62, 0)
    452   CURLU *url;
    453 #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */
    454 
    455 #if CURL_AT_LEAST_VERSION (7, 55, 0)
    456   /* A string used as the request target directly, without modifications */
    457   const char *queryTarget;
    458 #endif /* CURL_AT_LEAST_VERSION(7, 55, 0) */
    459 
    460   /* Custom query method, NULL for default */
    461   const char *method;
    462 
    463   /* Destination port for CURL query */
    464   uint16_t queryPort;
    465 
    466   /* List of additional request headers */
    467   struct curl_slist *headers;
    468 
    469   /* CURL query result error flag */
    470   volatile unsigned int queryError;
    471 
    472   /* Response HTTP code, zero if no response */
    473   volatile int responseCode;
    474 };
    475 
    476 
    477 static CURL *
    478 curlEasyInitForTest (struct curlQueryParams *p,
    479                      struct lcurl_data_cb_param *dcbp,
    480                      struct headers_check_result *hdr_chk_result)
    481 {
    482   CURL *c;
    483 
    484   c = curl_easy_init ();
    485   if (NULL == c)
    486     libcurlErrorExitDesc ("curl_easy_init() failed");
    487 
    488 #if CURL_AT_LEAST_VERSION (7, 62, 0)
    489   if (NULL != p->url)
    490   {
    491     if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CURLU, p->url))
    492       libcurlErrorExitDesc ("curl_easy_setopt() failed");
    493   }
    494   else /* combined with the next 'if()' */
    495 #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */
    496   if (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, p->queryPath))
    497     libcurlErrorExitDesc ("curl_easy_setopt() failed");
    498 
    499   if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) ||
    500       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) p->queryPort)) ||
    501       (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
    502                                      &copyBuffer)) ||
    503       (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, dcbp)) ||
    504       (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
    505                                      (long) response_timeout_val)) ||
    506       (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
    507                                      (long) response_timeout_val)) ||
    508       (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
    509                                      libcurl_errbuf)) ||
    510       (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERFUNCTION,
    511                                      lcurl_hdr_callback)) ||
    512       (CURLE_OK != curl_easy_setopt (c, CURLOPT_HEADERDATA,
    513                                      hdr_chk_result)) ||
    514 #if CURL_AT_LEAST_VERSION (7, 42, 0)
    515       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PATH_AS_IS,
    516                                      (long) 1)) ||
    517 #endif /* CURL_AT_LEAST_VERSION(7, 42, 0) */
    518       (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) ||
    519       (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
    520                                      (oneone) ?
    521                                      CURL_HTTP_VERSION_1_1 :
    522                                      CURL_HTTP_VERSION_1_0)))
    523     libcurlErrorExitDesc ("curl_easy_setopt() failed");
    524 
    525   if (CURLE_OK != curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, p->method))
    526     libcurlErrorExitDesc ("curl_easy_setopt() failed");
    527 
    528   if (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTPHEADER, p->headers))
    529     libcurlErrorExitDesc ("curl_easy_setopt() failed");
    530 
    531 
    532 #if CURL_AT_LEAST_VERSION (7, 55, 0)
    533   if (NULL != p->queryTarget)
    534   {
    535     if (CURLE_OK != curl_easy_setopt (c, CURLOPT_REQUEST_TARGET,
    536                                       p->queryTarget))
    537       libcurlErrorExitDesc ("curl_easy_setopt() failed");
    538   }
    539 #endif /* CURL_AT_LEAST_VERSION(7, 55, 0) */
    540 
    541   return c;
    542 }
    543 
    544 
    545 static CURLcode
    546 performQueryExternal (struct MHD_Daemon *d, CURL *c)
    547 {
    548   CURLM *multi;
    549   time_t start;
    550   struct timeval tv;
    551   CURLcode ret;
    552 
    553   ret = CURLE_FAILED_INIT; /* will be replaced with real result */
    554   multi = NULL;
    555   multi = curl_multi_init ();
    556   if (multi == NULL)
    557     libcurlErrorExitDesc ("curl_multi_init() failed");
    558   if (CURLM_OK != curl_multi_add_handle (multi, c))
    559     libcurlErrorExitDesc ("curl_multi_add_handle() failed");
    560 
    561   start = time (NULL);
    562   while (time (NULL) - start <= TIMEOUTS_VAL)
    563   {
    564     fd_set rs;
    565     fd_set ws;
    566     fd_set es;
    567     MHD_socket maxMhdSk;
    568     int maxCurlSk;
    569     int running;
    570 
    571     maxMhdSk = MHD_INVALID_SOCKET;
    572     maxCurlSk = -1;
    573     FD_ZERO (&rs);
    574     FD_ZERO (&ws);
    575     FD_ZERO (&es);
    576     if (NULL != multi)
    577     {
    578       curl_multi_perform (multi, &running);
    579       if (0 == running)
    580       {
    581         struct CURLMsg *msg;
    582         int msgLeft;
    583         int totalMsgs = 0;
    584         do
    585         {
    586           msg = curl_multi_info_read (multi, &msgLeft);
    587           if (NULL == msg)
    588             libcurlErrorExitDesc ("curl_multi_info_read() failed");
    589           totalMsgs++;
    590           if (CURLMSG_DONE == msg->msg)
    591             ret = msg->data.result;
    592         } while (msgLeft > 0);
    593         if (1 != totalMsgs)
    594         {
    595           fprintf (stderr,
    596                    "curl_multi_info_read returned wrong "
    597                    "number of results (%d).\n",
    598                    totalMsgs);
    599           externalErrorExit ();
    600         }
    601         curl_multi_remove_handle (multi, c);
    602         curl_multi_cleanup (multi);
    603         multi = NULL;
    604       }
    605       else
    606       {
    607         if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk))
    608           libcurlErrorExitDesc ("curl_multi_fdset() failed");
    609       }
    610     }
    611     if (NULL == multi)
    612     { /* libcurl has finished, check whether MHD still needs to perform cleanup */
    613       if (0 != MHD_get_timeout64s (d))
    614         break; /* MHD finished as well */
    615     }
    616     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk))
    617       mhdErrorExitDesc ("MHD_get_fdset() failed");
    618     tv.tv_sec = 0;
    619     tv.tv_usec = 1000;
    620 #ifdef MHD_POSIX_SOCKETS
    621     if (maxMhdSk > maxCurlSk)
    622       maxCurlSk = maxMhdSk;
    623 #endif /* MHD_POSIX_SOCKETS */
    624     if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv))
    625     {
    626 #ifdef MHD_POSIX_SOCKETS
    627       if (EINTR != errno)
    628         externalErrorExitDesc ("Unexpected select() error");
    629 #else
    630       if ((WSAEINVAL != WSAGetLastError ()) ||
    631           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    632         externalErrorExitDesc ("Unexpected select() error");
    633       Sleep (1);
    634 #endif
    635     }
    636     if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
    637       mhdErrorExitDesc ("MHD_run_from_select() failed");
    638   }
    639 
    640   return ret;
    641 }
    642 
    643 
    644 /* Returns zero for successful response and non-zero for failed response */
    645 static unsigned int
    646 doCurlQueryInThread (struct MHD_Daemon *d,
    647                      struct curlQueryParams *p,
    648                      struct headers_check_result *hdr_res,
    649                      const char *expected_data,
    650                      size_t expected_data_size)
    651 {
    652   const union MHD_DaemonInfo *dinfo;
    653   CURL *c;
    654   struct lcurl_data_cb_param dcbp;
    655   CURLcode errornum;
    656   int use_external_poll;
    657   long resp_code;
    658 
    659   dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_FLAGS);
    660   if (NULL == dinfo)
    661     mhdErrorExitDesc ("MHD_get_daemon_info() failed");
    662   use_external_poll = (0 == (dinfo->flags
    663                              & MHD_USE_INTERNAL_POLLING_THREAD));
    664 
    665   if (NULL == p->queryPath
    666 #if CURL_AT_LEAST_VERSION (7, 62, 0)
    667       && NULL == p->url
    668 #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */
    669       )
    670     abort ();
    671 
    672   if (0 == p->queryPort)
    673     abort ();
    674 
    675   /* Test must not fail due to test's internal buffer shortage */
    676   dcbp.size = expected_data_size * 2 + 1;
    677   dcbp.buf = malloc (dcbp.size);
    678   if (NULL == dcbp.buf)
    679     externalErrorExit ();
    680   dcbp.pos = 0;
    681 
    682   memset (hdr_res, 0, sizeof(*hdr_res));
    683 
    684   c = curlEasyInitForTest (p,
    685                            &dcbp, hdr_res);
    686 
    687   if (! use_external_poll)
    688     errornum = curl_easy_perform (c);
    689   else
    690     errornum = performQueryExternal (d, c);
    691 
    692   if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &resp_code))
    693     libcurlErrorExitDesc ("curl_easy_getinfo() failed");
    694 
    695   p->responseCode = (int) resp_code;
    696   if ((CURLE_OK == errornum) && (200 != resp_code))
    697   {
    698     fprintf (stderr,
    699              "Got reply with unexpected status code: %d\n",
    700              p->responseCode);
    701     mhdErrorExit ();
    702   }
    703 
    704   if (CURLE_OK != errornum)
    705   {
    706     if ((CURLE_GOT_NOTHING != errornum) && (CURLE_RECV_ERROR != errornum)
    707         && (CURLE_HTTP_RETURNED_ERROR != errornum))
    708     {
    709       if (CURLE_OPERATION_TIMEDOUT == errornum)
    710         mhdErrorExitDesc ("Request was aborted due to timeout");
    711       fprintf (stderr, "libcurl returned unexpected error: %s\n",
    712                curl_easy_strerror (errornum));
    713       mhdErrorExitDesc ("Request failed due to unexpected error");
    714     }
    715     p->queryError = 1;
    716     if ((0 != resp_code) &&
    717         ((499 < resp_code) || (400 > resp_code))) /* TODO: add all expected error codes */
    718     {
    719       fprintf (stderr,
    720                "Got reply with unexpected status code: %ld\n",
    721                resp_code);
    722       mhdErrorExit ();
    723     }
    724   }
    725   else
    726   {
    727     if (dcbp.pos != expected_data_size)
    728       mhdErrorExit ("libcurl reports wrong size of MHD reply body data");
    729     else if (0 != memcmp (expected_data, dcbp.buf,
    730                           expected_data_size))
    731       mhdErrorExit ("libcurl reports wrong MHD reply body data");
    732     else
    733       p->queryError = 0;
    734   }
    735 
    736   curl_easy_cleanup (c);
    737   free (dcbp.buf);
    738 
    739   return p->queryError;
    740 }
    741 
    742 
    743 /* Perform test queries, shut down MHD daemon, and free parameters */
    744 static unsigned int
    745 performTestQueries (struct MHD_Daemon *d, uint16_t d_port,
    746                     struct ahc_cls_type *ahc_param,
    747                     struct check_uri_cls *uri_cb_param)
    748 {
    749   struct curlQueryParams qParam;
    750   unsigned int ret = 0;          /* Return value */
    751   struct headers_check_result rp_headers_check;
    752   struct curl_slist *curl_headers;
    753   curl_headers = NULL;
    754 
    755   /* Common parameters, to be individually overridden by specific test cases */
    756   qParam.queryPort = d_port;
    757   qParam.method = NULL;  /* Use libcurl default: GET */
    758   qParam.queryPath = URL_SCHEME_HOST EXPECTED_URI_BASE_PATH;
    759 #if CURL_AT_LEAST_VERSION (7, 55, 0)
    760   qParam.queryTarget = NULL;
    761 #endif /* CURL_AT_LEAST_VERSION(7, 55, 0) */
    762 #if CURL_AT_LEAST_VERSION (7, 62, 0)
    763   qParam.url = NULL;
    764 #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */
    765   qParam.headers = NULL; /* No additional headers */
    766   uri_cb_param->uri = EXPECTED_URI_BASE_PATH;
    767   ahc_param->rq_url = EXPECTED_URI_BASE_PATH;
    768   ahc_param->rq_method = "GET"; /* Default expected method */
    769 
    770   ahc_param->rp_data = "~";
    771   ahc_param->rp_data_size = 1;
    772 
    773   curl_headers = curl_slist_append (curl_headers, HEADER1);
    774   if (NULL == curl_headers)
    775     externalErrorExit ();
    776   curl_headers = curl_slist_append (curl_headers, HEADER4);
    777   if (NULL == curl_headers)
    778     externalErrorExit ();
    779   qParam.headers = curl_headers;
    780 
    781   memset (&ahc_param->header_check_param, 0,
    782           sizeof (ahc_param->header_check_param));
    783 
    784   if (tricky_url)
    785   {
    786 #if CURL_AT_LEAST_VERSION (7, 55, 0)
    787 #if CURL_AT_LEAST_VERSION (7, 62, 0)
    788     unsigned int urlu_flags = CURLU_PATH_AS_IS;
    789     CURLU *url;
    790     url = curl_url ();
    791     if (NULL == url)
    792       externalErrorExit ();
    793     qParam.url = url;
    794 
    795 #ifdef CURLU_ALLOW_SPACE
    796     urlu_flags |= CURLU_ALLOW_SPACE;
    797 #endif /* CURLU_ALLOW_SPACE */
    798 
    799     if ((CURLUE_OK != curl_url_set (qParam.url, CURLUPART_SCHEME, "http", 0)) ||
    800         (CURLUE_OK != curl_url_set (qParam.url, CURLUPART_HOST, URL_HOST,
    801                                     urlu_flags)) ||
    802         (CURLUE_OK != curl_url_set (qParam.url, CURLUPART_PATH,
    803                                     EXPECTED_URI_BASE_PATH_TRICKY,
    804                                     urlu_flags)))
    805       libcurlErrorExit ();
    806 
    807 #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */
    808 
    809     qParam.queryTarget = EXPECTED_URI_BASE_PATH_TRICKY;
    810     uri_cb_param->uri = EXPECTED_URI_BASE_PATH_TRICKY;
    811     ahc_param->rq_url = EXPECTED_URI_BASE_PATH_TRICKY;
    812 
    813     if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check,
    814                                   ahc_param->rp_data,
    815                                   ahc_param->rp_data_size))
    816     {
    817       /* TODO: Allow fail only if relevant MHD mode set */
    818       if (0 == qParam.responseCode)
    819       {
    820         fprintf (stderr, "Request failed without any valid response.\n");
    821         ret = 1;
    822       }
    823       else
    824       {
    825         if (verbose)
    826           printf ("Request failed with %d response code.\n",
    827                   qParam.responseCode);
    828         (void) qParam.responseCode; /* TODO: check for the right response code */
    829         ret = 0;
    830       }
    831     }
    832     else
    833     {
    834       if (200 != qParam.responseCode)
    835       {
    836         fprintf (stderr, "Request succeed with wrong response code: %d.\n",
    837                  qParam.responseCode);
    838         ret = 1;
    839       }
    840       else
    841       {
    842         ret = 0;
    843         if (verbose)
    844           printf ("Request succeed.\n");
    845       }
    846 
    847       if (! ahc_param->header_check_param.found_header1)
    848         mhdErrorExitDesc ("Required header1 was not detected in request");
    849       if (! ahc_param->header_check_param.found_header4)
    850         mhdErrorExitDesc ("Required header4 was not detected in request");
    851     }
    852 #if CURL_AT_LEAST_VERSION (7, 62, 0)
    853     curl_url_cleanup (url);
    854 #endif /* CURL_AT_LEAST_VERSION(7, 62, 0) */
    855 #else
    856     fprintf (stderr, "This test requires libcurl version 7.55.0 or newer.\n");
    857     abort ();
    858 #endif /* CURL_AT_LEAST_VERSION(7, 55, 0) */
    859   }
    860   else if (tricky_header2)
    861   {
    862     /* Reset libcurl headers */
    863     qParam.headers = NULL;
    864     curl_slist_free_all (curl_headers);
    865     curl_headers = NULL;
    866 
    867     /* Set special libcurl headers */
    868     curl_headers = curl_slist_append (curl_headers, HEADER1);
    869     if (NULL == curl_headers)
    870       externalErrorExit ();
    871     curl_headers = curl_slist_append (curl_headers, HEADER2CR);
    872     if (NULL == curl_headers)
    873       externalErrorExit ();
    874     curl_headers = curl_slist_append (curl_headers, HEADER4);
    875     if (NULL == curl_headers)
    876       externalErrorExit ();
    877     qParam.headers = curl_headers;
    878 
    879     if (0 != doCurlQueryInThread (d, &qParam, &rp_headers_check,
    880                                   ahc_param->rp_data,
    881                                   ahc_param->rp_data_size))
    882     {
    883       /* TODO: Allow fail only if relevant MHD mode set */
    884       if (0 == qParam.responseCode)
    885       {
    886         fprintf (stderr, "Request failed without any valid response.\n");
    887         ret = 1;
    888       }
    889       else
    890       {
    891         if (verbose)
    892           printf ("Request failed with %d response code.\n",
    893                   qParam.responseCode);
    894         (void) qParam.responseCode; /* TODO: check for the right response code */
    895         ret = 0;
    896       }
    897     }
    898     else
    899     {
    900       if (200 != qParam.responseCode)
    901       {
    902         fprintf (stderr, "Request succeed with wrong response code: %d.\n",
    903                  qParam.responseCode);
    904         ret = 1;
    905       }
    906       else
    907       {
    908         ret = 0;
    909         if (verbose)
    910           printf ("Request succeed.\n");
    911       }
    912 
    913       if (! ahc_param->header_check_param.found_header1)
    914         mhdErrorExitDesc ("Required header1 was not detected in request");
    915       if (! ahc_param->header_check_param.found_header2)
    916         mhdErrorExitDesc ("Required header2 was not detected in request");
    917       if (! ahc_param->header_check_param.found_header4)
    918         mhdErrorExitDesc ("Required header4 was not detected in request");
    919     }
    920   }
    921   else
    922     externalErrorExitDesc ("No valid test test was selected");
    923 
    924   MHD_stop_daemon (d);
    925   curl_slist_free_all (curl_headers);
    926   free (uri_cb_param);
    927   free (ahc_param);
    928 
    929   return ret;
    930 }
    931 
    932 
    933 enum testMhdThreadsType
    934 {
    935   testMhdThreadExternal              = 0,
    936   testMhdThreadInternal              = MHD_USE_INTERNAL_POLLING_THREAD,
    937   testMhdThreadInternalPerConnection = MHD_USE_THREAD_PER_CONNECTION
    938                                        | MHD_USE_INTERNAL_POLLING_THREAD,
    939   testMhdThreadInternalPool
    940 };
    941 
    942 enum testMhdPollType
    943 {
    944   testMhdPollBySelect = 0,
    945   testMhdPollByPoll   = MHD_USE_POLL,
    946   testMhdPollByEpoll  = MHD_USE_EPOLL,
    947   testMhdPollAuto     = MHD_USE_AUTO
    948 };
    949 
    950 /* Get number of threads for thread pool depending
    951  * on used poll function and test type. */
    952 static unsigned int
    953 testNumThreadsForPool (enum testMhdPollType pollType)
    954 {
    955   unsigned int numThreads = MHD_CPU_COUNT;
    956   (void) pollType; /* Don't care about pollType for this test */
    957   return numThreads; /* No practical limit for non-cleanup test */
    958 }
    959 
    960 
    961 static struct MHD_Daemon *
    962 startTestMhdDaemon (enum testMhdThreadsType thrType,
    963                     enum testMhdPollType pollType, uint16_t *pport,
    964                     struct ahc_cls_type **ahc_param,
    965                     struct check_uri_cls **uri_cb_param)
    966 {
    967   struct MHD_Daemon *d;
    968   const union MHD_DaemonInfo *dinfo;
    969 
    970   if ((NULL == ahc_param) || (NULL == uri_cb_param))
    971     abort ();
    972 
    973   *ahc_param = (struct ahc_cls_type *) malloc (sizeof(struct ahc_cls_type));
    974   if (NULL == *ahc_param)
    975     externalErrorExit ();
    976   *uri_cb_param =
    977     (struct check_uri_cls *) malloc (sizeof(struct check_uri_cls));
    978   if (NULL == *uri_cb_param)
    979     externalErrorExit ();
    980 
    981   if ( (0 == *pport) &&
    982        (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
    983   {
    984     *pport = 4150;
    985     if (tricky_url)
    986       *pport += 1;
    987     if (tricky_header2)
    988       *pport += 2;
    989     if (! oneone)
    990       *pport += 16;
    991   }
    992 
    993   if (testMhdThreadExternal == thrType)
    994     d = MHD_start_daemon (((unsigned int) thrType) | ((unsigned int) pollType)
    995                           | (verbose ? MHD_USE_ERROR_LOG : 0)
    996                           | MHD_USE_NO_THREAD_SAFETY,
    997                           *pport, NULL, NULL,
    998                           &ahcCheck, *ahc_param,
    999                           MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb,
   1000                           *uri_cb_param,
   1001                           MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
   1002                           MHD_OPTION_END);
   1003   else if (testMhdThreadInternalPool != thrType)
   1004     d = MHD_start_daemon (((unsigned int) thrType) | ((unsigned int) pollType)
   1005                           | (verbose ? MHD_USE_ERROR_LOG : 0),
   1006                           *pport, NULL, NULL,
   1007                           &ahcCheck, *ahc_param,
   1008                           MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb,
   1009                           *uri_cb_param,
   1010                           MHD_OPTION_END);
   1011   else
   1012     d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD
   1013                           | ((unsigned int) pollType)
   1014                           | (verbose ? MHD_USE_ERROR_LOG : 0),
   1015                           *pport, NULL, NULL,
   1016                           &ahcCheck, *ahc_param,
   1017                           MHD_OPTION_THREAD_POOL_SIZE,
   1018                           testNumThreadsForPool (pollType),
   1019                           MHD_OPTION_URI_LOG_CALLBACK, &check_uri_cb,
   1020                           *uri_cb_param,
   1021                           MHD_OPTION_END);
   1022 
   1023   if (NULL == d)
   1024   {
   1025     fprintf (stderr, "Failed to start MHD daemon, errno=%d.\n", errno);
   1026     abort ();
   1027   }
   1028 
   1029   if (0 == *pport)
   1030   {
   1031     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
   1032     if ((NULL == dinfo) || (0 == dinfo->port) )
   1033     {
   1034       fprintf (stderr, "MHD_get_daemon_info() failed.\n");
   1035       abort ();
   1036     }
   1037     *pport = dinfo->port;
   1038     if (0 == global_port)
   1039       global_port = *pport; /* Reuse the same port for all tests */
   1040   }
   1041 
   1042   return d;
   1043 }
   1044 
   1045 
   1046 /* Test runners */
   1047 
   1048 
   1049 static unsigned int
   1050 testExternalGet (void)
   1051 {
   1052   struct MHD_Daemon *d;
   1053   uint16_t d_port = global_port; /* Daemon's port */
   1054   struct ahc_cls_type *ahc_param;
   1055   struct check_uri_cls *uri_cb_param;
   1056 
   1057   d = startTestMhdDaemon (testMhdThreadExternal, testMhdPollBySelect, &d_port,
   1058                           &ahc_param, &uri_cb_param);
   1059 
   1060   return performTestQueries (d, d_port, ahc_param, uri_cb_param);
   1061 }
   1062 
   1063 
   1064 static unsigned int
   1065 testInternalGet (enum testMhdPollType pollType)
   1066 {
   1067   struct MHD_Daemon *d;
   1068   uint16_t d_port = global_port; /* Daemon's port */
   1069   struct ahc_cls_type *ahc_param;
   1070   struct check_uri_cls *uri_cb_param;
   1071 
   1072   d = startTestMhdDaemon (testMhdThreadInternal, pollType, &d_port,
   1073                           &ahc_param, &uri_cb_param);
   1074 
   1075   return performTestQueries (d, d_port, ahc_param, uri_cb_param);
   1076 }
   1077 
   1078 
   1079 static unsigned int
   1080 testMultithreadedGet (enum testMhdPollType pollType)
   1081 {
   1082   struct MHD_Daemon *d;
   1083   uint16_t d_port = global_port; /* Daemon's port */
   1084   struct ahc_cls_type *ahc_param;
   1085   struct check_uri_cls *uri_cb_param;
   1086 
   1087   d = startTestMhdDaemon (testMhdThreadInternalPerConnection, pollType, &d_port,
   1088                           &ahc_param, &uri_cb_param);
   1089   return performTestQueries (d, d_port, ahc_param, uri_cb_param);
   1090 }
   1091 
   1092 
   1093 static unsigned int
   1094 testMultithreadedPoolGet (enum testMhdPollType pollType)
   1095 {
   1096   struct MHD_Daemon *d;
   1097   uint16_t d_port = global_port; /* Daemon's port */
   1098   struct ahc_cls_type *ahc_param;
   1099   struct check_uri_cls *uri_cb_param;
   1100 
   1101   d = startTestMhdDaemon (testMhdThreadInternalPool, pollType, &d_port,
   1102                           &ahc_param, &uri_cb_param);
   1103   return performTestQueries (d, d_port, ahc_param, uri_cb_param);
   1104 }
   1105 
   1106 
   1107 static void
   1108 check_test_can_be_used (void)
   1109 {
   1110 #if ! CURL_AT_LEAST_VERSION (7, 55, 0)
   1111   if (tricky_url)
   1112   {
   1113     fprintf (stderr, "This test requires libcurl version 7.55.0 or newer.\n");
   1114     exit (77);
   1115   }
   1116 #endif /* ! CURL_AT_LEAST_VERSION(7, 55, 0) */
   1117   return;
   1118 }
   1119 
   1120 
   1121 int
   1122 main (int argc, char *const *argv)
   1123 {
   1124   unsigned int errorCount = 0;
   1125   unsigned int test_result = 0;
   1126   verbose = 0;
   1127 
   1128   if ((NULL == argv) || (0 == argv[0]))
   1129     return 99;
   1130   oneone = ! has_in_name (argv[0], "10");
   1131   tricky_url = has_in_name (argv[0], "_url") ? 1 : 0;
   1132   tricky_header2 = has_in_name (argv[0], "_header2") ? 1 : 0;
   1133   if (1 != tricky_url + tricky_header2)
   1134     return 99;
   1135   verbose = ! (has_param (argc, argv, "-q") ||
   1136                has_param (argc, argv, "--quiet") ||
   1137                has_param (argc, argv, "-s") ||
   1138                has_param (argc, argv, "--silent"));
   1139 
   1140   check_test_can_be_used ();
   1141 
   1142   test_global_init ();
   1143 
   1144   /* Could be set to non-zero value to enforce using specific port
   1145    * in the test */
   1146   global_port = 0;
   1147   test_result = testExternalGet ();
   1148   if (test_result)
   1149     fprintf (stderr, "FAILED: testExternalGet () - %u.\n", test_result);
   1150   else if (verbose)
   1151     printf ("PASSED: testExternalGet ().\n");
   1152   errorCount += test_result;
   1153   if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
   1154   {
   1155     test_result = testInternalGet (testMhdPollAuto);
   1156     if (test_result)
   1157       fprintf (stderr, "FAILED: testInternalGet (testMhdPollAuto) - %u.\n",
   1158                test_result);
   1159     else if (verbose)
   1160       printf ("PASSED: testInternalGet (testMhdPollBySelect).\n");
   1161     errorCount += test_result;
   1162 #ifdef _MHD_HEAVY_TESTS
   1163     /* Actually tests are not heavy, but took too long to complete while
   1164      * not really provide any additional results. */
   1165     test_result = testInternalGet (testMhdPollBySelect);
   1166     if (test_result)
   1167       fprintf (stderr, "FAILED: testInternalGet (testMhdPollBySelect) - %u.\n",
   1168                test_result);
   1169     else if (verbose)
   1170       printf ("PASSED: testInternalGet (testMhdPollBySelect).\n");
   1171     errorCount += test_result;
   1172     test_result = testMultithreadedPoolGet (testMhdPollBySelect);
   1173     if (test_result)
   1174       fprintf (stderr,
   1175                "FAILED: testMultithreadedPoolGet (testMhdPollBySelect) - %u.\n",
   1176                test_result);
   1177     else if (verbose)
   1178       printf ("PASSED: testMultithreadedPoolGet (testMhdPollBySelect).\n");
   1179     errorCount += test_result;
   1180     test_result = testMultithreadedGet (testMhdPollBySelect);
   1181     if (test_result)
   1182       fprintf (stderr,
   1183                "FAILED: testMultithreadedGet (testMhdPollBySelect) - %u.\n",
   1184                test_result);
   1185     else if (verbose)
   1186       printf ("PASSED: testMultithreadedGet (testMhdPollBySelect).\n");
   1187     errorCount += test_result;
   1188     if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL))
   1189     {
   1190       test_result = testInternalGet (testMhdPollByPoll);
   1191       if (test_result)
   1192         fprintf (stderr, "FAILED: testInternalGet (testMhdPollByPoll) - %u.\n",
   1193                  test_result);
   1194       else if (verbose)
   1195         printf ("PASSED: testInternalGet (testMhdPollByPoll).\n");
   1196       errorCount += test_result;
   1197     }
   1198     if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL))
   1199     {
   1200       test_result = testInternalGet (testMhdPollByEpoll);
   1201       if (test_result)
   1202         fprintf (stderr, "FAILED: testInternalGet (testMhdPollByEpoll) - %u.\n",
   1203                  test_result);
   1204       else if (verbose)
   1205         printf ("PASSED: testInternalGet (testMhdPollByEpoll).\n");
   1206       errorCount += test_result;
   1207     }
   1208 #else
   1209     /* Mute compiler warnings */
   1210     (void) testMultithreadedGet;
   1211     (void) testMultithreadedPoolGet;
   1212 #endif /* _MHD_HEAVY_TESTS */
   1213   }
   1214   if (0 != errorCount)
   1215     fprintf (stderr,
   1216              "Error (code: %u)\n",
   1217              errorCount);
   1218   else if (verbose)
   1219     printf ("All tests passed.\n");
   1220 
   1221   test_global_cleanup ();
   1222 
   1223   return (errorCount == 0) ? 0 : 1;       /* 0 == pass */
   1224 }