libmicrohttpd

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

test_delete.c (16278B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2016 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 /**
     23  * @file daemontest_delete.c
     24  * @brief  Testcase for libmicrohttpd DELETE operations
     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 #include <errno.h>
     37 #include "mhd_has_in_name.h"
     38 
     39 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     40    test into a marked, classifiable test error (TESTING.md, P5). */
     41 #include "mhd_panic_tripwire.h"
     42 
     43 #ifndef WINDOWS
     44 #include <unistd.h>
     45 #endif
     46 
     47 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
     48 #undef MHD_CPU_COUNT
     49 #endif
     50 #if ! defined(MHD_CPU_COUNT)
     51 #define MHD_CPU_COUNT 2
     52 #endif
     53 
     54 static int oneone;
     55 
     56 struct CBC
     57 {
     58   char *buf;
     59   size_t pos;
     60   size_t size;
     61 };
     62 
     63 static size_t
     64 putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
     65 {
     66   size_t *pos = ptr;
     67   size_t wrt;
     68 
     69   wrt = size * nmemb;
     70   if (wrt > 8 - (*pos))
     71     wrt = 8 - (*pos);
     72   memcpy (stream, &("Hello123"[*pos]), wrt);
     73   (*pos) += wrt;
     74   return wrt;
     75 }
     76 
     77 
     78 static size_t
     79 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     80 {
     81   struct CBC *cbc = ctx;
     82 
     83   if (cbc->pos + size * nmemb > cbc->size)
     84     return 0;                   /* overflow */
     85   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     86   cbc->pos += size * nmemb;
     87   return size * nmemb;
     88 }
     89 
     90 
     91 static enum MHD_Result
     92 ahc_echo (void *cls,
     93           struct MHD_Connection *connection,
     94           const char *url,
     95           const char *method,
     96           const char *version,
     97           const char *upload_data, size_t *upload_data_size,
     98           void **req_cls)
     99 {
    100   int *done = cls;
    101   struct MHD_Response *response;
    102   enum MHD_Result ret;
    103   (void) version; (void) req_cls;   /* Unused. Silent compiler warning. */
    104 
    105   if (0 != strcmp ("DELETE", method))
    106     return MHD_NO;              /* unexpected method */
    107   if ((*done) == 0)
    108   {
    109     if (*upload_data_size != 8)
    110       return MHD_YES;           /* not yet ready */
    111     if (0 == memcmp (upload_data, "Hello123", 8))
    112     {
    113       *upload_data_size = 0;
    114     }
    115     else
    116     {
    117       printf ("Invalid upload data `%8s'!\n", upload_data);
    118       return MHD_NO;
    119     }
    120     *done = 1;
    121     return MHD_YES;
    122   }
    123   response = MHD_create_response_from_buffer_copy (strlen (url),
    124                                                    (const void *) url);
    125   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    126   MHD_destroy_response (response);
    127   return ret;
    128 }
    129 
    130 
    131 static unsigned int
    132 testInternalDelete (void)
    133 {
    134   struct MHD_Daemon *d;
    135   CURL *c;
    136   char buf[2048];
    137   struct CBC cbc;
    138   size_t pos = 0;
    139   int done_flag = 0;
    140   CURLcode errornum;
    141   uint16_t port;
    142 
    143   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    144     port = 0;
    145   else
    146     port = 1152;
    147 
    148   cbc.buf = buf;
    149   cbc.size = 2048;
    150   cbc.pos = 0;
    151   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    152                         port,
    153                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
    154   if (d == NULL)
    155     return 1;
    156   if (0 == port)
    157   {
    158     const union MHD_DaemonInfo *dinfo;
    159     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    160     if ((NULL == dinfo) || (0 == dinfo->port) )
    161     {
    162       MHD_stop_daemon (d); return 32;
    163     }
    164     port = dinfo->port;
    165   }
    166   c = curl_easy_init ();
    167   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    168   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    169   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    170   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    171   curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
    172   curl_easy_setopt (c, CURLOPT_READDATA, &pos);
    173   curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, "DELETE");
    174   curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
    175   curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
    176   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    177   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    178   if (oneone)
    179     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    180   else
    181     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    182   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    183   /* NOTE: use of CONNECTTIMEOUT without also
    184    *   setting NOSIGNAL results in really weird
    185    *   crashes on my system! */
    186   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    187   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    188   {
    189     fprintf (stderr,
    190              "curl_easy_perform failed: `%s'\n",
    191              curl_easy_strerror (errornum));
    192     curl_easy_cleanup (c);
    193     MHD_stop_daemon (d);
    194     return 2;
    195   }
    196   curl_easy_cleanup (c);
    197   MHD_stop_daemon (d);
    198   if (cbc.pos != strlen ("/hello_world"))
    199     return 4;
    200   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    201     return 8;
    202   return 0;
    203 }
    204 
    205 
    206 static unsigned int
    207 testMultithreadedDelete (void)
    208 {
    209   struct MHD_Daemon *d;
    210   CURL *c;
    211   char buf[2048];
    212   struct CBC cbc;
    213   size_t pos = 0;
    214   int done_flag = 0;
    215   CURLcode errornum;
    216   uint16_t port;
    217 
    218   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    219     port = 0;
    220   else
    221     port = 1153;
    222 
    223   cbc.buf = buf;
    224   cbc.size = 2048;
    225   cbc.pos = 0;
    226   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
    227                         | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    228                         port,
    229                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
    230   if (d == NULL)
    231     return 16;
    232   if (0 == port)
    233   {
    234     const union MHD_DaemonInfo *dinfo;
    235     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    236     if ((NULL == dinfo) || (0 == dinfo->port) )
    237     {
    238       MHD_stop_daemon (d); return 32;
    239     }
    240     port = dinfo->port;
    241   }
    242   c = curl_easy_init ();
    243   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    244   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    245   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    246   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    247   curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
    248   curl_easy_setopt (c, CURLOPT_READDATA, &pos);
    249   curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, "DELETE");
    250   curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
    251   curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
    252   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    253   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    254   if (oneone)
    255     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    256   else
    257     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    258   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    259   /* NOTE: use of CONNECTTIMEOUT without also
    260    *   setting NOSIGNAL results in really weird
    261    *   crashes on my system! */
    262   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    263   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    264   {
    265     fprintf (stderr,
    266              "curl_easy_perform failed: `%s'\n",
    267              curl_easy_strerror (errornum));
    268     curl_easy_cleanup (c);
    269     MHD_stop_daemon (d);
    270     return 32;
    271   }
    272   curl_easy_cleanup (c);
    273   MHD_stop_daemon (d);
    274   if (cbc.pos != strlen ("/hello_world"))
    275     return 64;
    276   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    277     return 128;
    278 
    279   return 0;
    280 }
    281 
    282 
    283 static unsigned int
    284 testMultithreadedPoolDelete (void)
    285 {
    286   struct MHD_Daemon *d;
    287   CURL *c;
    288   char buf[2048];
    289   struct CBC cbc;
    290   size_t pos = 0;
    291   int done_flag = 0;
    292   CURLcode errornum;
    293   uint16_t port;
    294 
    295   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    296     port = 0;
    297   else
    298     port = 1154;
    299 
    300   cbc.buf = buf;
    301   cbc.size = 2048;
    302   cbc.pos = 0;
    303   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    304                         port,
    305                         NULL, NULL, &ahc_echo, &done_flag,
    306                         MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT,
    307                         MHD_OPTION_END);
    308   if (d == NULL)
    309     return 16;
    310   if (0 == port)
    311   {
    312     const union MHD_DaemonInfo *dinfo;
    313     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    314     if ((NULL == dinfo) || (0 == dinfo->port) )
    315     {
    316       MHD_stop_daemon (d); return 32;
    317     }
    318     port = dinfo->port;
    319   }
    320   c = curl_easy_init ();
    321   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    322   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    323   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    324   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    325   curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
    326   curl_easy_setopt (c, CURLOPT_READDATA, &pos);
    327   curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, "DELETE");
    328   curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
    329   curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
    330   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    331   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    332   if (oneone)
    333     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    334   else
    335     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    336   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    337   /* NOTE: use of CONNECTTIMEOUT without also
    338    *   setting NOSIGNAL results in really weird
    339    *   crashes on my system! */
    340   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    341   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    342   {
    343     fprintf (stderr,
    344              "curl_easy_perform failed: `%s'\n",
    345              curl_easy_strerror (errornum));
    346     curl_easy_cleanup (c);
    347     MHD_stop_daemon (d);
    348     return 32;
    349   }
    350   curl_easy_cleanup (c);
    351   MHD_stop_daemon (d);
    352   if (cbc.pos != strlen ("/hello_world"))
    353     return 64;
    354   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    355     return 128;
    356 
    357   return 0;
    358 }
    359 
    360 
    361 static unsigned int
    362 testExternalDelete (void)
    363 {
    364   struct MHD_Daemon *d;
    365   CURL *c;
    366   char buf[2048];
    367   struct CBC cbc;
    368   CURLM *multi;
    369   CURLMcode mret;
    370   fd_set rs;
    371   fd_set ws;
    372   fd_set es;
    373   MHD_socket maxsock;
    374 #ifdef MHD_WINSOCK_SOCKETS
    375   int maxposixs; /* Max socket number unused on W32 */
    376 #else  /* MHD_POSIX_SOCKETS */
    377 #define maxposixs maxsock
    378 #endif /* MHD_POSIX_SOCKETS */
    379   int running;
    380   struct CURLMsg *msg;
    381   time_t start;
    382   struct timeval tv;
    383   size_t pos = 0;
    384   int done_flag = 0;
    385   uint16_t port;
    386 
    387   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    388     port = 0;
    389   else
    390     port = 1154;
    391 
    392   multi = NULL;
    393   cbc.buf = buf;
    394   cbc.size = 2048;
    395   cbc.pos = 0;
    396   d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY,
    397                         port,
    398                         NULL, NULL, &ahc_echo, &done_flag,
    399                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
    400                         MHD_OPTION_END);
    401   if (d == NULL)
    402     return 256;
    403   if (0 == port)
    404   {
    405     const union MHD_DaemonInfo *dinfo;
    406     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    407     if ((NULL == dinfo) || (0 == dinfo->port) )
    408     {
    409       MHD_stop_daemon (d); return 32;
    410     }
    411     port = dinfo->port;
    412   }
    413   c = curl_easy_init ();
    414   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
    415   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    416   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    417   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    418   curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
    419   curl_easy_setopt (c, CURLOPT_READDATA, &pos);
    420   curl_easy_setopt (c, CURLOPT_CUSTOMREQUEST, "DELETE");
    421   curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
    422   curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
    423   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    424   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    425   if (oneone)
    426     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    427   else
    428     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    429   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    430   /* NOTE: use of CONNECTTIMEOUT without also
    431    *   setting NOSIGNAL results in really weird
    432    *   crashes on my system! */
    433   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    434 
    435 
    436   multi = curl_multi_init ();
    437   if (multi == NULL)
    438   {
    439     curl_easy_cleanup (c);
    440     MHD_stop_daemon (d);
    441     return 512;
    442   }
    443   mret = curl_multi_add_handle (multi, c);
    444   if (mret != CURLM_OK)
    445   {
    446     curl_multi_cleanup (multi);
    447     curl_easy_cleanup (c);
    448     MHD_stop_daemon (d);
    449     return 1024;
    450   }
    451   start = time (NULL);
    452   while ((time (NULL) - start < 5) && (multi != NULL))
    453   {
    454     maxsock = MHD_INVALID_SOCKET;
    455     maxposixs = -1;
    456     FD_ZERO (&rs);
    457     FD_ZERO (&ws);
    458     FD_ZERO (&es);
    459     curl_multi_perform (multi, &running);
    460     mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    461     if (mret != CURLM_OK)
    462     {
    463       curl_multi_remove_handle (multi, c);
    464       curl_multi_cleanup (multi);
    465       curl_easy_cleanup (c);
    466       MHD_stop_daemon (d);
    467       return 2048;
    468     }
    469     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    470     {
    471       curl_multi_remove_handle (multi, c);
    472       curl_multi_cleanup (multi);
    473       curl_easy_cleanup (c);
    474       MHD_stop_daemon (d);
    475       return 4096;
    476     }
    477     tv.tv_sec = 0;
    478     tv.tv_usec = 1000;
    479     if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    480     {
    481 #ifdef MHD_POSIX_SOCKETS
    482       if (EINTR != errno)
    483       {
    484         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    485                  (int) errno, __LINE__);
    486         fflush (stderr);
    487         exit (99);
    488       }
    489 #else
    490       if ((WSAEINVAL != WSAGetLastError ()) ||
    491           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    492       {
    493         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    494                  (int) WSAGetLastError (), __LINE__);
    495         fflush (stderr);
    496         exit (99);
    497       }
    498       Sleep (1);
    499 #endif
    500     }
    501     curl_multi_perform (multi, &running);
    502     if (0 == running)
    503     {
    504       int pending;
    505       int curl_fine = 0;
    506       while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    507       {
    508         if (msg->msg == CURLMSG_DONE)
    509         {
    510           if (msg->data.result == CURLE_OK)
    511             curl_fine = 1;
    512           else
    513           {
    514             fprintf (stderr,
    515                      "%s failed at %s:%d: `%s'\n",
    516                      "curl_multi_perform",
    517                      __FILE__,
    518                      __LINE__, curl_easy_strerror (msg->data.result));
    519             abort ();
    520           }
    521         }
    522       }
    523       if (! curl_fine)
    524       {
    525         fprintf (stderr, "libcurl haven't returned OK code\n");
    526         abort ();
    527       }
    528       curl_multi_remove_handle (multi, c);
    529       curl_multi_cleanup (multi);
    530       curl_easy_cleanup (c);
    531       c = NULL;
    532       multi = NULL;
    533     }
    534     MHD_run (d);
    535   }
    536   if (multi != NULL)
    537   {
    538     curl_multi_remove_handle (multi, c);
    539     curl_easy_cleanup (c);
    540     curl_multi_cleanup (multi);
    541   }
    542   MHD_stop_daemon (d);
    543   if (cbc.pos != strlen ("/hello_world"))
    544     return 8192;
    545   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    546     return 16384;
    547   return 0;
    548 }
    549 
    550 
    551 int
    552 main (int argc, char *const *argv)
    553 {
    554   unsigned int errorCount = 0;
    555   (void) argc;   /* Unused. Silent compiler warning. */
    556 
    557   if ((NULL == argv) || (0 == argv[0]))
    558     return 99;
    559   oneone = has_in_name (argv[0], "11");
    560   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    561     return 2;
    562   if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
    563   {
    564     errorCount += testInternalDelete ();
    565     errorCount += testMultithreadedDelete ();
    566     errorCount += testMultithreadedPoolDelete ();
    567   }
    568   errorCount += testExternalDelete ();
    569   if (errorCount != 0)
    570     fprintf (stderr, "Error (code: %u)\n", errorCount);
    571   curl_global_cleanup ();
    572   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
    573 }