1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22#include "test.h" 23#include "memdebug.h" 24 25static const char *HOSTHEADER = "Host: www.host.foo.com"; 26static const char *JAR = "log/jar506"; 27#define THREADS 2 28 29/* struct containing data of a thread */ 30struct Tdata { 31 CURLSH *share; 32 char *url; 33}; 34 35struct userdata { 36 char *text; 37 int counter; 38}; 39 40int lock[3]; 41 42/* lock callback */ 43static void my_lock(CURL *handle, curl_lock_data data, 44 curl_lock_access laccess, void *useptr) 45{ 46 const char *what; 47 struct userdata *user = (struct userdata *)useptr; 48 int locknum; 49 50 (void)handle; 51 (void)laccess; 52 53 switch (data) { 54 case CURL_LOCK_DATA_SHARE: 55 what = "share"; 56 locknum = 0; 57 break; 58 case CURL_LOCK_DATA_DNS: 59 what = "dns"; 60 locknum = 1; 61 break; 62 case CURL_LOCK_DATA_COOKIE: 63 what = "cookie"; 64 locknum = 2; 65 break; 66 default: 67 fprintf(stderr, "lock: no such data: %d\n", (int)data); 68 return; 69 } 70 71 /* detect locking of locked locks */ 72 if(lock[locknum]) { 73 printf("lock: double locked %s\n", what); 74 return; 75 } 76 lock[locknum]++; 77 78 printf("lock: %-6s [%s]: %d\n", what, user->text, user->counter); 79 user->counter++; 80} 81 82/* unlock callback */ 83static void my_unlock(CURL *handle, curl_lock_data data, void *useptr) 84{ 85 const char *what; 86 struct userdata *user = (struct userdata *)useptr; 87 int locknum; 88 (void)handle; 89 switch (data) { 90 case CURL_LOCK_DATA_SHARE: 91 what = "share"; 92 locknum = 0; 93 break; 94 case CURL_LOCK_DATA_DNS: 95 what = "dns"; 96 locknum = 1; 97 break; 98 case CURL_LOCK_DATA_COOKIE: 99 what = "cookie"; 100 locknum = 2; 101 break; 102 default: 103 fprintf(stderr, "unlock: no such data: %d\n", (int)data); 104 return; 105 } 106 107 /* detect unlocking of unlocked locks */ 108 if(!lock[locknum]) { 109 printf("unlock: double unlocked %s\n", what); 110 return; 111 } 112 lock[locknum]--; 113 114 printf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter); 115 user->counter++; 116} 117 118 119/* build host entry */ 120static struct curl_slist *sethost(struct curl_slist *headers) 121{ 122 (void)headers; 123 return curl_slist_append(NULL, HOSTHEADER); 124} 125 126 127/* the dummy thread function */ 128static void *fire(void *ptr) 129{ 130 CURLcode code; 131 struct curl_slist *headers; 132 struct Tdata *tdata = (struct Tdata*)ptr; 133 CURL *curl; 134 int i=0; 135 136 curl = curl_easy_init(); 137 if(!curl) { 138 fprintf(stderr, "curl_easy_init() failed\n"); 139 return NULL; 140 } 141 142 headers = sethost(NULL); 143 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 144 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 145 curl_easy_setopt(curl, CURLOPT_URL, tdata->url); 146 printf("CURLOPT_SHARE\n"); 147 curl_easy_setopt(curl, CURLOPT_SHARE, tdata->share); 148 149 printf("PERFORM\n"); 150 code = curl_easy_perform(curl); 151 if(code) { 152 fprintf(stderr, "perform url '%s' repeat %d failed, curlcode %d\n", 153 tdata->url, i, (int)code); 154 } 155 156 printf("CLEANUP\n"); 157 curl_easy_cleanup(curl); 158 curl_slist_free_all(headers); 159 160 return NULL; 161} 162 163 164/* build request url */ 165static char *suburl(const char *base, int i) 166{ 167 return curl_maprintf("%s%.4d", base, i); 168} 169 170 171/* test function */ 172int test(char *URL) 173{ 174 int res; 175 CURLSHcode scode = CURLSHE_OK; 176 CURLcode code = CURLE_OK; 177 char *url = NULL; 178 struct Tdata tdata; 179 CURL *curl; 180 CURLSH *share; 181 struct curl_slist *headers = NULL; 182 struct curl_slist *cookies = NULL; 183 struct curl_slist *next_cookie = NULL; 184 int i; 185 struct userdata user; 186 187 user.text = (char *)"Pigs in space"; 188 user.counter = 0; 189 190 printf("GLOBAL_INIT\n"); 191 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 192 fprintf(stderr, "curl_global_init() failed\n"); 193 return TEST_ERR_MAJOR_BAD; 194 } 195 196 /* prepare share */ 197 printf("SHARE_INIT\n"); 198 if((share = curl_share_init()) == NULL) { 199 fprintf(stderr, "curl_share_init() failed\n"); 200 curl_global_cleanup(); 201 return TEST_ERR_MAJOR_BAD; 202 } 203 204 if(CURLSHE_OK == scode) { 205 printf("CURLSHOPT_LOCKFUNC\n"); 206 scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock); 207 } 208 if(CURLSHE_OK == scode) { 209 printf("CURLSHOPT_UNLOCKFUNC\n"); 210 scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock); 211 } 212 if(CURLSHE_OK == scode) { 213 printf("CURLSHOPT_USERDATA\n"); 214 scode = curl_share_setopt(share, CURLSHOPT_USERDATA, &user); 215 } 216 if(CURLSHE_OK == scode) { 217 printf("CURL_LOCK_DATA_COOKIE\n"); 218 scode = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); 219 } 220 if(CURLSHE_OK == scode) { 221 printf("CURL_LOCK_DATA_DNS\n"); 222 scode = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); 223 } 224 225 if(CURLSHE_OK != scode) { 226 fprintf(stderr, "curl_share_setopt() failed\n"); 227 curl_share_cleanup(share); 228 curl_global_cleanup(); 229 return TEST_ERR_MAJOR_BAD; 230 } 231 232 /* initial cookie manipulation */ 233 if((curl = curl_easy_init()) == NULL) { 234 fprintf(stderr, "curl_easy_init() failed\n"); 235 curl_share_cleanup(share); 236 curl_global_cleanup(); 237 return TEST_ERR_MAJOR_BAD; 238 } 239 printf("CURLOPT_SHARE\n"); 240 test_setopt(curl, CURLOPT_SHARE, share); 241 printf("CURLOPT_COOKIELIST injected_and_clobbered\n"); 242 test_setopt(curl, CURLOPT_COOKIELIST, 243 "Set-Cookie: injected_and_clobbered=yes; " 244 "domain=host.foo.com; expires=Sat Feb 2 11:56:27 GMT 2030"); 245 printf("CURLOPT_COOKIELIST ALL\n"); 246 test_setopt(curl, CURLOPT_COOKIELIST, "ALL"); 247 printf("CURLOPT_COOKIELIST session\n"); 248 test_setopt(curl, CURLOPT_COOKIELIST, "Set-Cookie: session=elephants"); 249 printf("CURLOPT_COOKIELIST injected\n"); 250 test_setopt(curl, CURLOPT_COOKIELIST, 251 "Set-Cookie: injected=yes; domain=host.foo.com; " 252 "expires=Sat Feb 2 11:56:27 GMT 2030"); 253 printf("CURLOPT_COOKIELIST SESS\n"); 254 test_setopt(curl, CURLOPT_COOKIELIST, "SESS"); 255 printf("CLEANUP\n"); 256 curl_easy_cleanup(curl); 257 258 259 res = 0; 260 261 /* start treads */ 262 for(i=1; i<=THREADS; i++) { 263 264 /* set thread data */ 265 tdata.url = suburl(URL, i); /* must be curl_free()d */ 266 tdata.share = share; 267 268 /* simulate thread, direct call of "thread" function */ 269 printf("*** run %d\n",i); 270 fire(&tdata); 271 272 curl_free(tdata.url); 273 } 274 275 276 /* fetch a another one and save cookies */ 277 printf("*** run %d\n", i); 278 if((curl = curl_easy_init()) == NULL) { 279 fprintf(stderr, "curl_easy_init() failed\n"); 280 curl_share_cleanup(share); 281 curl_global_cleanup(); 282 return TEST_ERR_MAJOR_BAD; 283 } 284 285 url = suburl(URL, i); 286 headers = sethost(NULL); 287 test_setopt(curl, CURLOPT_HTTPHEADER, headers); 288 test_setopt(curl, CURLOPT_URL, url); 289 printf("CURLOPT_SHARE\n"); 290 test_setopt(curl, CURLOPT_SHARE, share); 291 printf("CURLOPT_COOKIEJAR\n"); 292 test_setopt(curl, CURLOPT_COOKIEJAR, JAR); 293 printf("CURLOPT_COOKIELIST FLUSH\n"); 294 test_setopt(curl, CURLOPT_COOKIELIST, "FLUSH"); 295 296 printf("PERFORM\n"); 297 curl_easy_perform(curl); 298 299 printf("CLEANUP\n"); 300 curl_easy_cleanup(curl); 301 curl_free(url); 302 curl_slist_free_all(headers); 303 304 /* load cookies */ 305 if((curl = curl_easy_init()) == NULL) { 306 fprintf(stderr, "curl_easy_init() failed\n"); 307 curl_share_cleanup(share); 308 curl_global_cleanup(); 309 return TEST_ERR_MAJOR_BAD; 310 } 311 url = suburl(URL, i); 312 headers = sethost(NULL); 313 test_setopt(curl, CURLOPT_HTTPHEADER, headers); 314 test_setopt(curl, CURLOPT_URL, url); 315 printf("CURLOPT_SHARE\n"); 316 test_setopt(curl, CURLOPT_SHARE, share); 317 printf("CURLOPT_COOKIELIST ALL\n"); 318 test_setopt(curl, CURLOPT_COOKIELIST, "ALL"); 319 printf("CURLOPT_COOKIEJAR\n"); 320 test_setopt(curl, CURLOPT_COOKIEFILE, JAR); 321 printf("CURLOPT_COOKIELIST RELOAD\n"); 322 test_setopt(curl, CURLOPT_COOKIELIST, "RELOAD"); 323 324 code = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies); 325 if(code != CURLE_OK) { 326 fprintf(stderr, "curl_easy_getinfo() failed\n"); 327 res = TEST_ERR_MAJOR_BAD; 328 goto test_cleanup; 329 } 330 printf("loaded cookies:\n"); 331 if(!cookies) { 332 fprintf(stderr, " reloading cookies from '%s' failed\n", JAR); 333 res = TEST_ERR_MAJOR_BAD; 334 goto test_cleanup; 335 } 336 printf("-----------------\n"); 337 next_cookie = cookies; 338 while(next_cookie) { 339 printf(" %s\n", next_cookie->data); 340 next_cookie = next_cookie->next; 341 } 342 printf("-----------------\n"); 343 curl_slist_free_all(cookies); 344 345 /* try to free share, expect to fail because share is in use*/ 346 printf("try SHARE_CLEANUP...\n"); 347 scode = curl_share_cleanup(share); 348 if(scode==CURLSHE_OK) { 349 fprintf(stderr, "curl_share_cleanup succeed but error expected\n"); 350 share = NULL; 351 } 352 else { 353 printf("SHARE_CLEANUP failed, correct\n"); 354 } 355 356test_cleanup: 357 358 /* clean up last handle */ 359 printf("CLEANUP\n"); 360 curl_easy_cleanup(curl); 361 curl_slist_free_all(headers); 362 curl_free(url); 363 364 /* free share */ 365 printf("SHARE_CLEANUP\n"); 366 scode = curl_share_cleanup(share); 367 if(scode!=CURLSHE_OK) 368 fprintf(stderr, "curl_share_cleanup failed, code errno %d\n", 369 (int)scode); 370 371 printf("GLOBAL_CLEANUP\n"); 372 curl_global_cleanup(); 373 374 return res; 375} 376 377