1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007 Christian Grothoff 4 5 libmicrohttpd is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 2, or (at your 8 option) any later version. 9 10 libmicrohttpd is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libmicrohttpd; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 Boston, MA 02111-1307, USA. 19 */ 20 21 /** 22 * @file test_https_get_select.c 23 * @brief Testcase for libmicrohttpd HTTPS GET operations 24 * @author Sagie Amir 25 */ 26 27 #include "platform.h" 28 #include "microhttpd.h" 29 #include <limits.h> 30 #include <sys/stat.h> 31 #include <curl/curl.h> 32 #include <gcrypt.h> 33 #include "tls_test_common.h" 34 35 extern const char srv_key_pem[]; 36 extern const char srv_self_signed_cert_pem[]; 37 extern const char srv_signed_cert_pem[]; 38 extern const char srv_signed_key_pem[]; 39 40 static int oneone; 41 42 static int 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 **unused) 50 { 51 static int ptr; 52 const char *me = cls; 53 struct MHD_Response *response; 54 int ret; 55 56 if (0 != strcmp (me, method)) 57 return MHD_NO; /* unexpected method */ 58 if (&ptr != *unused) 59 { 60 *unused = &ptr; 61 return MHD_YES; 62 } 63 *unused = NULL; 64 response = MHD_create_response_from_buffer (strlen (url), 65 (void *) url, 66 MHD_RESPMEM_MUST_COPY); 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 int 76 testExternalGet (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 max; 88 int running; 89 struct CURLMsg *msg; 90 time_t start; 91 struct timeval tv; 92 const char *aes256_sha = "AES256-SHA"; 93 94 multi = NULL; 95 cbc.buf = buf; 96 cbc.size = 2048; 97 cbc.pos = 0; 98 d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL | flags, 99 1082, NULL, NULL, &ahc_echo, "GET", 100 MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, 101 MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, 102 MHD_OPTION_END); 103 if (d == NULL) 104 return 256; 105 106 if (curl_uses_nss_ssl() == 0) 107 aes256_sha = "rsa_aes_256_sha"; 108 109 c = curl_easy_init (); 110 curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1:1082/hello_world"); 111 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 112 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 113 /* TLS options */ 114 curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); 115 curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, aes256_sha); 116 curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); 117 curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); 118 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); 119 if (oneone) 120 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 121 else 122 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 123 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 124 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 125 /* NOTE: use of CONNECTTIMEOUT without also 126 setting NOSIGNAL results in really weird 127 crashes on my system! */ 128 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 129 130 131 multi = curl_multi_init (); 132 if (multi == NULL) 133 { 134 curl_easy_cleanup (c); 135 MHD_stop_daemon (d); 136 return 512; 137 } 138 mret = curl_multi_add_handle (multi, c); 139 if (mret != CURLM_OK) 140 { 141 curl_multi_cleanup (multi); 142 curl_easy_cleanup (c); 143 MHD_stop_daemon (d); 144 return 1024; 145 } 146 start = time (NULL); 147 while ((time (NULL) - start < 5) && (multi != NULL)) 148 { 149 max = 0; 150 FD_ZERO (&rs); 151 FD_ZERO (&ws); 152 FD_ZERO (&es); 153 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); 154 if (mret != CURLM_OK) 155 { 156 curl_multi_remove_handle (multi, c); 157 curl_multi_cleanup (multi); 158 curl_easy_cleanup (c); 159 MHD_stop_daemon (d); 160 return 2048; 161 } 162 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) 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 4096; 169 } 170 tv.tv_sec = 0; 171 tv.tv_usec = 1000; 172 select (max + 1, &rs, &ws, &es, &tv); 173 curl_multi_perform (multi, &running); 174 if (running == 0) 175 { 176 msg = curl_multi_info_read (multi, &running); 177 if (msg == NULL) 178 break; 179 if (msg->msg == CURLMSG_DONE) 180 { 181 if (msg->data.result != CURLE_OK) 182 printf ("%s failed at %s:%d: `%s'\n", 183 "curl_multi_perform", 184 __FILE__, 185 __LINE__, curl_easy_strerror (msg->data.result)); 186 curl_multi_remove_handle (multi, c); 187 curl_multi_cleanup (multi); 188 curl_easy_cleanup (c); 189 c = NULL; 190 multi = NULL; 191 } 192 } 193 MHD_run (d); 194 } 195 if (multi != NULL) 196 { 197 curl_multi_remove_handle (multi, c); 198 curl_easy_cleanup (c); 199 curl_multi_cleanup (multi); 200 } 201 MHD_stop_daemon (d); 202 if (cbc.pos != strlen ("/hello_world")) 203 return 8192; 204 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 205 return 16384; 206 return 0; 207 } 208 209 210 int 211 main (int argc, char *const *argv) 212 { 213 unsigned int errorCount = 0; 214 215 if (0 != curl_global_init (CURL_GLOBAL_ALL)) 216 { 217 fprintf (stderr, "Error: %s\n", strerror (errno)); 218 return -1; 219 } 220 #if EPOLL_SUPPORT 221 if (0 != (errorCount = testExternalGet (MHD_USE_EPOLL_LINUX_ONLY))) 222 fprintf (stderr, "Fail: %d\n", errorCount); 223 #endif 224 if (0 != (errorCount = testExternalGet (0))) 225 fprintf (stderr, "Fail: %d\n", errorCount); 226 curl_global_cleanup (); 227 return errorCount != 0; 228 } 229