blob: d31bcd114c63fcd96c230c87cff88570e82c0a4b [file] [log] [blame]
Daniel Stenbergba4e69b2002-09-03 11:52:59 +00001/***************************************************************************
Daniel Stenberg34e8baa2004-05-12 12:04:38 +00002 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
Daniel Stenberg24dee482001-01-03 09:29:33 +00006 * \___|\___/|_| \_\_____|
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.
Daniel Stenberg34e8baa2004-05-12 12:04:38 +000013 *
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);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +000031
Daniel Stenbergae1912c1999-12-29 14:20:26 +000032 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
Daniel Stenberg34e8baa2004-05-12 12:04:38 +000061
Daniel Stenbergae1912c1999-12-29 14:20:26 +000062Example set of cookies:
Daniel Stenberg34e8baa2004-05-12 12:04:38 +000063
Daniel Stenbergae1912c1999-12-29 14:20:26 +000064 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 Stenbergbbafb2e2004-05-11 11:30:23 +000095#include "memory.h"
Daniel Stenbergae1912c1999-12-29 14:20:26 +000096
Daniel Stenberg0f8facb2000-10-09 11:12:34 +000097/* The last #include file should be: */
Daniel Stenberg2bd71d72003-06-26 06:50:32 +000098#ifdef CURLDEBUG
Daniel Stenberg0f8facb2000-10-09 11:12:34 +000099#include "memdebug.h"
100#endif
101
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000102static void freecookie(struct Cookie *co)
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000103{
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000104 if(co->expirestr)
105 free(co->expirestr);
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000106 if(co->domain)
107 free(co->domain);
108 if(co->path)
109 free(co->path);
110 if(co->name)
111 free(co->name);
112 if(co->value)
113 free(co->value);
114
115 free(co);
116}
117
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000118static bool tailmatch(const char *little, const char *bigone)
119{
Daniel Stenbergd5710642004-02-26 13:40:43 +0000120 size_t littlelen = strlen(little);
121 size_t biglen = strlen(bigone);
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000122
123 if(littlelen > biglen)
124 return FALSE;
125
Daniel Stenberg99482502004-03-10 09:41:37 +0000126 return (bool)strequal(little, bigone+biglen-littlelen);
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000127}
128
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000129/****************************************************************************
130 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000131 * Curl_cookie_add()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000132 *
133 * Add a single cookie line to the cookie keeping object.
134 *
135 ***************************************************************************/
136
Daniel Stenberg40311042001-01-05 10:11:41 +0000137struct Cookie *
Daniel Stenberg168703b2003-08-11 09:55:11 +0000138Curl_cookie_add(struct SessionHandle *data,
139 /* The 'data' pointer here may be NULL at times, and thus
140 must only be used very carefully for things that can deal
141 with data being NULL. Such as infof() and similar */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000142
Daniel Stenberg168703b2003-08-11 09:55:11 +0000143 struct CookieInfo *c,
Daniel Stenberg40311042001-01-05 10:11:41 +0000144 bool httpheader, /* TRUE if HTTP header-style line */
Daniel Stenbergd8b2c812002-07-29 22:22:49 +0000145 char *lineptr, /* first character of the line */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000146 char *domain, /* default domain */
147 char *path) /* full path used when this cookie is set,
148 used to get default path for the cookie
149 unless set */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000150{
151 struct Cookie *clist;
152 char what[MAX_COOKIE_LINE];
153 char name[MAX_NAME];
154 char *ptr;
155 char *semiptr;
156 struct Cookie *co;
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000157 struct Cookie *lastc=NULL;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000158 time_t now = time(NULL);
159 bool replace_old = FALSE;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000160 bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000161
162 /* First, alloc and init a new struct for it */
Daniel Stenberg7d8cd592004-02-26 14:52:16 +0000163 co = (struct Cookie *)calloc(sizeof(struct Cookie), 1);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000164 if(!co)
165 return NULL; /* bail out if we're this low on memory */
166
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000167 if(httpheader) {
168 /* This line was read off a HTTP-header */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000169 char *sep;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000170 semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
Daniel Stenbergd8b2c812002-07-29 22:22:49 +0000171
172 while(*lineptr && isspace((int)*lineptr))
173 lineptr++;
174
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000175 ptr = lineptr;
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000176 do {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000177 /* we have a <what>=<this> pair or a 'secure' word here */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000178 sep = strchr(ptr, '=');
179 if(sep && (!semiptr || (semiptr>sep)) ) {
180 /*
181 * There is a = sign and if there was a semicolon too, which make sure
182 * that the semicolon comes _after_ the equal sign.
183 */
184
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000185 name[0]=what[0]=0; /* init the buffers */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000186 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
Daniel Stenberg3612c372002-02-27 07:38:04 +0000187 MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000188 name, what)) {
Daniel Stenberg3612c372002-02-27 07:38:04 +0000189 /* this is a <name>=<what> pair */
190
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000191 char *whatptr;
192
Daniel Stenberg3612c372002-02-27 07:38:04 +0000193 /* Strip off trailing whitespace from the 'what' */
Daniel Stenbergd5710642004-02-26 13:40:43 +0000194 size_t len=strlen(what);
Daniel Stenberg3612c372002-02-27 07:38:04 +0000195 while(len && isspace((int)what[len-1])) {
196 what[len-1]=0;
197 len--;
198 }
199
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000200 /* Skip leading whitespace from the 'what' */
201 whatptr=what;
202 while(isspace((int)*whatptr)) {
203 whatptr++;
204 }
205
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000206 if(strequal("path", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000207 co->path=strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000208 if(!co->path) {
209 badcookie = TRUE; /* out of memory bad */
210 break;
211 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000212 }
213 else if(strequal("domain", name)) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000214 /* note that this name may or may not have a preceeding dot, but
215 we don't care about that, we treat the names the same anyway */
216
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000217 const char *domptr=whatptr;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000218 int dotcount=1;
219 unsigned int i;
220
221 static const char *seventhree[]= {
222 "com", "edu", "net", "org", "gov", "mil", "int"
223 };
224
225 /* Count the dots, we need to make sure that there are THREE dots
226 in the normal domains, or TWO in the seventhree-domains. */
227
228 if('.' == whatptr[0])
229 /* don't count the initial dot, assume it */
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000230 domptr++;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000231
232 do {
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000233 domptr = strchr(domptr, '.');
234 if(domptr) {
235 domptr++;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000236 dotcount++;
237 }
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000238 } while(domptr);
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000239
240 for(i=0;
241 i<sizeof(seventhree)/sizeof(seventhree[0]); i++) {
242 if(tailmatch(seventhree[i], whatptr)) {
243 dotcount++; /* we allow one dot less for these */
244 break;
245 }
246 }
Daniel Stenberg98ee12b2003-08-04 23:05:57 +0000247 /* The original Netscape cookie spec defined that this domain name
248 MUST have three dots (or two if one of the seven holy TLDs),
249 but it seems that these kinds of cookies are in use "out there"
250 so we cannot be that strict. I've therefore lowered the check
251 to not allow less than two dots. */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000252
Daniel Stenberg98ee12b2003-08-04 23:05:57 +0000253 if(dotcount < 2) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000254 /* Received and skipped a cookie with a domain using too few
255 dots. */
256 badcookie=TRUE; /* mark this as a bad cookie */
Daniel Stenberg168703b2003-08-11 09:55:11 +0000257 infof(data, "skipped cookie with illegal dotcount domain: %s",
258 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000259 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000260 else {
261 /* Now, we make sure that our host is within the given domain,
262 or the given domain is not valid and thus cannot be set. */
263
Daniel Stenberg755f98e2004-05-21 20:40:15 +0000264 if('.' == whatptr[0])
265 whatptr++; /* ignore preceeding dot */
266
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000267 if(!domain || tailmatch(whatptr, domain)) {
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000268 const char *tailptr=whatptr;
269 if(tailptr[0] == '.')
270 tailptr++;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000271 co->domain=strdup(tailptr); /* don't prefix w/dots
272 internally */
273 if(!co->domain) {
274 badcookie = TRUE;
275 break;
276 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000277 co->tailmatch=TRUE; /* we always do that if the domain name was
278 given */
279 }
Daniel Stenberg465de792003-05-15 22:28:19 +0000280 else {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000281 /* we did not get a tailmatch and then the attempted set domain
282 is not a domain to which the current host belongs. Mark as
283 bad. */
284 badcookie=TRUE;
Daniel Stenberg168703b2003-08-11 09:55:11 +0000285 infof(data, "skipped cookie with bad tailmatch domain: %s",
286 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000287 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000288 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000289 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000290 else if(strequal("version", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000291 co->version=strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000292 if(!co->version) {
293 badcookie = TRUE;
294 break;
295 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000296 }
297 else if(strequal("max-age", name)) {
298 /* Defined in RFC2109:
299
300 Optional. The Max-Age attribute defines the lifetime of the
301 cookie, in seconds. The delta-seconds value is a decimal non-
302 negative integer. After delta-seconds seconds elapse, the
303 client should discard the cookie. A value of zero means the
304 cookie should be discarded immediately.
305
306 */
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000307 co->maxage = strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000308 if(!co->maxage) {
309 badcookie = TRUE;
310 break;
311 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000312 co->expires =
Daniel Stenberg3612c372002-02-27 07:38:04 +0000313 atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000314 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000315 else if(strequal("expires", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000316 co->expirestr=strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000317 if(!co->expirestr) {
318 badcookie = TRUE;
319 break;
320 }
Daniel Stenberg96dde762000-05-22 14:12:12 +0000321 co->expires = curl_getdate(what, &now);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000322 }
323 else if(!co->name) {
324 co->name = strdup(name);
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000325 co->value = strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000326 if(!co->name || !co->value) {
327 badcookie = TRUE;
328 break;
329 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000330 }
Daniel Stenbergc8926132001-08-14 08:17:29 +0000331 /*
332 else this is the second (or more) name we don't know
333 about! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000334 }
335 else {
336 /* this is an "illegal" <what>=<this> pair */
337 }
338 }
339 else {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000340 if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000341 what)) {
342 if(strequal("secure", what))
343 co->secure = TRUE;
Daniel Stenbergc8926132001-08-14 08:17:29 +0000344 /* else,
345 unsupported keyword without assign! */
346
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000347 }
348 }
Daniel Stenberga23a8972002-02-26 13:07:53 +0000349 if(!semiptr || !*semiptr) {
350 /* we already know there are no more cookies */
351 semiptr = NULL;
352 continue;
353 }
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000354
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000355 ptr=semiptr+1;
356 while(ptr && *ptr && isspace((int)*ptr))
357 ptr++;
358 semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
Daniel Stenberg87037132002-01-07 23:05:36 +0000359
360 if(!semiptr && *ptr)
361 /* There are no more semicolons, but there's a final name=value pair
362 coming up */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000363 semiptr=strchr(ptr, '\0');
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000364 } while(semiptr);
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000365
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000366 if(!badcookie && !co->domain) {
367 if(domain) {
368 /* no domain was given in the header line, set the default */
369 co->domain=strdup(domain);
370 if(!co->domain)
371 badcookie = TRUE;
372 }
Daniel Stenberga23a8972002-02-26 13:07:53 +0000373 }
374
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000375 if(!badcookie && !co->path && path) {
376 /* no path was given in the header line, set the default */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000377 char *endslash = strrchr(path, '/');
378 if(endslash) {
Daniel Stenbergd5710642004-02-26 13:40:43 +0000379 size_t pathlen = endslash-path+1; /* include the ending slash */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000380 co->path=malloc(pathlen+1); /* one extra for the zero byte */
381 if(co->path) {
382 memcpy(co->path, path, pathlen);
383 co->path[pathlen]=0; /* zero terminate */
384 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000385 else
386 badcookie = TRUE;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000387 }
388 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000389
390 if(badcookie || !co->name) {
391 /* we didn't get a cookie name or a bad one,
392 this is an illegal line, bail out */
393 freecookie(co);
394 return NULL;
395 }
396
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000397 }
398 else {
399 /* This line is NOT a HTTP header style line, we do offer support for
400 reading the odd netscape cookies-file format here */
401 char *firstptr;
Daniel Stenbergd5676592001-05-29 19:17:39 +0000402 char *tok_buf;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000403 int fields;
404
405 if(lineptr[0]=='#') {
406 /* don't even try the comments */
407 free(co);
408 return NULL;
409 }
410 /* strip off the possible end-of-line characters */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000411 ptr=strchr(lineptr, '\r');
412 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000413 *ptr=0; /* clear it */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000414 ptr=strchr(lineptr, '\n');
415 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000416 *ptr=0; /* clear it */
417
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000418 firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000419
420 /* Here's a quick check to eliminate normal HTTP-headers from this */
421 if(!firstptr || strchr(firstptr, ':')) {
422 free(co);
423 return NULL;
424 }
425
426 /* Now loop through the fields and init the struct we already have
427 allocated */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000428 for(ptr=firstptr, fields=0; ptr && !badcookie;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000429 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000430 switch(fields) {
431 case 0:
Daniel Stenberg465de792003-05-15 22:28:19 +0000432 if(ptr[0]=='.') /* skip preceeding dots */
433 ptr++;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000434 co->domain = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000435 if(!co->domain)
436 badcookie = TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000437 break;
438 case 1:
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000439 /* This field got its explanation on the 23rd of May 2001 by
440 Andrés García:
441
442 flag: A TRUE/FALSE value indicating if all machines within a given
443 domain can access the variable. This value is set automatically by
444 the browser, depending on the value you set for the domain.
445
446 As far as I can see, it is set to true when the cookie says
447 .domain.com and to false when the domain is complete www.domain.com
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000448 */
Daniel Stenberg99482502004-03-10 09:41:37 +0000449 co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000450 break;
451 case 2:
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000452 /* It turns out, that sometimes the file format allows the path
453 field to remain not filled in, we try to detect this and work
454 around it! Andrés García made us aware of this... */
455 if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
456 /* only if the path doesn't look like a boolean option! */
457 co->path = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000458 if(!co->path)
459 badcookie = TRUE;
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000460 break;
461 }
462 /* this doesn't look like a path, make one up! */
463 co->path = strdup("/");
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000464 if(!co->path)
465 badcookie = TRUE;
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000466 fields++; /* add a field and fall down to secure */
467 /* FALLTHROUGH */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000468 case 3:
Daniel Stenberg99482502004-03-10 09:41:37 +0000469 co->secure = (bool)strequal(ptr, "TRUE");
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000470 break;
471 case 4:
472 co->expires = atoi(ptr);
473 break;
474 case 5:
475 co->name = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000476 if(!co->name)
477 badcookie = TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000478 break;
479 case 6:
480 co->value = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000481 if(!co->value)
482 badcookie = TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000483 break;
484 }
485 }
Daniel Stenberg168703b2003-08-11 09:55:11 +0000486 if(6 == fields) {
487 /* we got a cookie with blank contents, fix it */
488 co->value = strdup("");
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000489 if(!co->value)
490 badcookie = TRUE;
491 else
492 fields++;
Daniel Stenberg168703b2003-08-11 09:55:11 +0000493 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000494
495 if(!badcookie && (7 != fields))
496 /* we did not find the sufficient number of fields */
497 badcookie = TRUE;
498
499 if(badcookie) {
500 freecookie(co);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000501 return NULL;
502 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000503
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000504 }
505
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000506 if(!c->running && /* read from a file */
507 c->newsession && /* clean session cookies */
508 !co->expires) { /* this is a session cookie since it doesn't expire! */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000509 freecookie(co);
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000510 return NULL;
511 }
512
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000513 co->livecookie = c->running;
514
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000515 /* now, we have parsed the incoming line, we must now check if this
516 superceeds an already existing cookie, which it may if the previous have
517 the same domain and path as this */
518
519 clist = c->cookies;
520 replace_old = FALSE;
521 while(clist) {
522 if(strequal(clist->name, co->name)) {
523 /* the names are identical */
524
525 if(clist->domain && co->domain) {
Daniel Stenberg465de792003-05-15 22:28:19 +0000526 if(strequal(clist->domain, co->domain))
527 /* The domains are identical */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000528 replace_old=TRUE;
529 }
530 else if(!clist->domain && !co->domain)
531 replace_old = TRUE;
532
533 if(replace_old) {
534 /* the domains were identical */
535
536 if(clist->path && co->path) {
537 if(strequal(clist->path, co->path)) {
538 replace_old = TRUE;
539 }
540 else
541 replace_old = FALSE;
542 }
543 else if(!clist->path && !co->path)
544 replace_old = TRUE;
545 else
546 replace_old = FALSE;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000547
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000548 }
549
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000550 if(replace_old && !co->livecookie && clist->livecookie) {
551 /* Both cookies matched fine, except that the already present
552 cookie is "live", which means it was set from a header, while
553 the new one isn't "live" and thus only read from a file. We let
554 live cookies stay alive */
555
556 /* Free the newcomer and get out of here! */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000557 freecookie(co);
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000558 return NULL;
559 }
560
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000561 if(replace_old) {
562 co->next = clist->next; /* get the next-pointer first */
563
564 /* then free all the old pointers */
565 if(clist->name)
566 free(clist->name);
567 if(clist->value)
568 free(clist->value);
569 if(clist->domain)
570 free(clist->domain);
571 if(clist->path)
572 free(clist->path);
573 if(clist->expirestr)
574 free(clist->expirestr);
575
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000576 if(clist->version)
577 free(clist->version);
578 if(clist->maxage)
579 free(clist->maxage);
580
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000581 *clist = *co; /* then store all the new data */
Daniel Stenbergc6822f52001-10-24 11:36:55 +0000582
583 free(co); /* free the newly alloced memory */
584 co = clist; /* point to the previous struct instead */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000585
Daniel Stenbergd9a77732002-01-07 14:56:15 +0000586 /* We have replaced a cookie, now skip the rest of the list but
587 make sure the 'lastc' pointer is properly set */
588 do {
589 lastc = clist;
590 clist = clist->next;
591 } while(clist);
592 break;
593 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000594 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000595 lastc = clist;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000596 clist = clist->next;
597 }
598
Daniel Stenberg168703b2003-08-11 09:55:11 +0000599 if(c->running)
600 /* Only show this when NOT reading the cookies from a file */
601 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
602 replace_old?"Replaced":"Added", co->name, co->value,
603 co->domain, co->path, co->expires);
604
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000605 if(!replace_old) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000606 /* then make the last item point on this new one */
607 if(lastc)
608 lastc->next = co;
609 else
610 c->cookies = co;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000611 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000612
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000613 c->numcookies++; /* one more cookie in the jar */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000614 return co;
615}
616
617/*****************************************************************************
618 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000619 * Curl_cookie_init()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000620 *
621 * Inits a cookie struct to read data from a local file. This is always
622 * called before any cookies are set. File may be NULL.
623 *
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000624 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
625 *
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000626 ****************************************************************************/
Daniel Stenberg168703b2003-08-11 09:55:11 +0000627struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
628 char *file,
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000629 struct CookieInfo *inc,
630 bool newsession)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000631{
632 char line[MAX_COOKIE_LINE];
633 struct CookieInfo *c;
634 FILE *fp;
Daniel Stenberg9280c202000-02-10 23:14:53 +0000635 bool fromfile=TRUE;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000636
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000637 if(NULL == inc) {
638 /* we didn't get a struct, create one */
639 c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo));
640 if(!c)
641 return NULL; /* failed to get memory */
642 memset(c, 0, sizeof(struct CookieInfo));
643 c->filename = strdup(file?file:"none"); /* copy the name just in case */
644 }
645 else {
646 /* we got an already existing one, use that */
647 c = inc;
648 }
649 c->running = FALSE; /* this is not running, this is init */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000650
Daniel Stenbergf2a25962001-10-10 12:48:32 +0000651 if(file && strequal(file, "-")) {
Daniel Stenberg9280c202000-02-10 23:14:53 +0000652 fp = stdin;
653 fromfile=FALSE;
654 }
655 else
656 fp = file?fopen(file, "r"):NULL;
657
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000658 c->newsession = newsession; /* new session? */
659
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000660 if(fp) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000661 char *lineptr;
662 bool headerline;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000663 while(fgets(line, MAX_COOKIE_LINE, fp)) {
Daniel Stenberg01387f42002-10-28 21:52:00 +0000664 if(checkprefix("Set-Cookie:", line)) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000665 /* This is a cookie line, get it! */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000666 lineptr=&line[11];
667 headerline=TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000668 }
669 else {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000670 lineptr=line;
671 headerline=FALSE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000672 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000673 while(*lineptr && isspace((int)*lineptr))
674 lineptr++;
675
Daniel Stenberg168703b2003-08-11 09:55:11 +0000676 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000677 }
Daniel Stenberg9280c202000-02-10 23:14:53 +0000678 if(fromfile)
679 fclose(fp);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000680 }
681
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000682 c->running = TRUE; /* now, we're running */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000683
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000684 return c;
685}
686
687/*****************************************************************************
688 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000689 * Curl_cookie_getlist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000690 *
691 * For a given host and path, return a linked list of cookies that the
692 * client should send to the server if used now. The secure boolean informs
693 * the cookie if a secure connection is achieved or not.
694 *
695 * It shall only return cookies that haven't expired.
696 *
697 ****************************************************************************/
698
Daniel Stenberg40311042001-01-05 10:11:41 +0000699struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
700 char *host, char *path, bool secure)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000701{
702 struct Cookie *newco;
703 struct Cookie *co;
704 time_t now = time(NULL);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000705 struct Cookie *mainco=NULL;
706
707 if(!c || !c->cookies)
708 return NULL; /* no cookie struct or no cookies in the struct */
709
710 co = c->cookies;
711
712 while(co) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000713 /* only process this cookie if it is not expired or had no expire
714 date AND that if the cookie requires we're secure we must only
715 continue if we are! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000716 if( (co->expires<=0 || (co->expires> now)) &&
717 (co->secure?secure:TRUE) ) {
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000718
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000719 /* now check if the domain is correct */
720 if(!co->domain ||
721 (co->tailmatch && tailmatch(co->domain, host)) ||
722 (!co->tailmatch && strequal(host, co->domain)) ) {
723 /* the right part of the host matches the domain stuff in the
724 cookie data */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000725
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000726 /* now check the left part of the path with the cookies path
727 requirement */
728 if(!co->path ||
729 checkprefix(co->path, path) ) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000730
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000731 /* and now, we know this is a match and we should create an
732 entry for the return-linked-list */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000733
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000734 newco = (struct Cookie *)malloc(sizeof(struct Cookie));
735 if(newco) {
736 /* first, copy the whole source cookie: */
737 memcpy(newco, co, sizeof(struct Cookie));
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000738
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000739 /* then modify our next */
740 newco->next = mainco;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000741
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000742 /* point the main to us */
743 mainco = newco;
744 }
Daniel Stenberg5dcab072004-05-10 14:04:06 +0000745 else {
746 /* failure, clear up the allocated chain and return NULL */
747 while(mainco) {
748 co = mainco->next;
749 free(mainco);
750 mainco = co;
751 }
752
753 return NULL;
754 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000755 }
756 }
757 }
758 co = co->next;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000759 }
760
761 return mainco; /* return the new list */
762}
763
764
765/*****************************************************************************
766 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000767 * Curl_cookie_freelist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000768 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000769 * Free a list of cookies previously returned by Curl_cookie_getlist();
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000770 *
771 ****************************************************************************/
772
Daniel Stenberg40311042001-01-05 10:11:41 +0000773void Curl_cookie_freelist(struct Cookie *co)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000774{
775 struct Cookie *next;
776 if(co) {
777 while(co) {
778 next = co->next;
779 free(co); /* we only free the struct since the "members" are all
780 just copied! */
781 co = next;
782 }
783 }
784}
785
786/*****************************************************************************
787 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000788 * Curl_cookie_cleanup()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000789 *
790 * Free a "cookie object" previous created with cookie_init().
791 *
792 ****************************************************************************/
Daniel Stenberg40311042001-01-05 10:11:41 +0000793void Curl_cookie_cleanup(struct CookieInfo *c)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000794{
795 struct Cookie *co;
796 struct Cookie *next;
797 if(c) {
798 if(c->filename)
799 free(c->filename);
800 co = c->cookies;
801
802 while(co) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000803 next = co->next;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000804 freecookie(co);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000805 co = next;
806 }
Daniel Stenberg0f8facb2000-10-09 11:12:34 +0000807 free(c); /* free the base struct as well */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000808 }
809}
810
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000811/*
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000812 * Curl_cookie_output()
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000813 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000814 * Writes all internally known cookies to the specified file. Specify
815 * "-" as file name to write to stdout.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000816 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000817 * The function returns non-zero on write failure.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000818 */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000819int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000820{
821 struct Cookie *co;
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000822 FILE *out;
823 bool use_stdout=FALSE;
824
Daniel Stenberg3f5227d2001-09-10 07:43:08 +0000825 if((NULL == c) || (0 == c->numcookies))
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000826 /* If there are no known cookies, we don't write or even create any
827 destination file */
828 return 0;
829
830 if(strequal("-", dumphere)) {
831 /* use stdout */
832 out = stdout;
833 use_stdout=TRUE;
834 }
835 else {
836 out = fopen(dumphere, "w");
837 if(!out)
838 return 1; /* failure */
839 }
840
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000841 if(c) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000842 fputs("# Netscape HTTP Cookie File\n"
843 "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
Daniel Stenberge719f412001-10-08 06:43:22 +0000844 "# This file was generated by libcurl! Edit at your own risk.\n\n",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000845 out);
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000846 co = c->cookies;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000847
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000848 while(co) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000849 fprintf(out,
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000850 "%s%s\t" /* domain */
851 "%s\t" /* tailmatch */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000852 "%s\t" /* path */
853 "%s\t" /* secure */
854 "%u\t" /* expires */
855 "%s\t" /* name */
856 "%s\n", /* value */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000857
858 /* Make sure all domains are prefixed with a dot if they allow
859 tailmatching. This is Mozilla-style. */
860 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000861 co->domain?co->domain:"unknown",
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000862 co->tailmatch?"TRUE":"FALSE",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000863 co->path?co->path:"/",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000864 co->secure?"TRUE":"FALSE",
865 (unsigned int)co->expires,
866 co->name,
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000867 co->value?co->value:"");
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000868
869 co=co->next;
870 }
871 }
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000872
873 if(!use_stdout)
874 fclose(out);
875
876 return 0;
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000877}
878
Daniel Stenberg08ef2082002-06-11 11:13:01 +0000879#endif /* CURL_DISABLE_HTTP */