libmicrohttpd

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

test_postform.c (20750B)


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