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