libmicrohttpd

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

test_https_get_select.c (8265B)


      1 /*
      2  This file is part of libmicrohttpd
      3  Copyright (C) 2007 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 test_https_get_select.c
     24  * @brief  Testcase for libmicrohttpd HTTPS GET operations using external select
     25  * @author Sagie Amir
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 
     29 #include "platform.h"
     30 #include "microhttpd.h"
     31 #include <limits.h>
     32 #include <sys/stat.h>
     33 #include <curl/curl.h>
     34 #ifdef MHD_HTTPS_REQUIRE_GCRYPT
     35 #include <gcrypt.h>
     36 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */
     37 #include "tls_test_common.h"
     38 #include "tls_test_keys.h"
     39 
     40 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     41    test into a marked, classifiable test error (TESTING.md, P5). */
     42 #include "mhd_panic_tripwire.h"
     43 
     44 static int oneone;
     45 
     46 static enum MHD_Result
     47 ahc_echo (void *cls,
     48           struct MHD_Connection *connection,
     49           const char *url,
     50           const char *method,
     51           const char *version,
     52           const char *upload_data, size_t *upload_data_size,
     53           void **req_cls)
     54 {
     55   static int ptr;
     56   struct MHD_Response *response;
     57   enum MHD_Result ret;
     58   (void) cls;
     59   (void) version; (void) upload_data; (void) upload_data_size;       /* Unused. Silent compiler warning. */
     60 
     61   if (0 != strcmp (MHD_HTTP_METHOD_GET, method))
     62     return MHD_NO;              /* unexpected method */
     63   if (&ptr != *req_cls)
     64   {
     65     *req_cls = &ptr;
     66     return MHD_YES;
     67   }
     68   *req_cls = NULL;
     69   response = MHD_create_response_from_buffer_copy (strlen (url),
     70                                                    (const void *) url);
     71   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
     72   MHD_destroy_response (response);
     73   if (ret == MHD_NO)
     74     abort ();
     75   return ret;
     76 }
     77 
     78 
     79 static unsigned int
     80 testExternalGet (unsigned int flags)
     81 {
     82   struct MHD_Daemon *d;
     83   CURL *c;
     84   char buf[2048];
     85   struct CBC cbc;
     86   CURLM *multi;
     87   CURLMcode mret;
     88   fd_set rs;
     89   fd_set ws;
     90   fd_set es;
     91   MHD_socket maxsock;
     92 #ifdef MHD_WINSOCK_SOCKETS
     93   int maxposixs; /* Max socket number unused on W32 */
     94 #else  /* MHD_POSIX_SOCKETS */
     95 #define maxposixs maxsock
     96 #endif /* MHD_POSIX_SOCKETS */
     97   int running;
     98   struct CURLMsg *msg;
     99   time_t start;
    100   struct timeval tv;
    101   uint16_t port;
    102 
    103   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    104     port = 0;
    105   else
    106     port = 3030;
    107 
    108   multi = NULL;
    109   cbc.buf = buf;
    110   cbc.size = 2048;
    111   cbc.pos = 0;
    112   d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_TLS | flags,
    113                         port, NULL, NULL, &ahc_echo, NULL,
    114                         MHD_OPTION_HTTPS_MEM_KEY, srv_self_signed_key_pem,
    115                         MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
    116                         MHD_OPTION_END);
    117   if (d == NULL)
    118     return 256;
    119   if (0 == port)
    120   {
    121     const union MHD_DaemonInfo *dinfo;
    122     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    123     if ((NULL == dinfo) || (0 == dinfo->port) )
    124     {
    125       MHD_stop_daemon (d); return 32;
    126     }
    127     port = dinfo->port;
    128   }
    129 
    130   c = curl_easy_init ();
    131 #ifdef _DEBUG
    132   curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
    133 #endif
    134   curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1/hello_world");
    135   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    136   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    137   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    138   /* TLS options */
    139   curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
    140   curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L);
    141   curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L);
    142   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    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, 1L);
    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     maxsock = MHD_INVALID_SOCKET;
    174     maxposixs = -1;
    175     FD_ZERO (&rs);
    176     FD_ZERO (&ws);
    177     FD_ZERO (&es);
    178     mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    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, &maxsock))
    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     if (-1 != maxposixs)
    198     {
    199       if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    200       {
    201 #ifdef MHD_POSIX_SOCKETS
    202         if (EINTR != errno)
    203           abort ();
    204 #else
    205         if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 !=
    206                                                                         ws.
    207                                                                         fd_count)
    208             || (0 != es.fd_count) )
    209           abort ();
    210         Sleep (1000);
    211 #endif
    212       }
    213     }
    214     else
    215       (void) sleep (1);
    216     curl_multi_perform (multi, &running);
    217     if (0 == running)
    218     {
    219       int pending;
    220       int curl_fine = 0;
    221       while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    222       {
    223         if (msg->msg == CURLMSG_DONE)
    224         {
    225           if (msg->data.result == CURLE_OK)
    226             curl_fine = 1;
    227           else
    228           {
    229             fprintf (stderr,
    230                      "%s failed at %s:%d: `%s'\n",
    231                      "curl_multi_perform",
    232                      __FILE__,
    233                      __LINE__, curl_easy_strerror (msg->data.result));
    234             abort ();
    235           }
    236         }
    237       }
    238       if (! curl_fine)
    239       {
    240         fprintf (stderr, "libcurl haven't returned OK code\n");
    241         abort ();
    242       }
    243       curl_multi_remove_handle (multi, c);
    244       curl_multi_cleanup (multi);
    245       curl_easy_cleanup (c);
    246       c = NULL;
    247       multi = NULL;
    248     }
    249     MHD_run (d);
    250   }
    251   if (multi != NULL)
    252   {
    253     curl_multi_remove_handle (multi, c);
    254     curl_easy_cleanup (c);
    255     curl_multi_cleanup (multi);
    256   }
    257   MHD_stop_daemon (d);
    258   if (cbc.pos != strlen ("/hello_world"))
    259     return 8192;
    260   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    261     return 16384;
    262   return 0;
    263 }
    264 
    265 
    266 int
    267 main (int argc, char *const *argv)
    268 {
    269   unsigned int errorCount = 0;
    270   (void) argc;   /* Unused. Silent compiler warning. */
    271 
    272   oneone = 1;
    273   if (! testsuite_curl_global_init ())
    274     return 99;
    275   if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
    276   {
    277     fprintf (stderr, "Curl does not support SSL.  Cannot run the test.\n");
    278     curl_global_cleanup ();
    279     return 77;
    280   }
    281 
    282 #ifdef EPOLL_SUPPORT
    283   errorCount += testExternalGet (MHD_USE_EPOLL);
    284 #endif
    285   if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
    286     errorCount += testExternalGet (MHD_NO_FLAG);
    287   errorCount += testExternalGet (MHD_USE_NO_THREAD_SAFETY);
    288   curl_global_cleanup ();
    289   if (errorCount != 0)
    290     fprintf (stderr, "Failed test: %s, error: %u.\n", argv[0], errorCount);
    291   return errorCount != 0 ? 1 : 0;
    292 }