Home | History | Annotate | Download | only in testcurl
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2013 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 3, 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_process_arguments.c
     23  * @brief  Testcase for HTTP URI arguments
     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 static int oneone;
     40 
     41 struct CBC
     42 {
     43   char *buf;
     44   size_t pos;
     45   size_t size;
     46 };
     47 
     48 
     49 static size_t
     50 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     51 {
     52   struct CBC *cbc = ctx;
     53 
     54   if (cbc->pos + size * nmemb > cbc->size)
     55     return 0;                   /* overflow */
     56   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     57   cbc->pos += size * nmemb;
     58   return size * nmemb;
     59 }
     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   const char *hdr;
     76 
     77   if (0 != strcmp (me, method))
     78     return MHD_NO;              /* unexpected method */
     79   if (&ptr != *unused)
     80     {
     81       *unused = &ptr;
     82       return MHD_YES;
     83     }
     84   *unused = NULL;
     85   hdr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "k");
     86   if ((hdr == NULL) || (0 != strcmp (hdr, "v x")))
     87     abort ();
     88   hdr = MHD_lookup_connection_value (connection,
     89                                      MHD_GET_ARGUMENT_KIND, "hash");
     90   if ((hdr == NULL) || (0 != strcmp (hdr, "#foo")))
     91     abort ();
     92   hdr = MHD_lookup_connection_value (connection,
     93                                      MHD_GET_ARGUMENT_KIND, "space");
     94   if ((hdr == NULL) || (0 != strcmp (hdr, "\240bar")))
     95     abort ();
     96   if (3 != MHD_get_connection_values (connection,
     97 				      MHD_GET_ARGUMENT_KIND,
     98 				      NULL, NULL))
     99     abort ();
    100   response = MHD_create_response_from_buffer (strlen (url),
    101 					      (void *) url,
    102 					      MHD_RESPMEM_MUST_COPY);
    103   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    104   MHD_destroy_response (response);
    105   if (ret == MHD_NO)
    106     abort ();
    107   return ret;
    108 }
    109 
    110 
    111 static int
    112 testExternalGet ()
    113 {
    114   struct MHD_Daemon *d;
    115   CURL *c;
    116   char buf[2048];
    117   struct CBC cbc;
    118   CURLM *multi;
    119   CURLMcode mret;
    120   fd_set rs;
    121   fd_set ws;
    122   fd_set es;
    123   MHD_socket max;
    124   int running;
    125   struct CURLMsg *msg;
    126   time_t start;
    127   struct timeval tv;
    128 
    129   multi = NULL;
    130   cbc.buf = buf;
    131   cbc.size = 2048;
    132   cbc.pos = 0;
    133   d = MHD_start_daemon (MHD_USE_DEBUG,
    134                         21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
    135   if (d == NULL)
    136     return 256;
    137   c = curl_easy_init ();
    138   curl_easy_setopt (c, CURLOPT_URL,
    139                     "http://127.0.0.1:21080/hello+world?k=v+x&hash=%23foo&space=%A0bar");
    140   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    141   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    142   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    143   if (oneone)
    144     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    145   else
    146     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    147   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    148   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    149   /* NOTE: use of CONNECTTIMEOUT without also
    150      setting NOSIGNAL results in really weird
    151      crashes on my system! */
    152   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    153 
    154 
    155   multi = curl_multi_init ();
    156   if (multi == NULL)
    157     {
    158       curl_easy_cleanup (c);
    159       MHD_stop_daemon (d);
    160       return 512;
    161     }
    162   mret = curl_multi_add_handle (multi, c);
    163   if (mret != CURLM_OK)
    164     {
    165       curl_multi_cleanup (multi);
    166       curl_easy_cleanup (c);
    167       MHD_stop_daemon (d);
    168       return 1024;
    169     }
    170   start = time (NULL);
    171   while ((time (NULL) - start < 5) && (multi != NULL))
    172     {
    173       max = 0;
    174       FD_ZERO (&rs);
    175       FD_ZERO (&ws);
    176       FD_ZERO (&es);
    177       curl_multi_perform (multi, &running);
    178       mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
    179       if (mret != CURLM_OK)
    180         {
    181           curl_multi_remove_handle (multi, c);
    182           curl_multi_cleanup (multi);
    183           curl_easy_cleanup (c);
    184           MHD_stop_daemon (d);
    185           return 2048;
    186         }
    187       if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
    188         {
    189           curl_multi_remove_handle (multi, c);
    190           curl_multi_cleanup (multi);
    191           curl_easy_cleanup (c);
    192           MHD_stop_daemon (d);
    193           return 4096;
    194         }
    195       tv.tv_sec = 0;
    196       tv.tv_usec = 1000;
    197       select (max + 1, &rs, &ws, &es, &tv);
    198       curl_multi_perform (multi, &running);
    199       if (running == 0)
    200         {
    201           msg = curl_multi_info_read (multi, &running);
    202           if (msg == NULL)
    203             break;
    204           if (msg->msg == CURLMSG_DONE)
    205             {
    206               if (msg->data.result != CURLE_OK)
    207                 printf ("%s failed at %s:%d: `%s'\n",
    208                         "curl_multi_perform",
    209                         __FILE__,
    210                         __LINE__, curl_easy_strerror (msg->data.result));
    211               curl_multi_remove_handle (multi, c);
    212               curl_multi_cleanup (multi);
    213               curl_easy_cleanup (c);
    214               c = NULL;
    215               multi = NULL;
    216             }
    217         }
    218       MHD_run (d);
    219     }
    220   if (multi != NULL)
    221     {
    222       curl_multi_remove_handle (multi, c);
    223       curl_easy_cleanup (c);
    224       curl_multi_cleanup (multi);
    225     }
    226   MHD_stop_daemon (d);
    227   if (cbc.pos != strlen ("/hello+world"))
    228     return 8192;
    229   if (0 != strncmp ("/hello+world", cbc.buf, strlen ("/hello+world")))
    230     return 16384;
    231   return 0;
    232 }
    233 
    234 
    235 int
    236 main (int argc, char *const *argv)
    237 {
    238   unsigned int errorCount = 0;
    239 
    240   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
    241     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
    242   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    243     return 2;
    244   errorCount += testExternalGet ();
    245   if (errorCount != 0)
    246     fprintf (stderr, "Error (code: %u)\n", errorCount);
    247   curl_global_cleanup ();
    248   return errorCount != 0;       /* 0 == pass */
    249 }
    250