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