1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, 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 http://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 char *text; 37 int counter; 38 }; 39 40 int lock[3]; 41 42 /* lock callback */ 43 static void my_lock(CURL *handle, curl_lock_data data, curl_lock_access laccess, 44 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 */ 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(!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 */ 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 int i=0; 135 136 if ((curl = curl_easy_init()) == NULL) { 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 != CURLE_OK ) { 151 fprintf(stderr, "perform url '%s' repeat %d failed, curlcode %d\n", 152 tdata->url, i, (int)code); 153 } 154 155 printf( "CLEANUP\n" ); 156 curl_easy_cleanup(curl); 157 curl_slist_free_all(headers); 158 159 return NULL; 160 } 161 162 163 /* build request url */ 164 static char *suburl(const char *base, int i) 165 { 166 return curl_maprintf("%s%.4d", base, i); 167 } 168 169 170 /* test function */ 171 int test(char *URL) 172 { 173 int res; 174 CURLSHcode scode = CURLSHE_OK; 175 CURLcode code = CURLE_OK; 176 char *url = NULL; 177 struct Tdata tdata; 178 CURL *curl; 179 CURLSH *share; 180 struct curl_slist *headers = NULL; 181 struct curl_slist *cookies = NULL; 182 struct curl_slist *next_cookie = NULL; 183 int i; 184 struct userdata user; 185 186 user.text = (char *)"Pigs in space"; 187 user.counter = 0; 188 189 printf( "GLOBAL_INIT\n" ); 190 if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 191 fprintf(stderr, "curl_global_init() failed\n"); 192 return TEST_ERR_MAJOR_BAD; 193 } 194 195 /* prepare share */ 196 printf( "SHARE_INIT\n" ); 197 if ((share = curl_share_init()) == NULL) { 198 fprintf(stderr, "curl_share_init() failed\n"); 199 curl_global_cleanup(); 200 return TEST_ERR_MAJOR_BAD; 201 } 202 203 if ( CURLSHE_OK == scode ) { 204 printf( "CURLSHOPT_LOCKFUNC\n" ); 205 scode = curl_share_setopt( share, CURLSHOPT_LOCKFUNC, my_lock); 206 } 207 if ( CURLSHE_OK == scode ) { 208 printf( "CURLSHOPT_UNLOCKFUNC\n" ); 209 scode = curl_share_setopt( share, CURLSHOPT_UNLOCKFUNC, my_unlock); 210 } 211 if ( CURLSHE_OK == scode ) { 212 printf( "CURLSHOPT_USERDATA\n" ); 213 scode = curl_share_setopt( share, CURLSHOPT_USERDATA, &user); 214 } 215 if ( CURLSHE_OK == scode ) { 216 printf( "CURL_LOCK_DATA_COOKIE\n" ); 217 scode = curl_share_setopt( share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); 218 } 219 if ( CURLSHE_OK == scode ) { 220 printf( "CURL_LOCK_DATA_DNS\n" ); 221 scode = curl_share_setopt( share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); 222 } 223 224 if ( CURLSHE_OK != scode ) { 225 fprintf(stderr, "curl_share_setopt() failed\n"); 226 curl_share_cleanup(share); 227 curl_global_cleanup(); 228 return TEST_ERR_MAJOR_BAD; 229 } 230 231 /* initial cookie manipulation */ 232 if ((curl = curl_easy_init()) == NULL) { 233 fprintf(stderr, "curl_easy_init() failed\n"); 234 curl_share_cleanup(share); 235 curl_global_cleanup(); 236 return TEST_ERR_MAJOR_BAD; 237 } 238 printf( "CURLOPT_SHARE\n" ); 239 test_setopt( curl, CURLOPT_SHARE, share ); 240 printf( "CURLOPT_COOKIELIST injected_and_clobbered\n" ); 241 test_setopt( curl, CURLOPT_COOKIELIST, 242 "Set-Cookie: injected_and_clobbered=yes; " 243 "domain=host.foo.com; expires=Sat Feb 2 11:56:27 GMT 2030" ); 244 printf( "CURLOPT_COOKIELIST ALL\n" ); 245 test_setopt( curl, CURLOPT_COOKIELIST, "ALL" ); 246 printf( "CURLOPT_COOKIELIST session\n" ); 247 test_setopt( curl, CURLOPT_COOKIELIST, "Set-Cookie: session=elephants" ); 248 printf( "CURLOPT_COOKIELIST injected\n" ); 249 test_setopt( curl, CURLOPT_COOKIELIST, 250 "Set-Cookie: injected=yes; domain=host.foo.com; " 251 "expires=Sat Feb 2 11:56:27 GMT 2030" ); 252 printf( "CURLOPT_COOKIELIST SESS\n" ); 253 test_setopt( curl, CURLOPT_COOKIELIST, "SESS" ); 254 printf( "CLEANUP\n" ); 255 curl_easy_cleanup( curl ); 256 257 258 res = 0; 259 260 /* start treads */ 261 for (i=1; i<=THREADS; i++ ) { 262 263 /* set thread data */ 264 tdata.url = suburl( URL, i ); /* must be curl_free()d */ 265 tdata.share = share; 266 267 /* simulate thread, direct call of "thread" function */ 268 printf( "*** run %d\n",i ); 269 fire( &tdata ); 270 271 curl_free( tdata.url ); 272 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 { 327 fprintf(stderr, "curl_easy_getinfo() failed\n"); 328 res = TEST_ERR_MAJOR_BAD; 329 goto test_cleanup; 330 } 331 printf("loaded cookies:\n"); 332 if ( !cookies ) 333 { 334 fprintf(stderr, " reloading cookies from '%s' failed\n", JAR); 335 res = TEST_ERR_MAJOR_BAD; 336 goto test_cleanup; 337 } 338 printf("-----------------\n"); 339 next_cookie = cookies; 340 while ( next_cookie ) 341 { 342 printf( " %s\n", next_cookie->data ); 343 next_cookie = next_cookie->next; 344 } 345 printf("-----------------\n"); 346 curl_slist_free_all( cookies ); 347 348 /* try to free share, expect to fail because share is in use*/ 349 printf( "try SHARE_CLEANUP...\n" ); 350 scode = curl_share_cleanup( share ); 351 if ( scode==CURLSHE_OK ) 352 { 353 fprintf(stderr, "curl_share_cleanup succeed but error expected\n"); 354 share = NULL; 355 } else { 356 printf( "SHARE_CLEANUP failed, correct\n" ); 357 } 358 359 test_cleanup: 360 361 /* clean up last handle */ 362 printf( "CLEANUP\n" ); 363 curl_easy_cleanup( curl ); 364 curl_slist_free_all( headers ); 365 curl_free(url); 366 367 /* free share */ 368 printf( "SHARE_CLEANUP\n" ); 369 scode = curl_share_cleanup( share ); 370 if ( scode!=CURLSHE_OK ) 371 fprintf(stderr, "curl_share_cleanup failed, code errno %d\n", 372 (int)scode); 373 374 printf( "GLOBAL_CLEANUP\n" ); 375 curl_global_cleanup(); 376 377 return res; 378 } 379 380