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, ©Buffer); 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 }