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_get.c
     23  * @brief  Testcase for libmicrohttpd GET 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 #include "socat.c"
     40 
     41 static int oneone;
     42 
     43 struct CBC
     44 {
     45   char *buf;
     46   size_t pos;
     47   size_t size;
     48 };
     49 
     50 static size_t
     51 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     52 {
     53   struct CBC *cbc = ctx;
     54 
     55   if (cbc->pos + size * nmemb > cbc->size)
     56     return 0;                   /* overflow */
     57   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     58   cbc->pos += size * nmemb;
     59   return size * nmemb;
     60 }
     61 
     62 static int
     63 ahc_echo (void *cls,
     64           struct MHD_Connection *connection,
     65           const char *url,
     66           const char *method,
     67           const char *version,
     68           const char *upload_data, size_t *upload_data_size,
     69           void **unused)
     70 {
     71   static int ptr;
     72   const char *me = cls;
     73   struct MHD_Response *response;
     74   int ret;
     75 
     76   if (0 != strcmp (me, method))
     77     return MHD_NO;              /* unexpected method */
     78   if (&ptr != *unused)
     79     {
     80       *unused = &ptr;
     81       return MHD_YES;
     82     }
     83   *unused = NULL;
     84   response = MHD_create_response_from_buffer (strlen (url),
     85 					      (void *) url,
     86 					      MHD_RESPMEM_MUST_COPY);
     87   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
     88   MHD_destroy_response (response);
     89   if (ret == MHD_NO)
     90     abort ();
     91   return ret;
     92 }
     93 
     94 
     95 static int
     96 testInternalGet ()
     97 {
     98   struct MHD_Daemon *d;
     99   CURL *c;
    100   char buf[2048];
    101   struct CBC cbc;
    102   int i;
    103 
    104   cbc.buf = buf;
    105   cbc.size = 2048;
    106   cbc.pos = 0;
    107   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
    108                         11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
    109   if (d == NULL)
    110     return 1;
    111   zzuf_socat_start ();
    112   for (i = 0; i < LOOP_COUNT; i++)
    113     {
    114       fprintf (stderr, ".");
    115       c = curl_easy_init ();
    116       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
    117       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    118       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    119       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    120       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    121       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    122       if (oneone)
    123         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    124       else
    125         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    126       // NOTE: use of CONNECTTIMEOUT without also
    127       //   setting NOSIGNAL results in really weird
    128       //   crashes on my system!
    129       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    130       curl_easy_perform (c);
    131       curl_easy_cleanup (c);
    132     }
    133   fprintf (stderr, "\n");
    134   zzuf_socat_stop ();
    135   MHD_stop_daemon (d);
    136   return 0;
    137 }
    138 
    139 static int
    140 testMultithreadedGet ()
    141 {
    142   struct MHD_Daemon *d;
    143   CURL *c;
    144   char buf[2048];
    145   struct CBC cbc;
    146   int i;
    147 
    148   cbc.buf = buf;
    149   cbc.size = 2048;
    150   cbc.pos = 0;
    151   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ ,
    152                         11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
    153   if (d == NULL)
    154     return 16;
    155   zzuf_socat_start ();
    156   for (i = 0; i < LOOP_COUNT; i++)
    157     {
    158       fprintf (stderr, ".");
    159       c = curl_easy_init ();
    160       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
    161       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    162       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    163       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    164       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    165       if (oneone)
    166         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    167       else
    168         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    169       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    170       // NOTE: use of CONNECTTIMEOUT without also
    171       //   setting NOSIGNAL results in really weird
    172       //   crashes on my system!
    173       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    174       curl_easy_perform (c);
    175       curl_easy_cleanup (c);
    176     }
    177   fprintf (stderr, "\n");
    178   zzuf_socat_stop ();
    179   MHD_stop_daemon (d);
    180   return 0;
    181 }
    182 
    183 
    184 static int
    185 testExternalGet ()
    186 {
    187   struct MHD_Daemon *d;
    188   CURL *c;
    189   char buf[2048];
    190   struct CBC cbc;
    191   CURLM *multi;
    192   CURLMcode mret;
    193   fd_set rs;
    194   fd_set ws;
    195   fd_set es;
    196   int max;
    197   int running;
    198   time_t start;
    199   struct timeval tv;
    200   int i;
    201 
    202   multi = NULL;
    203   cbc.buf = buf;
    204   cbc.size = 2048;
    205   cbc.pos = 0;
    206   d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ ,
    207                         11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
    208   if (d == NULL)
    209     return 256;
    210   multi = curl_multi_init ();
    211   if (multi == NULL)
    212     {
    213       MHD_stop_daemon (d);
    214       return 512;
    215     }
    216   zzuf_socat_start ();
    217   for (i = 0; i < LOOP_COUNT; i++)
    218     {
    219       fprintf (stderr, ".");
    220       c = curl_easy_init ();
    221       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
    222       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    223       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    224       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    225       if (oneone)
    226         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    227       else
    228         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    229       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    230       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    231       // NOTE: use of CONNECTTIMEOUT without also
    232       //   setting NOSIGNAL results in really weird
    233       //   crashes on my system!
    234       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    235       mret = curl_multi_add_handle (multi, c);
    236       if (mret != CURLM_OK)
    237         {
    238           curl_multi_cleanup (multi);
    239           curl_easy_cleanup (c);
    240           zzuf_socat_stop ();
    241           MHD_stop_daemon (d);
    242           return 1024;
    243         }
    244       start = time (NULL);
    245       while ((time (NULL) - start < 5) && (c != NULL))
    246         {
    247           max = 0;
    248           FD_ZERO (&rs);
    249           FD_ZERO (&ws);
    250           FD_ZERO (&es);
    251           curl_multi_perform (multi, &running);
    252           mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
    253           if (mret != CURLM_OK)
    254             {
    255               curl_multi_remove_handle (multi, c);
    256               curl_multi_cleanup (multi);
    257               curl_easy_cleanup (c);
    258               zzuf_socat_stop ();
    259               MHD_stop_daemon (d);
    260               return 2048;
    261             }
    262           if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
    263             {
    264               curl_multi_remove_handle (multi, c);
    265               curl_multi_cleanup (multi);
    266               curl_easy_cleanup (c);
    267               zzuf_socat_stop ();
    268               MHD_stop_daemon (d);
    269               return 4096;
    270             }
    271           tv.tv_sec = 0;
    272           tv.tv_usec = 1000;
    273           select (max + 1, &rs, &ws, &es, &tv);
    274           curl_multi_perform (multi, &running);
    275           if (running == 0)
    276             {
    277               curl_multi_info_read (multi, &running);
    278               curl_multi_remove_handle (multi, c);
    279               curl_easy_cleanup (c);
    280               c = NULL;
    281             }
    282           MHD_run (d);
    283         }
    284       if (c != NULL)
    285         {
    286           curl_multi_remove_handle (multi, c);
    287           curl_easy_cleanup (c);
    288         }
    289     }
    290   fprintf (stderr, "\n");
    291   curl_multi_cleanup (multi);
    292   zzuf_socat_stop ();
    293   MHD_stop_daemon (d);
    294   return 0;
    295 }
    296 
    297 
    298 int
    299 main (int argc, char *const *argv)
    300 {
    301   unsigned int errorCount = 0;
    302 
    303   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
    304     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
    305   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    306     return 2;
    307   errorCount += testInternalGet ();
    308   errorCount += testMultithreadedGet ();
    309   errorCount += testExternalGet ();
    310   if (errorCount != 0)
    311     fprintf (stderr, "Error (code: %u)\n", errorCount);
    312   curl_global_cleanup ();
    313   return errorCount != 0;       /* 0 == pass */
    314 }
    315