test_urlparse.c (6045B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2009, 2011 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 daemontest_urlparse.c 24 * @brief Testcase for libmicrohttpd url parsing 25 * @author Christian Grothoff 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 29 #include "MHD_config.h" 30 #include "platform.h" 31 #include <curl/curl.h> 32 #include <microhttpd.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include "mhd_has_in_name.h" 37 38 #ifdef _WIN32 39 #ifndef WIN32_LEAN_AND_MEAN 40 #define WIN32_LEAN_AND_MEAN 1 41 #endif /* !WIN32_LEAN_AND_MEAN */ 42 #include <windows.h> 43 #endif 44 45 #ifndef WINDOWS 46 #include <unistd.h> 47 #include <sys/socket.h> 48 #endif 49 50 static int oneone; 51 52 static int matches; 53 54 struct CBC 55 { 56 char *buf; 57 size_t pos; 58 size_t size; 59 }; 60 61 static size_t 62 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 63 { 64 struct CBC *cbc = ctx; 65 66 if (cbc->pos + size * nmemb > cbc->size) 67 return 0; /* overflow */ 68 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 69 cbc->pos += size * nmemb; 70 return size * nmemb; 71 } 72 73 74 static enum MHD_Result 75 test_values (void *cls, 76 enum MHD_ValueKind kind, 77 const char *key, 78 const char *value) 79 { 80 (void) cls; (void) kind; /* Unused. Silent compiler warning. */ 81 if ( (0 == strcmp (key, "a")) && 82 (0 == strcmp (value, "b")) ) 83 matches += 1; 84 if ( (0 == strcmp (key, "c")) && 85 (0 == strcmp (value, "")) ) 86 matches += 2; 87 if ( (0 == strcmp (key, "d")) && 88 (NULL == value) ) 89 matches += 4; 90 return MHD_YES; 91 } 92 93 94 static enum MHD_Result 95 ahc_echo (void *cls, 96 struct MHD_Connection *connection, 97 const char *url, 98 const char *method, 99 const char *version, 100 const char *upload_data, size_t *upload_data_size, 101 void **req_cls) 102 { 103 static int ptr; 104 struct MHD_Response *response; 105 enum MHD_Result ret; 106 (void) cls; 107 (void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 108 109 if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) 110 return MHD_NO; /* unexpected method */ 111 if (&ptr != *req_cls) 112 { 113 *req_cls = &ptr; 114 return MHD_YES; 115 } 116 MHD_get_connection_values (connection, 117 MHD_GET_ARGUMENT_KIND, 118 &test_values, 119 NULL); 120 *req_cls = NULL; 121 response = MHD_create_response_from_buffer_copy (strlen (url), 122 (const void *) url); 123 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 124 MHD_destroy_response (response); 125 if (ret == MHD_NO) 126 abort (); 127 return ret; 128 } 129 130 131 static unsigned int 132 testInternalGet (uint32_t poll_flag) 133 { 134 struct MHD_Daemon *d; 135 CURL *c; 136 char buf[2048]; 137 struct CBC cbc; 138 CURLcode errornum; 139 uint16_t port; 140 141 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 142 port = 0; 143 else 144 { 145 port = 1510; 146 if (oneone) 147 port += 5; 148 } 149 150 cbc.buf = buf; 151 cbc.size = 2048; 152 cbc.pos = 0; 153 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 154 | (enum MHD_FLAG) poll_flag, 155 port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); 156 if (d == NULL) 157 return 1; 158 if (0 == port) 159 { 160 const union MHD_DaemonInfo *dinfo; 161 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 162 if ((NULL == dinfo) || (0 == dinfo->port) ) 163 { 164 MHD_stop_daemon (d); return 32; 165 } 166 port = dinfo->port; 167 } 168 c = curl_easy_init (); 169 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world?a=b&c=&d"); 170 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 171 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 172 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 173 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 174 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 175 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 176 if (oneone) 177 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 178 else 179 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 180 /* NOTE: use of CONNECTTIMEOUT without also 181 setting NOSIGNAL results in really weird 182 crashes on my system!*/ 183 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 184 if (CURLE_OK != (errornum = curl_easy_perform (c))) 185 { 186 fprintf (stderr, 187 "curl_easy_perform failed: `%s'\n", 188 curl_easy_strerror (errornum)); 189 curl_easy_cleanup (c); 190 MHD_stop_daemon (d); 191 return 2; 192 } 193 curl_easy_cleanup (c); 194 MHD_stop_daemon (d); 195 if (cbc.pos != strlen ("/hello_world")) 196 return 4; 197 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 198 return 8; 199 if (matches != 7) 200 return 16; 201 return 0; 202 } 203 204 205 int 206 main (int argc, char *const *argv) 207 { 208 unsigned int errorCount = 0; 209 (void) argc; /* Unused. Silent compiler warning. */ 210 211 if ((NULL == argv) || (0 == argv[0])) 212 return 99; 213 oneone = has_in_name (argv[0], "11"); 214 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 215 return 2; 216 errorCount += testInternalGet (0); 217 if (errorCount != 0) 218 fprintf (stderr, "Error (code: %u)\n", errorCount); 219 curl_global_cleanup (); 220 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 221 }