Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl-7.19.0 / lib / cookie.c
blob99da589825a83112674dfa64e5a5d172cb11cd83
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: cookie.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
24 /***
27 RECEIVING COOKIE INFORMATION
28 ============================
30 struct CookieInfo *cookie_init(char *file);
32 Inits a cookie struct to store data in a local file. This is always
33 called before any cookies are set.
35 int cookies_set(struct CookieInfo *cookie, char *cookie_line);
37 The 'cookie_line' parameter is a full "Set-cookie:" line as
38 received from a server.
40 The function need to replace previously stored lines that this new
41 line superceeds.
43 It may remove lines that are expired.
45 It should return an indication of success/error.
48 SENDING COOKIE INFORMATION
49 ==========================
51 struct Cookies *cookie_getlist(struct CookieInfo *cookie,
52 char *host, char *path, bool secure);
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.
59 It shall only return cookies that haven't expired.
62 Example set of cookies:
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 ****/
81 #include "setup.h"
83 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
85 #include <stdlib.h>
86 #include <string.h>
88 #define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */
89 #include <curl/mprintf.h>
91 #include "urldata.h"
92 #include "cookie.h"
93 #include "strequal.h"
94 #include "strtok.h"
95 #include "sendf.h"
96 #include "memory.h"
97 #include "share.h"
98 #include "strtoofft.h"
100 /* The last #include file should be: */
101 #ifdef CURLDEBUG
102 #include "memdebug.h"
103 #endif
106 static void freecookie(struct Cookie *co)
108 if(co->expirestr)
109 free(co->expirestr);
110 if(co->domain)
111 free(co->domain);
112 if(co->path)
113 free(co->path);
114 if(co->name)
115 free(co->name);
116 if(co->value)
117 free(co->value);
118 if(co->maxage)
119 free(co->maxage);
120 if(co->version)
121 free(co->version);
123 free(co);
126 static bool tailmatch(const char *little, const char *bigone)
128 size_t littlelen = strlen(little);
129 size_t biglen = strlen(bigone);
131 if(littlelen > biglen)
132 return FALSE;
134 return (bool)strequal(little, bigone+biglen-littlelen);
138 * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
140 void Curl_cookie_loadfiles(struct SessionHandle *data)
142 struct curl_slist *list = data->change.cookielist;
143 if(list) {
144 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
145 while(list) {
146 data->cookies = Curl_cookie_init(data,
147 list->data,
148 data->cookies,
149 data->set.cookiesession);
150 list = list->next;
152 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
153 curl_slist_free_all(data->change.cookielist); /* clean up list */
154 data->change.cookielist = NULL; /* don't do this again! */
158 /****************************************************************************
160 * Curl_cookie_add()
162 * Add a single cookie line to the cookie keeping object.
164 ***************************************************************************/
166 struct Cookie *
167 Curl_cookie_add(struct SessionHandle *data,
168 /* The 'data' pointer here may be NULL at times, and thus
169 must only be used very carefully for things that can deal
170 with data being NULL. Such as infof() and similar */
172 struct CookieInfo *c,
173 bool httpheader, /* TRUE if HTTP header-style line */
174 char *lineptr, /* first character of the line */
175 const char *domain, /* default domain */
176 const char *path) /* full path used when this cookie is set,
177 used to get default path for the cookie
178 unless set */
180 struct Cookie *clist;
181 char name[MAX_NAME];
182 struct Cookie *co;
183 struct Cookie *lastc=NULL;
184 time_t now = time(NULL);
185 bool replace_old = FALSE;
186 bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
188 #ifdef CURL_DISABLE_VERBOSE_STRINGS
189 (void)data;
190 #endif
192 /* First, alloc and init a new struct for it */
193 co = (struct Cookie *)calloc(sizeof(struct Cookie), 1);
194 if(!co)
195 return NULL; /* bail out if we're this low on memory */
197 if(httpheader) {
198 /* This line was read off a HTTP-header */
199 const char *ptr;
200 const char *sep;
201 const char *semiptr;
202 char *what;
204 what = malloc(MAX_COOKIE_LINE);
205 if(!what) {
206 free(co);
207 return NULL;
210 semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
212 while(*lineptr && ISBLANK(*lineptr))
213 lineptr++;
215 ptr = lineptr;
216 do {
217 /* we have a <what>=<this> pair or a 'secure' word here */
218 sep = strchr(ptr, '=');
219 if(sep && (!semiptr || (semiptr>sep)) ) {
221 * There is a = sign and if there was a semicolon too, which make sure
222 * that the semicolon comes _after_ the equal sign.
225 name[0]=what[0]=0; /* init the buffers */
226 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
227 MAX_COOKIE_LINE_TXT "[^;\r\n]",
228 name, what)) {
229 /* this is a <name>=<what> pair */
231 const char *whatptr;
233 /* Strip off trailing whitespace from the 'what' */
234 size_t len=strlen(what);
235 while(len && ISBLANK(what[len-1])) {
236 what[len-1]=0;
237 len--;
240 /* Skip leading whitespace from the 'what' */
241 whatptr=what;
242 while(*whatptr && ISBLANK(*whatptr)) {
243 whatptr++;
246 if(strequal("path", name)) {
247 co->path=strdup(whatptr);
248 if(!co->path) {
249 badcookie = TRUE; /* out of memory bad */
250 break;
253 else if(strequal("domain", name)) {
254 /* note that this name may or may not have a preceeding dot, but
255 we don't care about that, we treat the names the same anyway */
257 const char *domptr=whatptr;
258 int dotcount=1;
260 /* Count the dots, we need to make sure that there are enough
261 of them. */
263 if('.' == whatptr[0])
264 /* don't count the initial dot, assume it */
265 domptr++;
267 do {
268 domptr = strchr(domptr, '.');
269 if(domptr) {
270 domptr++;
271 dotcount++;
273 } while(domptr);
275 /* The original Netscape cookie spec defined that this domain name
276 MUST have three dots (or two if one of the seven holy TLDs),
277 but it seems that these kinds of cookies are in use "out there"
278 so we cannot be that strict. I've therefore lowered the check
279 to not allow less than two dots. */
281 if(dotcount < 2) {
282 /* Received and skipped a cookie with a domain using too few
283 dots. */
284 badcookie=TRUE; /* mark this as a bad cookie */
285 infof(data, "skipped cookie with illegal dotcount domain: %s\n",
286 whatptr);
288 else {
289 /* Now, we make sure that our host is within the given domain,
290 or the given domain is not valid and thus cannot be set. */
292 if('.' == whatptr[0])
293 whatptr++; /* ignore preceeding dot */
295 if(!domain || tailmatch(whatptr, domain)) {
296 const char *tailptr=whatptr;
297 if(tailptr[0] == '.')
298 tailptr++;
299 co->domain=strdup(tailptr); /* don't prefix w/dots
300 internally */
301 if(!co->domain) {
302 badcookie = TRUE;
303 break;
305 co->tailmatch=TRUE; /* we always do that if the domain name was
306 given */
308 else {
309 /* we did not get a tailmatch and then the attempted set domain
310 is not a domain to which the current host belongs. Mark as
311 bad. */
312 badcookie=TRUE;
313 infof(data, "skipped cookie with bad tailmatch domain: %s\n",
314 whatptr);
318 else if(strequal("version", name)) {
319 co->version=strdup(whatptr);
320 if(!co->version) {
321 badcookie = TRUE;
322 break;
325 else if(strequal("max-age", name)) {
326 /* Defined in RFC2109:
328 Optional. The Max-Age attribute defines the lifetime of the
329 cookie, in seconds. The delta-seconds value is a decimal non-
330 negative integer. After delta-seconds seconds elapse, the
331 client should discard the cookie. A value of zero means the
332 cookie should be discarded immediately.
335 co->maxage = strdup(whatptr);
336 if(!co->maxage) {
337 badcookie = TRUE;
338 break;
340 co->expires =
341 atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now;
343 else if(strequal("expires", name)) {
344 co->expirestr=strdup(whatptr);
345 if(!co->expirestr) {
346 badcookie = TRUE;
347 break;
349 co->expires = curl_getdate(what, &now);
351 else if(!co->name) {
352 co->name = strdup(name);
353 co->value = strdup(whatptr);
354 if(!co->name || !co->value) {
355 badcookie = TRUE;
356 break;
360 else this is the second (or more) name we don't know
361 about! */
363 else {
364 /* this is an "illegal" <what>=<this> pair */
367 else {
368 if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
369 what)) {
370 if(strequal("secure", what)) {
371 co->secure = TRUE;
373 else if (strequal("httponly", what)) {
374 co->httponly = TRUE;
376 /* else,
377 unsupported keyword without assign! */
381 if(!semiptr || !*semiptr) {
382 /* we already know there are no more cookies */
383 semiptr = NULL;
384 continue;
387 ptr=semiptr+1;
388 while(ptr && *ptr && ISBLANK(*ptr))
389 ptr++;
390 semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
392 if(!semiptr && *ptr)
393 /* There are no more semicolons, but there's a final name=value pair
394 coming up */
395 semiptr=strchr(ptr, '\0');
396 } while(semiptr);
398 if(!badcookie && !co->domain) {
399 if(domain) {
400 /* no domain was given in the header line, set the default */
401 co->domain=strdup(domain);
402 if(!co->domain)
403 badcookie = TRUE;
407 if(!badcookie && !co->path && path) {
408 /* no path was given in the header line, set the default */
409 char *endslash = strrchr(path, '/');
410 if(endslash) {
411 size_t pathlen = endslash-path+1; /* include the ending slash */
412 co->path=malloc(pathlen+1); /* one extra for the zero byte */
413 if(co->path) {
414 memcpy(co->path, path, pathlen);
415 co->path[pathlen]=0; /* zero terminate */
417 else
418 badcookie = TRUE;
422 free(what);
424 if(badcookie || !co->name) {
425 /* we didn't get a cookie name or a bad one,
426 this is an illegal line, bail out */
427 freecookie(co);
428 return NULL;
432 else {
433 /* This line is NOT a HTTP header style line, we do offer support for
434 reading the odd netscape cookies-file format here */
435 char *ptr;
436 char *firstptr;
437 char *tok_buf;
438 int fields;
440 /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
441 marked with httpOnly after the domain name are not accessible
442 from javascripts, but since curl does not operate at javascript
443 level, we include them anyway. In Firefox's cookie files, these
444 lines are preceeded with #HttpOnly_ and then everything is
445 as usual, so we skip 10 characters of the line..
447 if (strncmp(lineptr, "#HttpOnly_", 10) == 0) {
448 lineptr += 10;
449 co->httponly = TRUE;
453 if(lineptr[0]=='#') {
454 /* don't even try the comments */
455 free(co);
456 return NULL;
458 /* strip off the possible end-of-line characters */
459 ptr=strchr(lineptr, '\r');
460 if(ptr)
461 *ptr=0; /* clear it */
462 ptr=strchr(lineptr, '\n');
463 if(ptr)
464 *ptr=0; /* clear it */
466 firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
468 /* Here's a quick check to eliminate normal HTTP-headers from this */
469 if(!firstptr || strchr(firstptr, ':')) {
470 free(co);
471 return NULL;
474 /* Now loop through the fields and init the struct we already have
475 allocated */
476 for(ptr=firstptr, fields=0; ptr && !badcookie;
477 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
478 switch(fields) {
479 case 0:
480 if(ptr[0]=='.') /* skip preceeding dots */
481 ptr++;
482 co->domain = strdup(ptr);
483 if(!co->domain)
484 badcookie = TRUE;
485 break;
486 case 1:
487 /* This field got its explanation on the 23rd of May 2001 by
488 Andrés García:
490 flag: A TRUE/FALSE value indicating if all machines within a given
491 domain can access the variable. This value is set automatically by
492 the browser, depending on the value you set for the domain.
494 As far as I can see, it is set to true when the cookie says
495 .domain.com and to false when the domain is complete www.domain.com
497 co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
498 break;
499 case 2:
500 /* It turns out, that sometimes the file format allows the path
501 field to remain not filled in, we try to detect this and work
502 around it! Andrés García made us aware of this... */
503 if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
504 /* only if the path doesn't look like a boolean option! */
505 co->path = strdup(ptr);
506 if(!co->path)
507 badcookie = TRUE;
508 break;
510 /* this doesn't look like a path, make one up! */
511 co->path = strdup("/");
512 if(!co->path)
513 badcookie = TRUE;
514 fields++; /* add a field and fall down to secure */
515 /* FALLTHROUGH */
516 case 3:
517 co->secure = (bool)strequal(ptr, "TRUE");
518 break;
519 case 4:
520 co->expires = curlx_strtoofft(ptr, NULL, 10);
521 break;
522 case 5:
523 co->name = strdup(ptr);
524 if(!co->name)
525 badcookie = TRUE;
526 break;
527 case 6:
528 co->value = strdup(ptr);
529 if(!co->value)
530 badcookie = TRUE;
531 break;
534 if(6 == fields) {
535 /* we got a cookie with blank contents, fix it */
536 co->value = strdup("");
537 if(!co->value)
538 badcookie = TRUE;
539 else
540 fields++;
543 if(!badcookie && (7 != fields))
544 /* we did not find the sufficient number of fields */
545 badcookie = TRUE;
547 if(badcookie) {
548 freecookie(co);
549 return NULL;
554 if(!c->running && /* read from a file */
555 c->newsession && /* clean session cookies */
556 !co->expires) { /* this is a session cookie since it doesn't expire! */
557 freecookie(co);
558 return NULL;
561 co->livecookie = c->running;
563 /* now, we have parsed the incoming line, we must now check if this
564 superceeds an already existing cookie, which it may if the previous have
565 the same domain and path as this */
567 clist = c->cookies;
568 replace_old = FALSE;
569 while(clist) {
570 if(strequal(clist->name, co->name)) {
571 /* the names are identical */
573 if(clist->domain && co->domain) {
574 if(strequal(clist->domain, co->domain))
575 /* The domains are identical */
576 replace_old=TRUE;
578 else if(!clist->domain && !co->domain)
579 replace_old = TRUE;
581 if(replace_old) {
582 /* the domains were identical */
584 if(clist->path && co->path) {
585 if(strequal(clist->path, co->path)) {
586 replace_old = TRUE;
588 else
589 replace_old = FALSE;
591 else if(!clist->path && !co->path)
592 replace_old = TRUE;
593 else
594 replace_old = FALSE;
598 if(replace_old && !co->livecookie && clist->livecookie) {
599 /* Both cookies matched fine, except that the already present
600 cookie is "live", which means it was set from a header, while
601 the new one isn't "live" and thus only read from a file. We let
602 live cookies stay alive */
604 /* Free the newcomer and get out of here! */
605 freecookie(co);
606 return NULL;
609 if(replace_old) {
610 co->next = clist->next; /* get the next-pointer first */
612 /* then free all the old pointers */
613 if(clist->name)
614 free(clist->name);
615 if(clist->value)
616 free(clist->value);
617 if(clist->domain)
618 free(clist->domain);
619 if(clist->path)
620 free(clist->path);
621 if(clist->expirestr)
622 free(clist->expirestr);
624 if(clist->version)
625 free(clist->version);
626 if(clist->maxage)
627 free(clist->maxage);
629 *clist = *co; /* then store all the new data */
631 free(co); /* free the newly alloced memory */
632 co = clist; /* point to the previous struct instead */
634 /* We have replaced a cookie, now skip the rest of the list but
635 make sure the 'lastc' pointer is properly set */
636 do {
637 lastc = clist;
638 clist = clist->next;
639 } while(clist);
640 break;
643 lastc = clist;
644 clist = clist->next;
647 if(c->running)
648 /* Only show this when NOT reading the cookies from a file */
649 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
650 replace_old?"Replaced":"Added", co->name, co->value,
651 co->domain, co->path, co->expires);
653 if(!replace_old) {
654 /* then make the last item point on this new one */
655 if(lastc)
656 lastc->next = co;
657 else
658 c->cookies = co;
661 c->numcookies++; /* one more cookie in the jar */
662 return co;
665 /*****************************************************************************
667 * Curl_cookie_init()
669 * Inits a cookie struct to read data from a local file. This is always
670 * called before any cookies are set. File may be NULL.
672 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
674 ****************************************************************************/
675 struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
676 const char *file,
677 struct CookieInfo *inc,
678 bool newsession)
680 struct CookieInfo *c;
681 FILE *fp;
682 bool fromfile=TRUE;
684 if(NULL == inc) {
685 /* we didn't get a struct, create one */
686 c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
687 if(!c)
688 return NULL; /* failed to get memory */
689 c->filename = strdup(file?file:"none"); /* copy the name just in case */
691 else {
692 /* we got an already existing one, use that */
693 c = inc;
695 c->running = FALSE; /* this is not running, this is init */
697 if(file && strequal(file, "-")) {
698 fp = stdin;
699 fromfile=FALSE;
701 else if(file && !*file) {
702 /* points to a "" string */
703 fp = NULL;
705 else
706 fp = file?fopen(file, "r"):NULL;
708 c->newsession = newsession; /* new session? */
710 if(fp) {
711 char *lineptr;
712 bool headerline;
714 char *line = (char *)malloc(MAX_COOKIE_LINE);
715 if(line) {
716 while(fgets(line, MAX_COOKIE_LINE, fp)) {
717 if(checkprefix("Set-Cookie:", line)) {
718 /* This is a cookie line, get it! */
719 lineptr=&line[11];
720 headerline=TRUE;
722 else {
723 lineptr=line;
724 headerline=FALSE;
726 while(*lineptr && ISBLANK(*lineptr))
727 lineptr++;
729 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
731 free(line); /* free the line buffer */
733 if(fromfile)
734 fclose(fp);
737 c->running = TRUE; /* now, we're running */
739 return c;
742 /*****************************************************************************
744 * Curl_cookie_getlist()
746 * For a given host and path, return a linked list of cookies that the
747 * client should send to the server if used now. The secure boolean informs
748 * the cookie if a secure connection is achieved or not.
750 * It shall only return cookies that haven't expired.
752 ****************************************************************************/
754 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
755 const char *host, const char *path,
756 bool secure)
758 struct Cookie *newco;
759 struct Cookie *co;
760 time_t now = time(NULL);
761 struct Cookie *mainco=NULL;
763 if(!c || !c->cookies)
764 return NULL; /* no cookie struct or no cookies in the struct */
766 co = c->cookies;
768 while(co) {
769 /* only process this cookie if it is not expired or had no expire
770 date AND that if the cookie requires we're secure we must only
771 continue if we are! */
772 if( (co->expires<=0 || (co->expires> now)) &&
773 (co->secure?secure:TRUE) ) {
775 /* now check if the domain is correct */
776 if(!co->domain ||
777 (co->tailmatch && tailmatch(co->domain, host)) ||
778 (!co->tailmatch && strequal(host, co->domain)) ) {
779 /* the right part of the host matches the domain stuff in the
780 cookie data */
782 /* now check the left part of the path with the cookies path
783 requirement */
784 if(!co->path ||
785 /* not using checkprefix() because matching should be
786 case-sensitive */
787 !strncmp(co->path, path, strlen(co->path)) ) {
789 /* and now, we know this is a match and we should create an
790 entry for the return-linked-list */
792 newco = (struct Cookie *)malloc(sizeof(struct Cookie));
793 if(newco) {
794 /* first, copy the whole source cookie: */
795 memcpy(newco, co, sizeof(struct Cookie));
797 /* then modify our next */
798 newco->next = mainco;
800 /* point the main to us */
801 mainco = newco;
803 else {
804 /* failure, clear up the allocated chain and return NULL */
805 while(mainco) {
806 co = mainco->next;
807 free(mainco);
808 mainco = co;
811 return NULL;
816 co = co->next;
819 return mainco; /* return the new list */
822 /*****************************************************************************
824 * Curl_cookie_clearall()
826 * Clear all existing cookies and reset the counter.
828 ****************************************************************************/
829 void Curl_cookie_clearall(struct CookieInfo *cookies)
831 if(cookies) {
832 Curl_cookie_freelist(cookies->cookies, TRUE);
833 cookies->cookies = NULL;
834 cookies->numcookies = 0;
838 /*****************************************************************************
840 * Curl_cookie_freelist()
842 * Free a list of cookies previously returned by Curl_cookie_getlist();
844 * The 'cookiestoo' argument tells this function whether to just free the
845 * list or actually also free all cookies within the list as well.
847 ****************************************************************************/
849 void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
851 struct Cookie *next;
852 if(co) {
853 while(co) {
854 next = co->next;
855 if(cookiestoo)
856 freecookie(co);
857 else
858 free(co); /* we only free the struct since the "members" are all just
859 pointed out in the main cookie list! */
860 co = next;
866 /*****************************************************************************
868 * Curl_cookie_clearsess()
870 * Free all session cookies in the cookies list.
872 ****************************************************************************/
873 void Curl_cookie_clearsess(struct CookieInfo *cookies)
875 struct Cookie *first, *curr, *next, *prev = NULL;
877 if(!cookies->cookies)
878 return;
880 first = curr = prev = cookies->cookies;
882 for(; curr; curr = next) {
883 next = curr->next;
884 if(!curr->expires) {
885 if(first == curr)
886 first = next;
888 if(prev == curr)
889 prev = next;
890 else
891 prev->next = next;
893 freecookie(curr);
894 cookies->numcookies--;
896 else
897 prev = curr;
900 cookies->cookies = first;
904 /*****************************************************************************
906 * Curl_cookie_cleanup()
908 * Free a "cookie object" previous created with cookie_init().
910 ****************************************************************************/
911 void Curl_cookie_cleanup(struct CookieInfo *c)
913 struct Cookie *co;
914 struct Cookie *next;
915 if(c) {
916 if(c->filename)
917 free(c->filename);
918 co = c->cookies;
920 while(co) {
921 next = co->next;
922 freecookie(co);
923 co = next;
925 free(c); /* free the base struct as well */
929 /* get_netscape_format()
931 * Formats a string for Netscape output file, w/o a newline at the end.
933 * Function returns a char * to a formatted line. Has to be free()d
935 static char *get_netscape_format(const struct Cookie *co)
937 return aprintf(
938 "%s" /* httponly preamble */
939 "%s%s\t" /* domain */
940 "%s\t" /* tailmatch */
941 "%s\t" /* path */
942 "%s\t" /* secure */
943 "%" FORMAT_OFF_T "\t" /* expires */
944 "%s\t" /* name */
945 "%s", /* value */
946 co->httponly?"#HttpOnly_":"",
947 /* Make sure all domains are prefixed with a dot if they allow
948 tailmatching. This is Mozilla-style. */
949 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
950 co->domain?co->domain:"unknown",
951 co->tailmatch?"TRUE":"FALSE",
952 co->path?co->path:"/",
953 co->secure?"TRUE":"FALSE",
954 co->expires,
955 co->name,
956 co->value?co->value:"");
960 * Curl_cookie_output()
962 * Writes all internally known cookies to the specified file. Specify
963 * "-" as file name to write to stdout.
965 * The function returns non-zero on write failure.
967 int Curl_cookie_output(struct CookieInfo *c, const char *dumphere)
969 struct Cookie *co;
970 FILE *out;
971 bool use_stdout=FALSE;
973 if((NULL == c) || (0 == c->numcookies))
974 /* If there are no known cookies, we don't write or even create any
975 destination file */
976 return 0;
978 if(strequal("-", dumphere)) {
979 /* use stdout */
980 out = stdout;
981 use_stdout=TRUE;
983 else {
984 out = fopen(dumphere, "w");
985 if(!out)
986 return 1; /* failure */
989 if(c) {
990 char *format_ptr;
992 fputs("# Netscape HTTP Cookie File\n"
993 "# http://curl.haxx.se/rfc/cookie_spec.html\n"
994 "# This file was generated by libcurl! Edit at your own risk.\n\n",
995 out);
996 co = c->cookies;
998 while(co) {
999 format_ptr = get_netscape_format(co);
1000 if(format_ptr == NULL) {
1001 fprintf(out, "#\n# Fatal libcurl error\n");
1002 fclose(out);
1003 return 1;
1005 fprintf(out, "%s\n", format_ptr);
1006 free(format_ptr);
1007 co=co->next;
1011 if(!use_stdout)
1012 fclose(out);
1014 return 0;
1017 struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
1019 struct curl_slist *list = NULL;
1020 struct curl_slist *beg;
1021 struct Cookie *c;
1022 char *line;
1024 if((data->cookies == NULL) ||
1025 (data->cookies->numcookies == 0))
1026 return NULL;
1028 c = data->cookies->cookies;
1030 beg = list;
1031 while(c) {
1032 /* fill the list with _all_ the cookies we know */
1033 line = get_netscape_format(c);
1034 if(line == NULL) {
1035 curl_slist_free_all(beg);
1036 return NULL;
1038 list = curl_slist_append(list, line);
1039 free(line);
1040 if(list == NULL) {
1041 curl_slist_free_all(beg);
1042 return NULL;
1044 else if(beg == NULL) {
1045 beg = list;
1047 c = c->next;
1050 return list;
1053 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */