libmicrohttpd

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

test_parse_cookies.c (38921B)


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