1 2 /* 3 This file is part of libmicrohttpd 4 Copyright (C) 2007 Christian Grothoff 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., 59 Temple Place - Suite 330, 19 Boston, MA 02111-1307, USA. 20 */ 21 22 /** 23 * @file test_parse_cookies.c 24 * @brief Testcase for HTTP cookie parsing 25 * @author Christian Grothoff 26 */ 27 28 #include "MHD_config.h" 29 #include "platform.h" 30 #include <curl/curl.h> 31 #include <microhttpd.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <time.h> 35 36 #ifndef WINDOWS 37 #include <unistd.h> 38 #endif 39 40 static int oneone; 41 42 struct CBC 43 { 44 char *buf; 45 size_t pos; 46 size_t size; 47 }; 48 49 static size_t 50 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 51 { 52 struct CBC *cbc = ctx; 53 54 if (cbc->pos + size * nmemb > cbc->size) 55 return 0; /* overflow */ 56 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 57 cbc->pos += size * nmemb; 58 return size * nmemb; 59 } 60 61 static int 62 ahc_echo (void *cls, 63 struct MHD_Connection *connection, 64 const char *url, 65 const char *method, 66 const char *version, 67 const char *upload_data, size_t *upload_data_size, 68 void **unused) 69 { 70 static int ptr; 71 const char *me = cls; 72 struct MHD_Response *response; 73 int ret; 74 const char *hdr; 75 76 if (0 != strcmp (me, method)) 77 return MHD_NO; /* unexpected method */ 78 if (&ptr != *unused) 79 { 80 *unused = &ptr; 81 return MHD_YES; 82 } 83 *unused = NULL; 84 ret = 0; 85 86 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name1"); 87 if ((hdr == NULL) || (0 != strcmp (hdr, "var1"))) 88 abort (); 89 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name2"); 90 if ((hdr == NULL) || (0 != strcmp (hdr, "var2"))) 91 abort (); 92 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name3"); 93 if ((hdr == NULL) || (0 != strcmp (hdr, ""))) 94 abort (); 95 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name4"); 96 if ((hdr == NULL) || (0 != strcmp (hdr, "var4 with spaces"))) 97 abort (); 98 response = MHD_create_response_from_buffer (strlen (url), 99 (void *) url, 100 MHD_RESPMEM_PERSISTENT); 101 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 102 MHD_destroy_response (response); 103 if (ret == MHD_NO) 104 abort (); 105 return ret; 106 } 107 108 static int 109 testExternalGet () 110 { 111 struct MHD_Daemon *d; 112 CURL *c; 113 char buf[2048]; 114 struct CBC cbc; 115 CURLM *multi; 116 CURLMcode mret; 117 fd_set rs; 118 fd_set ws; 119 fd_set es; 120 MHD_socket max; 121 int running; 122 struct CURLMsg *msg; 123 time_t start; 124 struct timeval tv; 125 126 multi = NULL; 127 cbc.buf = buf; 128 cbc.size = 2048; 129 cbc.pos = 0; 130 d = MHD_start_daemon (MHD_USE_DEBUG, 131 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 132 if (d == NULL) 133 return 256; 134 c = curl_easy_init (); 135 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:21080/hello_world"); 136 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 137 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 138 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); 139 /* note that the string below intentionally uses the 140 various ways cookies can be specified to exercise the 141 parser! Do not change! */ 142 curl_easy_setopt (c, CURLOPT_COOKIE, 143 "name1=var1; name2=var2,name3 ;name4=\"var4 with spaces\";"); 144 if (oneone) 145 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 146 else 147 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 148 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 149 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 150 /* NOTE: use of CONNECTTIMEOUT without also 151 setting NOSIGNAL results in really weird 152 crashes on my system! */ 153 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 154 155 156 multi = curl_multi_init (); 157 if (multi == NULL) 158 { 159 curl_easy_cleanup (c); 160 MHD_stop_daemon (d); 161 return 512; 162 } 163 mret = curl_multi_add_handle (multi, c); 164 if (mret != CURLM_OK) 165 { 166 curl_multi_cleanup (multi); 167 curl_easy_cleanup (c); 168 MHD_stop_daemon (d); 169 return 1024; 170 } 171 start = time (NULL); 172 while ((time (NULL) - start < 5) && (multi != NULL)) 173 { 174 max = 0; 175 FD_ZERO (&rs); 176 FD_ZERO (&ws); 177 FD_ZERO (&es); 178 curl_multi_perform (multi, &running); 179 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); 180 if (mret != CURLM_OK) 181 { 182 curl_multi_remove_handle (multi, c); 183 curl_multi_cleanup (multi); 184 curl_easy_cleanup (c); 185 MHD_stop_daemon (d); 186 return 2048; 187 } 188 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) 189 { 190 curl_multi_remove_handle (multi, c); 191 curl_multi_cleanup (multi); 192 curl_easy_cleanup (c); 193 MHD_stop_daemon (d); 194 return 4096; 195 } 196 tv.tv_sec = 0; 197 tv.tv_usec = 1000; 198 select (max + 1, &rs, &ws, &es, &tv); 199 curl_multi_perform (multi, &running); 200 if (running == 0) 201 { 202 msg = curl_multi_info_read (multi, &running); 203 if (msg == NULL) 204 break; 205 if (msg->msg == CURLMSG_DONE) 206 { 207 if (msg->data.result != CURLE_OK) 208 printf ("%s failed at %s:%d: `%s'\n", 209 "curl_multi_perform", 210 __FILE__, 211 __LINE__, curl_easy_strerror (msg->data.result)); 212 curl_multi_remove_handle (multi, c); 213 curl_multi_cleanup (multi); 214 curl_easy_cleanup (c); 215 c = NULL; 216 multi = NULL; 217 } 218 } 219 MHD_run (d); 220 } 221 if (multi != NULL) 222 { 223 curl_multi_remove_handle (multi, c); 224 curl_easy_cleanup (c); 225 curl_multi_cleanup (multi); 226 } 227 MHD_stop_daemon (d); 228 if (cbc.pos != strlen ("/hello_world")) 229 return 8192; 230 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 231 return 16384; 232 return 0; 233 } 234 235 236 int 237 main (int argc, char *const *argv) 238 { 239 unsigned int errorCount = 0; 240 241 oneone = (NULL != strrchr (argv[0], (int) '/')) ? 242 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0; 243 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 244 return 2; 245 errorCount += testExternalGet (); 246 if (errorCount != 0) 247 fprintf (stderr, "Error (code: %u)\n", errorCount); 248 curl_global_cleanup (); 249 return errorCount != 0; /* 0 == pass */ 250 } 251