Home | History | Annotate | Download | only in https
      1 /*
      2  This file is part of libmicrohttpd
      3  Copyright (C) 2007 Christian Grothoff
      4 
      5  libmicrohttpd is free software; you can redistribute it and/or modify
      6  it under the terms of the GNU General Public License as published
      7  by the Free Software Foundation; either version 2, or (at your
      8  option) any later version.
      9 
     10  libmicrohttpd is distributed in the hope that it will be useful, but
     11  WITHOUT ANY WARRANTY; without even the implied warranty of
     12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  General Public License for more details.
     14 
     15  You should have received a copy of the GNU General Public License
     16  along with libmicrohttpd; see the file COPYING.  If not, write to the
     17  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     18  Boston, MA 02111-1307, USA.
     19  */
     20 
     21 /**
     22  * @file test_https_get_select.c
     23  * @brief  Testcase for libmicrohttpd HTTPS GET operations
     24  * @author Sagie Amir
     25  */
     26 
     27 #include "platform.h"
     28 #include "microhttpd.h"
     29 #include <limits.h>
     30 #include <sys/stat.h>
     31 #include <curl/curl.h>
     32 #include <gcrypt.h>
     33 #include "tls_test_common.h"
     34 
     35 extern const char srv_key_pem[];
     36 extern const char srv_self_signed_cert_pem[];
     37 extern const char srv_signed_cert_pem[];
     38 extern const char srv_signed_key_pem[];
     39 
     40 static int oneone;
     41 
     42 static int
     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 **unused)
     50 {
     51   static int ptr;
     52   const char *me = cls;
     53   struct MHD_Response *response;
     54   int ret;
     55 
     56   if (0 != strcmp (me, method))
     57     return MHD_NO;              /* unexpected method */
     58   if (&ptr != *unused)
     59     {
     60       *unused = &ptr;
     61       return MHD_YES;
     62     }
     63   *unused = NULL;
     64   response = MHD_create_response_from_buffer (strlen (url),
     65 					      (void *) url,
     66 					      MHD_RESPMEM_MUST_COPY);
     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 int
     76 testExternalGet (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 max;
     88   int running;
     89   struct CURLMsg *msg;
     90   time_t start;
     91   struct timeval tv;
     92   const char *aes256_sha = "AES256-SHA";
     93 
     94   multi = NULL;
     95   cbc.buf = buf;
     96   cbc.size = 2048;
     97   cbc.pos = 0;
     98   d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL | flags,
     99                         1082, NULL, NULL, &ahc_echo, "GET",
    100                         MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem,
    101                         MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
    102 			MHD_OPTION_END);
    103   if (d == NULL)
    104     return 256;
    105 
    106   if (curl_uses_nss_ssl() == 0)
    107     aes256_sha = "rsa_aes_256_sha";
    108 
    109   c = curl_easy_init ();
    110   curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1:1082/hello_world");
    111   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    112   curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    113   /* TLS options */
    114   curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
    115   curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, aes256_sha);
    116   curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
    117   curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0);
    118   curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    119   if (oneone)
    120     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    121   else
    122     curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    123   curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    124   curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    125   /* NOTE: use of CONNECTTIMEOUT without also
    126      setting NOSIGNAL results in really weird
    127      crashes on my system! */
    128   curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    129 
    130 
    131   multi = curl_multi_init ();
    132   if (multi == NULL)
    133     {
    134       curl_easy_cleanup (c);
    135       MHD_stop_daemon (d);
    136       return 512;
    137     }
    138   mret = curl_multi_add_handle (multi, c);
    139   if (mret != CURLM_OK)
    140     {
    141       curl_multi_cleanup (multi);
    142       curl_easy_cleanup (c);
    143       MHD_stop_daemon (d);
    144       return 1024;
    145     }
    146   start = time (NULL);
    147   while ((time (NULL) - start < 5) && (multi != NULL))
    148     {
    149       max = 0;
    150       FD_ZERO (&rs);
    151       FD_ZERO (&ws);
    152       FD_ZERO (&es);
    153       mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
    154       if (mret != CURLM_OK)
    155         {
    156           curl_multi_remove_handle (multi, c);
    157           curl_multi_cleanup (multi);
    158           curl_easy_cleanup (c);
    159           MHD_stop_daemon (d);
    160           return 2048;
    161         }
    162       if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
    163         {
    164           curl_multi_remove_handle (multi, c);
    165           curl_multi_cleanup (multi);
    166           curl_easy_cleanup (c);
    167           MHD_stop_daemon (d);
    168           return 4096;
    169         }
    170       tv.tv_sec = 0;
    171       tv.tv_usec = 1000;
    172       select (max + 1, &rs, &ws, &es, &tv);
    173       curl_multi_perform (multi, &running);
    174       if (running == 0)
    175         {
    176           msg = curl_multi_info_read (multi, &running);
    177           if (msg == NULL)
    178             break;
    179           if (msg->msg == CURLMSG_DONE)
    180             {
    181               if (msg->data.result != CURLE_OK)
    182                 printf ("%s failed at %s:%d: `%s'\n",
    183                         "curl_multi_perform",
    184                         __FILE__,
    185                         __LINE__, curl_easy_strerror (msg->data.result));
    186               curl_multi_remove_handle (multi, c);
    187               curl_multi_cleanup (multi);
    188               curl_easy_cleanup (c);
    189               c = NULL;
    190               multi = NULL;
    191             }
    192         }
    193       MHD_run (d);
    194     }
    195   if (multi != NULL)
    196     {
    197       curl_multi_remove_handle (multi, c);
    198       curl_easy_cleanup (c);
    199       curl_multi_cleanup (multi);
    200     }
    201   MHD_stop_daemon (d);
    202   if (cbc.pos != strlen ("/hello_world"))
    203     return 8192;
    204   if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
    205     return 16384;
    206   return 0;
    207 }
    208 
    209 
    210 int
    211 main (int argc, char *const *argv)
    212 {
    213   unsigned int errorCount = 0;
    214 
    215   if (0 != curl_global_init (CURL_GLOBAL_ALL))
    216     {
    217       fprintf (stderr, "Error: %s\n", strerror (errno));
    218       return -1;
    219     }
    220 #if EPOLL_SUPPORT
    221   if (0 != (errorCount = testExternalGet (MHD_USE_EPOLL_LINUX_ONLY)))
    222     fprintf (stderr, "Fail: %d\n", errorCount);
    223 #endif
    224   if (0 != (errorCount = testExternalGet (0)))
    225     fprintf (stderr, "Fail: %d\n", errorCount);
    226   curl_global_cleanup ();
    227   return errorCount != 0;
    228 }
    229