test_https_get_select.c (8098B)
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 static int oneone; 41 42 static enum MHD_Result 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 **req_cls) 50 { 51 static int ptr; 52 struct MHD_Response *response; 53 enum MHD_Result ret; 54 (void) cls; 55 (void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 56 57 if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) 58 return MHD_NO; /* unexpected method */ 59 if (&ptr != *req_cls) 60 { 61 *req_cls = &ptr; 62 return MHD_YES; 63 } 64 *req_cls = NULL; 65 response = MHD_create_response_from_buffer_copy (strlen (url), 66 (const void *) url); 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 unsigned int 76 testExternalGet (unsigned 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 maxsock; 88 #ifdef MHD_WINSOCK_SOCKETS 89 int maxposixs; /* Max socket number unused on W32 */ 90 #else /* MHD_POSIX_SOCKETS */ 91 #define maxposixs maxsock 92 #endif /* MHD_POSIX_SOCKETS */ 93 int running; 94 struct CURLMsg *msg; 95 time_t start; 96 struct timeval tv; 97 uint16_t port; 98 99 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 100 port = 0; 101 else 102 port = 3030; 103 104 multi = NULL; 105 cbc.buf = buf; 106 cbc.size = 2048; 107 cbc.pos = 0; 108 d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_TLS | flags, 109 port, NULL, NULL, &ahc_echo, NULL, 110 MHD_OPTION_HTTPS_MEM_KEY, srv_self_signed_key_pem, 111 MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, 112 MHD_OPTION_END); 113 if (d == NULL) 114 return 256; 115 if (0 == port) 116 { 117 const union MHD_DaemonInfo *dinfo; 118 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 119 if ((NULL == dinfo) || (0 == dinfo->port) ) 120 { 121 MHD_stop_daemon (d); return 32; 122 } 123 port = dinfo->port; 124 } 125 126 c = curl_easy_init (); 127 #ifdef _DEBUG 128 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L); 129 #endif 130 curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1/hello_world"); 131 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 132 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 133 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 134 /* TLS options */ 135 curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT); 136 curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L); 137 curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L); 138 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 139 if (oneone) 140 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 141 else 142 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 143 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 144 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 145 /* NOTE: use of CONNECTTIMEOUT without also 146 setting NOSIGNAL results in really weird 147 crashes on my system! */ 148 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 149 150 151 multi = curl_multi_init (); 152 if (multi == NULL) 153 { 154 curl_easy_cleanup (c); 155 MHD_stop_daemon (d); 156 return 512; 157 } 158 mret = curl_multi_add_handle (multi, c); 159 if (mret != CURLM_OK) 160 { 161 curl_multi_cleanup (multi); 162 curl_easy_cleanup (c); 163 MHD_stop_daemon (d); 164 return 1024; 165 } 166 start = time (NULL); 167 while ((time (NULL) - start < 5) && (multi != NULL)) 168 { 169 maxsock = MHD_INVALID_SOCKET; 170 maxposixs = -1; 171 FD_ZERO (&rs); 172 FD_ZERO (&ws); 173 FD_ZERO (&es); 174 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); 175 if (mret != CURLM_OK) 176 { 177 curl_multi_remove_handle (multi, c); 178 curl_multi_cleanup (multi); 179 curl_easy_cleanup (c); 180 MHD_stop_daemon (d); 181 return 2048; 182 } 183 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) 184 { 185 curl_multi_remove_handle (multi, c); 186 curl_multi_cleanup (multi); 187 curl_easy_cleanup (c); 188 MHD_stop_daemon (d); 189 return 4096; 190 } 191 tv.tv_sec = 0; 192 tv.tv_usec = 1000; 193 if (-1 != maxposixs) 194 { 195 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) 196 { 197 #ifdef MHD_POSIX_SOCKETS 198 if (EINTR != errno) 199 abort (); 200 #else 201 if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 != 202 ws. 203 fd_count) 204 || (0 != es.fd_count) ) 205 abort (); 206 Sleep (1000); 207 #endif 208 } 209 } 210 else 211 (void) sleep (1); 212 curl_multi_perform (multi, &running); 213 if (0 == running) 214 { 215 int pending; 216 int curl_fine = 0; 217 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 218 { 219 if (msg->msg == CURLMSG_DONE) 220 { 221 if (msg->data.result == CURLE_OK) 222 curl_fine = 1; 223 else 224 { 225 fprintf (stderr, 226 "%s failed at %s:%d: `%s'\n", 227 "curl_multi_perform", 228 __FILE__, 229 __LINE__, curl_easy_strerror (msg->data.result)); 230 abort (); 231 } 232 } 233 } 234 if (! curl_fine) 235 { 236 fprintf (stderr, "libcurl haven't returned OK code\n"); 237 abort (); 238 } 239 curl_multi_remove_handle (multi, c); 240 curl_multi_cleanup (multi); 241 curl_easy_cleanup (c); 242 c = NULL; 243 multi = NULL; 244 } 245 MHD_run (d); 246 } 247 if (multi != NULL) 248 { 249 curl_multi_remove_handle (multi, c); 250 curl_easy_cleanup (c); 251 curl_multi_cleanup (multi); 252 } 253 MHD_stop_daemon (d); 254 if (cbc.pos != strlen ("/hello_world")) 255 return 8192; 256 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 257 return 16384; 258 return 0; 259 } 260 261 262 int 263 main (int argc, char *const *argv) 264 { 265 unsigned int errorCount = 0; 266 (void) argc; /* Unused. Silent compiler warning. */ 267 268 oneone = 1; 269 if (! testsuite_curl_global_init ()) 270 return 99; 271 if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version) 272 { 273 fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n"); 274 curl_global_cleanup (); 275 return 77; 276 } 277 278 #ifdef EPOLL_SUPPORT 279 errorCount += testExternalGet (MHD_USE_EPOLL); 280 #endif 281 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 282 errorCount += testExternalGet (MHD_NO_FLAG); 283 errorCount += testExternalGet (MHD_USE_NO_THREAD_SAFETY); 284 curl_global_cleanup (); 285 if (errorCount != 0) 286 fprintf (stderr, "Failed test: %s, error: %u.\n", argv[0], errorCount); 287 return errorCount != 0 ? 1 : 0; 288 }