1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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 25 static const char *HOSTHEADER = "Host: www.host.foo.com"; 26 static const char *JAR = "log/jar506"; 27 #define THREADS 2 28 29 /* struct containing data of a thread */ 30 struct Tdata { 31 CURLSH *share; 32 char *url; 33 }; 34 35 struct userdata { 36 const char *text; 37 int counter; 38 }; 39 40 static int locks[3]; 41 42 /* lock callback */ 43 static 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(locks[locknum]) { 73 printf("lock: double locked %s\n", what); 74 return; 75 } 76 locks[locknum]++; 77 78 printf("lock: %-6s [%s]: %d\n", what, user->text, user->counter); 79 user->counter++; 80 } 81 82 /* unlock callback */ 83 static 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(!locks[locknum]) { 109 printf("unlock: double unlocked %s\n", what); 110 return; 111 } 112 locks[locknum]--; 113 114 printf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter); 115 user->counter++; 116 } 117 118 119 /* build host entry */ 120 static 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 */ 128 static void *fire(void *ptr) 129 { 130 CURLcode code; 131 struct curl_slist *headers; 132 struct Tdata *tdata = (struct Tdata*)ptr; 133 CURL *curl; 134 135 curl = curl_easy_init(); 136 if(!curl) { 137 fprintf(stderr, "curl_easy_init() failed\n"); 138 return NULL; 139 } 140 141 headers = sethost(NULL); 142 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 143 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 144 curl_easy_setopt(curl, CURLOPT_URL, tdata->url); 145 printf("CURLOPT_SHARE\n"); 146 curl_easy_setopt(curl, CURLOPT_SHARE, tdata->share); 147 148 printf("PERFORM\n"); 149 code = curl_easy_perform(curl); 150 if(code) { 151 int i = 0; 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 */ 165 static char *suburl(const char *base, int i) 166 { 167 return curl_maprintf("%s%.4d", base, i); 168 } 169 170 171 /* test function */ 172 int 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 = "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 share = curl_share_init(); 199 if(!share) { 200 fprintf(stderr, "curl_share_init() failed\n"); 201 curl_global_cleanup(); 202 return TEST_ERR_MAJOR_BAD; 203 } 204 205 if(CURLSHE_OK == scode) { 206 printf("CURLSHOPT_LOCKFUNC\n"); 207 scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock); 208 } 209 if(CURLSHE_OK == scode) { 210 printf("CURLSHOPT_UNLOCKFUNC\n"); 211 scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock); 212 } 213 if(CURLSHE_OK == scode) { 214 printf("CURLSHOPT_USERDATA\n"); 215 scode = curl_share_setopt(share, CURLSHOPT_USERDATA, &user); 216 } 217 if(CURLSHE_OK == scode) { 218 printf("CURL_LOCK_DATA_COOKIE\n"); 219 scode = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); 220 } 221 if(CURLSHE_OK == scode) { 222 printf("CURL_LOCK_DATA_DNS\n"); 223 scode = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); 224 } 225 226 if(CURLSHE_OK != scode) { 227 fprintf(stderr, "curl_share_setopt() failed\n"); 228 curl_share_cleanup(share); 229 curl_global_cleanup(); 230 return TEST_ERR_MAJOR_BAD; 231 } 232 233 /* initial cookie manipulation */ 234 curl = curl_easy_init(); 235 if(!curl) { 236 fprintf(stderr, "curl_easy_init() failed\n"); 237 curl_share_cleanup(share); 238 curl_global_cleanup(); 239 return TEST_ERR_MAJOR_BAD; 240 } 241 printf("CURLOPT_SHARE\n"); 242 test_setopt(curl, CURLOPT_SHARE, share); 243 printf("CURLOPT_COOKIELIST injected_and_clobbered\n"); 244 test_setopt(curl, CURLOPT_COOKIELIST, 245 "Set-Cookie: injected_and_clobbered=yes; " 246 "domain=host.foo.com; expires=Sat Feb 2 11:56:27 GMT 2030"); 247 printf("CURLOPT_COOKIELIST ALL\n"); 248 test_setopt(curl, CURLOPT_COOKIELIST, "ALL"); 249 printf("CURLOPT_COOKIELIST session\n"); 250 test_setopt(curl, CURLOPT_COOKIELIST, "Set-Cookie: session=elephants"); 251 printf("CURLOPT_COOKIELIST injected\n"); 252 test_setopt(curl, CURLOPT_COOKIELIST, 253 "Set-Cookie: injected=yes; domain=host.foo.com; " 254 "expires=Sat Feb 2 11:56:27 GMT 2030"); 255 printf("CURLOPT_COOKIELIST SESS\n"); 256 test_setopt(curl, CURLOPT_COOKIELIST, "SESS"); 257 printf("CLEANUP\n"); 258 curl_easy_cleanup(curl); 259 260 261 res = 0; 262 263 /* start treads */ 264 for(i = 1; i <= THREADS; i++) { 265 266 /* set thread data */ 267 tdata.url = suburl(URL, i); /* must be curl_free()d */ 268 tdata.share = share; 269 270 /* simulate thread, direct call of "thread" function */ 271 printf("*** run %d\n",i); 272 fire(&tdata); 273 274 curl_free(tdata.url); 275 } 276 277 278 /* fetch a another one and save cookies */ 279 printf("*** run %d\n", i); 280 curl = curl_easy_init(); 281 if(!curl) { 282 fprintf(stderr, "curl_easy_init() failed\n"); 283 curl_share_cleanup(share); 284 curl_global_cleanup(); 285 return TEST_ERR_MAJOR_BAD; 286 } 287 288 url = suburl(URL, i); 289 headers = sethost(NULL); 290 test_setopt(curl, CURLOPT_HTTPHEADER, headers); 291 test_setopt(curl, CURLOPT_URL, url); 292 printf("CURLOPT_SHARE\n"); 293 test_setopt(curl, CURLOPT_SHARE, share); 294 printf("CURLOPT_COOKIEJAR\n"); 295 test_setopt(curl, CURLOPT_COOKIEJAR, JAR); 296 printf("CURLOPT_COOKIELIST FLUSH\n"); 297 test_setopt(curl, CURLOPT_COOKIELIST, "FLUSH"); 298 299 printf("PERFORM\n"); 300 curl_easy_perform(curl); 301 302 printf("CLEANUP\n"); 303 curl_easy_cleanup(curl); 304 curl_free(url); 305 curl_slist_free_all(headers); 306 307 /* load cookies */ 308 curl = curl_easy_init(); 309 if(!curl) { 310 fprintf(stderr, "curl_easy_init() failed\n"); 311 curl_share_cleanup(share); 312 curl_global_cleanup(); 313 return TEST_ERR_MAJOR_BAD; 314 } 315 url = suburl(URL, i); 316 headers = sethost(NULL); 317 test_setopt(curl, CURLOPT_HTTPHEADER, headers); 318 test_setopt(curl, CURLOPT_URL, url); 319 printf("CURLOPT_SHARE\n"); 320 test_setopt(curl, CURLOPT_SHARE, share); 321 printf("CURLOPT_COOKIELIST ALL\n"); 322 test_setopt(curl, CURLOPT_COOKIELIST, "ALL"); 323 printf("CURLOPT_COOKIEJAR\n"); 324 test_setopt(curl, CURLOPT_COOKIEFILE, JAR); 325 printf("CURLOPT_COOKIELIST RELOAD\n"); 326 test_setopt(curl, CURLOPT_COOKIELIST, "RELOAD"); 327 328 code = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies); 329 if(code != CURLE_OK) { 330 fprintf(stderr, "curl_easy_getinfo() failed\n"); 331 res = TEST_ERR_MAJOR_BAD; 332 goto test_cleanup; 333 } 334 printf("loaded cookies:\n"); 335 if(!cookies) { 336 fprintf(stderr, " reloading cookies from '%s' failed\n", JAR); 337 res = TEST_ERR_MAJOR_BAD; 338 goto test_cleanup; 339 } 340 printf("-----------------\n"); 341 next_cookie = cookies; 342 while(next_cookie) { 343 printf(" %s\n", next_cookie->data); 344 next_cookie = next_cookie->next; 345 } 346 printf("-----------------\n"); 347 curl_slist_free_all(cookies); 348 349 /* try to free share, expect to fail because share is in use*/ 350 printf("try SHARE_CLEANUP...\n"); 351 scode = curl_share_cleanup(share); 352 if(scode == CURLSHE_OK) { 353 fprintf(stderr, "curl_share_cleanup succeed but error expected\n"); 354 share = NULL; 355 } 356 else { 357 printf("SHARE_CLEANUP failed, correct\n"); 358 } 359 360 test_cleanup: 361 362 /* clean up last handle */ 363 printf("CLEANUP\n"); 364 curl_easy_cleanup(curl); 365 curl_slist_free_all(headers); 366 curl_free(url); 367 368 /* free share */ 369 printf("SHARE_CLEANUP\n"); 370 scode = curl_share_cleanup(share); 371 if(scode != CURLSHE_OK) 372 fprintf(stderr, "curl_share_cleanup failed, code errno %d\n", 373 (int)scode); 374 375 printf("GLOBAL_CLEANUP\n"); 376 curl_global_cleanup(); 377 378 return res; 379 } 380