Home | History | Annotate | Download | only in libtest
      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   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 */
    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 
    381