libmicrohttpd

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

test_tricky.c (37345B)


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