blob: f6f842f6679f689f066e6835b789b62591d8f6ea [file] [log] [blame]
Daniel Stenbergba4e69b2002-09-03 11:52:59 +00001/***************************************************************************
Daniel Stenberg24dee482001-01-03 09:29:33 +00002 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Daniel Stenberg053f6c82004-01-07 09:19:33 +00008 * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
Daniel Stenberg24dee482001-01-03 09:29:33 +00009 *
Daniel Stenbergba4e69b2002-09-03 11:52:59 +000010 * 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 *
Daniel Stenberg24dee482001-01-03 09:29:33 +000014 * 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
Daniel Stenbergba4e69b2002-09-03 11:52:59 +000016 * furnished to do so, under the terms of the COPYING file.
Daniel Stenberg24dee482001-01-03 09:29:33 +000017 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * $Id$
Daniel Stenbergba4e69b2002-09-03 11:52:59 +000022 ***************************************************************************/
Daniel Stenbergae1912c1999-12-29 14:20:26 +000023
24/***
25
26
27RECEIVING COOKIE INFORMATION
28============================
29
30struct CookieInfo *cookie_init(char *file);
31
32 Inits a cookie struct to store data in a local file. This is always
33 called before any cookies are set.
34
35int cookies_set(struct CookieInfo *cookie, char *cookie_line);
36
37 The 'cookie_line' parameter is a full "Set-cookie:" line as
38 received from a server.
39
40 The function need to replace previously stored lines that this new
41 line superceeds.
42
43 It may remove lines that are expired.
44
45 It should return an indication of success/error.
46
47
48SENDING COOKIE INFORMATION
49==========================
50
51struct Cookies *cookie_getlist(struct CookieInfo *cookie,
52 char *host, char *path, bool secure);
53
54 For a given host and path, return a linked list of cookies that
55 the client should send to the server if used now. The secure
56 boolean informs the cookie if a secure connection is achieved or
57 not.
58
59 It shall only return cookies that haven't expired.
60
61
62Example set of cookies:
63
64 Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
65 Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
66 domain=.fidelity.com; path=/ftgw; secure
67 Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
68 domain=.fidelity.com; path=/; secure
69 Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
70 domain=.fidelity.com; path=/; secure
71 Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
72 domain=.fidelity.com; path=/; secure
73 Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
74 domain=.fidelity.com; path=/; secure
75 Set-cookie:
76 Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
77 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
78****/
79
Sterling Hughesad6fca22003-03-31 15:59:17 +000080
Daniel Stenbergb6e18f22000-08-24 14:26:33 +000081#include "setup.h"
82
Daniel Stenberg08ef2082002-06-11 11:13:01 +000083#ifndef CURL_DISABLE_HTTP
84
Daniel Stenbergae1912c1999-12-29 14:20:26 +000085#include <stdlib.h>
86#include <string.h>
87#include <ctype.h>
88
Daniel Stenberg168703b2003-08-11 09:55:11 +000089#include "urldata.h"
Daniel Stenbergae1912c1999-12-29 14:20:26 +000090#include "cookie.h"
Daniel Stenbergae1912c1999-12-29 14:20:26 +000091#include "getdate.h"
Daniel Stenberg96dde762000-05-22 14:12:12 +000092#include "strequal.h"
Daniel Stenberg870bacd2001-05-30 11:06:56 +000093#include "strtok.h"
Daniel Stenberg168703b2003-08-11 09:55:11 +000094#include "sendf.h"
Daniel Stenbergae1912c1999-12-29 14:20:26 +000095
Daniel Stenberg0f8facb2000-10-09 11:12:34 +000096/* The last #include file should be: */
Daniel Stenberg2bd71d72003-06-26 06:50:32 +000097#ifdef CURLDEBUG
Daniel Stenberg0f8facb2000-10-09 11:12:34 +000098#include "memdebug.h"
99#endif
100
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000101static void
102free_cookiemess(struct Cookie *co)
103{
104 if(co->domain)
105 free(co->domain);
106 if(co->path)
107 free(co->path);
108 if(co->name)
109 free(co->name);
110 if(co->value)
111 free(co->value);
112
113 free(co);
114}
115
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000116static bool tailmatch(const char *little, const char *bigone)
117{
118 unsigned int littlelen = strlen(little);
119 unsigned int biglen = strlen(bigone);
120
121 if(littlelen > biglen)
122 return FALSE;
123
124 return strequal(little, bigone+biglen-littlelen);
125}
126
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000127/****************************************************************************
128 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000129 * Curl_cookie_add()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000130 *
131 * Add a single cookie line to the cookie keeping object.
132 *
133 ***************************************************************************/
134
Daniel Stenberg40311042001-01-05 10:11:41 +0000135struct Cookie *
Daniel Stenberg168703b2003-08-11 09:55:11 +0000136Curl_cookie_add(struct SessionHandle *data,
137 /* The 'data' pointer here may be NULL at times, and thus
138 must only be used very carefully for things that can deal
139 with data being NULL. Such as infof() and similar */
140
141 struct CookieInfo *c,
Daniel Stenberg40311042001-01-05 10:11:41 +0000142 bool httpheader, /* TRUE if HTTP header-style line */
Daniel Stenbergd8b2c812002-07-29 22:22:49 +0000143 char *lineptr, /* first character of the line */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000144 char *domain, /* default domain */
145 char *path) /* full path used when this cookie is set,
146 used to get default path for the cookie
147 unless set */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000148{
149 struct Cookie *clist;
150 char what[MAX_COOKIE_LINE];
151 char name[MAX_NAME];
152 char *ptr;
153 char *semiptr;
154 struct Cookie *co;
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000155 struct Cookie *lastc=NULL;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000156 time_t now = time(NULL);
157 bool replace_old = FALSE;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000158 bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000159
160 /* First, alloc and init a new struct for it */
161 co = (struct Cookie *)malloc(sizeof(struct Cookie));
162 if(!co)
163 return NULL; /* bail out if we're this low on memory */
164
165 /* clear the whole struct first */
166 memset(co, 0, sizeof(struct Cookie));
167
168 if(httpheader) {
169 /* This line was read off a HTTP-header */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000170 char *sep;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000171 semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
Daniel Stenbergd8b2c812002-07-29 22:22:49 +0000172
173 while(*lineptr && isspace((int)*lineptr))
174 lineptr++;
175
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000176 ptr = lineptr;
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000177 do {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000178 /* we have a <what>=<this> pair or a 'secure' word here */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000179 sep = strchr(ptr, '=');
180 if(sep && (!semiptr || (semiptr>sep)) ) {
181 /*
182 * There is a = sign and if there was a semicolon too, which make sure
183 * that the semicolon comes _after_ the equal sign.
184 */
185
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000186 name[0]=what[0]=0; /* init the buffers */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000187 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
Daniel Stenberg3612c372002-02-27 07:38:04 +0000188 MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000189 name, what)) {
Daniel Stenberg3612c372002-02-27 07:38:04 +0000190 /* this is a <name>=<what> pair */
191
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000192 char *whatptr;
193
Daniel Stenberg3612c372002-02-27 07:38:04 +0000194 /* Strip off trailing whitespace from the 'what' */
195 int len=strlen(what);
196 while(len && isspace((int)what[len-1])) {
197 what[len-1]=0;
198 len--;
199 }
200
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000201 /* Skip leading whitespace from the 'what' */
202 whatptr=what;
203 while(isspace((int)*whatptr)) {
204 whatptr++;
205 }
206
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000207 if(strequal("path", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000208 co->path=strdup(whatptr);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000209 }
210 else if(strequal("domain", name)) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000211 /* note that this name may or may not have a preceeding dot, but
212 we don't care about that, we treat the names the same anyway */
213
214 char *ptr=whatptr;
215 int dotcount=1;
216 unsigned int i;
217
218 static const char *seventhree[]= {
219 "com", "edu", "net", "org", "gov", "mil", "int"
220 };
221
222 /* Count the dots, we need to make sure that there are THREE dots
223 in the normal domains, or TWO in the seventhree-domains. */
224
225 if('.' == whatptr[0])
226 /* don't count the initial dot, assume it */
227 ptr++;
228
229 do {
230 ptr = strchr(ptr, '.');
231 if(ptr) {
232 ptr++;
233 dotcount++;
234 }
235 } while(ptr);
236
237 for(i=0;
238 i<sizeof(seventhree)/sizeof(seventhree[0]); i++) {
239 if(tailmatch(seventhree[i], whatptr)) {
240 dotcount++; /* we allow one dot less for these */
241 break;
242 }
243 }
Daniel Stenberg98ee12b2003-08-04 23:05:57 +0000244 /* The original Netscape cookie spec defined that this domain name
245 MUST have three dots (or two if one of the seven holy TLDs),
246 but it seems that these kinds of cookies are in use "out there"
247 so we cannot be that strict. I've therefore lowered the check
248 to not allow less than two dots. */
249
250 if(dotcount < 2) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000251 /* Received and skipped a cookie with a domain using too few
252 dots. */
253 badcookie=TRUE; /* mark this as a bad cookie */
Daniel Stenberg168703b2003-08-11 09:55:11 +0000254 infof(data, "skipped cookie with illegal dotcount domain: %s",
255 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000256 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000257 else {
258 /* Now, we make sure that our host is within the given domain,
259 or the given domain is not valid and thus cannot be set. */
260
261 if(!domain || tailmatch(whatptr, domain)) {
Daniel Stenberg465de792003-05-15 22:28:19 +0000262 char *ptr=whatptr;
263 if(ptr[0] == '.')
264 ptr++;
265 co->domain=strdup(ptr); /* dont prefix with dots internally */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000266 co->tailmatch=TRUE; /* we always do that if the domain name was
267 given */
268 }
Daniel Stenberg465de792003-05-15 22:28:19 +0000269 else {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000270 /* we did not get a tailmatch and then the attempted set domain
271 is not a domain to which the current host belongs. Mark as
272 bad. */
273 badcookie=TRUE;
Daniel Stenberg168703b2003-08-11 09:55:11 +0000274 infof(data, "skipped cookie with bad tailmatch domain: %s",
275 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000276 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000277 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000278 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000279 else if(strequal("version", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000280 co->version=strdup(whatptr);
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000281 }
282 else if(strequal("max-age", name)) {
283 /* Defined in RFC2109:
284
285 Optional. The Max-Age attribute defines the lifetime of the
286 cookie, in seconds. The delta-seconds value is a decimal non-
287 negative integer. After delta-seconds seconds elapse, the
288 client should discard the cookie. A value of zero means the
289 cookie should be discarded immediately.
290
291 */
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000292 co->maxage = strdup(whatptr);
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000293 co->expires =
Daniel Stenberg3612c372002-02-27 07:38:04 +0000294 atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000295 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000296 else if(strequal("expires", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000297 co->expirestr=strdup(whatptr);
Daniel Stenberg96dde762000-05-22 14:12:12 +0000298 co->expires = curl_getdate(what, &now);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000299 }
300 else if(!co->name) {
301 co->name = strdup(name);
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000302 co->value = strdup(whatptr);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000303 }
Daniel Stenbergc8926132001-08-14 08:17:29 +0000304 /*
305 else this is the second (or more) name we don't know
306 about! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000307 }
308 else {
309 /* this is an "illegal" <what>=<this> pair */
310 }
311 }
312 else {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000313 if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000314 what)) {
315 if(strequal("secure", what))
316 co->secure = TRUE;
Daniel Stenbergc8926132001-08-14 08:17:29 +0000317 /* else,
318 unsupported keyword without assign! */
319
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000320 }
321 }
Daniel Stenberga23a8972002-02-26 13:07:53 +0000322 if(!semiptr || !*semiptr) {
323 /* we already know there are no more cookies */
324 semiptr = NULL;
325 continue;
326 }
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000327
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000328 ptr=semiptr+1;
329 while(ptr && *ptr && isspace((int)*ptr))
330 ptr++;
331 semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
Daniel Stenberg87037132002-01-07 23:05:36 +0000332
333 if(!semiptr && *ptr)
334 /* There are no more semicolons, but there's a final name=value pair
335 coming up */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000336 semiptr=strchr(ptr, '\0');
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000337 } while(semiptr);
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000338
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000339 if(badcookie || (NULL == co->name)) {
340 /* we didn't get a cookie name or a bad one,
341 this is an illegal line, bail out */
342 if(co->expirestr)
343 free(co->expirestr);
Daniel Stenberga23a8972002-02-26 13:07:53 +0000344 if(co->domain)
345 free(co->domain);
346 if(co->path)
347 free(co->path);
348 if(co->name)
349 free(co->name);
350 if(co->value)
351 free(co->value);
352 free(co);
353 return NULL;
354 }
355
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000356 if(NULL == co->domain)
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000357 /* no domain was given in the header line, set the default now */
Daniel Stenberg6d359842001-10-30 12:08:17 +0000358 co->domain=domain?strdup(domain):NULL;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000359 if((NULL == co->path) && path) {
360 /* no path was given in the header line, set the default now */
361 char *endslash = strrchr(path, '/');
362 if(endslash) {
363 int pathlen = endslash-path+1; /* include the ending slash */
364 co->path=malloc(pathlen+1); /* one extra for the zero byte */
365 if(co->path) {
366 memcpy(co->path, path, pathlen);
367 co->path[pathlen]=0; /* zero terminate */
368 }
369 }
370 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000371 }
372 else {
373 /* This line is NOT a HTTP header style line, we do offer support for
374 reading the odd netscape cookies-file format here */
375 char *firstptr;
Daniel Stenbergd5676592001-05-29 19:17:39 +0000376 char *tok_buf;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000377 int fields;
378
379 if(lineptr[0]=='#') {
380 /* don't even try the comments */
381 free(co);
382 return NULL;
383 }
384 /* strip off the possible end-of-line characters */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000385 ptr=strchr(lineptr, '\r');
386 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000387 *ptr=0; /* clear it */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000388 ptr=strchr(lineptr, '\n');
389 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000390 *ptr=0; /* clear it */
391
Daniel Stenbergd5676592001-05-29 19:17:39 +0000392 firstptr=strtok_r(lineptr, "\t", &tok_buf); /* first tokenize it on the TAB */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000393
394 /* Here's a quick check to eliminate normal HTTP-headers from this */
395 if(!firstptr || strchr(firstptr, ':')) {
396 free(co);
397 return NULL;
398 }
399
400 /* Now loop through the fields and init the struct we already have
401 allocated */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000402 for(ptr=firstptr, fields=0; ptr;
403 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000404 switch(fields) {
405 case 0:
Daniel Stenberg465de792003-05-15 22:28:19 +0000406 if(ptr[0]=='.') /* skip preceeding dots */
407 ptr++;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000408 co->domain = strdup(ptr);
409 break;
410 case 1:
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000411 /* This field got its explanation on the 23rd of May 2001 by
412 Andrés García:
413
414 flag: A TRUE/FALSE value indicating if all machines within a given
415 domain can access the variable. This value is set automatically by
416 the browser, depending on the value you set for the domain.
417
418 As far as I can see, it is set to true when the cookie says
419 .domain.com and to false when the domain is complete www.domain.com
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000420 */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000421 co->tailmatch=strequal(ptr, "TRUE"); /* store information */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000422 break;
423 case 2:
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000424 /* It turns out, that sometimes the file format allows the path
425 field to remain not filled in, we try to detect this and work
426 around it! Andrés García made us aware of this... */
427 if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
428 /* only if the path doesn't look like a boolean option! */
429 co->path = strdup(ptr);
430 break;
431 }
432 /* this doesn't look like a path, make one up! */
433 co->path = strdup("/");
434 fields++; /* add a field and fall down to secure */
435 /* FALLTHROUGH */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000436 case 3:
437 co->secure = strequal(ptr, "TRUE");
438 break;
439 case 4:
440 co->expires = atoi(ptr);
441 break;
442 case 5:
443 co->name = strdup(ptr);
444 break;
445 case 6:
446 co->value = strdup(ptr);
447 break;
448 }
449 }
450
Daniel Stenberg168703b2003-08-11 09:55:11 +0000451 if(6 == fields) {
452 /* we got a cookie with blank contents, fix it */
453 co->value = strdup("");
454 }
455 else if(7 != fields) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000456 /* we did not find the sufficient number of fields to recognize this
457 as a valid line, abort and go home */
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000458 free_cookiemess(co);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000459 return NULL;
460 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000461 }
462
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000463 if(!c->running && /* read from a file */
464 c->newsession && /* clean session cookies */
465 !co->expires) { /* this is a session cookie since it doesn't expire! */
466 free_cookiemess(co);
467 return NULL;
468 }
469
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000470 co->livecookie = c->running;
471
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000472 /* now, we have parsed the incoming line, we must now check if this
473 superceeds an already existing cookie, which it may if the previous have
474 the same domain and path as this */
475
476 clist = c->cookies;
477 replace_old = FALSE;
478 while(clist) {
479 if(strequal(clist->name, co->name)) {
480 /* the names are identical */
481
482 if(clist->domain && co->domain) {
Daniel Stenberg465de792003-05-15 22:28:19 +0000483 if(strequal(clist->domain, co->domain))
484 /* The domains are identical */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000485 replace_old=TRUE;
486 }
487 else if(!clist->domain && !co->domain)
488 replace_old = TRUE;
489
490 if(replace_old) {
491 /* the domains were identical */
492
493 if(clist->path && co->path) {
494 if(strequal(clist->path, co->path)) {
495 replace_old = TRUE;
496 }
497 else
498 replace_old = FALSE;
499 }
500 else if(!clist->path && !co->path)
501 replace_old = TRUE;
502 else
503 replace_old = FALSE;
504
505 }
506
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000507 if(replace_old && !co->livecookie && clist->livecookie) {
508 /* Both cookies matched fine, except that the already present
509 cookie is "live", which means it was set from a header, while
510 the new one isn't "live" and thus only read from a file. We let
511 live cookies stay alive */
512
513 /* Free the newcomer and get out of here! */
514 if(co->domain)
515 free(co->domain);
516 if(co->path)
517 free(co->path);
518 if(co->name)
519 free(co->name);
520 if(co->value)
521 free(co->value);
522
523 free(co);
524 return NULL;
525 }
526
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000527 if(replace_old) {
528 co->next = clist->next; /* get the next-pointer first */
529
530 /* then free all the old pointers */
531 if(clist->name)
532 free(clist->name);
533 if(clist->value)
534 free(clist->value);
535 if(clist->domain)
536 free(clist->domain);
537 if(clist->path)
538 free(clist->path);
539 if(clist->expirestr)
540 free(clist->expirestr);
541
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000542 if(clist->version)
543 free(clist->version);
544 if(clist->maxage)
545 free(clist->maxage);
546
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000547 *clist = *co; /* then store all the new data */
Daniel Stenbergc6822f52001-10-24 11:36:55 +0000548
549 free(co); /* free the newly alloced memory */
550 co = clist; /* point to the previous struct instead */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000551
Daniel Stenbergd9a77732002-01-07 14:56:15 +0000552 /* We have replaced a cookie, now skip the rest of the list but
553 make sure the 'lastc' pointer is properly set */
554 do {
555 lastc = clist;
556 clist = clist->next;
557 } while(clist);
558 break;
559 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000560 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000561 lastc = clist;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000562 clist = clist->next;
563 }
564
Daniel Stenberg168703b2003-08-11 09:55:11 +0000565 if(c->running)
566 /* Only show this when NOT reading the cookies from a file */
567 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
568 replace_old?"Replaced":"Added", co->name, co->value,
569 co->domain, co->path, co->expires);
570
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000571 if(!replace_old) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000572 /* then make the last item point on this new one */
573 if(lastc)
574 lastc->next = co;
575 else
576 c->cookies = co;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000577 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000578
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000579 c->numcookies++; /* one more cookie in the jar */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000580 return co;
581}
582
583/*****************************************************************************
584 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000585 * Curl_cookie_init()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000586 *
587 * Inits a cookie struct to read data from a local file. This is always
588 * called before any cookies are set. File may be NULL.
589 *
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000590 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
591 *
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000592 ****************************************************************************/
Daniel Stenberg168703b2003-08-11 09:55:11 +0000593struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
594 char *file,
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000595 struct CookieInfo *inc,
596 bool newsession)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000597{
598 char line[MAX_COOKIE_LINE];
599 struct CookieInfo *c;
600 FILE *fp;
Daniel Stenberg9280c202000-02-10 23:14:53 +0000601 bool fromfile=TRUE;
602
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000603 if(NULL == inc) {
604 /* we didn't get a struct, create one */
605 c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo));
606 if(!c)
607 return NULL; /* failed to get memory */
608 memset(c, 0, sizeof(struct CookieInfo));
609 c->filename = strdup(file?file:"none"); /* copy the name just in case */
610 }
611 else {
612 /* we got an already existing one, use that */
613 c = inc;
614 }
615 c->running = FALSE; /* this is not running, this is init */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000616
Daniel Stenbergf2a25962001-10-10 12:48:32 +0000617 if(file && strequal(file, "-")) {
Daniel Stenberg9280c202000-02-10 23:14:53 +0000618 fp = stdin;
619 fromfile=FALSE;
620 }
621 else
622 fp = file?fopen(file, "r"):NULL;
623
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000624 c->newsession = newsession; /* new session? */
625
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000626 if(fp) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000627 char *lineptr;
628 bool headerline;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000629 while(fgets(line, MAX_COOKIE_LINE, fp)) {
Daniel Stenberg01387f42002-10-28 21:52:00 +0000630 if(checkprefix("Set-Cookie:", line)) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000631 /* This is a cookie line, get it! */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000632 lineptr=&line[11];
633 headerline=TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000634 }
635 else {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000636 lineptr=line;
637 headerline=FALSE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000638 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000639 while(*lineptr && isspace((int)*lineptr))
640 lineptr++;
641
Daniel Stenberg168703b2003-08-11 09:55:11 +0000642 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000643 }
Daniel Stenberg9280c202000-02-10 23:14:53 +0000644 if(fromfile)
645 fclose(fp);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000646 }
647
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000648 c->running = TRUE; /* now, we're running */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000649
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000650 return c;
651}
652
653/*****************************************************************************
654 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000655 * Curl_cookie_getlist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000656 *
657 * For a given host and path, return a linked list of cookies that the
658 * client should send to the server if used now. The secure boolean informs
659 * the cookie if a secure connection is achieved or not.
660 *
661 * It shall only return cookies that haven't expired.
662 *
663 ****************************************************************************/
664
Daniel Stenberg40311042001-01-05 10:11:41 +0000665struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
666 char *host, char *path, bool secure)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000667{
668 struct Cookie *newco;
669 struct Cookie *co;
670 time_t now = time(NULL);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000671 struct Cookie *mainco=NULL;
672
673 if(!c || !c->cookies)
674 return NULL; /* no cookie struct or no cookies in the struct */
675
676 co = c->cookies;
677
678 while(co) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000679 /* only process this cookie if it is not expired or had no expire
680 date AND that if the cookie requires we're secure we must only
681 continue if we are! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000682 if( (co->expires<=0 || (co->expires> now)) &&
683 (co->secure?secure:TRUE) ) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000684
685 /* now check if the domain is correct */
686 if(!co->domain ||
687 (co->tailmatch && tailmatch(co->domain, host)) ||
688 (!co->tailmatch && strequal(host, co->domain)) ) {
689 /* the right part of the host matches the domain stuff in the
690 cookie data */
691
692 /* now check the left part of the path with the cookies path
693 requirement */
694 if(!co->path ||
695 checkprefix(co->path, path) ) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000696
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000697 /* and now, we know this is a match and we should create an
698 entry for the return-linked-list */
699
700 newco = (struct Cookie *)malloc(sizeof(struct Cookie));
701 if(newco) {
702 /* first, copy the whole source cookie: */
703 memcpy(newco, co, sizeof(struct Cookie));
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000704
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000705 /* then modify our next */
706 newco->next = mainco;
707
708 /* point the main to us */
709 mainco = newco;
710 }
711 }
712 }
713 }
714 co = co->next;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000715 }
716
717 return mainco; /* return the new list */
718}
719
720
721/*****************************************************************************
722 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000723 * Curl_cookie_freelist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000724 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000725 * Free a list of cookies previously returned by Curl_cookie_getlist();
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000726 *
727 ****************************************************************************/
728
Daniel Stenberg40311042001-01-05 10:11:41 +0000729void Curl_cookie_freelist(struct Cookie *co)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000730{
731 struct Cookie *next;
732 if(co) {
733 while(co) {
734 next = co->next;
735 free(co); /* we only free the struct since the "members" are all
736 just copied! */
737 co = next;
738 }
739 }
740}
741
742/*****************************************************************************
743 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000744 * Curl_cookie_cleanup()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000745 *
746 * Free a "cookie object" previous created with cookie_init().
747 *
748 ****************************************************************************/
Daniel Stenberg40311042001-01-05 10:11:41 +0000749void Curl_cookie_cleanup(struct CookieInfo *c)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000750{
751 struct Cookie *co;
752 struct Cookie *next;
753 if(c) {
754 if(c->filename)
755 free(c->filename);
756 co = c->cookies;
757
758 while(co) {
759 if(co->name)
760 free(co->name);
761 if(co->value)
762 free(co->value);
763 if(co->domain)
764 free(co->domain);
765 if(co->path)
766 free(co->path);
767 if(co->expirestr)
768 free(co->expirestr);
769
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000770 if(co->version)
771 free(co->version);
772 if(co->maxage)
773 free(co->maxage);
774
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000775 next = co->next;
776 free(co);
777 co = next;
778 }
Daniel Stenberg0f8facb2000-10-09 11:12:34 +0000779 free(c); /* free the base struct as well */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000780 }
781}
782
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000783/*
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000784 * Curl_cookie_output()
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000785 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000786 * Writes all internally known cookies to the specified file. Specify
787 * "-" as file name to write to stdout.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000788 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000789 * The function returns non-zero on write failure.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000790 */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000791int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000792{
793 struct Cookie *co;
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000794 FILE *out;
795 bool use_stdout=FALSE;
796
Daniel Stenberg3f5227d2001-09-10 07:43:08 +0000797 if((NULL == c) || (0 == c->numcookies))
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000798 /* If there are no known cookies, we don't write or even create any
799 destination file */
800 return 0;
801
802 if(strequal("-", dumphere)) {
803 /* use stdout */
804 out = stdout;
805 use_stdout=TRUE;
806 }
807 else {
808 out = fopen(dumphere, "w");
809 if(!out)
810 return 1; /* failure */
811 }
812
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000813 if(c) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000814 fputs("# Netscape HTTP Cookie File\n"
815 "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
Daniel Stenberge719f412001-10-08 06:43:22 +0000816 "# This file was generated by libcurl! Edit at your own risk.\n\n",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000817 out);
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000818 co = c->cookies;
819
820 while(co) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000821 fprintf(out,
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000822 "%s%s\t" /* domain */
823 "%s\t" /* tailmatch */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000824 "%s\t" /* path */
825 "%s\t" /* secure */
826 "%u\t" /* expires */
827 "%s\t" /* name */
828 "%s\n", /* value */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000829
830 /* Make sure all domains are prefixed with a dot if they allow
831 tailmatching. This is Mozilla-style. */
832 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000833 co->domain?co->domain:"unknown",
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000834 co->tailmatch?"TRUE":"FALSE",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000835 co->path?co->path:"/",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000836 co->secure?"TRUE":"FALSE",
837 (unsigned int)co->expires,
838 co->name,
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000839 co->value?co->value:"");
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000840
841 co=co->next;
842 }
843 }
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000844
845 if(!use_stdout)
846 fclose(out);
847
848 return 0;
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000849}
850
Daniel Stenberg08ef2082002-06-11 11:13:01 +0000851#endif /* CURL_DISABLE_HTTP */