libmicrohttpd

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

test_get_sendfile.c (18190B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2009 Christian Grothoff
      4      Copyright (C) 2014-2022 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  * @file test_get_sendfile.c
     23  * @brief  Testcase for libmicrohttpd response from FD
     24  * @author Christian Grothoff
     25  * @author Karlson2k (Evgeny Grin)
     26  */
     27 
     28 #include "MHD_config.h"
     29 #include "platform.h"
     30 #include <curl/curl.h>
     31 #include <microhttpd.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <time.h>
     35 #include <sys/types.h>
     36 #include <fcntl.h>
     37 #include <errno.h>
     38 #include "mhd_sockets.h"
     39 #include "mhd_has_in_name.h"
     40 
     41 #ifndef WINDOWS
     42 #include <sys/socket.h>
     43 #include <unistd.h>
     44 #endif
     45 
     46 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
     47 #undef MHD_CPU_COUNT
     48 #endif
     49 #if ! defined(MHD_CPU_COUNT)
     50 #define MHD_CPU_COUNT 2
     51 #endif
     52 
     53 #define TESTSTR \
     54   "This is the content of the test file we are sending using sendfile (if available)"
     55 
     56 static char *sourcefile;
     57 
     58 static int oneone;
     59 
     60 struct CBC
     61 {
     62   char *buf;
     63   size_t pos;
     64   size_t size;
     65 };
     66 
     67 
     68 static size_t
     69 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     70 {
     71   struct CBC *cbc = ctx;
     72 
     73   if (cbc->pos + size * nmemb > cbc->size)
     74     return 0;                   /* overflow */
     75   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     76   cbc->pos += size * nmemb;
     77   return size * nmemb;
     78 }
     79 
     80 
     81 static enum MHD_Result
     82 ahc_echo (void *cls,
     83           struct MHD_Connection *connection,
     84           const char *url,
     85           const char *method,
     86           const char *version,
     87           const char *upload_data, size_t *upload_data_size,
     88           void **req_cls)
     89 {
     90   static int ptr;
     91   struct MHD_Response *response;
     92   enum MHD_Result ret;
     93   int fd;
     94   (void) cls;
     95   (void) url; (void) version;                      /* Unused. Silent compiler warning. */
     96   (void) upload_data; (void) upload_data_size;     /* Unused. Silent compiler warning. */
     97 
     98   if (0 != strcmp (MHD_HTTP_METHOD_GET, method))
     99     return MHD_NO;              /* unexpected method */
    100   if (&ptr != *req_cls)
    101   {
    102     *req_cls = &ptr;
    103     return MHD_YES;
    104   }
    105   *req_cls = NULL;
    106   fd = open (sourcefile, O_RDONLY);
    107   if (fd == -1)
    108   {
    109     fprintf (stderr, "Failed to open `%s': %s\n",
    110              sourcefile,
    111              strerror (errno));
    112     exit (1);
    113   }
    114   response = MHD_create_response_from_fd (strlen (TESTSTR), fd);
    115   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    116   MHD_destroy_response (response);
    117   if (ret == MHD_NO)
    118     abort ();
    119   return ret;
    120 }
    121 
    122 
    123 static unsigned int
    124 testInternalGet (void)
    125 {
    126   struct MHD_Daemon *d;
    127   CURL *c;
    128   char buf[2048];
    129   struct CBC cbc;
    130   CURLcode errornum;
    131   uint16_t port;
    132 
    133   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    134     port = 0;
    135   else
    136   {
    137     port = 1200;
    138     if (oneone)
    139       port += 10;
    140   }
    141 
    142   cbc.buf = buf;
    143   cbc.size = 2048;
    144   cbc.pos = 0;
    145   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    146                         port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
    147   if (d == NULL)
    148     return 1;
    149   if (0 == port)
    150   {
    151     const union MHD_DaemonInfo *dinfo;
    152     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    153     if ((NULL == dinfo) || (0 == dinfo->port) )
    154     {
    155       MHD_stop_daemon (d); return 32;
    156     }
    157     port = dinfo->port;
    158   }
    159   c = curl_easy_init ();
    160   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
    161   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    162   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    163   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    164   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    165   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    166   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    167   if (oneone)
    168     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    169   else
    170     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    171   /* NOTE: use of CONNECTTIMEOUT without also
    172      setting NOSIGNAL results in really weird
    173      crashes on my system!*/
    174   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    175   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    176   {
    177     fprintf (stderr,
    178              "curl_easy_perform failed: `%s'\n",
    179              curl_easy_strerror (errornum));
    180     curl_easy_cleanup (c);
    181     MHD_stop_daemon (d);
    182     return 2;
    183   }
    184   curl_easy_cleanup (c);
    185   MHD_stop_daemon (d);
    186   if (cbc.pos != strlen (TESTSTR))
    187     return 4;
    188   if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
    189     return 8;
    190   return 0;
    191 }
    192 
    193 
    194 static unsigned int
    195 testMultithreadedGet (void)
    196 {
    197   struct MHD_Daemon *d;
    198   CURL *c;
    199   char buf[2048];
    200   struct CBC cbc;
    201   CURLcode errornum;
    202   uint16_t port;
    203 
    204   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    205     port = 0;
    206   else
    207   {
    208     port = 1201;
    209     if (oneone)
    210       port += 10;
    211   }
    212 
    213   cbc.buf = buf;
    214   cbc.size = 2048;
    215   cbc.pos = 0;
    216   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
    217                         | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    218                         port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
    219   if (d == NULL)
    220     return 16;
    221   if (0 == port)
    222   {
    223     const union MHD_DaemonInfo *dinfo;
    224     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    225     if ((NULL == dinfo) || (0 == dinfo->port) )
    226     {
    227       MHD_stop_daemon (d); return 32;
    228     }
    229     port = dinfo->port;
    230   }
    231   c = curl_easy_init ();
    232   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
    233   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    234   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    235   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    236   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    237   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    238   if (oneone)
    239     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    240   else
    241     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    242   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    243   /* NOTE: use of CONNECTTIMEOUT without also
    244      setting NOSIGNAL results in really weird
    245      crashes on my system! */
    246   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    247   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    248   {
    249     fprintf (stderr,
    250              "curl_easy_perform failed: `%s'\n",
    251              curl_easy_strerror (errornum));
    252     curl_easy_cleanup (c);
    253     MHD_stop_daemon (d);
    254     return 32;
    255   }
    256   curl_easy_cleanup (c);
    257   MHD_stop_daemon (d);
    258   if (cbc.pos != strlen (TESTSTR))
    259     return 64;
    260   if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
    261     return 128;
    262   return 0;
    263 }
    264 
    265 
    266 static unsigned int
    267 testMultithreadedPoolGet (void)
    268 {
    269   struct MHD_Daemon *d;
    270   CURL *c;
    271   char buf[2048];
    272   struct CBC cbc;
    273   CURLcode errornum;
    274   uint16_t port;
    275 
    276   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    277     port = 0;
    278   else
    279   {
    280     port = 1202;
    281     if (oneone)
    282       port += 10;
    283   }
    284 
    285   cbc.buf = buf;
    286   cbc.size = 2048;
    287   cbc.pos = 0;
    288   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    289                         port, NULL, NULL, &ahc_echo, NULL,
    290                         MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT,
    291                         MHD_OPTION_END);
    292   if (d == NULL)
    293     return 16;
    294   if (0 == port)
    295   {
    296     const union MHD_DaemonInfo *dinfo;
    297     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    298     if ((NULL == dinfo) || (0 == dinfo->port) )
    299     {
    300       MHD_stop_daemon (d); return 32;
    301     }
    302     port = dinfo->port;
    303   }
    304   c = curl_easy_init ();
    305   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
    306   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    307   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    308   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    309   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    310   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    311   if (oneone)
    312     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    313   else
    314     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    315   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    316   /* NOTE: use of CONNECTTIMEOUT without also
    317      setting NOSIGNAL results in really weird
    318      crashes on my system!*/
    319   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    320   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    321   {
    322     fprintf (stderr,
    323              "curl_easy_perform failed: `%s'\n",
    324              curl_easy_strerror (errornum));
    325     curl_easy_cleanup (c);
    326     MHD_stop_daemon (d);
    327     return 32;
    328   }
    329   curl_easy_cleanup (c);
    330   MHD_stop_daemon (d);
    331   if (cbc.pos != strlen (TESTSTR))
    332     return 64;
    333   if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
    334     return 128;
    335   return 0;
    336 }
    337 
    338 
    339 static unsigned int
    340 testExternalGet (int thread_unsafe)
    341 {
    342   struct MHD_Daemon *d;
    343   CURL *c;
    344   char buf[2048];
    345   struct CBC cbc;
    346   CURLM *multi;
    347   CURLMcode mret;
    348   fd_set rs;
    349   fd_set ws;
    350   fd_set es;
    351   MHD_socket maxsock;
    352 #ifdef MHD_WINSOCK_SOCKETS
    353   int maxposixs; /* Max socket number unused on W32 */
    354 #else  /* MHD_POSIX_SOCKETS */
    355 #define maxposixs maxsock
    356 #endif /* MHD_POSIX_SOCKETS */
    357   int running;
    358   struct CURLMsg *msg;
    359   time_t start;
    360   struct timeval tv;
    361   uint16_t port;
    362 
    363   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    364     port = 0;
    365   else
    366   {
    367     port = 1203;
    368     if (oneone)
    369       port += 10;
    370   }
    371 
    372   multi = NULL;
    373   cbc.buf = buf;
    374   cbc.size = 2048;
    375   cbc.pos = 0;
    376   d = MHD_start_daemon (MHD_USE_ERROR_LOG
    377                         | (thread_unsafe ? MHD_USE_NO_THREAD_SAFETY : 0),
    378                         port, NULL, NULL, &ahc_echo, NULL,
    379                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
    380                         MHD_OPTION_END);
    381   if (d == NULL)
    382     return 256;
    383   if (0 == port)
    384   {
    385     const union MHD_DaemonInfo *dinfo;
    386     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    387     if ((NULL == dinfo) || (0 == dinfo->port) )
    388     {
    389       MHD_stop_daemon (d); return 32;
    390     }
    391     port = dinfo->port;
    392   }
    393   c = curl_easy_init ();
    394   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/");
    395   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    396   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    397   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    398   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    399   if (oneone)
    400     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    401   else
    402     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    403   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    404   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    405   /* NOTE: use of CONNECTTIMEOUT without also
    406      setting NOSIGNAL results in really weird
    407      crashes on my system! */
    408   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    409 
    410 
    411   multi = curl_multi_init ();
    412   if (multi == NULL)
    413   {
    414     curl_easy_cleanup (c);
    415     MHD_stop_daemon (d);
    416     return 512;
    417   }
    418   mret = curl_multi_add_handle (multi, c);
    419   if (mret != CURLM_OK)
    420   {
    421     curl_multi_cleanup (multi);
    422     curl_easy_cleanup (c);
    423     MHD_stop_daemon (d);
    424     return 1024;
    425   }
    426   start = time (NULL);
    427   while ((time (NULL) - start < 5) && (multi != NULL))
    428   {
    429     maxsock = MHD_INVALID_SOCKET;
    430     maxposixs = -1;
    431     FD_ZERO (&rs);
    432     FD_ZERO (&ws);
    433     FD_ZERO (&es);
    434     curl_multi_perform (multi, &running);
    435     mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    436     if (mret != CURLM_OK)
    437     {
    438       curl_multi_remove_handle (multi, c);
    439       curl_multi_cleanup (multi);
    440       curl_easy_cleanup (c);
    441       MHD_stop_daemon (d);
    442       return 2048;
    443     }
    444     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    445     {
    446       curl_multi_remove_handle (multi, c);
    447       curl_multi_cleanup (multi);
    448       curl_easy_cleanup (c);
    449       MHD_stop_daemon (d);
    450       return 4096;
    451     }
    452     tv.tv_sec = 0;
    453     tv.tv_usec = 1000;
    454     if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    455     {
    456 #ifdef MHD_POSIX_SOCKETS
    457       if (EINTR != errno)
    458       {
    459         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    460                  (int) errno, __LINE__);
    461         fflush (stderr);
    462         exit (99);
    463       }
    464 #else
    465       if ((WSAEINVAL != WSAGetLastError ()) ||
    466           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    467       {
    468         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    469                  (int) WSAGetLastError (), __LINE__);
    470         fflush (stderr);
    471         exit (99);
    472       }
    473       Sleep (1);
    474 #endif
    475     }
    476     curl_multi_perform (multi, &running);
    477     if (0 == running)
    478     {
    479       int pending;
    480       int curl_fine = 0;
    481       while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    482       {
    483         if (msg->msg == CURLMSG_DONE)
    484         {
    485           if (msg->data.result == CURLE_OK)
    486             curl_fine = 1;
    487           else
    488           {
    489             fprintf (stderr,
    490                      "%s failed at %s:%d: `%s'\n",
    491                      "curl_multi_perform",
    492                      __FILE__,
    493                      __LINE__, curl_easy_strerror (msg->data.result));
    494             abort ();
    495           }
    496         }
    497       }
    498       if (! curl_fine)
    499       {
    500         fprintf (stderr, "libcurl haven't returned OK code\n");
    501         abort ();
    502       }
    503       curl_multi_remove_handle (multi, c);
    504       curl_multi_cleanup (multi);
    505       curl_easy_cleanup (c);
    506       c = NULL;
    507       multi = NULL;
    508     }
    509     MHD_run (d);
    510   }
    511   if (multi != NULL)
    512   {
    513     curl_multi_remove_handle (multi, c);
    514     curl_easy_cleanup (c);
    515     curl_multi_cleanup (multi);
    516   }
    517   MHD_stop_daemon (d);
    518   if (cbc.pos != strlen (TESTSTR))
    519   {
    520     fprintf (stderr,
    521              "Got %.*s instead of %s!\n",
    522              (int) cbc.pos,
    523              cbc.buf,
    524              TESTSTR);
    525     return 8192;
    526   }
    527   if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
    528     return 16384;
    529   return 0;
    530 }
    531 
    532 
    533 static unsigned int
    534 testUnknownPortGet (void)
    535 {
    536   struct MHD_Daemon *d;
    537   const union MHD_DaemonInfo *di;
    538   CURL *c;
    539   char buf[2048];
    540   struct CBC cbc;
    541   CURLcode errornum;
    542   uint16_t port;
    543 
    544   struct sockaddr_in addr;
    545   socklen_t addr_len = sizeof(addr);
    546   memset (&addr, 0, sizeof(addr));
    547   addr.sin_family = AF_INET;
    548   addr.sin_port = 0;
    549   addr.sin_addr.s_addr = INADDR_ANY;
    550 
    551   cbc.buf = buf;
    552   cbc.size = 2048;
    553   cbc.pos = 0;
    554   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    555                         0, NULL, NULL, &ahc_echo, NULL,
    556                         MHD_OPTION_SOCK_ADDR, &addr,
    557                         MHD_OPTION_END);
    558   if (d == NULL)
    559     return 32768;
    560 
    561   if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    562   {
    563     di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
    564     if (di == NULL)
    565       return 65536;
    566 
    567     if (0 != getsockname (di->listen_fd, (struct sockaddr *) &addr, &addr_len))
    568       return 131072;
    569 
    570     if (addr.sin_family != AF_INET)
    571       return 26214;
    572     port = (uint16_t) ntohs (addr.sin_port);
    573   }
    574   else
    575   {
    576     const union MHD_DaemonInfo *dinfo;
    577     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    578     if ((NULL == dinfo) || (0 == dinfo->port) )
    579     {
    580       MHD_stop_daemon (d); return 32;
    581     }
    582     port = dinfo->port;
    583   }
    584 
    585   snprintf (buf, sizeof(buf), "http://127.0.0.1:%u/",
    586             (unsigned int) port);
    587 
    588   c = curl_easy_init ();
    589   curl_easy_setopt (c, CURLOPT_URL, buf);
    590   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    591   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    592   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    593   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    594   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    595   if (oneone)
    596     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    597   else
    598     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    599   /* NOTE: use of CONNECTTIMEOUT without also
    600      setting NOSIGNAL results in really weird
    601      crashes on my system! */
    602   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    603   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    604   {
    605     fprintf (stderr,
    606              "curl_easy_perform failed: `%s'\n",
    607              curl_easy_strerror (errornum));
    608     curl_easy_cleanup (c);
    609     MHD_stop_daemon (d);
    610     return 524288;
    611   }
    612   curl_easy_cleanup (c);
    613   MHD_stop_daemon (d);
    614   if (cbc.pos != strlen (TESTSTR))
    615     return 1048576;
    616   if (0 != strncmp (TESTSTR, cbc.buf, strlen (TESTSTR)))
    617     return 2097152;
    618   return 0;
    619 }
    620 
    621 
    622 int
    623 main (int argc, char *const *argv)
    624 {
    625   unsigned int errorCount = 0;
    626   const char *tmp;
    627   FILE *f;
    628   (void) argc;   /* Unused. Silent compiler warning. */
    629 
    630   if ((NULL == argv) || (0 == argv[0]))
    631     return 99;
    632   oneone = has_in_name (argv[0], "11");
    633 
    634   if ( (NULL == (tmp = getenv ("TMPDIR"))) &&
    635        (NULL == (tmp = getenv ("TMP"))) &&
    636        (NULL == (tmp = getenv ("TEMP"))) )
    637     tmp = "/tmp";
    638   sourcefile = malloc (strlen (tmp) + 32);
    639   snprintf (sourcefile,
    640             strlen (tmp) + 32,
    641             "%s/%s%s",
    642             tmp,
    643             "test-mhd-sendfile",
    644             oneone ? "11" : "");
    645   f = fopen (sourcefile, "w");
    646   if (NULL == f)
    647   {
    648     fprintf (stderr, "failed to write test file\n");
    649     free (sourcefile);
    650     return 1;
    651   }
    652   if (1 !=
    653       fwrite (TESTSTR, strlen (TESTSTR), 1, f))
    654     abort ();
    655   fclose (f);
    656   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    657     return 2;
    658   if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
    659   {
    660     errorCount += testInternalGet ();
    661     errorCount += testMultithreadedGet ();
    662     errorCount += testMultithreadedPoolGet ();
    663     errorCount += testUnknownPortGet ();
    664     errorCount += testExternalGet (0);
    665   }
    666   errorCount += testExternalGet (! 0);
    667   if (errorCount != 0)
    668     fprintf (stderr, "Error (code: %u)\n", errorCount);
    669   curl_global_cleanup ();
    670   unlink (sourcefile);
    671   free (sourcefile);
    672   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
    673 }