libmicrohttpd

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

test_delete.c (16111B)


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