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