libmicrohttpd

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

test_postform.c (20917B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007 Christian Grothoff
      4      Copyright (C) 2014-2023 Evgeny Grin (Karlson2k)
      5 
      6      libmicrohttpd is free software; you can redistribute it and/or modify
      7      it under the terms of the GNU General Public License as published
      8      by the Free Software Foundation; either version 2, or (at your
      9      option) any later version.
     10 
     11      libmicrohttpd is distributed in the hope that it will be useful, but
     12      WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      General Public License for more details.
     15 
     16      You should have received a copy of the GNU General Public License
     17      along with libmicrohttpd; see the file COPYING.  If not, write to the
     18      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19      Boston, MA 02110-1301, USA.
     20 */
     21 
     22 /**
     23  * @file test_postform.c
     24  * @brief  Testcase for libmicrohttpd POST operations using multipart/postform data
     25  * @author Christian Grothoff
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 
     29 #include "MHD_config.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 #ifdef MHD_HTTPS_REQUIRE_GCRYPT
     37 #ifdef HAVE_GCRYPT_H
     38 #include <gcrypt.h>
     39 #endif
     40 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */
     41 #include <errno.h>
     42 
     43 #ifndef WINDOWS
     44 #include <unistd.h>
     45 #endif
     46 
     47 #ifndef CURL_VERSION_BITS
     48 #define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z))
     49 #endif /* ! CURL_VERSION_BITS */
     50 #ifndef CURL_AT_LEAST_VERSION
     51 #define CURL_AT_LEAST_VERSION(x,y,z) \
     52   (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z))
     53 #endif /* ! CURL_AT_LEAST_VERSION */
     54 
     55 #if CURL_AT_LEAST_VERSION (7,56,0)
     56 #define HAS_CURL_MIME 1
     57 #endif /* CURL_AT_LEAST_VERSION(7,56,0) */
     58 
     59 #include "mhd_has_in_name.h"
     60 
     61 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     62    test into a marked, classifiable test error (TESTING.md, P5). */
     63 #include "mhd_panic_tripwire.h"
     64 
     65 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
     66 #undef MHD_CPU_COUNT
     67 #endif
     68 #if ! defined(MHD_CPU_COUNT)
     69 #define MHD_CPU_COUNT 2
     70 #endif
     71 
     72 static int oneone;
     73 
     74 struct CBC
     75 {
     76   char *buf;
     77   size_t pos;
     78   size_t size;
     79 };
     80 
     81 
     82 static void
     83 completed_cb (void *cls,
     84               struct MHD_Connection *connection,
     85               void **req_cls,
     86               enum MHD_RequestTerminationCode toe)
     87 {
     88   struct MHD_PostProcessor *pp = *req_cls;
     89   (void) cls; (void) connection; (void) toe;            /* Unused. Silent compiler warning. */
     90 
     91   if (NULL != pp)
     92     MHD_destroy_post_processor (pp);
     93   *req_cls = NULL;
     94 }
     95 
     96 
     97 static size_t
     98 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     99 {
    100   struct CBC *cbc = ctx;
    101 
    102   if (cbc->pos + size * nmemb > cbc->size)
    103     return 0;                   /* overflow */
    104   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
    105   cbc->pos += size * nmemb;
    106   return size * nmemb;
    107 }
    108 
    109 
    110 /**
    111  * Note that this post_iterator is not perfect
    112  * in that it fails to support incremental processing.
    113  * (to be fixed in the future)
    114  */
    115 static enum MHD_Result
    116 post_iterator (void *cls,
    117                enum MHD_ValueKind kind,
    118                const char *key,
    119                const char *filename,
    120                const char *content_type,
    121                const char *transfer_encoding,
    122                const char *value, uint64_t off, size_t size)
    123 {
    124   int *eok = cls;
    125   (void) kind; (void) filename; (void) content_type; /* Unused. Silent compiler warning. */
    126   (void) transfer_encoding; (void) off;            /* Unused. Silent compiler warning. */
    127 
    128 #if 0
    129   fprintf (stderr, "PI sees %s-%.*s\n", key, size, value);
    130 #endif
    131   if ((0 == strcmp (key, "name")) &&
    132       (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size)))
    133     (*eok) |= 1;
    134   if ((0 == strcmp (key, "project")) &&
    135       (size == strlen ("curl")) && (0 == strncmp (value, "curl", size)))
    136     (*eok) |= 2;
    137   return MHD_YES;
    138 }
    139 
    140 
    141 static enum MHD_Result
    142 ahc_echo (void *cls,
    143           struct MHD_Connection *connection,
    144           const char *url,
    145           const char *method,
    146           const char *version,
    147           const char *upload_data, size_t *upload_data_size,
    148           void **req_cls)
    149 {
    150   static int eok;
    151   struct MHD_Response *response;
    152   struct MHD_PostProcessor *pp;
    153   enum MHD_Result ret;
    154   (void) cls; (void) version;      /* Unused. Silent compiler warning. */
    155 
    156   if (0 != strcmp ("POST", method))
    157   {
    158     printf ("METHOD: %s\n", method);
    159     return MHD_NO;              /* unexpected method */
    160   }
    161   pp = *req_cls;
    162   if (pp == NULL)
    163   {
    164     eok = 0;
    165     pp = MHD_create_post_processor (connection,
    166                                     1024,
    167                                     &post_iterator,
    168                                     &eok);
    169     if (NULL == pp)
    170       abort ();
    171     *req_cls = pp;
    172   }
    173   if (MHD_YES !=
    174       MHD_post_process (pp,
    175                         upload_data,
    176                         *upload_data_size))
    177     abort ();
    178   if ((eok == 3) && (0 == *upload_data_size))
    179   {
    180     response = MHD_create_response_from_buffer_copy (strlen (url),
    181                                                      (const void *) url);
    182     ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    183     MHD_destroy_response (response);
    184     MHD_destroy_post_processor (pp);
    185     *req_cls = NULL;
    186     return ret;
    187   }
    188   *upload_data_size = 0;
    189   return MHD_YES;
    190 }
    191 
    192 
    193 struct mhd_test_postdata
    194 {
    195 #if defined(HAS_CURL_MIME)
    196   curl_mime *mime;
    197 #else  /* ! HAS_CURL_MIME */
    198   struct curl_httppost *post;
    199 #endif /* ! HAS_CURL_MIME */
    200 };
    201 
    202 /* Return non-zero if succeed */
    203 static int
    204 add_test_form (CURL *handle, struct mhd_test_postdata *postdata)
    205 {
    206 #if defined(HAS_CURL_MIME)
    207   postdata->mime = curl_mime_init (handle);
    208   if (NULL == postdata->mime)
    209     return 0;
    210   else
    211   {
    212     curl_mimepart *part;
    213     part = curl_mime_addpart (postdata->mime);
    214     if (NULL != part)
    215     {
    216       if ( (CURLE_OK == curl_mime_data (part, "daniel",
    217                                         CURL_ZERO_TERMINATED)) &&
    218            (CURLE_OK == curl_mime_name (part, "name")) )
    219       {
    220         part = curl_mime_addpart (postdata->mime);
    221         if (NULL != part)
    222         {
    223           if ( (CURLE_OK == curl_mime_data (part, "curl",
    224                                             CURL_ZERO_TERMINATED)) &&
    225                (CURLE_OK == curl_mime_name (part, "project")) )
    226           {
    227             if (CURLE_OK == curl_easy_setopt (handle,
    228                                               CURLOPT_MIMEPOST, postdata->mime))
    229             {
    230               return ! 0;
    231             }
    232           }
    233         }
    234       }
    235     }
    236   }
    237   curl_mime_free (postdata->mime);
    238   postdata->mime = NULL;
    239   return 0;
    240 #else  /* ! HAS_CURL_MIME */
    241   postdata->post = NULL;
    242   struct curl_httppost *last = NULL;
    243 
    244   if (0 == curl_formadd (&postdata->post, &last,
    245                          CURLFORM_COPYNAME, "name",
    246                          CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END))
    247   {
    248     if (0 == curl_formadd (&postdata->post, &last,
    249                            CURLFORM_COPYNAME, "project",
    250                            CURLFORM_COPYCONTENTS, "curl", CURLFORM_END))
    251     {
    252       if (CURLE_OK == curl_easy_setopt (handle,
    253                                         CURLOPT_HTTPPOST, postdata->post))
    254       {
    255         return ! 0;
    256       }
    257     }
    258   }
    259   curl_formfree (postdata->post);
    260   return 0;
    261 #endif /* ! HAS_CURL_MIME */
    262 }
    263 
    264 
    265 static void
    266 free_test_form (struct mhd_test_postdata *postdata)
    267 {
    268 #if defined(HAS_CURL_MIME)
    269   if (NULL != postdata->mime)
    270     curl_mime_free (postdata->mime);
    271 #else  /* ! HAS_CURL_MIME */
    272   if (NULL != postdata->post)
    273     curl_formfree (postdata->post);
    274 #endif /* ! HAS_CURL_MIME */
    275 }
    276 
    277 
    278 static unsigned int
    279 testInternalPost (void)
    280 {
    281   struct MHD_Daemon *d;
    282   CURL *c;
    283   char buf[2048];
    284   struct CBC cbc;
    285   CURLcode errornum;
    286   struct mhd_test_postdata form;
    287   uint16_t port;
    288 
    289   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    290     port = 0;
    291   else
    292   {
    293     port = 1390;
    294     if (oneone)
    295       port += 10;
    296   }
    297 
    298   cbc.buf = buf;
    299   cbc.size = 2048;
    300   cbc.pos = 0;
    301   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    302                         port, NULL, NULL, &ahc_echo, NULL,
    303                         MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
    304                         MHD_OPTION_END);
    305   if (d == NULL)
    306     return 1;
    307   if (0 == port)
    308   {
    309     const union MHD_DaemonInfo *dinfo;
    310     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    311     if ((NULL == dinfo) || (0 == dinfo->port) )
    312     {
    313       MHD_stop_daemon (d); return 32;
    314     }
    315     port = dinfo->port;
    316   }
    317   c = curl_easy_init ();
    318   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    319   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    320   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    321   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    322   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    323   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    324   if (oneone)
    325     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    326   else
    327     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    328   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    329   /* NOTE: use of CONNECTTIMEOUT without also
    330    *   setting NOSIGNAL results in really weird
    331    *   crashes on my system! */
    332   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    333   if (! add_test_form (c, &form))
    334   {
    335     fprintf (stderr, "libcurl form initialisation error.\n");
    336     curl_easy_cleanup (c);
    337     return 2;
    338   }
    339   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    340   {
    341     fprintf (stderr,
    342              "curl_easy_perform failed: `%s'\n",
    343              curl_easy_strerror (errornum));
    344     curl_easy_cleanup (c);
    345     free_test_form (&form);
    346     MHD_stop_daemon (d);
    347     return 2;
    348   }
    349   curl_easy_cleanup (c);
    350   free_test_form (&form);
    351   MHD_stop_daemon (d);
    352   if (cbc.pos != strlen ("/hello_world"))
    353     return 4;
    354   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    355     return 8;
    356   return 0;
    357 }
    358 
    359 
    360 static unsigned int
    361 testMultithreadedPost (void)
    362 {
    363   struct MHD_Daemon *d;
    364   CURL *c;
    365   char buf[2048];
    366   struct CBC cbc;
    367   CURLcode errornum;
    368   struct mhd_test_postdata form;
    369   uint16_t port;
    370 
    371   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    372     port = 0;
    373   else
    374   {
    375     port = 1390;
    376     if (oneone)
    377       port += 10;
    378   }
    379 
    380   cbc.buf = buf;
    381   cbc.size = 2048;
    382   cbc.pos = 0;
    383   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
    384                         | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    385                         port, NULL, NULL, &ahc_echo, NULL,
    386                         MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
    387                         MHD_OPTION_END);
    388   if (d == NULL)
    389     return 16;
    390   if (0 == port)
    391   {
    392     const union MHD_DaemonInfo *dinfo;
    393     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    394     if ((NULL == dinfo) || (0 == dinfo->port) )
    395     {
    396       MHD_stop_daemon (d); return 32;
    397     }
    398     port = dinfo->port;
    399   }
    400   c = curl_easy_init ();
    401   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    402   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    403   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    404   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    405   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    406   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    407   if (oneone)
    408     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    409   else
    410     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    411   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L);
    412   /* NOTE: use of CONNECTTIMEOUT without also
    413    *   setting NOSIGNAL results in really weird
    414    *   crashes on my system! */
    415   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    416   if (! add_test_form (c, &form))
    417   {
    418     fprintf (stderr, "libcurl form initialisation error.\n");
    419     curl_easy_cleanup (c);
    420     return 2;
    421   }
    422   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    423   {
    424     fprintf (stderr,
    425              "curl_easy_perform failed: `%s'\n",
    426              curl_easy_strerror (errornum));
    427     curl_easy_cleanup (c);
    428     free_test_form (&form);
    429     MHD_stop_daemon (d);
    430     return 32;
    431   }
    432   curl_easy_cleanup (c);
    433   free_test_form (&form);
    434   MHD_stop_daemon (d);
    435   if (cbc.pos != strlen ("/hello_world"))
    436     return 64;
    437   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    438     return 128;
    439   return 0;
    440 }
    441 
    442 
    443 static unsigned int
    444 testMultithreadedPoolPost (void)
    445 {
    446   struct MHD_Daemon *d;
    447   CURL *c;
    448   char buf[2048];
    449   struct CBC cbc;
    450   CURLcode errornum;
    451   struct mhd_test_postdata form;
    452   uint16_t port;
    453 
    454   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    455     port = 0;
    456   else
    457   {
    458     port = 1391;
    459     if (oneone)
    460       port += 10;
    461   }
    462 
    463   cbc.buf = buf;
    464   cbc.size = 2048;
    465   cbc.pos = 0;
    466   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    467                         port, NULL, NULL, &ahc_echo, NULL,
    468                         MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT,
    469                         MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
    470                         MHD_OPTION_END);
    471   if (d == NULL)
    472     return 16;
    473   if (0 == port)
    474   {
    475     const union MHD_DaemonInfo *dinfo;
    476     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    477     if ((NULL == dinfo) || (0 == dinfo->port) )
    478     {
    479       MHD_stop_daemon (d); return 32;
    480     }
    481     port = dinfo->port;
    482   }
    483   c = curl_easy_init ();
    484   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    485   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    486   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    487   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    488   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    489   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    490   if (oneone)
    491     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    492   else
    493     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    494   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L);
    495   /* NOTE: use of CONNECTTIMEOUT without also
    496    *   setting NOSIGNAL results in really weird
    497    *   crashes on my system! */
    498   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    499   if (! add_test_form (c, &form))
    500   {
    501     fprintf (stderr, "libcurl form initialisation error.\n");
    502     curl_easy_cleanup (c);
    503     return 2;
    504   }
    505   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    506   {
    507     fprintf (stderr,
    508              "curl_easy_perform failed: `%s'\n",
    509              curl_easy_strerror (errornum));
    510     curl_easy_cleanup (c);
    511     free_test_form (&form);
    512     MHD_stop_daemon (d);
    513     return 32;
    514   }
    515   curl_easy_cleanup (c);
    516   free_test_form (&form);
    517   MHD_stop_daemon (d);
    518   if (cbc.pos != strlen ("/hello_world"))
    519     return 64;
    520   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    521     return 128;
    522   return 0;
    523 }
    524 
    525 
    526 static unsigned int
    527 testExternalPost (void)
    528 {
    529   struct MHD_Daemon *d;
    530   CURL *c;
    531   char buf[2048];
    532   struct CBC cbc;
    533   CURLM *multi;
    534   CURLMcode mret;
    535   fd_set rs;
    536   fd_set ws;
    537   fd_set es;
    538   MHD_socket maxsock;
    539 #ifdef MHD_WINSOCK_SOCKETS
    540   int maxposixs; /* Max socket number unused on W32 */
    541 #else  /* MHD_POSIX_SOCKETS */
    542 #define maxposixs maxsock
    543 #endif /* MHD_POSIX_SOCKETS */
    544   int running;
    545   struct CURLMsg *msg;
    546   time_t start;
    547   struct timeval tv;
    548   struct mhd_test_postdata form;
    549   uint16_t port;
    550 
    551   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    552     port = 0;
    553   else
    554   {
    555     port = 1392;
    556     if (oneone)
    557       port += 10;
    558   }
    559 
    560   multi = NULL;
    561   cbc.buf = buf;
    562   cbc.size = 2048;
    563   cbc.pos = 0;
    564   d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY,
    565                         port, NULL, NULL, &ahc_echo, NULL,
    566                         MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
    567                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
    568                         MHD_OPTION_END);
    569   if (d == NULL)
    570     return 256;
    571   if (0 == port)
    572   {
    573     const union MHD_DaemonInfo *dinfo;
    574     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    575     if ((NULL == dinfo) || (0 == dinfo->port) )
    576     {
    577       MHD_stop_daemon (d); return 32;
    578     }
    579     port = dinfo->port;
    580   }
    581   c = curl_easy_init ();
    582   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    583   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    584   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    585   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    586   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    587   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    588   if (oneone)
    589     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    590   else
    591     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    592   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    593   /* NOTE: use of CONNECTTIMEOUT without also
    594    *   setting NOSIGNAL results in really weird
    595    *   crashes on my system! */
    596   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    597   if (! add_test_form (c, &form))
    598   {
    599     fprintf (stderr, "libcurl form initialisation error.\n");
    600     curl_easy_cleanup (c);
    601     return 2;
    602   }
    603 
    604   multi = curl_multi_init ();
    605   if (multi == NULL)
    606   {
    607     curl_easy_cleanup (c);
    608     free_test_form (&form);
    609     MHD_stop_daemon (d);
    610     return 512;
    611   }
    612   mret = curl_multi_add_handle (multi, c);
    613   if (mret != CURLM_OK)
    614   {
    615     curl_multi_cleanup (multi);
    616     free_test_form (&form);
    617     curl_easy_cleanup (c);
    618     MHD_stop_daemon (d);
    619     return 1024;
    620   }
    621   start = time (NULL);
    622   while ((time (NULL) - start < 5) && (multi != NULL))
    623   {
    624     maxsock = MHD_INVALID_SOCKET;
    625     maxposixs = -1;
    626     FD_ZERO (&rs);
    627     FD_ZERO (&ws);
    628     FD_ZERO (&es);
    629     curl_multi_perform (multi, &running);
    630     mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    631     if (mret != CURLM_OK)
    632     {
    633       curl_multi_remove_handle (multi, c);
    634       curl_multi_cleanup (multi);
    635       curl_easy_cleanup (c);
    636       MHD_stop_daemon (d);
    637       free_test_form (&form);
    638       return 2048;
    639     }
    640     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    641     {
    642       curl_multi_remove_handle (multi, c);
    643       curl_multi_cleanup (multi);
    644       curl_easy_cleanup (c);
    645       free_test_form (&form);
    646       MHD_stop_daemon (d);
    647       return 4096;
    648     }
    649     tv.tv_sec = 0;
    650     tv.tv_usec = 1000;
    651     if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    652     {
    653 #ifdef MHD_POSIX_SOCKETS
    654       if (EINTR != errno)
    655       {
    656         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    657                  (int) errno, __LINE__);
    658         fflush (stderr);
    659         exit (99);
    660       }
    661 #else
    662       if ((WSAEINVAL != WSAGetLastError ()) ||
    663           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    664       {
    665         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    666                  (int) WSAGetLastError (), __LINE__);
    667         fflush (stderr);
    668         exit (99);
    669       }
    670       Sleep (1);
    671 #endif
    672     }
    673     curl_multi_perform (multi, &running);
    674     if (0 == running)
    675     {
    676       int pending;
    677       int curl_fine = 0;
    678       while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    679       {
    680         if (msg->msg == CURLMSG_DONE)
    681         {
    682           if (msg->data.result == CURLE_OK)
    683             curl_fine = 1;
    684           else
    685           {
    686             fprintf (stderr,
    687                      "%s failed at %s:%d: `%s'\n",
    688                      "curl_multi_perform",
    689                      __FILE__,
    690                      __LINE__, curl_easy_strerror (msg->data.result));
    691             abort ();
    692           }
    693         }
    694       }
    695       if (! curl_fine)
    696       {
    697         fprintf (stderr, "libcurl haven't returned OK code\n");
    698         abort ();
    699       }
    700       curl_multi_remove_handle (multi, c);
    701       curl_multi_cleanup (multi);
    702       curl_easy_cleanup (c);
    703       c = NULL;
    704       multi = NULL;
    705     }
    706     MHD_run (d);
    707   }
    708   if (multi != NULL)
    709   {
    710     curl_multi_remove_handle (multi, c);
    711     curl_easy_cleanup (c);
    712     curl_multi_cleanup (multi);
    713   }
    714   free_test_form (&form);
    715   MHD_stop_daemon (d);
    716   if (cbc.pos != strlen ("/hello_world"))
    717     return 8192;
    718   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    719     return 16384;
    720   return 0;
    721 }
    722 
    723 
    724 int
    725 main (int argc, char *const *argv)
    726 {
    727   unsigned int errorCount = 0;
    728   (void) argc;   /* Unused. Silent compiler warning. */
    729 
    730 #ifdef MHD_HTTPS_REQUIRE_GCRYPT
    731 #ifdef HAVE_GCRYPT_H
    732   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
    733 #ifdef GCRYCTL_INITIALIZATION_FINISHED
    734   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
    735 #endif
    736 #endif
    737 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */
    738   if ((NULL == argv) || (0 == argv[0]))
    739     return 99;
    740   oneone = has_in_name (argv[0], "11");
    741   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    742     return 2;
    743   if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
    744   {
    745     errorCount += testInternalPost ();
    746     errorCount += testMultithreadedPost ();
    747     errorCount += testMultithreadedPoolPost ();
    748   }
    749   errorCount += testExternalPost ();
    750   if (errorCount != 0)
    751     fprintf (stderr, "Error (code: %u)\n", errorCount);
    752   curl_global_cleanup ();
    753   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
    754 }