test_https_get_select.c (8265B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007 Christian Grothoff 4 Copyright (C) 2014-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 2, 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_select.c 24 * @brief Testcase for libmicrohttpd HTTPS GET operations using external select 25 * @author Sagie Amir 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 29 #include "platform.h" 30 #include "microhttpd.h" 31 #include <limits.h> 32 #include <sys/stat.h> 33 #include <curl/curl.h> 34 #ifdef MHD_HTTPS_REQUIRE_GCRYPT 35 #include <gcrypt.h> 36 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */ 37 #include "tls_test_common.h" 38 #include "tls_test_keys.h" 39 40 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 41 test into a marked, classifiable test error (TESTING.md, P5). */ 42 #include "mhd_panic_tripwire.h" 43 44 static int oneone; 45 46 static enum MHD_Result 47 ahc_echo (void *cls, 48 struct MHD_Connection *connection, 49 const char *url, 50 const char *method, 51 const char *version, 52 const char *upload_data, size_t *upload_data_size, 53 void **req_cls) 54 { 55 static int ptr; 56 struct MHD_Response *response; 57 enum MHD_Result ret; 58 (void) cls; 59 (void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 60 61 if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) 62 return MHD_NO; /* unexpected method */ 63 if (&ptr != *req_cls) 64 { 65 *req_cls = &ptr; 66 return MHD_YES; 67 } 68 *req_cls = NULL; 69 response = MHD_create_response_from_buffer_copy (strlen (url), 70 (const void *) url); 71 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 72 MHD_destroy_response (response); 73 if (ret == MHD_NO) 74 abort (); 75 return ret; 76 } 77 78 79 static unsigned int 80 testExternalGet (unsigned int flags) 81 { 82 struct MHD_Daemon *d; 83 CURL *c; 84 char buf[2048]; 85 struct CBC cbc; 86 CURLM *multi; 87 CURLMcode mret; 88 fd_set rs; 89 fd_set ws; 90 fd_set es; 91 MHD_socket maxsock; 92 #ifdef MHD_WINSOCK_SOCKETS 93 int maxposixs; /* Max socket number unused on W32 */ 94 #else /* MHD_POSIX_SOCKETS */ 95 #define maxposixs maxsock 96 #endif /* MHD_POSIX_SOCKETS */ 97 int running; 98 struct CURLMsg *msg; 99 time_t start; 100 struct timeval tv; 101 uint16_t port; 102 103 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 104 port = 0; 105 else 106 port = 3030; 107 108 multi = NULL; 109 cbc.buf = buf; 110 cbc.size = 2048; 111 cbc.pos = 0; 112 d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_TLS | flags, 113 port, NULL, NULL, &ahc_echo, NULL, 114 MHD_OPTION_HTTPS_MEM_KEY, srv_self_signed_key_pem, 115 MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, 116 MHD_OPTION_END); 117 if (d == NULL) 118 return 256; 119 if (0 == port) 120 { 121 const union MHD_DaemonInfo *dinfo; 122 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 123 if ((NULL == dinfo) || (0 == dinfo->port) ) 124 { 125 MHD_stop_daemon (d); return 32; 126 } 127 port = dinfo->port; 128 } 129 130 c = curl_easy_init (); 131 #ifdef _DEBUG 132 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); 133 #endif 134 curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1/hello_world"); 135 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 136 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 137 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 138 /* TLS options */ 139 curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT); 140 curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L); 141 curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L); 142 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 143 if (oneone) 144 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 145 else 146 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 147 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 148 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 149 /* NOTE: use of CONNECTTIMEOUT without also 150 setting NOSIGNAL results in really weird 151 crashes on my system! */ 152 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 153 154 155 multi = curl_multi_init (); 156 if (multi == NULL) 157 { 158 curl_easy_cleanup (c); 159 MHD_stop_daemon (d); 160 return 512; 161 } 162 mret = curl_multi_add_handle (multi, c); 163 if (mret != CURLM_OK) 164 { 165 curl_multi_cleanup (multi); 166 curl_easy_cleanup (c); 167 MHD_stop_daemon (d); 168 return 1024; 169 } 170 start = time (NULL); 171 while ((time (NULL) - start < 5) && (multi != NULL)) 172 { 173 maxsock = MHD_INVALID_SOCKET; 174 maxposixs = -1; 175 FD_ZERO (&rs); 176 FD_ZERO (&ws); 177 FD_ZERO (&es); 178 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); 179 if (mret != CURLM_OK) 180 { 181 curl_multi_remove_handle (multi, c); 182 curl_multi_cleanup (multi); 183 curl_easy_cleanup (c); 184 MHD_stop_daemon (d); 185 return 2048; 186 } 187 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) 188 { 189 curl_multi_remove_handle (multi, c); 190 curl_multi_cleanup (multi); 191 curl_easy_cleanup (c); 192 MHD_stop_daemon (d); 193 return 4096; 194 } 195 tv.tv_sec = 0; 196 tv.tv_usec = 1000; 197 if (-1 != maxposixs) 198 { 199 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) 200 { 201 #ifdef MHD_POSIX_SOCKETS 202 if (EINTR != errno) 203 abort (); 204 #else 205 if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 != 206 ws. 207 fd_count) 208 || (0 != es.fd_count) ) 209 abort (); 210 Sleep (1000); 211 #endif 212 } 213 } 214 else 215 (void) sleep (1); 216 curl_multi_perform (multi, &running); 217 if (0 == running) 218 { 219 int pending; 220 int curl_fine = 0; 221 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 222 { 223 if (msg->msg == CURLMSG_DONE) 224 { 225 if (msg->data.result == CURLE_OK) 226 curl_fine = 1; 227 else 228 { 229 fprintf (stderr, 230 "%s failed at %s:%d: `%s'\n", 231 "curl_multi_perform", 232 __FILE__, 233 __LINE__, curl_easy_strerror (msg->data.result)); 234 abort (); 235 } 236 } 237 } 238 if (! curl_fine) 239 { 240 fprintf (stderr, "libcurl haven't returned OK code\n"); 241 abort (); 242 } 243 curl_multi_remove_handle (multi, c); 244 curl_multi_cleanup (multi); 245 curl_easy_cleanup (c); 246 c = NULL; 247 multi = NULL; 248 } 249 MHD_run (d); 250 } 251 if (multi != NULL) 252 { 253 curl_multi_remove_handle (multi, c); 254 curl_easy_cleanup (c); 255 curl_multi_cleanup (multi); 256 } 257 MHD_stop_daemon (d); 258 if (cbc.pos != strlen ("/hello_world")) 259 return 8192; 260 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 261 return 16384; 262 return 0; 263 } 264 265 266 int 267 main (int argc, char *const *argv) 268 { 269 unsigned int errorCount = 0; 270 (void) argc; /* Unused. Silent compiler warning. */ 271 272 oneone = 1; 273 if (! testsuite_curl_global_init ()) 274 return 99; 275 if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version) 276 { 277 fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n"); 278 curl_global_cleanup (); 279 return 77; 280 } 281 282 #ifdef EPOLL_SUPPORT 283 errorCount += testExternalGet (MHD_USE_EPOLL); 284 #endif 285 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 286 errorCount += testExternalGet (MHD_NO_FLAG); 287 errorCount += testExternalGet (MHD_USE_NO_THREAD_SAFETY); 288 curl_global_cleanup (); 289 if (errorCount != 0) 290 fprintf (stderr, "Failed test: %s, error: %u.\n", argv[0], errorCount); 291 return errorCount != 0 ? 1 : 0; 292 }