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