libmicrohttpd

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

test_process_arguments.c (8907B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2013 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 3, 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 test_process_arguments.c
     24  * @brief  Testcase for HTTP URI arguments
     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 <errno.h>
     37 #include "mhd_has_in_name.h"
     38 
     39 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     40    test into a marked, classifiable test error (TESTING.md, P5). */
     41 #include "mhd_panic_tripwire.h"
     42 
     43 #ifndef WINDOWS
     44 #include <unistd.h>
     45 #endif
     46 
     47 static int oneone;
     48 
     49 struct CBC
     50 {
     51   char *buf;
     52   size_t pos;
     53   size_t size;
     54 };
     55 
     56 
     57 static size_t
     58 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     59 {
     60   struct CBC *cbc = ctx;
     61 
     62   if (cbc->pos + size * nmemb > cbc->size)
     63     return 0;                   /* overflow */
     64   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     65   cbc->pos += size * nmemb;
     66   return size * nmemb;
     67 }
     68 
     69 
     70 static enum MHD_Result
     71 ahc_echo (void *cls,
     72           struct MHD_Connection *connection,
     73           const char *url,
     74           const char *method,
     75           const char *version,
     76           const char *upload_data, size_t *upload_data_size,
     77           void **req_cls)
     78 {
     79   static int ptr;
     80   struct MHD_Response *response;
     81   enum MHD_Result ret;
     82   const char *hdr;
     83   (void) cls;
     84   (void) version; (void) upload_data; (void) upload_data_size;       /* Unused. Silent compiler warning. */
     85 
     86   if (0 != strcmp (MHD_HTTP_METHOD_GET, method))
     87     return MHD_NO;              /* unexpected method */
     88   if (&ptr != *req_cls)
     89   {
     90     *req_cls = &ptr;
     91     return MHD_YES;
     92   }
     93   *req_cls = NULL;
     94   hdr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "k");
     95   if ((hdr == NULL) || (0 != strcmp (hdr, "v x")))
     96     abort ();
     97   hdr = MHD_lookup_connection_value (connection,
     98                                      MHD_GET_ARGUMENT_KIND, "hash");
     99   if ((hdr == NULL) || (0 != strcmp (hdr, "#foo")))
    100     abort ();
    101   hdr = MHD_lookup_connection_value (connection,
    102                                      MHD_GET_ARGUMENT_KIND, "space");
    103   if ((hdr == NULL) || (0 != strcmp (hdr, "\240bar")))
    104     abort ();
    105   if (3 != MHD_get_connection_values (connection,
    106                                       MHD_GET_ARGUMENT_KIND,
    107                                       NULL, NULL))
    108     abort ();
    109   response = MHD_create_response_from_buffer_copy (strlen (url),
    110                                                    (const void *) url);
    111   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    112   MHD_destroy_response (response);
    113   if (ret == MHD_NO)
    114     abort ();
    115   return ret;
    116 }
    117 
    118 
    119 static unsigned int
    120 testExternalGet (void)
    121 {
    122   struct MHD_Daemon *d;
    123   CURL *c;
    124   char buf[2048];
    125   struct CBC cbc;
    126   CURLM *multi;
    127   CURLMcode mret;
    128   fd_set rs;
    129   fd_set ws;
    130   fd_set es;
    131   MHD_socket maxsock;
    132 #ifdef MHD_WINSOCK_SOCKETS
    133   int maxposixs; /* Max socket number unused on W32 */
    134 #else  /* MHD_POSIX_SOCKETS */
    135 #define maxposixs maxsock
    136 #endif /* MHD_POSIX_SOCKETS */
    137   int running;
    138   struct CURLMsg *msg;
    139   time_t start;
    140   struct timeval tv;
    141   uint16_t port;
    142 
    143   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    144     port = 0;
    145   else
    146   {
    147     port = 1410;
    148     if (oneone)
    149       port += 5;
    150   }
    151 
    152   multi = NULL;
    153   cbc.buf = buf;
    154   cbc.size = 2048;
    155   cbc.pos = 0;
    156   d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY,
    157                         port, NULL, NULL, &ahc_echo, NULL,
    158                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
    159                         MHD_OPTION_END);
    160   if (d == NULL)
    161     return 256;
    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,
    174                     "http://127.0.0.1/hello+world?k=v+x&hash=%23foo&space=%A0bar");
    175   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    176   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    177   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    178   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    179   if (oneone)
    180     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    181   else
    182     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    183   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    184   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    185   /* NOTE: use of CONNECTTIMEOUT without also
    186      setting NOSIGNAL results in really weird
    187      crashes on my system! */
    188   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    189 
    190 
    191   multi = curl_multi_init ();
    192   if (multi == NULL)
    193   {
    194     curl_easy_cleanup (c);
    195     MHD_stop_daemon (d);
    196     return 512;
    197   }
    198   mret = curl_multi_add_handle (multi, c);
    199   if (mret != CURLM_OK)
    200   {
    201     curl_multi_cleanup (multi);
    202     curl_easy_cleanup (c);
    203     MHD_stop_daemon (d);
    204     return 1024;
    205   }
    206   start = time (NULL);
    207   while ((time (NULL) - start < 5) && (multi != NULL))
    208   {
    209     maxsock = MHD_INVALID_SOCKET;
    210     maxposixs = -1;
    211     FD_ZERO (&rs);
    212     FD_ZERO (&ws);
    213     FD_ZERO (&es);
    214     curl_multi_perform (multi, &running);
    215     mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    216     if (mret != CURLM_OK)
    217     {
    218       curl_multi_remove_handle (multi, c);
    219       curl_multi_cleanup (multi);
    220       curl_easy_cleanup (c);
    221       MHD_stop_daemon (d);
    222       return 2048;
    223     }
    224     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    225     {
    226       curl_multi_remove_handle (multi, c);
    227       curl_multi_cleanup (multi);
    228       curl_easy_cleanup (c);
    229       MHD_stop_daemon (d);
    230       return 4096;
    231     }
    232     tv.tv_sec = 0;
    233     tv.tv_usec = 1000;
    234     if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    235     {
    236 #ifdef MHD_POSIX_SOCKETS
    237       if (EINTR != errno)
    238       {
    239         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    240                  (int) errno, __LINE__);
    241         fflush (stderr);
    242         exit (99);
    243       }
    244 #else
    245       if ((WSAEINVAL != WSAGetLastError ()) ||
    246           (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    247       {
    248         fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    249                  (int) WSAGetLastError (), __LINE__);
    250         fflush (stderr);
    251         exit (99);
    252       }
    253       Sleep (1);
    254 #endif
    255     }
    256     curl_multi_perform (multi, &running);
    257     if (0 == running)
    258     {
    259       int pending;
    260       int curl_fine = 0;
    261       while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    262       {
    263         if (msg->msg == CURLMSG_DONE)
    264         {
    265           if (msg->data.result == CURLE_OK)
    266             curl_fine = 1;
    267           else
    268           {
    269             fprintf (stderr,
    270                      "%s failed at %s:%d: `%s'\n",
    271                      "curl_multi_perform",
    272                      __FILE__,
    273                      __LINE__, curl_easy_strerror (msg->data.result));
    274             abort ();
    275           }
    276         }
    277       }
    278       if (! curl_fine)
    279       {
    280         fprintf (stderr, "libcurl haven't returned OK code\n");
    281         abort ();
    282       }
    283       curl_multi_remove_handle (multi, c);
    284       curl_multi_cleanup (multi);
    285       curl_easy_cleanup (c);
    286       c = NULL;
    287       multi = NULL;
    288     }
    289     MHD_run (d);
    290   }
    291   if (multi != NULL)
    292   {
    293     curl_multi_remove_handle (multi, c);
    294     curl_easy_cleanup (c);
    295     curl_multi_cleanup (multi);
    296   }
    297   MHD_stop_daemon (d);
    298   if (cbc.pos != strlen ("/hello+world"))
    299     return 8192;
    300   if (0 != strncmp ("/hello+world", cbc.buf, strlen ("/hello+world")))
    301     return 16384;
    302   return 0;
    303 }
    304 
    305 
    306 int
    307 main (int argc, char *const *argv)
    308 {
    309   unsigned int errorCount = 0;
    310   (void) argc;   /* Unused. Silent compiler warning. */
    311 
    312   if ((NULL == argv) || (0 == argv[0]))
    313     return 99;
    314   oneone = has_in_name (argv[0], "11");
    315   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    316     return 2;
    317   errorCount += testExternalGet ();
    318   if (errorCount != 0)
    319     fprintf (stderr, "Error (code: %u)\n", errorCount);
    320   curl_global_cleanup ();
    321   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
    322 }