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