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_long_header.c
     23  * @brief  Testcase for libmicrohttpd handling of very long headers
     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 /**
     42  * We will set the memory available per connection to
     43  * half of this value, so the actual value does not have
     44  * to be big at all...
     45  */
     46 #define VERY_LONG (1024*10)
     47 
     48 static int oneone;
     49 
     50 static int
     51 apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
     52 {
     53   return MHD_YES;
     54 }
     55 
     56 struct CBC
     57 {
     58   char *buf;
     59   size_t pos;
     60   size_t size;
     61 };
     62 
     63 static size_t
     64 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     65 {
     66   return size * nmemb;
     67 }
     68 
     69 static int
     70 ahc_echo (void *cls,
     71           struct MHD_Connection *connection,
     72           const char *url,
     73           const char *method,
     74           const char *version,
     75           const char *upload_data, size_t *upload_data_size,
     76           void **unused)
     77 {
     78   const char *me = cls;
     79   struct MHD_Response *response;
     80   int ret;
     81 
     82   if (0 != strcmp (me, method))
     83     return MHD_NO;              /* unexpected method */
     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   return ret;
     90 }
     91 
     92 
     93 static int
     94 testLongUrlGet ()
     95 {
     96   struct MHD_Daemon *d;
     97   CURL *c;
     98   char buf[2048];
     99   struct CBC cbc;
    100   char *url;
    101   int i;
    102 
    103   cbc.buf = buf;
    104   cbc.size = 2048;
    105   cbc.pos = 0;
    106   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
    107                         11080,
    108                         &apc_all,
    109                         NULL,
    110                         &ahc_echo,
    111                         "GET",
    112                         MHD_OPTION_CONNECTION_MEMORY_LIMIT,
    113                         (size_t) (VERY_LONG / 2), MHD_OPTION_END);
    114 
    115   if (d == NULL)
    116     return 1;
    117   zzuf_socat_start ();
    118   for (i = 0; i < LOOP_COUNT; i++)
    119     {
    120       fprintf (stderr, ".");
    121 
    122       c = curl_easy_init ();
    123       url = malloc (VERY_LONG);
    124       memset (url, 'a', VERY_LONG);
    125       url[VERY_LONG - 1] = '\0';
    126       memcpy (url, "http://localhost:11081/",
    127               strlen ("http://localhost:11081/"));
    128       curl_easy_setopt (c, CURLOPT_URL, url);
    129       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    130       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    131       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    132       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    133       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    134       if (oneone)
    135         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    136       else
    137         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    138       // NOTE: use of CONNECTTIMEOUT without also
    139       //   setting NOSIGNAL results in really weird
    140       //   crashes on my system!
    141       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    142       curl_easy_perform (c);
    143       curl_easy_cleanup (c);
    144     }
    145   fprintf (stderr, "\n");
    146   zzuf_socat_stop ();
    147 
    148   MHD_stop_daemon (d);
    149   free (url);
    150   return 0;
    151 }
    152 
    153 
    154 static int
    155 testLongHeaderGet ()
    156 {
    157   struct MHD_Daemon *d;
    158   CURL *c;
    159   char buf[2048];
    160   struct CBC cbc;
    161   char *url;
    162   struct curl_slist *header = NULL;
    163   int i;
    164 
    165   cbc.buf = buf;
    166   cbc.size = 2048;
    167   cbc.pos = 0;
    168   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ ,
    169                         11080,
    170                         &apc_all,
    171                         NULL,
    172                         &ahc_echo,
    173                         "GET",
    174                         MHD_OPTION_CONNECTION_MEMORY_LIMIT,
    175                         (size_t) (VERY_LONG / 2), MHD_OPTION_END);
    176   if (d == NULL)
    177     return 16;
    178   zzuf_socat_start ();
    179   for (i = 0; i < LOOP_COUNT; i++)
    180     {
    181       fprintf (stderr, ".");
    182       c = curl_easy_init ();
    183       url = malloc (VERY_LONG);
    184       memset (url, 'a', VERY_LONG);
    185       url[VERY_LONG - 1] = '\0';
    186       url[VERY_LONG / 2] = ':';
    187       url[VERY_LONG / 2 + 1] = ' ';
    188       header = curl_slist_append (header, url);
    189 
    190       curl_easy_setopt (c, CURLOPT_HTTPHEADER, header);
    191       curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
    192       curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    193       curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    194       curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    195       curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
    196       curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
    197       if (oneone)
    198         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    199       else
    200         curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    201       // NOTE: use of CONNECTTIMEOUT without also
    202       //   setting NOSIGNAL results in really weird
    203       //   crashes on my system!
    204       curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    205       curl_easy_perform (c);
    206       curl_slist_free_all (header);
    207       header = NULL;
    208       curl_easy_cleanup (c);
    209     }
    210   fprintf (stderr, "\n");
    211   zzuf_socat_stop ();
    212 
    213   MHD_stop_daemon (d);
    214   free (url);
    215   return 0;
    216 }
    217 
    218 
    219 int
    220 main (int argc, char *const *argv)
    221 {
    222   unsigned int errorCount = 0;
    223 
    224   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
    225     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
    226   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    227     return 2;
    228   errorCount += testLongUrlGet ();
    229   errorCount += testLongHeaderGet ();
    230   if (errorCount != 0)
    231     fprintf (stderr, "Error (code: %u)\n", errorCount);
    232   curl_global_cleanup ();
    233   return errorCount != 0;       /* 0 == pass */
    234 }
    235