libmicrohttpd

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

test_parse_cookies.c (39088B)


      1 /*
      2      This file is part of GNU libmicrohttpd
      3      Copyright (C) 2007 Christian Grothoff
      4      Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
      5 
      6      GNU libmicrohttpd is free software; you can redistribute it and/or modify
      7      it under the terms of the GNU General Public License as published
      8      by the Free Software Foundation; either version 2, or (at your
      9      option) any later version.
     10 
     11      GNU libmicrohttpd is distributed in the hope that it will be useful, but
     12      WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      General Public License for more details.
     15 
     16      You should have received a copy of the GNU General Public License
     17      along with libmicrohttpd; see the file COPYING.  If not, write to the
     18      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19      Boston, MA 02110-1301, USA.
     20 */
     21 
     22 /**
     23  * @file test_parse_cookies.c
     24  * @brief  Testcase for HTTP cookie parsing
     25  * @author Karlson2k (Evgeny Grin)
     26  * @author Christian Grothoff
     27  */
     28 
     29 #include "mhd_options.h"
     30 #include "platform.h"
     31 #include <curl/curl.h>
     32 #include <microhttpd.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <time.h>
     36 #include <errno.h>
     37 
     38 #ifndef _WIN32
     39 #include <sys/socket.h>
     40 #include <unistd.h>
     41 #endif
     42 
     43 #include "mhd_has_param.h"
     44 #include "mhd_has_in_name.h"
     45 
     46 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     47    test into a marked, classifiable test error (TESTING.md, P5). */
     48 #include "mhd_panic_tripwire.h"
     49 
     50 #ifndef MHD_STATICSTR_LEN_
     51 /**
     52  * Determine length of static string / macro strings at compile time.
     53  */
     54 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
     55 #endif /* ! MHD_STATICSTR_LEN_ */
     56 
     57 #ifndef CURL_VERSION_BITS
     58 #define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z))
     59 #endif /* ! CURL_VERSION_BITS */
     60 #ifndef CURL_AT_LEAST_VERSION
     61 #define CURL_AT_LEAST_VERSION(x,y,z) \
     62   (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z))
     63 #endif /* ! CURL_AT_LEAST_VERSION */
     64 
     65 #ifndef _MHD_INSTRMACRO
     66 /* Quoted macro parameter */
     67 #define _MHD_INSTRMACRO(a) #a
     68 #endif /* ! _MHD_INSTRMACRO */
     69 #ifndef _MHD_STRMACRO
     70 /* Quoted expanded macro parameter */
     71 #define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a)
     72 #endif /* ! _MHD_STRMACRO */
     73 
     74 #if defined(HAVE___FUNC__)
     75 #define externalErrorExit(ignore) \
     76   _externalErrorExit_func (NULL, __func__, __LINE__)
     77 #define externalErrorExitDesc(errDesc) \
     78   _externalErrorExit_func (errDesc, __func__, __LINE__)
     79 #define libcurlErrorExit(ignore) \
     80   _libcurlErrorExit_func (NULL, __func__, __LINE__)
     81 #define libcurlErrorExitDesc(errDesc) \
     82   _libcurlErrorExit_func (errDesc, __func__, __LINE__)
     83 #define mhdErrorExit(ignore) \
     84   _mhdErrorExit_func (NULL, __func__, __LINE__)
     85 #define mhdErrorExitDesc(errDesc) \
     86   _mhdErrorExit_func (errDesc, __func__, __LINE__)
     87 #define checkCURLE_OK(libcurlcall) \
     88   _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \
     89                        __func__, __LINE__)
     90 #elif defined(HAVE___FUNCTION__)
     91 #define externalErrorExit(ignore) \
     92   _externalErrorExit_func (NULL, __FUNCTION__, __LINE__)
     93 #define externalErrorExitDesc(errDesc) \
     94   _externalErrorExit_func (errDesc, __FUNCTION__, __LINE__)
     95 #define libcurlErrorExit(ignore) \
     96   _libcurlErrorExit_func (NULL, __FUNCTION__, __LINE__)
     97 #define libcurlErrorExitDesc(errDesc) \
     98   _libcurlErrorExit_func (errDesc, __FUNCTION__, __LINE__)
     99 #define mhdErrorExit(ignore) \
    100   _mhdErrorExit_func (NULL, __FUNCTION__, __LINE__)
    101 #define mhdErrorExitDesc(errDesc) \
    102   _mhdErrorExit_func (errDesc, __FUNCTION__, __LINE__)
    103 #define checkCURLE_OK(libcurlcall) \
    104   _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \
    105                        __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 #define checkCURLE_OK(libcurlcall) \
    116   _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), NULL, \
    117                        __LINE__)
    118 #endif
    119 
    120 
    121 _MHD_NORETURN static void
    122 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
    123 {
    124   fflush (stdout);
    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   fflush (stdout);
    150   if ((NULL != errDesc) && (0 != errDesc[0]))
    151     fprintf (stderr, "%s", errDesc);
    152   else
    153     fprintf (stderr, "CURL library call failed");
    154   if ((NULL != funcName) && (0 != funcName[0]))
    155     fprintf (stderr, " in %s", funcName);
    156   if (0 < lineNum)
    157     fprintf (stderr, " at line %d", lineNum);
    158 
    159   fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
    160            strerror (errno));
    161 #ifdef MHD_WINSOCK_SOCKETS
    162   fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
    163 #endif /* MHD_WINSOCK_SOCKETS */
    164   if (0 != libcurl_errbuf[0])
    165     fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf);
    166 
    167   fflush (stderr);
    168   exit (99);
    169 }
    170 
    171 
    172 _MHD_NORETURN static void
    173 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
    174 {
    175   fflush (stdout);
    176   if ((NULL != errDesc) && (0 != errDesc[0]))
    177     fprintf (stderr, "%s", errDesc);
    178   else
    179     fprintf (stderr, "MHD unexpected error");
    180   if ((NULL != funcName) && (0 != funcName[0]))
    181     fprintf (stderr, " in %s", funcName);
    182   if (0 < lineNum)
    183     fprintf (stderr, " at line %d", lineNum);
    184 
    185   fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
    186            strerror (errno));
    187 #ifdef MHD_WINSOCK_SOCKETS
    188   fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
    189 #endif /* MHD_WINSOCK_SOCKETS */
    190 
    191   fflush (stderr);
    192   exit (8);
    193 }
    194 
    195 
    196 /* Could be increased to facilitate debugging */
    197 #define TIMEOUTS_VAL 500000
    198 
    199 #define EXPECTED_URI_BASE_PATH  "/"
    200 
    201 #define URL_SCHEME "http:/" "/"
    202 
    203 #define URL_HOST "127.0.0.1"
    204 
    205 #define URL_SCHEME_HOST URL_SCHEME URL_HOST
    206 
    207 #define PAGE \
    208   "<html><head><title>libmicrohttpd test page</title></head>" \
    209   "<body>Success!</body></html>"
    210 
    211 #define PAGE_ERROR \
    212   "<html><body>Cookies parsing error</body></html>"
    213 
    214 
    215 #ifndef MHD_STATICSTR_LEN_
    216 /**
    217  * Determine length of static string / macro strings at compile time.
    218  */
    219 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
    220 #endif /* ! MHD_STATICSTR_LEN_ */
    221 
    222 
    223 struct strct_str_len
    224 {
    225   const char *str;
    226   const size_t len;
    227 };
    228 
    229 #define STR_LEN_(str)   {str, MHD_STATICSTR_LEN_ (str)}
    230 #define STR_NULL_       {NULL, 0}
    231 
    232 struct strct_cookie
    233 {
    234   struct strct_str_len name;
    235   struct strct_str_len value;
    236 };
    237 
    238 #define COOKIE_(name,value)     {STR_LEN_ (name), STR_LEN_ (value)}
    239 #define COOKIE_NULL             {STR_NULL_, STR_NULL_}
    240 
    241 struct strct_test_data
    242 {
    243   unsigned int line_num;
    244   const char *header_str;
    245   unsigned int num_cookies_strict_p2;
    246   unsigned int num_cookies_strict_p1;
    247   unsigned int num_cookies_strict_zero;
    248   unsigned int num_cookies_strict_n2;
    249   unsigned int num_cookies_strict_n3;
    250   struct strct_cookie cookies[5];
    251 };
    252 
    253 static const struct strct_test_data test_data[] = {
    254   {
    255     __LINE__,
    256     "name1=value1",
    257     1,
    258     1,
    259     1,
    260     1,
    261     1,
    262     {
    263       COOKIE_ ("name1", "value1"),
    264       COOKIE_NULL,
    265       COOKIE_NULL,
    266       COOKIE_NULL,
    267       COOKIE_NULL
    268     }
    269   },
    270   {
    271     __LINE__,
    272     "name1=value1;",
    273     0,
    274     1,
    275     1,
    276     1,
    277     1,
    278     {
    279       COOKIE_ ("name1", "value1"),
    280       COOKIE_NULL,
    281       COOKIE_NULL,
    282       COOKIE_NULL,
    283       COOKIE_NULL
    284     }
    285   },
    286   {
    287     __LINE__,
    288     "name1=value1; ",
    289     0,
    290     1,
    291     1,
    292     1,
    293     1,
    294     {
    295       COOKIE_ ("name1", "value1"),
    296       COOKIE_NULL,
    297       COOKIE_NULL,
    298       COOKIE_NULL,
    299       COOKIE_NULL
    300     }
    301   },
    302   {
    303     __LINE__,
    304     "; name1=value1",
    305     0,
    306     0,
    307     1,
    308     1,
    309     1,
    310     {
    311       COOKIE_ ("name1", "value1"),
    312       COOKIE_NULL,
    313       COOKIE_NULL,
    314       COOKIE_NULL,
    315       COOKIE_NULL
    316     }
    317   },
    318   {
    319     __LINE__,
    320     ";name1=value1",
    321     0,
    322     0,
    323     1,
    324     1,
    325     1,
    326     {
    327       COOKIE_ ("name1", "value1"),
    328       COOKIE_NULL,
    329       COOKIE_NULL,
    330       COOKIE_NULL,
    331       COOKIE_NULL
    332     }
    333   },
    334   {
    335     __LINE__,
    336     "name1=value1 ",
    337     1,
    338     1,
    339     1,
    340     1,
    341     1,
    342     {
    343       COOKIE_ ("name1", "value1"),
    344       COOKIE_NULL,
    345       COOKIE_NULL,
    346       COOKIE_NULL,
    347       COOKIE_NULL
    348     }
    349   },
    350   {
    351     __LINE__,
    352     "name1=value1 ;",
    353     0,
    354     0,
    355     1,
    356     1,
    357     1,
    358     {
    359       COOKIE_ ("name1", "value1"),
    360       COOKIE_NULL,
    361       COOKIE_NULL,
    362       COOKIE_NULL,
    363       COOKIE_NULL
    364     }
    365   },
    366   {
    367     __LINE__,
    368     "name1=value1 ; ",
    369     0,
    370     0,
    371     1,
    372     1,
    373     1,
    374     {
    375       COOKIE_ ("name1", "value1"),
    376       COOKIE_NULL,
    377       COOKIE_NULL,
    378       COOKIE_NULL,
    379       COOKIE_NULL
    380     }
    381   },
    382   {
    383     __LINE__,
    384     "name2=\"value 2\"",
    385     0,
    386     0,
    387     0,
    388     1,
    389     1,
    390     {
    391       COOKIE_ ("name2", "value 2"),
    392       COOKIE_NULL,
    393       COOKIE_NULL,
    394       COOKIE_NULL,
    395       COOKIE_NULL
    396     }
    397   },
    398   {
    399     __LINE__,
    400     "name1=value1;\tname2=value2",
    401     0,
    402     1,
    403     2,
    404     2,
    405     2,
    406     {
    407       COOKIE_ ("name1", "value1"),
    408       COOKIE_ ("name2", "value2"),
    409       COOKIE_NULL,
    410       COOKIE_NULL,
    411       COOKIE_NULL
    412     }
    413   },
    414   {
    415     __LINE__,
    416     "name1=value1; name1=value1",
    417     2,
    418     2,
    419     2,
    420     2,
    421     2,
    422     {
    423       COOKIE_ ("name1", "value1"),
    424       COOKIE_ ("name1", "value1"), /* The second value is not checked actually */
    425       COOKIE_NULL,
    426       COOKIE_NULL,
    427       COOKIE_NULL
    428     }
    429   },
    430   {
    431     __LINE__,
    432     "name1=value1; name2=value2",
    433     2,
    434     2,
    435     2,
    436     2,
    437     2,
    438     {
    439       COOKIE_ ("name1", "value1"),
    440       COOKIE_ ("name2", "value2"),
    441       COOKIE_NULL,
    442       COOKIE_NULL,
    443       COOKIE_NULL
    444     }
    445   },
    446   {
    447     __LINE__,
    448     "name1=value1; name2=value2    ",
    449     2,
    450     2,
    451     2,
    452     2,
    453     2,
    454     {
    455       COOKIE_ ("name1", "value1"),
    456       COOKIE_ ("name2", "value2"),
    457       COOKIE_NULL,
    458       COOKIE_NULL,
    459       COOKIE_NULL
    460     }
    461   },
    462   {
    463     __LINE__,
    464     "name1=value1;  name2=value2",
    465     0,
    466     1,
    467     2,
    468     2,
    469     2,
    470     {
    471       COOKIE_ ("name1", "value1"),
    472       COOKIE_ ("name2", "value2"),
    473       COOKIE_NULL,
    474       COOKIE_NULL,
    475       COOKIE_NULL
    476     }
    477   },
    478   {
    479     __LINE__,
    480     "name1=value1;name2=value2",
    481     0,
    482     1,
    483     2,
    484     2,
    485     2,
    486     {
    487       COOKIE_ ("name1", "value1"),
    488       COOKIE_ ("name2", "value2"),
    489       COOKIE_NULL,
    490       COOKIE_NULL,
    491       COOKIE_NULL
    492     }
    493   },
    494   {
    495     __LINE__,
    496     "name1=value1;\tname2=value2",
    497     0,
    498     1,
    499     2,
    500     2,
    501     2,
    502     {
    503       COOKIE_ ("name1", "value1"),
    504       COOKIE_ ("name2", "value2"),
    505       COOKIE_NULL,
    506       COOKIE_NULL,
    507       COOKIE_NULL
    508     }
    509   },
    510   {
    511     __LINE__,
    512     "name1=value1 ; name2=value2",
    513     0,
    514     0,
    515     2,
    516     2,
    517     2,
    518     {
    519       COOKIE_ ("name1", "value1"),
    520       COOKIE_ ("name2", "value2"),
    521       COOKIE_NULL,
    522       COOKIE_NULL,
    523       COOKIE_NULL
    524     }
    525   },
    526   {
    527     __LINE__,
    528     "     name1=value1; name2=value2",
    529     2,
    530     2,
    531     2,
    532     2,
    533     2,
    534     {
    535       COOKIE_ ("name1", "value1"),
    536       COOKIE_ ("name2", "value2"),
    537       COOKIE_NULL,
    538       COOKIE_NULL,
    539       COOKIE_NULL
    540     }
    541   },
    542   {
    543     __LINE__,
    544     "name1=var1; name2=var2; name3=; " \
    545     "name4=\"var4 with spaces\"; " \
    546     "name5=var_with_=_char",
    547     0,
    548     3,
    549     3,
    550     5,
    551     5,
    552     {
    553       COOKIE_ ("name1", "var1"),
    554       COOKIE_ ("name2", "var2"),
    555       COOKIE_ ("name3", ""),
    556       COOKIE_ ("name4", "var4 with spaces"),
    557       COOKIE_ ("name5", "var_with_=_char")
    558     }
    559   },
    560   {
    561     __LINE__,
    562     "name1=var1;name2=var2;name3=;" \
    563     "name4=\"var4 with spaces\";" \
    564     "name5=var_with_=_char",
    565     0,
    566     1,
    567     3,
    568     5,
    569     5,
    570     {
    571       COOKIE_ ("name1", "var1"),
    572       COOKIE_ ("name2", "var2"),
    573       COOKIE_ ("name3", ""),
    574       COOKIE_ ("name4", "var4 with spaces"),
    575       COOKIE_ ("name5", "var_with_=_char")
    576     }
    577   },
    578   {
    579     __LINE__,
    580     "name1=var1;  name2=var2;  name3=;  " \
    581     "name4=\"var4 with spaces\";  " \
    582     "name5=var_with_=_char\t \t",
    583     0,
    584     1,
    585     3,
    586     5,
    587     5,
    588     {
    589       COOKIE_ ("name1", "var1"),
    590       COOKIE_ ("name2", "var2"),
    591       COOKIE_ ("name3", ""),
    592       COOKIE_ ("name4", "var4 with spaces"),
    593       COOKIE_ ("name5", "var_with_=_char")
    594     }
    595   },
    596   {
    597     __LINE__,
    598     "name1=var1;;name2=var2;;name3=;;" \
    599     "name4=\"var4 with spaces\";;" \
    600     "name5=var_with_=_char;\t \t",
    601     0,
    602     1,
    603     3,
    604     5,
    605     5,
    606     {
    607       COOKIE_ ("name1", "var1"),
    608       COOKIE_ ("name2", "var2"),
    609       COOKIE_ ("name3", ""),
    610       COOKIE_ ("name4", "var4 with spaces"),
    611       COOKIE_ ("name5", "var_with_=_char")
    612     }
    613   },
    614   {
    615     __LINE__,
    616     "name3=; name1=var1; name2=var2; " \
    617     "name5=var_with_=_char;" \
    618     "name4=\"var4 with spaces\"",
    619     0,
    620     4,
    621     4,
    622     5,
    623     5,
    624     {
    625       COOKIE_ ("name1", "var1"),
    626       COOKIE_ ("name2", "var2"),
    627       COOKIE_ ("name3", ""),
    628       COOKIE_ ("name5", "var_with_=_char"),
    629       COOKIE_ ("name4", "var4 with spaces")
    630     }
    631   },
    632   {
    633     __LINE__,
    634     "name2=var2; name1=var1; " \
    635     "name5=var_with_=_char; name3=; " \
    636     "name4=\"var4 with spaces\";",
    637     0,
    638     4,
    639     4,
    640     5,
    641     5,
    642     {
    643       COOKIE_ ("name1", "var1"),
    644       COOKIE_ ("name2", "var2"),
    645       COOKIE_ ("name3", ""),
    646       COOKIE_ ("name5", "var_with_=_char"),
    647       COOKIE_ ("name4", "var4 with spaces")
    648     }
    649   },
    650   {
    651     __LINE__,
    652     "name2=var2; name1=var1; " \
    653     "name5=var_with_=_char; " \
    654     "name4=\"var4 with spaces\"; name3=",
    655     0,
    656     3,
    657     3,
    658     5,
    659     5,
    660     {
    661       COOKIE_ ("name1", "var1"),
    662       COOKIE_ ("name2", "var2"),
    663       COOKIE_ ("name5", "var_with_=_char"),
    664       COOKIE_ ("name3", ""),
    665       COOKIE_ ("name4", "var4 with spaces")
    666     }
    667   },
    668   {
    669     __LINE__,
    670     "name2=var2; name1=var1; " \
    671     "name4=\"var4 with spaces\"; " \
    672     "name5=var_with_=_char; name3=;",
    673     0,
    674     2,
    675     2,
    676     5,
    677     5,
    678     {
    679       COOKIE_ ("name1", "var1"),
    680       COOKIE_ ("name2", "var2"),
    681       COOKIE_ ("name3", ""),
    682       COOKIE_ ("name4", "var4 with spaces"),
    683       COOKIE_ ("name5", "var_with_=_char")
    684     }
    685   },
    686   {
    687     __LINE__,
    688     ";;;;;;;;name1=var1; name2=var2; name3=; " \
    689     "name4=\"var4 with spaces\"; " \
    690     "name5=var_with_=_char",
    691     0,
    692     0,
    693     3,
    694     5,
    695     5,
    696     {
    697       COOKIE_ ("name1", "var1"),
    698       COOKIE_ ("name2", "var2"),
    699       COOKIE_ ("name3", ""),
    700       COOKIE_ ("name4", "var4 with spaces"),
    701       COOKIE_ ("name5", "var_with_=_char")
    702     }
    703   },
    704   {
    705     __LINE__,
    706     "name1=var1; name2=var2; name3=; " \
    707     "name4=\"var4 with spaces\"; ; ; ; ; " \
    708     "name5=var_with_=_char",
    709     0,
    710     3,
    711     3,
    712     5,
    713     5,
    714     {
    715       COOKIE_ ("name1", "var1"),
    716       COOKIE_ ("name2", "var2"),
    717       COOKIE_ ("name3", ""),
    718       COOKIE_ ("name4", "var4 with spaces"),
    719       COOKIE_ ("name5", "var_with_=_char")
    720     }
    721   },
    722   {
    723     __LINE__,
    724     "name1=var1; name2=var2; name3=; " \
    725     "name4=\"var4 with spaces\"; " \
    726     "name5=var_with_=_char;;;;;;;;",
    727     0,
    728     3,
    729     3,
    730     5,
    731     5,
    732     {
    733       COOKIE_ ("name1", "var1"),
    734       COOKIE_ ("name2", "var2"),
    735       COOKIE_ ("name3", ""),
    736       COOKIE_ ("name4", "var4 with spaces"),
    737       COOKIE_ ("name5", "var_with_=_char")
    738     }
    739   },
    740   {
    741     __LINE__,
    742     "name1=var1; name2=var2; " \
    743     "name4=\"var4 with spaces\";" \
    744     "name5=var_with_=_char; ; ; ; ; name3=",
    745     0,
    746     2,
    747     2,
    748     5,
    749     5,
    750     {
    751       COOKIE_ ("name1", "var1"),
    752       COOKIE_ ("name2", "var2"),
    753       COOKIE_ ("name5", "var_with_=_char"),
    754       COOKIE_ ("name3", ""),
    755       COOKIE_ ("name4", "var4 with spaces")
    756     }
    757   },
    758   {
    759     __LINE__,
    760     "name5=var_with_=_char ;" \
    761     "name1=var1; name2=var2; name3=; " \
    762     "name4=\"var4 with spaces\" ",
    763     0,
    764     0,
    765     4,
    766     5,
    767     5,
    768     {
    769       COOKIE_ ("name1", "var1"),
    770       COOKIE_ ("name2", "var2"),
    771       COOKIE_ ("name3", ""),
    772       COOKIE_ ("name5", "var_with_=_char"),
    773       COOKIE_ ("name4", "var4 with spaces")
    774     }
    775   },
    776   {
    777     __LINE__,
    778     "name5=var_with_=_char; name4=\"var4 with spaces\";" \
    779     "name1=var1; name2=var2; name3=",
    780     0,
    781     1,
    782     1,
    783     5,
    784     5,
    785     {
    786       COOKIE_ ("name5", "var_with_=_char"),
    787       COOKIE_ ("name1", "var1"),
    788       COOKIE_ ("name2", "var2"),
    789       COOKIE_ ("name3", ""),
    790       COOKIE_ ("name4", "var4 with spaces")
    791     }
    792   },
    793   {
    794     __LINE__,
    795     "name5=var_with_=_char; name4=\"var4_without_spaces\"; " \
    796     "name1=var1; name2=var2; name3=",
    797     5,
    798     5,
    799     5,
    800     5,
    801     5,
    802     {
    803       COOKIE_ ("name5", "var_with_=_char"),
    804       COOKIE_ ("name1", "var1"),
    805       COOKIE_ ("name2", "var2"),
    806       COOKIE_ ("name3", ""),
    807       COOKIE_ ("name4", "var4_without_spaces")
    808     }
    809   },
    810   {
    811     __LINE__,
    812     "name1 = value1",
    813     0,
    814     0,
    815     0,
    816     0,
    817     1,
    818     {
    819       COOKIE_ ("name1", "value1"),
    820       COOKIE_NULL,
    821       COOKIE_NULL,
    822       COOKIE_NULL,
    823       COOKIE_NULL
    824     }
    825   },
    826   {
    827     __LINE__,
    828     "name1\t=\tvalue1",
    829     0,
    830     0,
    831     0,
    832     0,
    833     1,
    834     {
    835       COOKIE_ ("name1", "value1"),
    836       COOKIE_NULL,
    837       COOKIE_NULL,
    838       COOKIE_NULL,
    839       COOKIE_NULL
    840     }
    841   },
    842   {
    843     __LINE__,
    844     "name1\t = \tvalue1",
    845     0,
    846     0,
    847     0,
    848     0,
    849     1,
    850     {
    851       COOKIE_ ("name1", "value1"),
    852       COOKIE_NULL,
    853       COOKIE_NULL,
    854       COOKIE_NULL,
    855       COOKIE_NULL
    856     }
    857   },
    858   {
    859     __LINE__,
    860     "name1 = value1; name2 =\tvalue2",
    861     0,
    862     0,
    863     0,
    864     0,
    865     2,
    866     {
    867       COOKIE_ ("name1", "value1"),
    868       COOKIE_ ("name2", "value2"),
    869       COOKIE_NULL,
    870       COOKIE_NULL,
    871       COOKIE_NULL
    872     }
    873   },
    874   {
    875     __LINE__,
    876     "name1=value1; name2 =\tvalue2",
    877     0,
    878     1,
    879     1,
    880     1,
    881     2,
    882     {
    883       COOKIE_ ("name1", "value1"),
    884       COOKIE_ ("name2", "value2"),
    885       COOKIE_NULL,
    886       COOKIE_NULL,
    887       COOKIE_NULL
    888     }
    889   },
    890   {
    891     __LINE__,
    892     "name1 = value1; name2=value2",
    893     0,
    894     0,
    895     0,
    896     0,
    897     2,
    898     {
    899       COOKIE_ ("name1", "value1"),
    900       COOKIE_ ("name2", "value2"),
    901       COOKIE_NULL,
    902       COOKIE_NULL,
    903       COOKIE_NULL
    904     }
    905   },
    906   {
    907     __LINE__,
    908     "",
    909     0,
    910     0,
    911     0,
    912     0,
    913     0,
    914     {
    915       COOKIE_NULL,
    916       COOKIE_NULL,
    917       COOKIE_NULL,
    918       COOKIE_NULL,
    919       COOKIE_NULL
    920     }
    921   },
    922   {
    923     __LINE__,
    924     "      ",
    925     0,
    926     0,
    927     0,
    928     0,
    929     0,
    930     {
    931       COOKIE_NULL,
    932       COOKIE_NULL,
    933       COOKIE_NULL,
    934       COOKIE_NULL,
    935       COOKIE_NULL
    936     }
    937   },
    938   {
    939     __LINE__,
    940     "\t",
    941     0,
    942     0,
    943     0,
    944     0,
    945     0,
    946     {
    947       COOKIE_NULL,
    948       COOKIE_NULL,
    949       COOKIE_NULL,
    950       COOKIE_NULL,
    951       COOKIE_NULL
    952     }
    953   },
    954   {
    955     __LINE__,
    956     "var=,",
    957     0,
    958     0,
    959     0,
    960     0,
    961     0,
    962     {
    963       COOKIE_NULL,
    964       COOKIE_NULL,
    965       COOKIE_NULL,
    966       COOKIE_NULL,
    967       COOKIE_NULL
    968     }
    969   },
    970   {
    971     __LINE__,
    972     "var=\"\\ \"",
    973     0,
    974     0,
    975     0,
    976     0,
    977     0,
    978     {
    979       COOKIE_NULL,
    980       COOKIE_NULL,
    981       COOKIE_NULL,
    982       COOKIE_NULL,
    983       COOKIE_NULL
    984     }
    985   },
    986   {
    987     __LINE__,
    988     "var=value  space",
    989     0,
    990     0,
    991     0,
    992     0,
    993     0,
    994     {
    995       COOKIE_NULL,
    996       COOKIE_NULL,
    997       COOKIE_NULL,
    998       COOKIE_NULL,
    999       COOKIE_NULL
   1000     }
   1001   },
   1002   {
   1003     __LINE__,
   1004     "var=value\ttab",
   1005     0,
   1006     0,
   1007     0,
   1008     0,
   1009     0,
   1010     {
   1011       COOKIE_NULL,
   1012       COOKIE_NULL,
   1013       COOKIE_NULL,
   1014       COOKIE_NULL,
   1015       COOKIE_NULL
   1016     }
   1017   },
   1018   {
   1019     __LINE__,
   1020     "=",
   1021     0,
   1022     0,
   1023     0,
   1024     0,
   1025     0,
   1026     {
   1027       COOKIE_NULL,
   1028       COOKIE_NULL,
   1029       COOKIE_NULL,
   1030       COOKIE_NULL,
   1031       COOKIE_NULL
   1032     }
   1033   },
   1034   {
   1035     __LINE__,
   1036     "====",
   1037     0,
   1038     0,
   1039     0,
   1040     0,
   1041     0,
   1042     {
   1043       COOKIE_NULL,
   1044       COOKIE_NULL,
   1045       COOKIE_NULL,
   1046       COOKIE_NULL,
   1047       COOKIE_NULL
   1048     }
   1049   },
   1050   {
   1051     __LINE__,
   1052     ";=",
   1053     0,
   1054     0,
   1055     0,
   1056     0,
   1057     0,
   1058     {
   1059       COOKIE_NULL,
   1060       COOKIE_NULL,
   1061       COOKIE_NULL,
   1062       COOKIE_NULL,
   1063       COOKIE_NULL
   1064     }
   1065   },
   1066   {
   1067     __LINE__,
   1068     "var",
   1069     0,
   1070     0,
   1071     0,
   1072     0,
   1073     0,
   1074     {
   1075       COOKIE_NULL,
   1076       COOKIE_NULL,
   1077       COOKIE_NULL,
   1078       COOKIE_NULL,
   1079       COOKIE_NULL
   1080     }
   1081   },
   1082   {
   1083     __LINE__,
   1084     "=;",
   1085     0,
   1086     0,
   1087     0,
   1088     0,
   1089     0,
   1090     {
   1091       COOKIE_NULL,
   1092       COOKIE_NULL,
   1093       COOKIE_NULL,
   1094       COOKIE_NULL,
   1095       COOKIE_NULL
   1096     }
   1097   },
   1098   {
   1099     __LINE__,
   1100     "= ;",
   1101     0,
   1102     0,
   1103     0,
   1104     0,
   1105     0,
   1106     {
   1107       COOKIE_NULL,
   1108       COOKIE_NULL,
   1109       COOKIE_NULL,
   1110       COOKIE_NULL,
   1111       COOKIE_NULL
   1112     }
   1113   },
   1114   {
   1115     __LINE__,
   1116     ";= ;",
   1117     0,
   1118     0,
   1119     0,
   1120     0,
   1121     0,
   1122     {
   1123       COOKIE_NULL,
   1124       COOKIE_NULL,
   1125       COOKIE_NULL,
   1126       COOKIE_NULL,
   1127       COOKIE_NULL
   1128     }
   1129   }
   1130 };
   1131 
   1132 /* Global parameters */
   1133 static int verbose;
   1134 static int oneone;                  /**< If false use HTTP/1.0 for requests*/
   1135 static int use_discp_n3;
   1136 static int use_discp_n2;
   1137 static int use_discp_zero;
   1138 static int use_discp_p1;
   1139 static int use_discp_p2;
   1140 static int discp_level;
   1141 
   1142 static void
   1143 test_global_init (void)
   1144 {
   1145   libcurl_errbuf[0] = 0;
   1146 
   1147   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
   1148     externalErrorExit ();
   1149 }
   1150 
   1151 
   1152 static void
   1153 test_global_cleanup (void)
   1154 {
   1155   curl_global_cleanup ();
   1156 }
   1157 
   1158 
   1159 struct CBC
   1160 {
   1161   char *buf;
   1162   size_t pos;
   1163   size_t size;
   1164 };
   1165 
   1166 
   1167 static size_t
   1168 copyBuffer (void *ptr,
   1169             size_t size,
   1170             size_t nmemb,
   1171             void *ctx)
   1172 {
   1173   struct CBC *cbc = ctx;
   1174 
   1175   if (cbc->pos + size * nmemb > cbc->size)
   1176     return 0;                   /* overflow */
   1177   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
   1178   cbc->pos += size * nmemb;
   1179   return size * nmemb;
   1180 }
   1181 
   1182 
   1183 struct ahc_cls_type
   1184 {
   1185   const char *rq_method;
   1186   const char *rq_url;
   1187   const struct strct_test_data *check;
   1188 };
   1189 
   1190 
   1191 static enum MHD_Result
   1192 ahcCheck (void *cls,
   1193           struct MHD_Connection *connection,
   1194           const char *url,
   1195           const char *method,
   1196           const char *version,
   1197           const char *upload_data, size_t *upload_data_size,
   1198           void **req_cls)
   1199 {
   1200   static int marker;
   1201   struct MHD_Response *response;
   1202   enum MHD_Result ret;
   1203   struct ahc_cls_type *const param = (struct ahc_cls_type *) cls;
   1204   unsigned int expected_num_cookies;
   1205   unsigned int i;
   1206   int cookie_failed;
   1207 
   1208   if (NULL == param)
   1209     mhdErrorExitDesc ("cls parameter is NULL");
   1210   if (use_discp_p2)
   1211     expected_num_cookies = param->check->num_cookies_strict_p2;
   1212   else if (use_discp_p1)
   1213     expected_num_cookies = param->check->num_cookies_strict_p1;
   1214   else if (use_discp_zero)
   1215     expected_num_cookies = param->check->num_cookies_strict_zero;
   1216   else if (use_discp_n2)
   1217     expected_num_cookies = param->check->num_cookies_strict_n2;
   1218   else if (use_discp_n3)
   1219     expected_num_cookies = param->check->num_cookies_strict_n3;
   1220   else
   1221     externalErrorExit ();
   1222 
   1223 
   1224   if (oneone)
   1225   {
   1226     if (0 != strcmp (version, MHD_HTTP_VERSION_1_1))
   1227       mhdErrorExitDesc ("Unexpected HTTP version");
   1228   }
   1229   else
   1230   {
   1231     if (0 != strcmp (version, MHD_HTTP_VERSION_1_0))
   1232       mhdErrorExitDesc ("Unexpected HTTP version");
   1233   }
   1234 
   1235   if (0 != strcmp (url, param->rq_url))
   1236     mhdErrorExitDesc ("Unexpected URI");
   1237 
   1238   if (NULL != upload_data)
   1239     mhdErrorExitDesc ("'upload_data' is not NULL");
   1240 
   1241   if (NULL == upload_data_size)
   1242     mhdErrorExitDesc ("'upload_data_size' pointer is NULL");
   1243 
   1244   if (0 != *upload_data_size)
   1245     mhdErrorExitDesc ("'*upload_data_size' value is not zero");
   1246 
   1247   if (0 != strcmp (param->rq_method, method))
   1248     mhdErrorExitDesc ("Unexpected request method");
   1249 
   1250   cookie_failed = 0;
   1251   for (i = 0; i < expected_num_cookies; ++i)
   1252   {
   1253     const char *cookie_val;
   1254     size_t cookie_val_len;
   1255     const struct strct_cookie *const cookie_data = param->check->cookies + i;
   1256     if (NULL == cookie_data->name.str)
   1257       externalErrorExitDesc ("Broken test data");
   1258     if (NULL == cookie_data->value.str)
   1259       externalErrorExitDesc ("Broken test data");
   1260 
   1261     cookie_val =
   1262       MHD_lookup_connection_value (connection,
   1263                                    MHD_COOKIE_KIND,
   1264                                    cookie_data->name.str);
   1265     if (cookie_val == NULL)
   1266     {
   1267       fprintf (stderr, "'%s' cookie not found.\n",
   1268                cookie_data->name.str);
   1269       cookie_failed = 1;
   1270     }
   1271     else if (0 != strcmp (cookie_val,
   1272                           cookie_data->value.str))
   1273     {
   1274       fprintf (stderr, "'%s' cookie decoded incorrectly.\n"
   1275                "Expected: %s\nGot: %s\n",
   1276                cookie_data->name.str,
   1277                cookie_data->value.str,
   1278                cookie_val);
   1279       cookie_failed = 1;
   1280     }
   1281     else if (MHD_YES !=
   1282              MHD_lookup_connection_value_n (connection,
   1283                                             MHD_COOKIE_KIND,
   1284                                             cookie_data->name.str,
   1285                                             cookie_data->name.len,
   1286                                             &cookie_val, &cookie_val_len))
   1287     {
   1288       fprintf (stderr, "'%s' (length %lu) cookie not found.\n",
   1289                cookie_data->name.str,
   1290                (unsigned long) cookie_data->name.len);
   1291       cookie_failed = 1;
   1292     }
   1293     else
   1294     {
   1295       if (cookie_data->value.len != cookie_val_len)
   1296       {
   1297         fprintf (stderr, "'%s' (length %lu) cookie has wrong value length.\n"
   1298                  "Expected: %lu\nGot: %lu\n",
   1299                  cookie_data->name.str,
   1300                  (unsigned long) cookie_data->name.len,
   1301                  (unsigned long) cookie_data->value.len,
   1302                  (unsigned long) cookie_val_len);
   1303         cookie_failed = 1;
   1304       }
   1305       else if (0 != memcmp (cookie_val, cookie_data->value.str, cookie_val_len))
   1306       {
   1307         fprintf (stderr, "'%s' (length %lu) cookie has wrong value.\n"
   1308                  "Expected: %.*s\nGot: %.*s\n",
   1309                  cookie_data->name.str,
   1310                  (unsigned long) cookie_data->name.len,
   1311                  (int) cookie_data->value.len, cookie_data->value.str,
   1312                  (int) cookie_val_len, cookie_val);
   1313         cookie_failed = 1;
   1314       }
   1315     }
   1316   }
   1317   if (((int) expected_num_cookies) !=
   1318       MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, NULL, NULL))
   1319   {
   1320     fprintf (stderr, "Wrong total number of cookies.\n"
   1321              "Expected: %u\nGot: %d\n",
   1322              expected_num_cookies,
   1323              MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, NULL,
   1324                                           NULL));
   1325     cookie_failed = 1;
   1326   }
   1327   if (cookie_failed)
   1328   {
   1329     response =
   1330       MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE_ERROR),
   1331                                               PAGE_ERROR);
   1332     ret = MHD_queue_response (connection,
   1333                               MHD_HTTP_BAD_REQUEST,
   1334                               response);
   1335     MHD_destroy_response (response);
   1336 
   1337     return ret;
   1338   }
   1339 
   1340   if (&marker != *req_cls)
   1341   {
   1342     *req_cls = &marker;
   1343     return MHD_YES;
   1344   }
   1345   *req_cls = NULL;
   1346 
   1347   response =
   1348     MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
   1349                                             PAGE);
   1350   if (NULL == response)
   1351     mhdErrorExitDesc ("Failed to create response");
   1352 
   1353   ret = MHD_queue_response (connection,
   1354                             MHD_HTTP_OK,
   1355                             response);
   1356   MHD_destroy_response (response);
   1357   if (MHD_YES != ret)
   1358     mhdErrorExitDesc ("Failed to queue response");
   1359 
   1360   return ret;
   1361 }
   1362 
   1363 
   1364 static int
   1365 libcurl_debug_cb (CURL *handle,
   1366                   curl_infotype type,
   1367                   char *data,
   1368                   size_t size,
   1369                   void *userptr)
   1370 {
   1371   static const char excess_mark[] = "Excess found";
   1372   static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
   1373 
   1374   (void) handle;
   1375   (void) userptr;
   1376 
   1377 #ifdef _DEBUG
   1378   switch (type)
   1379   {
   1380   case CURLINFO_TEXT:
   1381     fprintf (stderr, "* %.*s", (int) size, data);
   1382     break;
   1383   case CURLINFO_HEADER_IN:
   1384     fprintf (stderr, "< %.*s", (int) size, data);
   1385     break;
   1386   case CURLINFO_HEADER_OUT:
   1387     fprintf (stderr, "> %.*s", (int) size, data);
   1388     break;
   1389   case CURLINFO_DATA_IN:
   1390 #if 0
   1391     fprintf (stderr, "<| %.*s\n", (int) size, data);
   1392 #endif
   1393     break;
   1394   case CURLINFO_DATA_OUT:
   1395   case CURLINFO_SSL_DATA_IN:
   1396   case CURLINFO_SSL_DATA_OUT:
   1397   case CURLINFO_END:
   1398   default:
   1399     break;
   1400   }
   1401 #endif /* _DEBUG */
   1402   if (CURLINFO_TEXT == type)
   1403   {
   1404     if ((size >= excess_mark_len) &&
   1405         (0 == memcmp (data, excess_mark, excess_mark_len)))
   1406       mhdErrorExitDesc ("Extra data has been detected in MHD reply");
   1407   }
   1408   return 0;
   1409 }
   1410 
   1411 
   1412 static CURL *
   1413 setupCURL (void *cbc, uint16_t port)
   1414 {
   1415   CURL *c;
   1416 
   1417   c = curl_easy_init ();
   1418   if (NULL == c)
   1419     libcurlErrorExitDesc ("curl_easy_init() failed");
   1420 
   1421   if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) ||
   1422       (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
   1423                                      &copyBuffer)) ||
   1424       (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) ||
   1425       (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
   1426                                      ((long) TIMEOUTS_VAL))) ||
   1427       (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
   1428                                      (oneone) ?
   1429                                      CURL_HTTP_VERSION_1_1 :
   1430                                      CURL_HTTP_VERSION_1_0)) ||
   1431       (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
   1432                                      ((long) TIMEOUTS_VAL))) ||
   1433       (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
   1434                                      libcurl_errbuf)) ||
   1435       (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) ||
   1436 #ifdef _DEBUG
   1437       (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) ||
   1438 #endif /* _DEBUG */
   1439       (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
   1440                                      &libcurl_debug_cb)) ||
   1441 #if CURL_AT_LEAST_VERSION (7, 85, 0)
   1442       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS_STR, "http")) ||
   1443 #elif CURL_AT_LEAST_VERSION (7, 19, 4)
   1444       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) ||
   1445 #endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
   1446 #if CURL_AT_LEAST_VERSION (7, 45, 0)
   1447       (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) ||
   1448 #endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
   1449       (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))))
   1450     libcurlErrorExitDesc ("curl_easy_setopt() failed");
   1451 
   1452   if (CURLE_OK !=
   1453       curl_easy_setopt (c, CURLOPT_URL,
   1454                         URL_SCHEME_HOST EXPECTED_URI_BASE_PATH))
   1455     libcurlErrorExitDesc ("Cannot set request URL");
   1456 
   1457   return c;
   1458 }
   1459 
   1460 
   1461 static CURLcode
   1462 performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse)
   1463 {
   1464   CURLM *multi;
   1465   time_t start;
   1466   struct timeval tv;
   1467   CURLcode ret;
   1468 
   1469   ret = CURLE_FAILED_INIT; /* will be replaced with real result */
   1470   if (NULL != *multi_reuse)
   1471     multi = *multi_reuse;
   1472   else
   1473   {
   1474     multi = curl_multi_init ();
   1475     if (multi == NULL)
   1476       libcurlErrorExitDesc ("curl_multi_init() failed");
   1477     *multi_reuse = multi;
   1478   }
   1479   if (CURLM_OK != curl_multi_add_handle (multi, c))
   1480     libcurlErrorExitDesc ("curl_multi_add_handle() failed");
   1481 
   1482   start = time (NULL);
   1483   while (time (NULL) - start <= TIMEOUTS_VAL)
   1484   {
   1485     fd_set rs;
   1486     fd_set ws;
   1487     fd_set es;
   1488     MHD_socket maxMhdSk;
   1489     int maxCurlSk;
   1490     int running;
   1491 
   1492     maxMhdSk = MHD_INVALID_SOCKET;
   1493     maxCurlSk = -1;
   1494     FD_ZERO (&rs);
   1495     FD_ZERO (&ws);
   1496     FD_ZERO (&es);
   1497     if (NULL != multi)
   1498     {
   1499       curl_multi_perform (multi, &running);
   1500       if (0 == running)
   1501       {
   1502         struct CURLMsg *msg;
   1503         int msgLeft;
   1504         int totalMsgs = 0;
   1505         do
   1506         {
   1507           msg = curl_multi_info_read (multi, &msgLeft);
   1508           if (NULL == msg)
   1509             libcurlErrorExitDesc ("curl_multi_info_read() failed");
   1510           totalMsgs++;
   1511           if (CURLMSG_DONE == msg->msg)
   1512             ret = msg->data.result;
   1513         } while (msgLeft > 0);
   1514         if (1 != totalMsgs)
   1515         {
   1516           fprintf (stderr,
   1517                    "curl_multi_info_read returned wrong "
   1518                    "number of results (%d).\n",
   1519                    totalMsgs);
   1520           externalErrorExit ();
   1521         }
   1522         curl_multi_remove_handle (multi, c);
   1523         multi = NULL;
   1524       }
   1525       else
   1526       {
   1527         if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk))
   1528           libcurlErrorExitDesc ("curl_multi_fdset() failed");
   1529       }
   1530     }
   1531     if (NULL == multi)
   1532     { /* libcurl has finished, check whether MHD still needs to perform cleanup */
   1533       if (0 != MHD_get_timeout64s (d))
   1534         break; /* MHD finished as well */
   1535     }
   1536     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk))
   1537       mhdErrorExitDesc ("MHD_get_fdset() failed");
   1538     tv.tv_sec = 0;
   1539     tv.tv_usec = 200000;
   1540     if (0 == MHD_get_timeout64s (d))
   1541       tv.tv_usec = 0;
   1542     else
   1543     {
   1544       long curl_to = -1;
   1545       curl_multi_timeout (multi, &curl_to);
   1546       if (0 == curl_to)
   1547         tv.tv_usec = 0;
   1548     }
   1549 #ifdef MHD_POSIX_SOCKETS
   1550     if (maxMhdSk > maxCurlSk)
   1551       maxCurlSk = maxMhdSk;
   1552 #endif /* MHD_POSIX_SOCKETS */
   1553     if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv))
   1554     {
   1555 #ifdef MHD_POSIX_SOCKETS
   1556       if (EINTR != errno)
   1557         externalErrorExitDesc ("Unexpected select() error");
   1558 #else
   1559       if ((WSAEINVAL != WSAGetLastError ()) ||
   1560           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
   1561         externalErrorExitDesc ("Unexpected select() error");
   1562       Sleep ((unsigned long) tv.tv_usec / 1000);
   1563 #endif
   1564     }
   1565     if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
   1566       mhdErrorExitDesc ("MHD_run_from_select() failed");
   1567   }
   1568 
   1569   return ret;
   1570 }
   1571 
   1572 
   1573 /**
   1574  * Check request result
   1575  * @param curl_code the CURL easy return code
   1576  * @param pcbc the pointer struct CBC
   1577  * @return non-zero if success, zero if failed
   1578  */
   1579 static unsigned int
   1580 check_result (CURLcode curl_code, CURL *c, long expected_code,
   1581               struct CBC *pcbc)
   1582 {
   1583   long code;
   1584 
   1585   if (CURLE_OK != curl_code)
   1586   {
   1587     fflush (stdout);
   1588     if (0 != libcurl_errbuf[0])
   1589       fprintf (stderr, "Request failed. "
   1590                "libcurl error: '%s'.\n"
   1591                "libcurl error description: '%s'.\n",
   1592                curl_easy_strerror (curl_code),
   1593                libcurl_errbuf);
   1594     else
   1595       fprintf (stderr, "Request failed. "
   1596                "libcurl error: '%s'.\n",
   1597                curl_easy_strerror (curl_code));
   1598     fflush (stderr);
   1599     return 0;
   1600   }
   1601 
   1602   if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
   1603     libcurlErrorExit ();
   1604 
   1605   if (expected_code != code)
   1606   {
   1607     fprintf (stderr, "### The response has wrong HTTP code: %ld\t"
   1608              "Expected: %ld.\n",
   1609              code, expected_code);
   1610     return 0;
   1611   }
   1612   else if (verbose)
   1613     printf ("### The response has expected HTTP code: %ld\n", expected_code);
   1614 
   1615   if (pcbc->pos != MHD_STATICSTR_LEN_ (PAGE))
   1616   {
   1617     fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ",
   1618              (unsigned) pcbc->pos, (int) pcbc->pos, pcbc->buf,
   1619              (unsigned) MHD_STATICSTR_LEN_ (PAGE));
   1620     mhdErrorExitDesc ("Wrong returned data length");
   1621   }
   1622   if (0 != memcmp (PAGE, pcbc->buf, pcbc->pos))
   1623   {
   1624     fprintf (stderr, "Got invalid response '%.*s'. ",
   1625              (int) pcbc->pos, pcbc->buf);
   1626     mhdErrorExitDesc ("Wrong returned data");
   1627   }
   1628   fflush (stderr);
   1629   fflush (stdout);
   1630 
   1631   return 1;
   1632 }
   1633 
   1634 
   1635 static unsigned int
   1636 testExternalPolling (void)
   1637 {
   1638   struct MHD_Daemon *d;
   1639   uint16_t port;
   1640   struct CBC cbc;
   1641   struct ahc_cls_type ahc_param;
   1642   char buf[2048];
   1643   CURL *c;
   1644   CURLM *multi_reuse;
   1645   size_t i;
   1646   int failed = 0;
   1647 
   1648   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
   1649     port = 0;
   1650   else
   1651     port = 1340 + oneone ? 0 : 6 + (uint16_t) (1 + discp_level);
   1652 
   1653   d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY,
   1654                         port, NULL, NULL,
   1655                         &ahcCheck, &ahc_param,
   1656                         MHD_OPTION_CLIENT_DISCIPLINE_LVL,
   1657                         (int) (discp_level),
   1658                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
   1659                         MHD_OPTION_END);
   1660   if (d == NULL)
   1661     return 1;
   1662   if (0 == port)
   1663   {
   1664     const union MHD_DaemonInfo *dinfo;
   1665 
   1666     dinfo = MHD_get_daemon_info (d,
   1667                                  MHD_DAEMON_INFO_BIND_PORT);
   1668     if ( (NULL == dinfo) ||
   1669          (0 == dinfo->port) )
   1670       mhdErrorExitDesc ("MHD_get_daemon_info() failed");
   1671     port = dinfo->port;
   1672   }
   1673 
   1674   ahc_param.rq_method = MHD_HTTP_METHOD_GET;
   1675   ahc_param.rq_url = EXPECTED_URI_BASE_PATH;
   1676   cbc.buf = buf;
   1677   cbc.size = sizeof (buf);
   1678   memset (cbc.buf, 0, cbc.size);
   1679   c = setupCURL (&cbc, port);
   1680   multi_reuse = NULL;
   1681   for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
   1682   {
   1683     cbc.pos = 0;
   1684     ahc_param.check = test_data + i;
   1685     if (CURLE_OK !=
   1686         curl_easy_setopt (c, CURLOPT_COOKIE,
   1687                           ahc_param.check->header_str))
   1688       libcurlErrorExitDesc ("Cannot set request cookies");
   1689 
   1690     if (check_result (performQueryExternal (d, c, &multi_reuse), c,
   1691                       MHD_HTTP_OK, &cbc))
   1692     {
   1693       if (verbose)
   1694         printf ("### Got expected response for the check at line %u.\n",
   1695                 test_data[i].line_num);
   1696       fflush (stdout);
   1697     }
   1698     else
   1699     {
   1700       fprintf (stderr, "### FAILED request for the check at line %u.\n",
   1701                test_data[i].line_num);
   1702       fflush (stderr);
   1703       failed = 1;
   1704     }
   1705   }
   1706 
   1707   curl_easy_cleanup (c);
   1708   if (NULL != multi_reuse)
   1709     curl_multi_cleanup (multi_reuse);
   1710 
   1711   MHD_stop_daemon (d);
   1712   return failed ? 1 : 0;
   1713 }
   1714 
   1715 
   1716 int
   1717 main (int argc, char *const *argv)
   1718 {
   1719   unsigned int errorCount = 0;
   1720 
   1721   /* Test type and test parameters */
   1722   verbose = ! (has_param (argc, argv, "-q") ||
   1723                has_param (argc, argv, "--quiet") ||
   1724                has_param (argc, argv, "-s") ||
   1725                has_param (argc, argv, "--silent"));
   1726   oneone = ! has_in_name (argv[0], "10");
   1727   use_discp_n3 = has_in_name (argv[0], "_discp_n3");
   1728   use_discp_n2 = has_in_name (argv[0], "_discp_n2");
   1729   use_discp_zero = has_in_name (argv[0], "_discp_zero");
   1730   use_discp_p1 = has_in_name (argv[0], "_discp_p1");
   1731   use_discp_p2 = has_in_name (argv[0], "_discp_p2");
   1732   if (1 != ((use_discp_n3 ? 1 : 0) + (use_discp_n2 ? 1 : 0)
   1733             + (use_discp_zero ? 1 : 0)
   1734             + (use_discp_p1 ? 1 : 0) + (use_discp_p2 ? 1 : 0)))
   1735     return 99;
   1736 
   1737   if (use_discp_n3)
   1738     discp_level = -3;
   1739   else if (use_discp_n2)
   1740     discp_level = -2;
   1741   else if (use_discp_zero)
   1742     discp_level = 0;
   1743   else if (use_discp_p1)
   1744     discp_level = 1;
   1745   else if (use_discp_p2)
   1746     discp_level = 2;
   1747 
   1748   test_global_init ();
   1749 
   1750   errorCount += testExternalPolling ();
   1751   if (errorCount != 0)
   1752     fprintf (stderr, "Error (code: %u)\n", errorCount);
   1753 
   1754   test_global_cleanup ();
   1755 
   1756   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
   1757 }