blob: 8d8d100f0189af2bc811b9e5f796d2a96455df1c [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;
Daniel Stenberg35558e62004-06-22 21:15:51 +0000152 char *what;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000153 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 Stenberg35558e62004-06-22 21:15:51 +0000170
171 what = malloc(MAX_COOKIE_LINE);
172 if(!what) {
173 free(co);
174 return NULL;
175 }
176
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000177 semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
Daniel Stenbergd8b2c812002-07-29 22:22:49 +0000178
179 while(*lineptr && isspace((int)*lineptr))
180 lineptr++;
181
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000182 ptr = lineptr;
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000183 do {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000184 /* we have a <what>=<this> pair or a 'secure' word here */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000185 sep = strchr(ptr, '=');
186 if(sep && (!semiptr || (semiptr>sep)) ) {
187 /*
188 * There is a = sign and if there was a semicolon too, which make sure
189 * that the semicolon comes _after_ the equal sign.
190 */
191
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000192 name[0]=what[0]=0; /* init the buffers */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000193 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
Daniel Stenberg3612c372002-02-27 07:38:04 +0000194 MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000195 name, what)) {
Daniel Stenberg3612c372002-02-27 07:38:04 +0000196 /* this is a <name>=<what> pair */
197
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000198 char *whatptr;
199
Daniel Stenberg3612c372002-02-27 07:38:04 +0000200 /* Strip off trailing whitespace from the 'what' */
Daniel Stenbergd5710642004-02-26 13:40:43 +0000201 size_t len=strlen(what);
Daniel Stenberg3612c372002-02-27 07:38:04 +0000202 while(len && isspace((int)what[len-1])) {
203 what[len-1]=0;
204 len--;
205 }
206
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000207 /* Skip leading whitespace from the 'what' */
208 whatptr=what;
209 while(isspace((int)*whatptr)) {
210 whatptr++;
211 }
212
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000213 if(strequal("path", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000214 co->path=strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000215 if(!co->path) {
216 badcookie = TRUE; /* out of memory bad */
217 break;
218 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000219 }
220 else if(strequal("domain", name)) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000221 /* note that this name may or may not have a preceeding dot, but
222 we don't care about that, we treat the names the same anyway */
223
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000224 const char *domptr=whatptr;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000225 int dotcount=1;
226 unsigned int i;
227
228 static const char *seventhree[]= {
229 "com", "edu", "net", "org", "gov", "mil", "int"
230 };
231
232 /* Count the dots, we need to make sure that there are THREE dots
233 in the normal domains, or TWO in the seventhree-domains. */
234
235 if('.' == whatptr[0])
236 /* don't count the initial dot, assume it */
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000237 domptr++;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000238
239 do {
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000240 domptr = strchr(domptr, '.');
241 if(domptr) {
242 domptr++;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000243 dotcount++;
244 }
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000245 } while(domptr);
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000246
247 for(i=0;
248 i<sizeof(seventhree)/sizeof(seventhree[0]); i++) {
249 if(tailmatch(seventhree[i], whatptr)) {
250 dotcount++; /* we allow one dot less for these */
251 break;
252 }
253 }
Daniel Stenberg98ee12b2003-08-04 23:05:57 +0000254 /* The original Netscape cookie spec defined that this domain name
255 MUST have three dots (or two if one of the seven holy TLDs),
256 but it seems that these kinds of cookies are in use "out there"
257 so we cannot be that strict. I've therefore lowered the check
258 to not allow less than two dots. */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000259
Daniel Stenberg98ee12b2003-08-04 23:05:57 +0000260 if(dotcount < 2) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000261 /* Received and skipped a cookie with a domain using too few
262 dots. */
263 badcookie=TRUE; /* mark this as a bad cookie */
Daniel Stenberg168703b2003-08-11 09:55:11 +0000264 infof(data, "skipped cookie with illegal dotcount domain: %s",
265 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000266 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000267 else {
268 /* Now, we make sure that our host is within the given domain,
269 or the given domain is not valid and thus cannot be set. */
270
Daniel Stenberg755f98e2004-05-21 20:40:15 +0000271 if('.' == whatptr[0])
272 whatptr++; /* ignore preceeding dot */
273
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000274 if(!domain || tailmatch(whatptr, domain)) {
Daniel Stenberg4d17d682004-01-29 13:56:45 +0000275 const char *tailptr=whatptr;
276 if(tailptr[0] == '.')
277 tailptr++;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000278 co->domain=strdup(tailptr); /* don't prefix w/dots
279 internally */
280 if(!co->domain) {
281 badcookie = TRUE;
282 break;
283 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000284 co->tailmatch=TRUE; /* we always do that if the domain name was
285 given */
286 }
Daniel Stenberg465de792003-05-15 22:28:19 +0000287 else {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000288 /* we did not get a tailmatch and then the attempted set domain
289 is not a domain to which the current host belongs. Mark as
290 bad. */
291 badcookie=TRUE;
Daniel Stenberg168703b2003-08-11 09:55:11 +0000292 infof(data, "skipped cookie with bad tailmatch domain: %s",
293 whatptr);
Daniel Stenberg465de792003-05-15 22:28:19 +0000294 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000295 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000296 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000297 else if(strequal("version", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000298 co->version=strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000299 if(!co->version) {
300 badcookie = TRUE;
301 break;
302 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000303 }
304 else if(strequal("max-age", name)) {
305 /* Defined in RFC2109:
306
307 Optional. The Max-Age attribute defines the lifetime of the
308 cookie, in seconds. The delta-seconds value is a decimal non-
309 negative integer. After delta-seconds seconds elapse, the
310 client should discard the cookie. A value of zero means the
311 cookie should be discarded immediately.
312
313 */
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000314 co->maxage = strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000315 if(!co->maxage) {
316 badcookie = TRUE;
317 break;
318 }
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000319 co->expires =
Daniel Stenberg3612c372002-02-27 07:38:04 +0000320 atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000321 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000322 else if(strequal("expires", name)) {
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000323 co->expirestr=strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000324 if(!co->expirestr) {
325 badcookie = TRUE;
326 break;
327 }
Daniel Stenberg96dde762000-05-22 14:12:12 +0000328 co->expires = curl_getdate(what, &now);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000329 }
330 else if(!co->name) {
331 co->name = strdup(name);
Daniel Stenberg2361aab2002-04-14 18:21:17 +0000332 co->value = strdup(whatptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000333 if(!co->name || !co->value) {
334 badcookie = TRUE;
335 break;
336 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000337 }
Daniel Stenbergc8926132001-08-14 08:17:29 +0000338 /*
339 else this is the second (or more) name we don't know
340 about! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000341 }
342 else {
343 /* this is an "illegal" <what>=<this> pair */
344 }
345 }
346 else {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000347 if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000348 what)) {
349 if(strequal("secure", what))
350 co->secure = TRUE;
Daniel Stenbergc8926132001-08-14 08:17:29 +0000351 /* else,
352 unsupported keyword without assign! */
353
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000354 }
355 }
Daniel Stenberga23a8972002-02-26 13:07:53 +0000356 if(!semiptr || !*semiptr) {
357 /* we already know there are no more cookies */
358 semiptr = NULL;
359 continue;
360 }
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000361
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000362 ptr=semiptr+1;
363 while(ptr && *ptr && isspace((int)*ptr))
364 ptr++;
365 semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
Daniel Stenberg87037132002-01-07 23:05:36 +0000366
367 if(!semiptr && *ptr)
368 /* There are no more semicolons, but there's a final name=value pair
369 coming up */
Daniel Stenberga23a8972002-02-26 13:07:53 +0000370 semiptr=strchr(ptr, '\0');
Daniel Stenberg28ad7dc2000-09-25 22:14:42 +0000371 } while(semiptr);
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000372
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000373 if(!badcookie && !co->domain) {
374 if(domain) {
375 /* no domain was given in the header line, set the default */
376 co->domain=strdup(domain);
377 if(!co->domain)
378 badcookie = TRUE;
379 }
Daniel Stenberga23a8972002-02-26 13:07:53 +0000380 }
381
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000382 if(!badcookie && !co->path && path) {
383 /* no path was given in the header line, set the default */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000384 char *endslash = strrchr(path, '/');
385 if(endslash) {
Daniel Stenbergd5710642004-02-26 13:40:43 +0000386 size_t pathlen = endslash-path+1; /* include the ending slash */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000387 co->path=malloc(pathlen+1); /* one extra for the zero byte */
388 if(co->path) {
389 memcpy(co->path, path, pathlen);
390 co->path[pathlen]=0; /* zero terminate */
391 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000392 else
393 badcookie = TRUE;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000394 }
395 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000396
Daniel Stenberg35558e62004-06-22 21:15:51 +0000397 free(what);
398
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000399 if(badcookie || !co->name) {
400 /* we didn't get a cookie name or a bad one,
401 this is an illegal line, bail out */
402 freecookie(co);
403 return NULL;
404 }
405
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000406 }
407 else {
408 /* This line is NOT a HTTP header style line, we do offer support for
409 reading the odd netscape cookies-file format here */
410 char *firstptr;
Daniel Stenbergd5676592001-05-29 19:17:39 +0000411 char *tok_buf;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000412 int fields;
413
414 if(lineptr[0]=='#') {
415 /* don't even try the comments */
416 free(co);
417 return NULL;
418 }
419 /* strip off the possible end-of-line characters */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000420 ptr=strchr(lineptr, '\r');
421 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000422 *ptr=0; /* clear it */
Daniel Stenberg96dde762000-05-22 14:12:12 +0000423 ptr=strchr(lineptr, '\n');
424 if(ptr)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000425 *ptr=0; /* clear it */
426
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000427 firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000428
429 /* Here's a quick check to eliminate normal HTTP-headers from this */
430 if(!firstptr || strchr(firstptr, ':')) {
431 free(co);
432 return NULL;
433 }
434
435 /* Now loop through the fields and init the struct we already have
436 allocated */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000437 for(ptr=firstptr, fields=0; ptr && !badcookie;
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000438 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000439 switch(fields) {
440 case 0:
Daniel Stenberg465de792003-05-15 22:28:19 +0000441 if(ptr[0]=='.') /* skip preceeding dots */
442 ptr++;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000443 co->domain = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000444 if(!co->domain)
445 badcookie = TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000446 break;
447 case 1:
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000448 /* This field got its explanation on the 23rd of May 2001 by
449 Andrés García:
450
451 flag: A TRUE/FALSE value indicating if all machines within a given
452 domain can access the variable. This value is set automatically by
453 the browser, depending on the value you set for the domain.
454
455 As far as I can see, it is set to true when the cookie says
456 .domain.com and to false when the domain is complete www.domain.com
Daniel Stenberg72dec6c2001-05-23 13:04:19 +0000457 */
Daniel Stenberg99482502004-03-10 09:41:37 +0000458 co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000459 break;
460 case 2:
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000461 /* It turns out, that sometimes the file format allows the path
462 field to remain not filled in, we try to detect this and work
463 around it! Andrés García made us aware of this... */
464 if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
465 /* only if the path doesn't look like a boolean option! */
466 co->path = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000467 if(!co->path)
468 badcookie = TRUE;
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000469 break;
470 }
471 /* this doesn't look like a path, make one up! */
472 co->path = strdup("/");
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000473 if(!co->path)
474 badcookie = TRUE;
Daniel Stenberg8dc9f432001-05-23 09:26:45 +0000475 fields++; /* add a field and fall down to secure */
476 /* FALLTHROUGH */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000477 case 3:
Daniel Stenberg99482502004-03-10 09:41:37 +0000478 co->secure = (bool)strequal(ptr, "TRUE");
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000479 break;
480 case 4:
481 co->expires = atoi(ptr);
482 break;
483 case 5:
484 co->name = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000485 if(!co->name)
486 badcookie = TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000487 break;
488 case 6:
489 co->value = strdup(ptr);
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000490 if(!co->value)
491 badcookie = TRUE;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000492 break;
493 }
494 }
Daniel Stenberg168703b2003-08-11 09:55:11 +0000495 if(6 == fields) {
496 /* we got a cookie with blank contents, fix it */
497 co->value = strdup("");
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000498 if(!co->value)
499 badcookie = TRUE;
500 else
501 fields++;
Daniel Stenberg168703b2003-08-11 09:55:11 +0000502 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000503
504 if(!badcookie && (7 != fields))
505 /* we did not find the sufficient number of fields */
506 badcookie = TRUE;
507
508 if(badcookie) {
509 freecookie(co);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000510 return NULL;
511 }
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000512
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000513 }
514
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000515 if(!c->running && /* read from a file */
516 c->newsession && /* clean session cookies */
517 !co->expires) { /* this is a session cookie since it doesn't expire! */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000518 freecookie(co);
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000519 return NULL;
520 }
521
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000522 co->livecookie = c->running;
523
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000524 /* now, we have parsed the incoming line, we must now check if this
525 superceeds an already existing cookie, which it may if the previous have
526 the same domain and path as this */
527
528 clist = c->cookies;
529 replace_old = FALSE;
530 while(clist) {
531 if(strequal(clist->name, co->name)) {
532 /* the names are identical */
533
534 if(clist->domain && co->domain) {
Daniel Stenberg465de792003-05-15 22:28:19 +0000535 if(strequal(clist->domain, co->domain))
536 /* The domains are identical */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000537 replace_old=TRUE;
538 }
539 else if(!clist->domain && !co->domain)
540 replace_old = TRUE;
541
542 if(replace_old) {
543 /* the domains were identical */
544
545 if(clist->path && co->path) {
546 if(strequal(clist->path, co->path)) {
547 replace_old = TRUE;
548 }
549 else
550 replace_old = FALSE;
551 }
552 else if(!clist->path && !co->path)
553 replace_old = TRUE;
554 else
555 replace_old = FALSE;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000556
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000557 }
558
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000559 if(replace_old && !co->livecookie && clist->livecookie) {
560 /* Both cookies matched fine, except that the already present
561 cookie is "live", which means it was set from a header, while
562 the new one isn't "live" and thus only read from a file. We let
563 live cookies stay alive */
564
565 /* Free the newcomer and get out of here! */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000566 freecookie(co);
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000567 return NULL;
568 }
569
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000570 if(replace_old) {
571 co->next = clist->next; /* get the next-pointer first */
572
573 /* then free all the old pointers */
574 if(clist->name)
575 free(clist->name);
576 if(clist->value)
577 free(clist->value);
578 if(clist->domain)
579 free(clist->domain);
580 if(clist->path)
581 free(clist->path);
582 if(clist->expirestr)
583 free(clist->expirestr);
584
Daniel Stenbergc6a8bb32000-02-01 23:54:51 +0000585 if(clist->version)
586 free(clist->version);
587 if(clist->maxage)
588 free(clist->maxage);
589
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000590 *clist = *co; /* then store all the new data */
Daniel Stenbergc6822f52001-10-24 11:36:55 +0000591
592 free(co); /* free the newly alloced memory */
593 co = clist; /* point to the previous struct instead */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000594
Daniel Stenbergd9a77732002-01-07 14:56:15 +0000595 /* We have replaced a cookie, now skip the rest of the list but
596 make sure the 'lastc' pointer is properly set */
597 do {
598 lastc = clist;
599 clist = clist->next;
600 } while(clist);
601 break;
602 }
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000603 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000604 lastc = clist;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000605 clist = clist->next;
606 }
607
Daniel Stenberg168703b2003-08-11 09:55:11 +0000608 if(c->running)
609 /* Only show this when NOT reading the cookies from a file */
610 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
611 replace_old?"Replaced":"Added", co->name, co->value,
612 co->domain, co->path, co->expires);
613
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000614 if(!replace_old) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000615 /* then make the last item point on this new one */
616 if(lastc)
617 lastc->next = co;
618 else
619 c->cookies = co;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000620 }
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000621
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000622 c->numcookies++; /* one more cookie in the jar */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000623 return co;
624}
625
626/*****************************************************************************
627 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000628 * Curl_cookie_init()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000629 *
630 * Inits a cookie struct to read data from a local file. This is always
631 * called before any cookies are set. File may be NULL.
632 *
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000633 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
634 *
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000635 ****************************************************************************/
Daniel Stenberg168703b2003-08-11 09:55:11 +0000636struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
637 char *file,
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000638 struct CookieInfo *inc,
639 bool newsession)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000640{
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000641 struct CookieInfo *c;
642 FILE *fp;
Daniel Stenberg9280c202000-02-10 23:14:53 +0000643 bool fromfile=TRUE;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000644
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000645 if(NULL == inc) {
646 /* we didn't get a struct, create one */
Daniel Stenbergce945bd2004-06-30 12:05:07 +0000647 c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000648 if(!c)
649 return NULL; /* failed to get memory */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000650 c->filename = strdup(file?file:"none"); /* copy the name just in case */
651 }
652 else {
653 /* we got an already existing one, use that */
654 c = inc;
655 }
656 c->running = FALSE; /* this is not running, this is init */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000657
Daniel Stenbergf2a25962001-10-10 12:48:32 +0000658 if(file && strequal(file, "-")) {
Daniel Stenberg9280c202000-02-10 23:14:53 +0000659 fp = stdin;
660 fromfile=FALSE;
661 }
662 else
663 fp = file?fopen(file, "r"):NULL;
664
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000665 c->newsession = newsession; /* new session? */
666
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000667 if(fp) {
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000668 char *lineptr;
669 bool headerline;
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000670
Daniel Stenbergce945bd2004-06-30 12:05:07 +0000671 char *line = (char *)malloc(MAX_COOKIE_LINE);
672 if(line) {
673 while(fgets(line, MAX_COOKIE_LINE, fp)) {
674 if(checkprefix("Set-Cookie:", line)) {
675 /* This is a cookie line, get it! */
676 lineptr=&line[11];
677 headerline=TRUE;
678 }
679 else {
680 lineptr=line;
681 headerline=FALSE;
682 }
683 while(*lineptr && isspace((int)*lineptr))
684 lineptr++;
685
686 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
687 }
688 free(line); /* free the line buffer */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000689 }
Daniel Stenberg9280c202000-02-10 23:14:53 +0000690 if(fromfile)
691 fclose(fp);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000692 }
693
Daniel Stenberg980a47b2002-05-07 09:58:13 +0000694 c->running = TRUE; /* now, we're running */
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000695
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000696 return c;
697}
698
699/*****************************************************************************
700 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000701 * Curl_cookie_getlist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000702 *
703 * For a given host and path, return a linked list of cookies that the
704 * client should send to the server if used now. The secure boolean informs
705 * the cookie if a secure connection is achieved or not.
706 *
707 * It shall only return cookies that haven't expired.
708 *
709 ****************************************************************************/
710
Daniel Stenberg40311042001-01-05 10:11:41 +0000711struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
712 char *host, char *path, bool secure)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000713{
714 struct Cookie *newco;
715 struct Cookie *co;
716 time_t now = time(NULL);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000717 struct Cookie *mainco=NULL;
718
719 if(!c || !c->cookies)
720 return NULL; /* no cookie struct or no cookies in the struct */
721
722 co = c->cookies;
723
724 while(co) {
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000725 /* only process this cookie if it is not expired or had no expire
726 date AND that if the cookie requires we're secure we must only
727 continue if we are! */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000728 if( (co->expires<=0 || (co->expires> now)) &&
729 (co->secure?secure:TRUE) ) {
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000730
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000731 /* now check if the domain is correct */
732 if(!co->domain ||
733 (co->tailmatch && tailmatch(co->domain, host)) ||
734 (!co->tailmatch && strequal(host, co->domain)) ) {
735 /* the right part of the host matches the domain stuff in the
736 cookie data */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000737
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000738 /* now check the left part of the path with the cookies path
739 requirement */
740 if(!co->path ||
741 checkprefix(co->path, path) ) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000742
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000743 /* and now, we know this is a match and we should create an
744 entry for the return-linked-list */
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000745
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000746 newco = (struct Cookie *)malloc(sizeof(struct Cookie));
747 if(newco) {
748 /* first, copy the whole source cookie: */
749 memcpy(newco, co, sizeof(struct Cookie));
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000750
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000751 /* then modify our next */
752 newco->next = mainco;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000753
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000754 /* point the main to us */
755 mainco = newco;
756 }
Daniel Stenberg5dcab072004-05-10 14:04:06 +0000757 else {
758 /* failure, clear up the allocated chain and return NULL */
759 while(mainco) {
760 co = mainco->next;
761 free(mainco);
762 mainco = co;
763 }
764
765 return NULL;
766 }
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000767 }
768 }
769 }
770 co = co->next;
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000771 }
772
773 return mainco; /* return the new list */
774}
775
776
777/*****************************************************************************
778 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000779 * Curl_cookie_freelist()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000780 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000781 * Free a list of cookies previously returned by Curl_cookie_getlist();
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000782 *
783 ****************************************************************************/
784
Daniel Stenberg40311042001-01-05 10:11:41 +0000785void Curl_cookie_freelist(struct Cookie *co)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000786{
787 struct Cookie *next;
788 if(co) {
789 while(co) {
790 next = co->next;
791 free(co); /* we only free the struct since the "members" are all
792 just copied! */
793 co = next;
794 }
795 }
796}
797
798/*****************************************************************************
799 *
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000800 * Curl_cookie_cleanup()
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000801 *
802 * Free a "cookie object" previous created with cookie_init().
803 *
804 ****************************************************************************/
Daniel Stenberg40311042001-01-05 10:11:41 +0000805void Curl_cookie_cleanup(struct CookieInfo *c)
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000806{
807 struct Cookie *co;
808 struct Cookie *next;
809 if(c) {
810 if(c->filename)
811 free(c->filename);
812 co = c->cookies;
813
814 while(co) {
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000815 next = co->next;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000816 freecookie(co);
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000817 co = next;
818 }
Daniel Stenberg0f8facb2000-10-09 11:12:34 +0000819 free(c); /* free the base struct as well */
Daniel Stenbergae1912c1999-12-29 14:20:26 +0000820 }
821}
822
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000823/*
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000824 * Curl_cookie_output()
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000825 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000826 * Writes all internally known cookies to the specified file. Specify
827 * "-" as file name to write to stdout.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000828 *
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000829 * The function returns non-zero on write failure.
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000830 */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000831int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000832{
833 struct Cookie *co;
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000834 FILE *out;
835 bool use_stdout=FALSE;
836
Daniel Stenberg3f5227d2001-09-10 07:43:08 +0000837 if((NULL == c) || (0 == c->numcookies))
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000838 /* If there are no known cookies, we don't write or even create any
839 destination file */
840 return 0;
841
842 if(strequal("-", dumphere)) {
843 /* use stdout */
844 out = stdout;
845 use_stdout=TRUE;
846 }
847 else {
848 out = fopen(dumphere, "w");
849 if(!out)
850 return 1; /* failure */
851 }
852
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000853 if(c) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000854 fputs("# Netscape HTTP Cookie File\n"
855 "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
Daniel Stenberge719f412001-10-08 06:43:22 +0000856 "# This file was generated by libcurl! Edit at your own risk.\n\n",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000857 out);
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000858 co = c->cookies;
Daniel Stenberg34e8baa2004-05-12 12:04:38 +0000859
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000860 while(co) {
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000861 fprintf(out,
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000862 "%s%s\t" /* domain */
863 "%s\t" /* tailmatch */
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000864 "%s\t" /* path */
865 "%s\t" /* secure */
866 "%u\t" /* expires */
867 "%s\t" /* name */
868 "%s\n", /* value */
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000869
870 /* Make sure all domains are prefixed with a dot if they allow
871 tailmatching. This is Mozilla-style. */
872 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000873 co->domain?co->domain:"unknown",
Daniel Stenbergefd836d2003-04-30 17:03:43 +0000874 co->tailmatch?"TRUE":"FALSE",
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000875 co->path?co->path:"/",
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000876 co->secure?"TRUE":"FALSE",
877 (unsigned int)co->expires,
878 co->name,
Daniel Stenberg598e8df2001-09-26 07:08:29 +0000879 co->value?co->value:"");
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000880
881 co=co->next;
882 }
883 }
Daniel Stenberga2b6ef32001-08-29 09:32:18 +0000884
885 if(!use_stdout)
886 fclose(out);
887
888 return 0;
Daniel Stenbergc9c21152001-08-23 14:05:25 +0000889}
890
Daniel Stenberg08ef2082002-06-11 11:13:01 +0000891#endif /* CURL_DISABLE_HTTP */