libmicrohttpd

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

test_https_get.c (7691B)


      1 /*
      2   This file is part of libmicrohttpd
      3   Copyright (C) 2007 Christian Grothoff
      4   Copyright (C) 2016-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_https_get.c
     24  * @brief  Testcase for libmicrohttpd HTTPS GET operations
     25  * @author Sagie Amir
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 
     29 #include "platform.h"
     30 #include "microhttpd.h"
     31 #include <curl/curl.h>
     32 #ifdef MHD_HTTPS_REQUIRE_GCRYPT
     33 #include <gcrypt.h>
     34 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */
     35 #include "tls_test_common.h"
     36 #include "tls_test_keys.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 
     43 static uint16_t global_port;
     44 
     45 
     46 /* perform a HTTP GET request via SSL/TLS */
     47 static unsigned int
     48 test_secure_get (const char *cipher_suite,
     49                  int proto_version)
     50 {
     51   unsigned int ret;
     52   struct MHD_Daemon *d;
     53   uint16_t port;
     54 
     55   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
     56     port = 0;
     57   else
     58     port = 3041;
     59 
     60   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
     61                         | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS
     62                         | MHD_USE_ERROR_LOG, port,
     63                         NULL, NULL,
     64                         &http_ahc, NULL,
     65                         MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
     66                         MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
     67                         MHD_OPTION_END);
     68 
     69   if (d == NULL)
     70   {
     71     fprintf (stderr, MHD_E_SERVER_INIT);
     72     return 1;
     73   }
     74   if (0 == port)
     75   {
     76     const union MHD_DaemonInfo *dinfo;
     77     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
     78     if ((NULL == dinfo) || (0 == dinfo->port) )
     79     {
     80       MHD_stop_daemon (d);
     81       return 1;
     82     }
     83     port = dinfo->port;
     84   }
     85 
     86   ret = test_https_transfer (NULL,
     87                              port,
     88                              cipher_suite,
     89                              proto_version);
     90 
     91   MHD_stop_daemon (d);
     92   return ret;
     93 }
     94 
     95 
     96 static enum MHD_Result
     97 ahc_empty (void *cls,
     98            struct MHD_Connection *connection,
     99            const char *url,
    100            const char *method,
    101            const char *version,
    102            const char *upload_data,
    103            size_t *upload_data_size,
    104            void **req_cls)
    105 {
    106   static int ptr;
    107   struct MHD_Response *response;
    108   enum MHD_Result ret;
    109   (void) cls;
    110   (void) url;
    111   (void) url;
    112   (void) version;          /* Unused. Silent compiler warning. */
    113   (void) upload_data;
    114   (void) upload_data_size; /* Unused. Silent compiler warning. */
    115 
    116   if (0 != strcmp (MHD_HTTP_METHOD_GET,
    117                    method))
    118     return MHD_NO;              /* unexpected method */
    119   if (&ptr != *req_cls)
    120   {
    121     *req_cls = &ptr;
    122     return MHD_YES;
    123   }
    124   *req_cls = NULL;
    125   response = MHD_create_response_empty (MHD_RF_NONE);
    126   ret = MHD_queue_response (connection,
    127                             MHD_HTTP_OK,
    128                             response);
    129   MHD_destroy_response (response);
    130   if (ret == MHD_NO)
    131   {
    132     fprintf (stderr, "Failed to queue response.\n");
    133     _exit (20);
    134   }
    135   return ret;
    136 }
    137 
    138 
    139 static int
    140 curlExcessFound (CURL *c,
    141                  curl_infotype type,
    142                  char *data,
    143                  size_t size,
    144                  void *cls)
    145 {
    146   static const char *excess_found = "Excess found";
    147   const size_t str_size = strlen (excess_found);
    148   (void) c;      /* Unused. Silence compiler warning. */
    149 
    150 #ifdef _DEBUG
    151   if ((CURLINFO_TEXT == type) ||
    152       (CURLINFO_HEADER_IN == type) ||
    153       (CURLINFO_HEADER_OUT == type))
    154     fprintf (stderr, "%.*s", (int) size, data);
    155 #endif /* _DEBUG */
    156   if ((CURLINFO_TEXT == type)
    157       && (size >= str_size)
    158       && (0 == strncmp (excess_found, data, str_size)))
    159     *(int *) cls = 1;
    160   return 0;
    161 }
    162 
    163 
    164 static unsigned int
    165 testEmptyGet (unsigned int poll_flag)
    166 {
    167   struct MHD_Daemon *d;
    168   CURL *c;
    169   char buf[2048];
    170   struct CBC cbc;
    171   CURLcode errornum;
    172   int excess_found = 0;
    173 
    174 
    175   if ( (0 == global_port) &&
    176        (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
    177   {
    178     global_port = 1225;
    179 
    180   }
    181 
    182   cbc.buf = buf;
    183   cbc.size = 2048;
    184   cbc.pos = 0;
    185   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
    186                         | poll_flag | MHD_USE_TLS,
    187                         global_port, NULL, NULL,
    188                         &ahc_empty, NULL,
    189                         MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
    190                         MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
    191                         MHD_OPTION_END);
    192   if (d == NULL)
    193     return 4194304;
    194   if (0 == global_port)
    195   {
    196     const union MHD_DaemonInfo *dinfo;
    197     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    198     if ((NULL == dinfo) || (0 == dinfo->port) )
    199     {
    200       MHD_stop_daemon (d); return 32;
    201     }
    202     global_port = dinfo->port;
    203   }
    204   c = curl_easy_init ();
    205 #ifdef _DEBUG
    206   curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
    207 #endif
    208   curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1/");
    209   curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    210   curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
    211   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    212   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    213   curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, &curlExcessFound);
    214   curl_easy_setopt (c, CURLOPT_DEBUGDATA, &excess_found);
    215   curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
    216   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    217   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    218   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    219   curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L);
    220   curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L);
    221   /* NOTE: use of CONNECTTIMEOUT without also
    222      setting NOSIGNAL results in really weird
    223      crashes on my system!*/
    224   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    225   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    226   {
    227     fprintf (stderr,
    228              "curl_easy_perform failed: `%s'\n",
    229              curl_easy_strerror (errornum));
    230     curl_easy_cleanup (c);
    231     MHD_stop_daemon (d);
    232     return 8388608;
    233   }
    234   curl_easy_cleanup (c);
    235   MHD_stop_daemon (d);
    236   if (cbc.pos != 0)
    237     return 16777216;
    238   if (excess_found)
    239     return 33554432;
    240   return 0;
    241 }
    242 
    243 
    244 int
    245 main (int argc, char *const *argv)
    246 {
    247   unsigned int errorCount = 0;
    248   (void) argc; (void) argv;   /* Unused. Silent compiler warning. */
    249 
    250 #ifdef MHD_HTTPS_REQUIRE_GCRYPT
    251   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
    252 #ifdef GCRYCTL_INITIALIZATION_FINISHED
    253   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
    254 #endif
    255 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */
    256   if (! testsuite_curl_global_init ())
    257     return 99;
    258   if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
    259   {
    260     fprintf (stderr, "Curl does not support SSL.  Cannot run the test.\n");
    261     curl_global_cleanup ();
    262     return 77;
    263   }
    264   errorCount +=
    265     test_secure_get (NULL, CURL_SSLVERSION_DEFAULT);
    266   errorCount += testEmptyGet (0);
    267   curl_global_cleanup ();
    268 
    269   return errorCount != 0 ? 1 : 0;
    270 }