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