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