libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

test_urlparse.c (6212B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2009, 2011 Christian Grothoff
      4      Copyright (C) 2014-2022 Evgeny Grin (Karlson2k)
      5 
      6      libmicrohttpd is free software; you can redistribute it and/or modify
      7      it under the terms of the GNU General Public License as published
      8      by the Free Software Foundation; either version 2, or (at your
      9      option) any later version.
     10 
     11      libmicrohttpd is distributed in the hope that it will be useful, but
     12      WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      General Public License for more details.
     15 
     16      You should have received a copy of the GNU General Public License
     17      along with libmicrohttpd; see the file COPYING.  If not, write to the
     18      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19      Boston, MA 02110-1301, USA.
     20 */
     21 
     22 /**
     23  * @file daemontest_urlparse.c
     24  * @brief  Testcase for libmicrohttpd url parsing
     25  * @author Christian Grothoff
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 
     29 #include "MHD_config.h"
     30 #include "platform.h"
     31 #include <curl/curl.h>
     32 #include <microhttpd.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <time.h>
     36 #include "mhd_has_in_name.h"
     37 
     38 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     39    test into a marked, classifiable test error (TESTING.md, P5). */
     40 #include "mhd_panic_tripwire.h"
     41 
     42 #ifdef _WIN32
     43 #ifndef WIN32_LEAN_AND_MEAN
     44 #define WIN32_LEAN_AND_MEAN 1
     45 #endif /* !WIN32_LEAN_AND_MEAN */
     46 #include <windows.h>
     47 #endif
     48 
     49 #ifndef WINDOWS
     50 #include <unistd.h>
     51 #include <sys/socket.h>
     52 #endif
     53 
     54 static int oneone;
     55 
     56 static int matches;
     57 
     58 struct CBC
     59 {
     60   char *buf;
     61   size_t pos;
     62   size_t size;
     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 
     78 static enum MHD_Result
     79 test_values (void *cls,
     80              enum MHD_ValueKind kind,
     81              const char *key,
     82              const char *value)
     83 {
     84   (void) cls; (void) kind;         /* Unused. Silent compiler warning. */
     85   if ( (0 == strcmp (key, "a")) &&
     86        (0 == strcmp (value, "b")) )
     87     matches += 1;
     88   if ( (0 == strcmp (key, "c")) &&
     89        (0 == strcmp (value, "")) )
     90     matches += 2;
     91   if ( (0 == strcmp (key, "d")) &&
     92        (NULL == value) )
     93     matches += 4;
     94   return MHD_YES;
     95 }
     96 
     97 
     98 static enum MHD_Result
     99 ahc_echo (void *cls,
    100           struct MHD_Connection *connection,
    101           const char *url,
    102           const char *method,
    103           const char *version,
    104           const char *upload_data, size_t *upload_data_size,
    105           void **req_cls)
    106 {
    107   static int ptr;
    108   struct MHD_Response *response;
    109   enum MHD_Result ret;
    110   (void) cls;
    111   (void) version; (void) upload_data; (void) upload_data_size;       /* Unused. Silent compiler warning. */
    112 
    113   if (0 != strcmp (MHD_HTTP_METHOD_GET, method))
    114     return MHD_NO;              /* unexpected method */
    115   if (&ptr != *req_cls)
    116   {
    117     *req_cls = &ptr;
    118     return MHD_YES;
    119   }
    120   MHD_get_connection_values (connection,
    121                              MHD_GET_ARGUMENT_KIND,
    122                              &test_values,
    123                              NULL);
    124   *req_cls = NULL;
    125   response = MHD_create_response_from_buffer_copy (strlen (url),
    126                                                    (const void *) url);
    127   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    128   MHD_destroy_response (response);
    129   if (ret == MHD_NO)
    130     abort ();
    131   return ret;
    132 }
    133 
    134 
    135 static unsigned int
    136 testInternalGet (uint32_t poll_flag)
    137 {
    138   struct MHD_Daemon *d;
    139   CURL *c;
    140   char buf[2048];
    141   struct CBC cbc;
    142   CURLcode errornum;
    143   uint16_t port;
    144 
    145   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    146     port = 0;
    147   else
    148   {
    149     port = 1510;
    150     if (oneone)
    151       port += 5;
    152   }
    153 
    154   cbc.buf = buf;
    155   cbc.size = 2048;
    156   cbc.pos = 0;
    157   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
    158                         | (enum MHD_FLAG) poll_flag,
    159                         port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
    160   if (d == NULL)
    161     return 1;
    162   if (0 == port)
    163   {
    164     const union MHD_DaemonInfo *dinfo;
    165     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    166     if ((NULL == dinfo) || (0 == dinfo->port) )
    167     {
    168       MHD_stop_daemon (d); return 32;
    169     }
    170     port = dinfo->port;
    171   }
    172   c = curl_easy_init ();
    173   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world?a=b&c=&d");
    174   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    175   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    176   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    177   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    178   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    179   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    180   if (oneone)
    181     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    182   else
    183     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    184   /* NOTE: use of CONNECTTIMEOUT without also
    185      setting NOSIGNAL results in really weird
    186      crashes on my system!*/
    187   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    188   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    189   {
    190     fprintf (stderr,
    191              "curl_easy_perform failed: `%s'\n",
    192              curl_easy_strerror (errornum));
    193     curl_easy_cleanup (c);
    194     MHD_stop_daemon (d);
    195     return 2;
    196   }
    197   curl_easy_cleanup (c);
    198   MHD_stop_daemon (d);
    199   if (cbc.pos != strlen ("/hello_world"))
    200     return 4;
    201   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    202     return 8;
    203   if (matches != 7)
    204     return 16;
    205   return 0;
    206 }
    207 
    208 
    209 int
    210 main (int argc, char *const *argv)
    211 {
    212   unsigned int errorCount = 0;
    213   (void) argc;   /* Unused. Silent compiler warning. */
    214 
    215   if ((NULL == argv) || (0 == argv[0]))
    216     return 99;
    217   oneone = has_in_name (argv[0], "11");
    218   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    219     return 2;
    220   errorCount += testInternalGet (0);
    221   if (errorCount != 0)
    222     fprintf (stderr, "Error (code: %u)\n", errorCount);
    223   curl_global_cleanup ();
    224   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
    225 }