Home | History | Annotate | Download | only in testzzuf
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2008 Christian Grothoff
      4 
      5      libmicrohttpd is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 2, or (at your
      8      option) any later version.
      9 
     10      libmicrohttpd is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libmicrohttpd; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     18      Boston, MA 02111-1307, USA.
     19 */
     20 
     21 /**
     22  * @file test_put.c
     23  * @brief  Testcase for libmicrohttpd PUT operations
     24  * @author Christian Grothoff
     25  */
     26 
     27 #include "MHD_config.h"
     28 #include "platform.h"
     29 #include <curl/curl.h>
     30 #include <microhttpd.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <time.h>
     34 
     35 #ifndef WINDOWS
     36 #include <unistd.h>
     37 #endif
     38 
     39 
     40 #include "socat.c"
     41 
     42 static int oneone;
     43 
     44 struct CBC
     45 {
     46   char *buf;
     47   size_t pos;
     48   size_t size;
     49 };
     50 
     51 static size_t
     52 putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
     53 {
     54   unsigned int *pos = ptr;
     55   unsigned int wrt;
     56 
     57   wrt = size * nmemb;
     58   if (wrt > 8 - (*pos))
     59     wrt = 8 - (*pos);
     60   memcpy (stream, &("Hello123"[*pos]), wrt);
     61   (*pos) += wrt;
     62   return wrt;
     63 }
     64 
     65 static size_t
     66 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     67 {
     68   struct CBC *cbc = ctx;
     69 
     70   if (cbc->pos + size * nmemb > cbc->size)
     71     return 0;                   /* overflow */
     72   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     73   cbc->pos += size * nmemb;
     74   return size * nmemb;
     75 }
     76 
     77 static int
     78 ahc_echo (void *cls,
     79           struct MHD_Connection *connection,
     80           const char *url,
     81           const char *method,
     82           const char *version,
     83           const char *upload_data, size_t *upload_data_size,
     84           void **unused)
     85 {
     86   int *done = cls;
     87   struct MHD_Response *response;
     88   int ret;
     89 
     90   if (0 != strcmp ("PUT", method))
     91     return MHD_NO;              /* unexpected method */
     92   if ((*done) == 0)
     93     {
     94       if (*upload_data_size != 8)
     95         return MHD_YES;         /* not yet ready */
     96       if (0 == memcmp (upload_data, "Hello123", 8))
     97         {
     98           *upload_data_size = 0;
     99         }
    100       else
    101         {
    102           printf ("Invalid upload data `%8s'!\n", upload_data);
    103           return MHD_NO;
    104         }
    105       *done = 1;
    106       return MHD_YES;
    107     }
    108   response = MHD_create_response_from_buffer (strlen (url),
    109 					      (void *) url,
    110 					      MHD_RESPMEM_MUST_COPY);
    111   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    112   MHD_destroy_response (response);
    113   return ret;
    114 }
    115 
    116 
    117 static int
    118 testInternalPut ()
    119 {
    120   struct MHD_Daemon *d;
    121   CURL *c;
    122   char buf[2048];
    123   struct CBC cbc;
    124   unsigned int pos = 0;
    125   int done_flag = 0;
    126   int i;
    127 
    128   cbc.buf = buf;
    129   cbc.size = 2048;
    130   cbc.pos = 0;
    131   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
    132                         11080,
    133                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
    134   if (d == NULL)
    135     return 1;
    136   zzuf_socat_start ();
    137   for (i = 0; i < LOOP_COUNT; i++)
    138     {
    139       fprintf (stderr, ".");
    140       c = curl_easy_init ();
    141       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
    142       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    143       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    144       curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
    145       curl_easy_setopt (c, CURLOPT_READDATA, &pos);
    146       curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
    147       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
    148       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    149       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    150       if (oneone)
    151         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    152       else
    153         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    154       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    155       // NOTE: use of CONNECTTIMEOUT without also
    156       //   setting NOSIGNAL results in really weird
    157       //   crashes on my system!
    158       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    159       curl_easy_perform (c);
    160       curl_easy_cleanup (c);
    161     }
    162   fprintf (stderr, "\n");
    163   zzuf_socat_stop ();
    164   MHD_stop_daemon (d);
    165   return 0;
    166 }
    167 
    168 static int
    169 testMultithreadedPut ()
    170 {
    171   struct MHD_Daemon *d;
    172   CURL *c;
    173   char buf[2048];
    174   struct CBC cbc;
    175   unsigned int pos = 0;
    176   int done_flag = 0;
    177   int i;
    178 
    179   cbc.buf = buf;
    180   cbc.size = 2048;
    181   cbc.pos = 0;
    182   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ ,
    183                         11080,
    184                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
    185   if (d == NULL)
    186     return 16;
    187   zzuf_socat_start ();
    188   for (i = 0; i < LOOP_COUNT; i++)
    189     {
    190       fprintf (stderr, ".");
    191       c = curl_easy_init ();
    192       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
    193       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    194       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    195       curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
    196       curl_easy_setopt (c, CURLOPT_READDATA, &pos);
    197       curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
    198       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
    199       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    200       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    201       if (oneone)
    202         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    203       else
    204         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    205       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    206       // NOTE: use of CONNECTTIMEOUT without also
    207       //   setting NOSIGNAL results in really weird
    208       //   crashes on my system!
    209       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    210       curl_easy_perform (c);
    211       curl_easy_cleanup (c);
    212     }
    213   fprintf (stderr, "\n");
    214   zzuf_socat_stop ();
    215   MHD_stop_daemon (d);
    216   return 0;
    217 }
    218 
    219 
    220 static int
    221 testExternalPut ()
    222 {
    223   struct MHD_Daemon *d;
    224   CURL *c;
    225   char buf[2048];
    226   struct CBC cbc;
    227   CURLM *multi;
    228   CURLMcode mret;
    229   fd_set rs;
    230   fd_set ws;
    231   fd_set es;
    232   int max;
    233   int running;
    234   time_t start;
    235   struct timeval tv;
    236   unsigned int pos = 0;
    237   int done_flag = 0;
    238   int i;
    239 
    240   multi = NULL;
    241   cbc.buf = buf;
    242   cbc.size = 2048;
    243   cbc.pos = 0;
    244   d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ ,
    245                         11080,
    246                         NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
    247   if (d == NULL)
    248     return 256;
    249   multi = curl_multi_init ();
    250   if (multi == NULL)
    251     {
    252       MHD_stop_daemon (d);
    253       return 512;
    254     }
    255   zzuf_socat_start ();
    256   for (i = 0; i < LOOP_COUNT; i++)
    257     {
    258       fprintf (stderr, ".");
    259 
    260       c = curl_easy_init ();
    261       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
    262       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    263       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    264       curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
    265       curl_easy_setopt (c, CURLOPT_READDATA, &pos);
    266       curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
    267       curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
    268       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    269       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    270       if (oneone)
    271         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    272       else
    273         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    274       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    275       // NOTE: use of CONNECTTIMEOUT without also
    276       //   setting NOSIGNAL results in really weird
    277       //   crashes on my system!
    278       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    279 
    280 
    281 
    282       mret = curl_multi_add_handle (multi, c);
    283       if (mret != CURLM_OK)
    284         {
    285           curl_multi_cleanup (multi);
    286           curl_easy_cleanup (c);
    287           zzuf_socat_stop ();
    288           MHD_stop_daemon (d);
    289           return 1024;
    290         }
    291       start = time (NULL);
    292       while ((time (NULL) - start < 5) && (c != NULL))
    293         {
    294           max = 0;
    295           FD_ZERO (&rs);
    296           FD_ZERO (&ws);
    297           FD_ZERO (&es);
    298           curl_multi_perform (multi, &running);
    299           mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
    300           if (mret != CURLM_OK)
    301             {
    302               curl_multi_remove_handle (multi, c);
    303               curl_multi_cleanup (multi);
    304               curl_easy_cleanup (c);
    305               zzuf_socat_stop ();
    306               MHD_stop_daemon (d);
    307               return 2048;
    308             }
    309           if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
    310             {
    311               curl_multi_remove_handle (multi, c);
    312               curl_multi_cleanup (multi);
    313               curl_easy_cleanup (c);
    314               zzuf_socat_stop ();
    315               MHD_stop_daemon (d);
    316               return 4096;
    317             }
    318           tv.tv_sec = 0;
    319           tv.tv_usec = 1000;
    320           select (max + 1, &rs, &ws, &es, &tv);
    321           curl_multi_perform (multi, &running);
    322           if (running == 0)
    323             {
    324               curl_multi_info_read (multi, &running);
    325               curl_multi_remove_handle (multi, c);
    326               curl_easy_cleanup (c);
    327               c = NULL;
    328             }
    329           MHD_run (d);
    330         }
    331       if (c != NULL)
    332         {
    333           curl_multi_remove_handle (multi, c);
    334           curl_easy_cleanup (c);
    335         }
    336     }
    337   fprintf (stderr, "\n");
    338   curl_multi_cleanup (multi);
    339   zzuf_socat_stop ();
    340   MHD_stop_daemon (d);
    341   return 0;
    342 }
    343 
    344 
    345 int
    346 main (int argc, char *const *argv)
    347 {
    348   unsigned int errorCount = 0;
    349 
    350   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
    351     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
    352   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    353     return 2;
    354   errorCount += testInternalPut ();
    355   errorCount += testMultithreadedPut ();
    356   errorCount += testExternalPut ();
    357   if (errorCount != 0)
    358     fprintf (stderr, "Error (code: %u)\n", errorCount);
    359   curl_global_cleanup ();
    360   return errorCount != 0;       /* 0 == pass */
    361 }
    362