blob: 41f14011ff7b095e536a9fe9f35101dd3dc6b1b1 [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{
Daniel Stenbergd5710642004-02-26 13:40:43 +0000118 size_t littlelen = strlen(little);
119 size_t biglen = strlen(bigone);
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000120
121 if(littlelen > biglen)
122 return FALSE;
123
Daniel Stenberg99482502004-03-10 09:41:37 +0000124 return (bool)strequal(little, bigone+biglen-littlelen);
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000125}
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 */
Daniel Stenberg7d8cd592004-02-26 14:52:16 +0000161 co = (struct Cookie *)calloc(sizeof(struct Cookie), 1);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000162 if(!co)
163 return NULL; /* bail out if we're this low on memory */
164
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000165 if(httpheader) {
166 /* This line was read off a HTTP-header */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000167 char *sep;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000168 semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
Daniel Stenbergd8b2c812002-07-29 22:22:49 +0000169
170 while(*lineptr && isspace((int)*lineptr))
171 lineptr++;
172
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000173 ptr = lineptr;
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000174 do {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000175 /* we have a <what>=<this> pair or a 'secure' word here */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000176 sep = strchr(ptr, '=');
177 if(sep && (!semiptr || (semiptr>sep)) ) {
178 /*
179 * There is a = sign and if there was a semicolon too, which make sure
180 * that the semicolon comes _after_ the equal sign.
181 */
182
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000183 name[0]=what[0]=0; /* init the buffers */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000184 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
Daniel Stenberg3612c372002-02-27 07:38:04 +0000185 MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000186 name, what)) {
Daniel Stenberg3612c372002-02-27 07:38:04 +0000187 /* this is a <name>=<what> pair */
188
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000189 char *whatptr;
190
Daniel Stenberg3612c372002-02-27 07:38:04 +0000191 /* Strip off trailing whitespace from the 'what' */
Daniel Stenbergd5710642004-02-26 13:40:43 +0000192 size_t len=strlen(what);
Daniel Stenberg3612c372002-02-27 07:38:04 +0000193 while(len && isspace((int)what[len-1])) {
194 what[len-1]=0;
195 len--;
196 }
197
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000198 /* Skip leading whitespace from the 'what' */
199 whatptr=what;
200 while(isspace((int)*whatptr)) {
201 whatptr++;
202 }
203
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000204 if(strequal("path", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000205 co->path=strdup(whatptr);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000206 }
207 else if(strequal("domain", name)) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000208 /* note that this name may or may not have a preceeding dot, but
209 we don't care about that, we treat the names the same anyway */
210
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000211 const char *domptr=whatptr;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000212 int dotcount=1;
213 unsigned int i;
214
215 static const char *seventhree[]= {
216 "com", "edu", "net", "org", "gov", "mil", "int"
217 };
218
219 /* Count the dots, we need to make sure that there are THREE dots
220 in the normal domains, or TWO in the seventhree-domains. */
221
222 if('.' == whatptr[0])
223 /* don't count the initial dot, assume it */
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000224 domptr++;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000225
226 do {
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000227 domptr = strchr(domptr, '.');
228 if(domptr) {
229 domptr++;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000230 dotcount++;
231 }
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000232 } while(domptr);
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000233
234 for(i=0;
235 i<sizeof(seventhree)/sizeof(seventhree[0]); i++) {
236 if(tailmatch(seventhree[i], whatptr)) {
237 dotcount++; /* we allow one dot less for these */
238 break;
239 }
240 }
Daniel Stenberg98ee12b2003-08-04 23:05:57 +0000241 /* The original Netscape cookie spec defined that this domain name
242 MUST have three dots (or two if one of the seven holy TLDs),
243 but it seems that these kinds of cookies are in use "out there"
244 so we cannot be that strict. I've therefore lowered the check
245 to not allow less than two dots. */
246
247 if(dotcount < 2) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000248 /* Received and skipped a cookie with a domain using too few
249 dots. */
250 badcookie=TRUE; /* mark this as a bad cookie */
Daniel Stenberg168703b2003-08-11 09:55:11 +0000251 infof(data, "skipped cookie with illegal dotcount domain: %s",
252 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000253 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000254 else {
255 /* Now, we make sure that our host is within the given domain,
256 or the given domain is not valid and thus cannot be set. */
257
258 if(!domain || tailmatch(whatptr, domain)) {
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000259 const char *tailptr=whatptr;
260 if(tailptr[0] == '.')
261 tailptr++;
262 co->domain=strdup(tailptr); /* don't prefix w/dots internally */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000263 co->tailmatch=TRUE; /* we always do that if the domain name was
264 given */
265 }
Daniel Stenberg465de792003-05-15 22:28:19 +0000266 else {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000267 /* we did not get a tailmatch and then the attempted set domain
268 is not a domain to which the current host belongs. Mark as
269 bad. */
270 badcookie=TRUE;
Daniel Stenberg168703b2003-08-11 09:55:11 +0000271 infof(data, "skipped cookie with bad tailmatch domain: %s",
272 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000273 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000274 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000275 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000276 else if(strequal("version", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000277 co->version=strdup(whatptr);
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000278 }
279 else if(strequal("max-age", name)) {
280 /* Defined in RFC2109:
281
282 Optional. The Max-Age attribute defines the lifetime of the
283 cookie, in seconds. The delta-seconds value is a decimal non-
284 negative integer. After delta-seconds seconds elapse, the
285 client should discard the cookie. A value of zero means the
286 cookie should be discarded immediately.
287
288 */
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000289 co->maxage = strdup(whatptr);
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000290 co->expires =
Daniel Stenberg3612c372002-02-27 07:38:04 +0000291 atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000292 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000293 else if(strequal("expires", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000294 co->expirestr=strdup(whatptr);
Daniel Stenberg96dde762000-05-22 14:12:12 +0000295 co->expires = curl_getdate(what, &now);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000296 }
297 else if(!co->name) {
298 co->name = strdup(name);
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000299 co->value = strdup(whatptr);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000300 }
Daniel Stenbergc8926132001-08-14 08:17:29 +0000301 /*
302 else this is the second (or more) name we don't know
303 about! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000304 }
305 else {
306 /* this is an "illegal" <what>=<this> pair */
307 }
308 }
309 else {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000310 if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000311 what)) {
312 if(strequal("secure", what))
313 co->secure = TRUE;
Daniel Stenbergc8926132001-08-14 08:17:29 +0000314 /* else,
315 unsupported keyword without assign! */
316
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000317 }
318 }
Daniel Stenberga23a8972002-02-26 13:07:53 +0000319 if(!semiptr || !*semiptr) {
320 /* we already know there are no more cookies */
321 semiptr = NULL;
322 continue;
323 }
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000324
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000325 ptr=semiptr+1;
326 while(ptr && *ptr && isspace((int)*ptr))
327 ptr++;
328 semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
Daniel Stenberg87037132002-01-07 23:05:36 +0000329
330 if(!semiptr && *ptr)
331 /* There are no more semicolons, but there's a final name=value pair
332 coming up */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000333 semiptr=strchr(ptr, '\0');
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000334 } while(semiptr);
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000335
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000336 if(badcookie || (NULL == co->name)) {
337 /* we didn't get a cookie name or a bad one,
338 this is an illegal line, bail out */
339 if(co->expirestr)
340 free(co->expirestr);
Daniel Stenberga23a8972002-02-26 13:07:53 +0000341 if(co->domain)
342 free(co->domain);
343 if(co->path)
344 free(co->path);
345 if(co->name)
346 free(co->name);
347 if(co->value)
348 free(co->value);
349 free(co);
350 return NULL;
351 }
352
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000353 if(NULL == co->domain)
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000354 /* no domain was given in the header line, set the default now */
Daniel Stenberg6d359842001-10-30 12:08:17 +0000355 co->domain=domain?strdup(domain):NULL;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000356 if((NULL == co->path) && path) {
357 /* no path was given in the header line, set the default now */
358 char *endslash = strrchr(path, '/');
359 if(endslash) {
Daniel Stenbergd5710642004-02-26 13:40:43 +0000360 size_t pathlen = endslash-path+1; /* include the ending slash */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000361 co->path=malloc(pathlen+1); /* one extra for the zero byte */
362 if(co->path) {
363 memcpy(co->path, path, pathlen);
364 co->path[pathlen]=0; /* zero terminate */
365 }
366 }
367 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000368 }
369 else {
370 /* This line is NOT a HTTP header style line, we do offer support for
371 reading the odd netscape cookies-file format here */
372 char *firstptr;
Daniel Stenbergd5676592001-05-29 19:17:39 +0000373 char *tok_buf;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000374 int fields;
375
376 if(lineptr[0]=='#') {
377 /* don't even try the comments */
378 free(co);
379 return NULL;
380 }
381 /* strip off the possible end-of-line characters */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000382 ptr=strchr(lineptr, '\r');
383 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000384 *ptr=0; /* clear it */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000385 ptr=strchr(lineptr, '\n');
386 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000387 *ptr=0; /* clear it */
388
Daniel Stenbergd5676592001-05-29 19:17:39 +0000389 firstptr=strtok_r(lineptr, "\t", &tok_buf); /* first tokenize it on the TAB */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000390
391 /* Here's a quick check to eliminate normal HTTP-headers from this */
392 if(!firstptr || strchr(firstptr, ':')) {
393 free(co);
394 return NULL;
395 }
396
397 /* Now loop through the fields and init the struct we already have
398 allocated */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000399 for(ptr=firstptr, fields=0; ptr;
400 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000401 switch(fields) {
402 case 0:
Daniel Stenberg465de792003-05-15 22:28:19 +0000403 if(ptr[0]=='.') /* skip preceeding dots */
404 ptr++;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000405 co->domain = strdup(ptr);
406 break;
407 case 1:
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000408 /* This field got its explanation on the 23rd of May 2001 by
409 Andrés García:
410
411 flag: A TRUE/FALSE value indicating if all machines within a given
412 domain can access the variable. This value is set automatically by
413 the browser, depending on the value you set for the domain.
414
415 As far as I can see, it is set to true when the cookie says
416 .domain.com and to false when the domain is complete www.domain.com
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000417 */
Daniel Stenberg99482502004-03-10 09:41:37 +0000418 co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000419 break;
420 case 2:
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000421 /* It turns out, that sometimes the file format allows the path
422 field to remain not filled in, we try to detect this and work
423 around it! Andrés García made us aware of this... */
424 if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
425 /* only if the path doesn't look like a boolean option! */
426 co->path = strdup(ptr);
427 break;
428 }
429 /* this doesn't look like a path, make one up! */
430 co->path = strdup("/");
431 fields++; /* add a field and fall down to secure */
432 /* FALLTHROUGH */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000433 case 3:
Daniel Stenberg99482502004-03-10 09:41:37 +0000434 co->secure = (bool)strequal(ptr, "TRUE");
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000435 break;
436 case 4:
437 co->expires = atoi(ptr);
438 break;
439 case 5:
440 co->name = strdup(ptr);
441 break;
442 case 6:
443 co->value = strdup(ptr);
444 break;
445 }
446 }
447
Daniel Stenberg168703b2003-08-11 09:55:11 +0000448 if(6 == fields) {
449 /* we got a cookie with blank contents, fix it */
450 co->value = strdup("");
451 }
452 else if(7 != fields) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000453 /* we did not find the sufficient number of fields to recognize this
454 as a valid line, abort and go home */
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000455 free_cookiemess(co);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000456 return NULL;
457 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000458 }
459
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000460 if(!c->running && /* read from a file */
461 c->newsession && /* clean session cookies */
462 !co->expires) { /* this is a session cookie since it doesn't expire! */
463 free_cookiemess(co);
464 return NULL;
465 }
466
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000467 co->livecookie = c->running;
468
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000469 /* now, we have parsed the incoming line, we must now check if this
470 superceeds an already existing cookie, which it may if the previous have
471 the same domain and path as this */
472
473 clist = c->cookies;
474 replace_old = FALSE;
475 while(clist) {
476 if(strequal(clist->name, co->name)) {
477 /* the names are identical */
478
479 if(clist->domain && co->domain) {
Daniel Stenberg465de792003-05-15 22:28:19 +0000480 if(strequal(clist->domain, co->domain))
481 /* The domains are identical */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000482 replace_old=TRUE;
483 }
484 else if(!clist->domain && !co->domain)
485 replace_old = TRUE;
486
487 if(replace_old) {
488 /* the domains were identical */
489
490 if(clist->path && co->path) {
491 if(strequal(clist->path, co->path)) {
492 replace_old = TRUE;
493 }
494 else
495 replace_old = FALSE;
496 }
497 else if(!clist->path && !co->path)
498 replace_old = TRUE;
499 else
500 replace_old = FALSE;
501
502 }
503
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000504 if(replace_old && !co->livecookie && clist->livecookie) {
505 /* Both cookies matched fine, except that the already present
506 cookie is "live", which means it was set from a header, while
507 the new one isn't "live" and thus only read from a file. We let
508 live cookies stay alive */
509
510 /* Free the newcomer and get out of here! */
511 if(co->domain)
512 free(co->domain);
513 if(co->path)
514 free(co->path);
515 if(co->name)
516 free(co->name);
517 if(co->value)
518 free(co->value);
519
520 free(co);
521 return NULL;
522 }
523
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000524 if(replace_old) {
525 co->next = clist->next; /* get the next-pointer first */
526
527 /* then free all the old pointers */
528 if(clist->name)
529 free(clist->name);
530 if(clist->value)
531 free(clist->value);
532 if(clist->domain)
533 free(clist->domain);
534 if(clist->path)
535 free(clist->path);
536 if(clist->expirestr)
537 free(clist->expirestr);
538
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000539 if(clist->version)
540 free(clist->version);
541 if(clist->maxage)
542 free(clist->maxage);
543
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000544 *clist = *co; /* then store all the new data */
Daniel Stenbergc6822f52001-10-24 11:36:55 +0000545
546 free(co); /* free the newly alloced memory */
547 co = clist; /* point to the previous struct instead */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000548
Daniel Stenbergd9a77732002-01-07 14:56:15 +0000549 /* We have replaced a cookie, now skip the rest of the list but
550 make sure the 'lastc' pointer is properly set */
551 do {
552 lastc = clist;
553 clist = clist->next;
554 } while(clist);
555 break;
556 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000557 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000558 lastc = clist;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000559 clist = clist->next;
560 }
561
Daniel Stenberg168703b2003-08-11 09:55:11 +0000562 if(c->running)
563 /* Only show this when NOT reading the cookies from a file */
564 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
565 replace_old?"Replaced":"Added", co->name, co->value,
566 co->domain, co->path, co->expires);
567
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000568 if(!replace_old) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000569 /* then make the last item point on this new one */
570 if(lastc)
571 lastc->next = co;
572 else
573 c->cookies = co;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000574 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000575
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000576 c->numcookies++; /* one more cookie in the jar */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000577 return co;
578}
579
580/*****************************************************************************
581 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000582 * Curl_cookie_init()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000583 *
584 * Inits a cookie struct to read data from a local file. This is always
585 * called before any cookies are set. File may be NULL.
586 *
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000587 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
588 *
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000589 ****************************************************************************/
Daniel Stenberg168703b2003-08-11 09:55:11 +0000590struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
591 char *file,
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000592 struct CookieInfo *inc,
593 bool newsession)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000594{
595 char line[MAX_COOKIE_LINE];
596 struct CookieInfo *c;
597 FILE *fp;
Daniel Stenberg9280c202000-02-10 23:14:53 +0000598 bool fromfile=TRUE;
599
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000600 if(NULL == inc) {
601 /* we didn't get a struct, create one */
602 c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo));
603 if(!c)
604 return NULL; /* failed to get memory */
605 memset(c, 0, sizeof(struct CookieInfo));
606 c->filename = strdup(file?file:"none"); /* copy the name just in case */
607 }
608 else {
609 /* we got an already existing one, use that */
610 c = inc;
611 }
612 c->running = FALSE; /* this is not running, this is init */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000613
Daniel Stenbergf2a25962001-10-10 12:48:32 +0000614 if(file && strequal(file, "-")) {
Daniel Stenberg9280c202000-02-10 23:14:53 +0000615 fp = stdin;
616 fromfile=FALSE;
617 }
618 else
619 fp = file?fopen(file, "r"):NULL;
620
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000621 c->newsession = newsession; /* new session? */
622
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000623 if(fp) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000624 char *lineptr;
625 bool headerline;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000626 while(fgets(line, MAX_COOKIE_LINE, fp)) {
Daniel Stenberg01387f42002-10-28 21:52:00 +0000627 if(checkprefix("Set-Cookie:", line)) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000628 /* This is a cookie line, get it! */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000629 lineptr=&line[11];
630 headerline=TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000631 }
632 else {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000633 lineptr=line;
634 headerline=FALSE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000635 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000636 while(*lineptr && isspace((int)*lineptr))
637 lineptr++;
638
Daniel Stenberg168703b2003-08-11 09:55:11 +0000639 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000640 }
Daniel Stenberg9280c202000-02-10 23:14:53 +0000641 if(fromfile)
642 fclose(fp);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000643 }
644
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000645 c->running = TRUE; /* now, we're running */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000646
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000647 return c;
648}
649
650/*****************************************************************************
651 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000652 * Curl_cookie_getlist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000653 *
654 * For a given host and path, return a linked list of cookies that the
655 * client should send to the server if used now. The secure boolean informs
656 * the cookie if a secure connection is achieved or not.
657 *
658 * It shall only return cookies that haven't expired.
659 *
660 ****************************************************************************/
661
Daniel Stenberg40311042001-01-05 10:11:41 +0000662struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
663 char *host, char *path, bool secure)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000664{
665 struct Cookie *newco;
666 struct Cookie *co;
667 time_t now = time(NULL);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000668 struct Cookie *mainco=NULL;
669
670 if(!c || !c->cookies)
671 return NULL; /* no cookie struct or no cookies in the struct */
672
673 co = c->cookies;
674
675 while(co) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000676 /* only process this cookie if it is not expired or had no expire
677 date AND that if the cookie requires we're secure we must only
678 continue if we are! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000679 if( (co->expires<=0 || (co->expires> now)) &&
680 (co->secure?secure:TRUE) ) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000681
682 /* now check if the domain is correct */
683 if(!co->domain ||
684 (co->tailmatch && tailmatch(co->domain, host)) ||
685 (!co->tailmatch && strequal(host, co->domain)) ) {
686 /* the right part of the host matches the domain stuff in the
687 cookie data */
688
689 /* now check the left part of the path with the cookies path
690 requirement */
691 if(!co->path ||
692 checkprefix(co->path, path) ) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000693
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000694 /* and now, we know this is a match and we should create an
695 entry for the return-linked-list */
696
697 newco = (struct Cookie *)malloc(sizeof(struct Cookie));
698 if(newco) {
699 /* first, copy the whole source cookie: */
700 memcpy(newco, co, sizeof(struct Cookie));
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000701
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000702 /* then modify our next */
703 newco->next = mainco;
704
705 /* point the main to us */
706 mainco = newco;
707 }
Daniel Stenberg5dcab072004-05-10 14:04:06 +0000708 else {
709 /* failure, clear up the allocated chain and return NULL */
710 while(mainco) {
711 co = mainco->next;
712 free(mainco);
713 mainco = co;
714 }
715
716 return NULL;
717 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000718 }
719 }
720 }
721 co = co->next;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000722 }
723
724 return mainco; /* return the new list */
725}
726
727
728/*****************************************************************************
729 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000730 * Curl_cookie_freelist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000731 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000732 * Free a list of cookies previously returned by Curl_cookie_getlist();
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000733 *
734 ****************************************************************************/
735
Daniel Stenberg40311042001-01-05 10:11:41 +0000736void Curl_cookie_freelist(struct Cookie *co)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000737{
738 struct Cookie *next;
739 if(co) {
740 while(co) {
741 next = co->next;
742 free(co); /* we only free the struct since the "members" are all
743 just copied! */
744 co = next;
745 }
746 }
747}
748
749/*****************************************************************************
750 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000751 * Curl_cookie_cleanup()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000752 *
753 * Free a "cookie object" previous created with cookie_init().
754 *
755 ****************************************************************************/
Daniel Stenberg40311042001-01-05 10:11:41 +0000756void Curl_cookie_cleanup(struct CookieInfo *c)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000757{
758 struct Cookie *co;
759 struct Cookie *next;
760 if(c) {
761 if(c->filename)
762 free(c->filename);
763 co = c->cookies;
764
765 while(co) {
766 if(co->name)
767 free(co->name);
768 if(co->value)
769 free(co->value);
770 if(co->domain)
771 free(co->domain);
772 if(co->path)
773 free(co->path);
774 if(co->expirestr)
775 free(co->expirestr);
776
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000777 if(co->version)
778 free(co->version);
779 if(co->maxage)
780 free(co->maxage);
781
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000782 next = co->next;
783 free(co);
784 co = next;
785 }
Daniel Stenberg0f8facb2000-10-09 11:12:34 +0000786 free(c); /* free the base struct as well */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000787 }
788}
789
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000790/*
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000791 * Curl_cookie_output()
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000792 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000793 * Writes all internally known cookies to the specified file. Specify
794 * "-" as file name to write to stdout.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000795 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000796 * The function returns non-zero on write failure.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000797 */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000798int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000799{
800 struct Cookie *co;
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000801 FILE *out;
802 bool use_stdout=FALSE;
803
Daniel Stenberg3f5227d2001-09-10 07:43:08 +0000804 if((NULL == c) || (0 == c->numcookies))
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000805 /* If there are no known cookies, we don't write or even create any
806 destination file */
807 return 0;
808
809 if(strequal("-", dumphere)) {
810 /* use stdout */
811 out = stdout;
812 use_stdout=TRUE;
813 }
814 else {
815 out = fopen(dumphere, "w");
816 if(!out)
817 return 1; /* failure */
818 }
819
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000820 if(c) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000821 fputs("# Netscape HTTP Cookie File\n"
822 "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
Daniel Stenberge719f412001-10-08 06:43:22 +0000823 "# This file was generated by libcurl! Edit at your own risk.\n\n",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000824 out);
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000825 co = c->cookies;
826
827 while(co) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000828 fprintf(out,
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000829 "%s%s\t" /* domain */
830 "%s\t" /* tailmatch */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000831 "%s\t" /* path */
832 "%s\t" /* secure */
833 "%u\t" /* expires */
834 "%s\t" /* name */
835 "%s\n", /* value */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000836
837 /* Make sure all domains are prefixed with a dot if they allow
838 tailmatching. This is Mozilla-style. */
839 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000840 co->domain?co->domain:"unknown",
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000841 co->tailmatch?"TRUE":"FALSE",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000842 co->path?co->path:"/",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000843 co->secure?"TRUE":"FALSE",
844 (unsigned int)co->expires,
845 co->name,
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000846 co->value?co->value:"");
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000847
848 co=co->next;
849 }
850 }
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000851
852 if(!use_stdout)
853 fclose(out);
854
855 return 0;
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000856}
857
Daniel Stenberg08ef2082002-06-11 11:13:01 +0000858#endif /* CURL_DISABLE_HTTP */