libmicrohttpd

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

test_https_get.c (7524B)


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