libmicrohttpd

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

test_https_get_select.c (8098B)


      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 static int oneone;
     41 
     42 static enum MHD_Result
     43 ahc_echo (void *cls,
     44           struct MHD_Connection *connection,
     45           const char *url,
     46           const char *method,
     47           const char *version,
     48           const char *upload_data, size_t *upload_data_size,
     49           void **req_cls)
     50 {
     51   static int ptr;
     52   struct MHD_Response *response;
     53   enum MHD_Result ret;
     54   (void) cls;
     55   (void) version; (void) upload_data; (void) upload_data_size;       /* Unused. Silent compiler warning. */
     56 
     57   if (0 != strcmp (MHD_HTTP_METHOD_GET, method))
     58     return MHD_NO;              /* unexpected method */
     59   if (&ptr != *req_cls)
     60   {
     61     *req_cls = &ptr;
     62     return MHD_YES;
     63   }
     64   *req_cls = NULL;
     65   response = MHD_create_response_from_buffer_copy (strlen (url),
     66                                                    (const void *) url);
     67   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
     68   MHD_destroy_response (response);
     69   if (ret == MHD_NO)
     70     abort ();
     71   return ret;
     72 }
     73 
     74 
     75 static unsigned int
     76 testExternalGet (unsigned int flags)
     77 {
     78   struct MHD_Daemon *d;
     79   CURL *c;
     80   char buf[2048];
     81   struct CBC cbc;
     82   CURLM *multi;
     83   CURLMcode mret;
     84   fd_set rs;
     85   fd_set ws;
     86   fd_set es;
     87   MHD_socket maxsock;
     88 #ifdef MHD_WINSOCK_SOCKETS
     89   int maxposixs; /* Max socket number unused on W32 */
     90 #else  /* MHD_POSIX_SOCKETS */
     91 #define maxposixs maxsock
     92 #endif /* MHD_POSIX_SOCKETS */
     93   int running;
     94   struct CURLMsg *msg;
     95   time_t start;
     96   struct timeval tv;
     97   uint16_t port;
     98 
     99   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    100     port = 0;
    101   else
    102     port = 3030;
    103 
    104   multi = NULL;
    105   cbc.buf = buf;
    106   cbc.size = 2048;
    107   cbc.pos = 0;
    108   d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_TLS | flags,
    109                         port, NULL, NULL, &ahc_echo, NULL,
    110                         MHD_OPTION_HTTPS_MEM_KEY, srv_self_signed_key_pem,
    111                         MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
    112                         MHD_OPTION_END);
    113   if (d == NULL)
    114     return 256;
    115   if (0 == port)
    116   {
    117     const union MHD_DaemonInfo *dinfo;
    118     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    119     if ((NULL == dinfo) || (0 == dinfo->port) )
    120     {
    121       MHD_stop_daemon (d); return 32;
    122     }
    123     port = dinfo->port;
    124   }
    125 
    126   c = curl_easy_init ();
    127 #ifdef _DEBUG
    128   curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
    129 #endif
    130   curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1/hello_world");
    131   curl_easy_setopt (c, CURLOPT_PORT, (long) port);
    132   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    133   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    134   /* TLS options */
    135   curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);
    136   curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L);
    137   curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L);
    138   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    139   if (oneone)
    140     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    141   else
    142     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    143   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    144   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    145   /* NOTE: use of CONNECTTIMEOUT without also
    146      setting NOSIGNAL results in really weird
    147      crashes on my system! */
    148   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    149 
    150 
    151   multi = curl_multi_init ();
    152   if (multi == NULL)
    153   {
    154     curl_easy_cleanup (c);
    155     MHD_stop_daemon (d);
    156     return 512;
    157   }
    158   mret = curl_multi_add_handle (multi, c);
    159   if (mret != CURLM_OK)
    160   {
    161     curl_multi_cleanup (multi);
    162     curl_easy_cleanup (c);
    163     MHD_stop_daemon (d);
    164     return 1024;
    165   }
    166   start = time (NULL);
    167   while ((time (NULL) - start < 5) && (multi != NULL))
    168   {
    169     maxsock = MHD_INVALID_SOCKET;
    170     maxposixs = -1;
    171     FD_ZERO (&rs);
    172     FD_ZERO (&ws);
    173     FD_ZERO (&es);
    174     mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    175     if (mret != CURLM_OK)
    176     {
    177       curl_multi_remove_handle (multi, c);
    178       curl_multi_cleanup (multi);
    179       curl_easy_cleanup (c);
    180       MHD_stop_daemon (d);
    181       return 2048;
    182     }
    183     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    184     {
    185       curl_multi_remove_handle (multi, c);
    186       curl_multi_cleanup (multi);
    187       curl_easy_cleanup (c);
    188       MHD_stop_daemon (d);
    189       return 4096;
    190     }
    191     tv.tv_sec = 0;
    192     tv.tv_usec = 1000;
    193     if (-1 != maxposixs)
    194     {
    195       if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    196       {
    197 #ifdef MHD_POSIX_SOCKETS
    198         if (EINTR != errno)
    199           abort ();
    200 #else
    201         if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 !=
    202                                                                         ws.
    203                                                                         fd_count)
    204             || (0 != es.fd_count) )
    205           abort ();
    206         Sleep (1000);
    207 #endif
    208       }
    209     }
    210     else
    211       (void) sleep (1);
    212     curl_multi_perform (multi, &running);
    213     if (0 == running)
    214     {
    215       int pending;
    216       int curl_fine = 0;
    217       while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    218       {
    219         if (msg->msg == CURLMSG_DONE)
    220         {
    221           if (msg->data.result == CURLE_OK)
    222             curl_fine = 1;
    223           else
    224           {
    225             fprintf (stderr,
    226                      "%s failed at %s:%d: `%s'\n",
    227                      "curl_multi_perform",
    228                      __FILE__,
    229                      __LINE__, curl_easy_strerror (msg->data.result));
    230             abort ();
    231           }
    232         }
    233       }
    234       if (! curl_fine)
    235       {
    236         fprintf (stderr, "libcurl haven't returned OK code\n");
    237         abort ();
    238       }
    239       curl_multi_remove_handle (multi, c);
    240       curl_multi_cleanup (multi);
    241       curl_easy_cleanup (c);
    242       c = NULL;
    243       multi = NULL;
    244     }
    245     MHD_run (d);
    246   }
    247   if (multi != NULL)
    248   {
    249     curl_multi_remove_handle (multi, c);
    250     curl_easy_cleanup (c);
    251     curl_multi_cleanup (multi);
    252   }
    253   MHD_stop_daemon (d);
    254   if (cbc.pos != strlen ("/hello_world"))
    255     return 8192;
    256   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    257     return 16384;
    258   return 0;
    259 }
    260 
    261 
    262 int
    263 main (int argc, char *const *argv)
    264 {
    265   unsigned int errorCount = 0;
    266   (void) argc;   /* Unused. Silent compiler warning. */
    267 
    268   oneone = 1;
    269   if (! testsuite_curl_global_init ())
    270     return 99;
    271   if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
    272   {
    273     fprintf (stderr, "Curl does not support SSL.  Cannot run the test.\n");
    274     curl_global_cleanup ();
    275     return 77;
    276   }
    277 
    278 #ifdef EPOLL_SUPPORT
    279   errorCount += testExternalGet (MHD_USE_EPOLL);
    280 #endif
    281   if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
    282     errorCount += testExternalGet (MHD_NO_FLAG);
    283   errorCount += testExternalGet (MHD_USE_NO_THREAD_SAFETY);
    284   curl_global_cleanup ();
    285   if (errorCount != 0)
    286     fprintf (stderr, "Failed test: %s, error: %u.\n", argv[0], errorCount);
    287   return errorCount != 0 ? 1 : 0;
    288 }