libmicrohttpd

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

test_get_sendfile.c (18357B)


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