Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / cookie.c
blobc3b01cd8ad9241dfae1eb652d860a45e45f33b8a
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, 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.2 2007/03/15 19:22:13 andy 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
105 #define my_isspace(x) ((x == ' ') || (x == '\t'))
107 static void freecookie(struct Cookie *co)
109 if(co->expirestr)
110 free(co->expirestr);
111 if(co->domain)
112 free(co->domain);
113 if(co->path)
114 free(co->path);
115 if(co->name)
116 free(co->name);
117 if(co->value)
118 free(co->value);
119 if(co->maxage)
120 free(co->maxage);
121 if(co->version)
122 free(co->version);
124 free(co);
127 static bool tailmatch(const char *little, const char *bigone)
129 size_t littlelen = strlen(little);
130 size_t biglen = strlen(bigone);
132 if(littlelen > biglen)
133 return FALSE;
135 return (bool)strequal(little, bigone+biglen-littlelen);
139 * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
141 void Curl_cookie_loadfiles(struct SessionHandle *data)
143 struct curl_slist *list = data->change.cookielist;
144 if(list) {
145 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
146 while(list) {
147 data->cookies = Curl_cookie_init(data,
148 list->data,
149 data->cookies,
150 data->set.cookiesession);
151 list = list->next;
153 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
154 curl_slist_free_all(data->change.cookielist); /* clean up list */
155 data->change.cookielist = NULL; /* don't do this again! */
159 /****************************************************************************
161 * Curl_cookie_add()
163 * Add a single cookie line to the cookie keeping object.
165 ***************************************************************************/
167 struct Cookie *
168 Curl_cookie_add(struct SessionHandle *data,
169 /* The 'data' pointer here may be NULL at times, and thus
170 must only be used very carefully for things that can deal
171 with data being NULL. Such as infof() and similar */
173 struct CookieInfo *c,
174 bool httpheader, /* TRUE if HTTP header-style line */
175 char *lineptr, /* first character of the line */
176 char *domain, /* default domain */
177 char *path) /* full path used when this cookie is set,
178 used to get default path for the cookie
179 unless set */
181 struct Cookie *clist;
182 char *what;
183 char name[MAX_NAME];
184 char *ptr;
185 char *semiptr;
186 struct Cookie *co;
187 struct Cookie *lastc=NULL;
188 time_t now = time(NULL);
189 bool replace_old = FALSE;
190 bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
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 char *sep;
201 what = malloc(MAX_COOKIE_LINE);
202 if(!what) {
203 free(co);
204 return NULL;
207 semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
209 while(*lineptr && my_isspace(*lineptr))
210 lineptr++;
212 ptr = lineptr;
213 do {
214 /* we have a <what>=<this> pair or a 'secure' word here */
215 sep = strchr(ptr, '=');
216 if(sep && (!semiptr || (semiptr>sep)) ) {
218 * There is a = sign and if there was a semicolon too, which make sure
219 * that the semicolon comes _after_ the equal sign.
222 name[0]=what[0]=0; /* init the buffers */
223 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
224 MAX_COOKIE_LINE_TXT "[^;\r\n]",
225 name, what)) {
226 /* this is a <name>=<what> pair */
228 char *whatptr;
230 /* Strip off trailing whitespace from the 'what' */
231 size_t len=strlen(what);
232 while(len && my_isspace(what[len-1])) {
233 what[len-1]=0;
234 len--;
237 /* Skip leading whitespace from the 'what' */
238 whatptr=what;
239 while(my_isspace(*whatptr)) {
240 whatptr++;
243 if(strequal("path", name)) {
244 co->path=strdup(whatptr);
245 if(!co->path) {
246 badcookie = TRUE; /* out of memory bad */
247 break;
250 else if(strequal("domain", name)) {
251 /* note that this name may or may not have a preceeding dot, but
252 we don't care about that, we treat the names the same anyway */
254 const char *domptr=whatptr;
255 int dotcount=1;
257 /* Count the dots, we need to make sure that there are enough
258 of them. */
260 if('.' == whatptr[0])
261 /* don't count the initial dot, assume it */
262 domptr++;
264 do {
265 domptr = strchr(domptr, '.');
266 if(domptr) {
267 domptr++;
268 dotcount++;
270 } while(domptr);
272 /* The original Netscape cookie spec defined that this domain name
273 MUST have three dots (or two if one of the seven holy TLDs),
274 but it seems that these kinds of cookies are in use "out there"
275 so we cannot be that strict. I've therefore lowered the check
276 to not allow less than two dots. */
278 if(dotcount < 2) {
279 /* Received and skipped a cookie with a domain using too few
280 dots. */
281 badcookie=TRUE; /* mark this as a bad cookie */
282 infof(data, "skipped cookie with illegal dotcount domain: %s\n",
283 whatptr);
285 else {
286 /* Now, we make sure that our host is within the given domain,
287 or the given domain is not valid and thus cannot be set. */
289 if('.' == whatptr[0])
290 whatptr++; /* ignore preceeding dot */
292 if(!domain || tailmatch(whatptr, domain)) {
293 const char *tailptr=whatptr;
294 if(tailptr[0] == '.')
295 tailptr++;
296 co->domain=strdup(tailptr); /* don't prefix w/dots
297 internally */
298 if(!co->domain) {
299 badcookie = TRUE;
300 break;
302 co->tailmatch=TRUE; /* we always do that if the domain name was
303 given */
305 else {
306 /* we did not get a tailmatch and then the attempted set domain
307 is not a domain to which the current host belongs. Mark as
308 bad. */
309 badcookie=TRUE;
310 infof(data, "skipped cookie with bad tailmatch domain: %s\n",
311 whatptr);
315 else if(strequal("version", name)) {
316 co->version=strdup(whatptr);
317 if(!co->version) {
318 badcookie = TRUE;
319 break;
322 else if(strequal("max-age", name)) {
323 /* Defined in RFC2109:
325 Optional. The Max-Age attribute defines the lifetime of the
326 cookie, in seconds. The delta-seconds value is a decimal non-
327 negative integer. After delta-seconds seconds elapse, the
328 client should discard the cookie. A value of zero means the
329 cookie should be discarded immediately.
332 co->maxage = strdup(whatptr);
333 if(!co->maxage) {
334 badcookie = TRUE;
335 break;
337 co->expires =
338 atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now;
340 else if(strequal("expires", name)) {
341 co->expirestr=strdup(whatptr);
342 if(!co->expirestr) {
343 badcookie = TRUE;
344 break;
346 co->expires = curl_getdate(what, &now);
348 else if(!co->name) {
349 co->name = strdup(name);
350 co->value = strdup(whatptr);
351 if(!co->name || !co->value) {
352 badcookie = TRUE;
353 break;
357 else this is the second (or more) name we don't know
358 about! */
360 else {
361 /* this is an "illegal" <what>=<this> pair */
364 else {
365 if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
366 what)) {
367 if(strequal("secure", what))
368 co->secure = TRUE;
369 /* else,
370 unsupported keyword without assign! */
374 if(!semiptr || !*semiptr) {
375 /* we already know there are no more cookies */
376 semiptr = NULL;
377 continue;
380 ptr=semiptr+1;
381 while(ptr && *ptr && my_isspace(*ptr))
382 ptr++;
383 semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
385 if(!semiptr && *ptr)
386 /* There are no more semicolons, but there's a final name=value pair
387 coming up */
388 semiptr=strchr(ptr, '\0');
389 } while(semiptr);
391 if(!badcookie && !co->domain) {
392 if(domain) {
393 /* no domain was given in the header line, set the default */
394 co->domain=strdup(domain);
395 if(!co->domain)
396 badcookie = TRUE;
400 if(!badcookie && !co->path && path) {
401 /* no path was given in the header line, set the default */
402 char *endslash = strrchr(path, '/');
403 if(endslash) {
404 size_t pathlen = endslash-path+1; /* include the ending slash */
405 co->path=malloc(pathlen+1); /* one extra for the zero byte */
406 if(co->path) {
407 memcpy(co->path, path, pathlen);
408 co->path[pathlen]=0; /* zero terminate */
410 else
411 badcookie = TRUE;
415 free(what);
417 if(badcookie || !co->name) {
418 /* we didn't get a cookie name or a bad one,
419 this is an illegal line, bail out */
420 freecookie(co);
421 return NULL;
425 else {
426 /* This line is NOT a HTTP header style line, we do offer support for
427 reading the odd netscape cookies-file format here */
428 char *firstptr;
429 char *tok_buf;
430 int fields;
432 if(lineptr[0]=='#') {
433 /* don't even try the comments */
434 free(co);
435 return NULL;
437 /* strip off the possible end-of-line characters */
438 ptr=strchr(lineptr, '\r');
439 if(ptr)
440 *ptr=0; /* clear it */
441 ptr=strchr(lineptr, '\n');
442 if(ptr)
443 *ptr=0; /* clear it */
445 firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
447 /* Here's a quick check to eliminate normal HTTP-headers from this */
448 if(!firstptr || strchr(firstptr, ':')) {
449 free(co);
450 return NULL;
453 /* Now loop through the fields and init the struct we already have
454 allocated */
455 for(ptr=firstptr, fields=0; ptr && !badcookie;
456 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
457 switch(fields) {
458 case 0:
459 if(ptr[0]=='.') /* skip preceeding dots */
460 ptr++;
461 co->domain = strdup(ptr);
462 if(!co->domain)
463 badcookie = TRUE;
464 break;
465 case 1:
466 /* This field got its explanation on the 23rd of May 2001 by
467 Andrés García:
469 flag: A TRUE/FALSE value indicating if all machines within a given
470 domain can access the variable. This value is set automatically by
471 the browser, depending on the value you set for the domain.
473 As far as I can see, it is set to true when the cookie says
474 .domain.com and to false when the domain is complete www.domain.com
476 co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
477 break;
478 case 2:
479 /* It turns out, that sometimes the file format allows the path
480 field to remain not filled in, we try to detect this and work
481 around it! Andrés García made us aware of this... */
482 if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
483 /* only if the path doesn't look like a boolean option! */
484 co->path = strdup(ptr);
485 if(!co->path)
486 badcookie = TRUE;
487 break;
489 /* this doesn't look like a path, make one up! */
490 co->path = strdup("/");
491 if(!co->path)
492 badcookie = TRUE;
493 fields++; /* add a field and fall down to secure */
494 /* FALLTHROUGH */
495 case 3:
496 co->secure = (bool)strequal(ptr, "TRUE");
497 break;
498 case 4:
499 co->expires = curlx_strtoofft(ptr, NULL, 10);
500 break;
501 case 5:
502 co->name = strdup(ptr);
503 if(!co->name)
504 badcookie = TRUE;
505 break;
506 case 6:
507 co->value = strdup(ptr);
508 if(!co->value)
509 badcookie = TRUE;
510 break;
513 if(6 == fields) {
514 /* we got a cookie with blank contents, fix it */
515 co->value = strdup("");
516 if(!co->value)
517 badcookie = TRUE;
518 else
519 fields++;
522 if(!badcookie && (7 != fields))
523 /* we did not find the sufficient number of fields */
524 badcookie = TRUE;
526 if(badcookie) {
527 freecookie(co);
528 return NULL;
533 if(!c->running && /* read from a file */
534 c->newsession && /* clean session cookies */
535 !co->expires) { /* this is a session cookie since it doesn't expire! */
536 freecookie(co);
537 return NULL;
540 co->livecookie = c->running;
542 /* now, we have parsed the incoming line, we must now check if this
543 superceeds an already existing cookie, which it may if the previous have
544 the same domain and path as this */
546 clist = c->cookies;
547 replace_old = FALSE;
548 while(clist) {
549 if(strequal(clist->name, co->name)) {
550 /* the names are identical */
552 if(clist->domain && co->domain) {
553 if(strequal(clist->domain, co->domain))
554 /* The domains are identical */
555 replace_old=TRUE;
557 else if(!clist->domain && !co->domain)
558 replace_old = TRUE;
560 if(replace_old) {
561 /* the domains were identical */
563 if(clist->path && co->path) {
564 if(strequal(clist->path, co->path)) {
565 replace_old = TRUE;
567 else
568 replace_old = FALSE;
570 else if(!clist->path && !co->path)
571 replace_old = TRUE;
572 else
573 replace_old = FALSE;
577 if(replace_old && !co->livecookie && clist->livecookie) {
578 /* Both cookies matched fine, except that the already present
579 cookie is "live", which means it was set from a header, while
580 the new one isn't "live" and thus only read from a file. We let
581 live cookies stay alive */
583 /* Free the newcomer and get out of here! */
584 freecookie(co);
585 return NULL;
588 if(replace_old) {
589 co->next = clist->next; /* get the next-pointer first */
591 /* then free all the old pointers */
592 if(clist->name)
593 free(clist->name);
594 if(clist->value)
595 free(clist->value);
596 if(clist->domain)
597 free(clist->domain);
598 if(clist->path)
599 free(clist->path);
600 if(clist->expirestr)
601 free(clist->expirestr);
603 if(clist->version)
604 free(clist->version);
605 if(clist->maxage)
606 free(clist->maxage);
608 *clist = *co; /* then store all the new data */
610 free(co); /* free the newly alloced memory */
611 co = clist; /* point to the previous struct instead */
613 /* We have replaced a cookie, now skip the rest of the list but
614 make sure the 'lastc' pointer is properly set */
615 do {
616 lastc = clist;
617 clist = clist->next;
618 } while(clist);
619 break;
622 lastc = clist;
623 clist = clist->next;
626 if(c->running)
627 /* Only show this when NOT reading the cookies from a file */
628 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
629 replace_old?"Replaced":"Added", co->name, co->value,
630 co->domain, co->path, co->expires);
632 if(!replace_old) {
633 /* then make the last item point on this new one */
634 if(lastc)
635 lastc->next = co;
636 else
637 c->cookies = co;
640 c->numcookies++; /* one more cookie in the jar */
641 return co;
644 /*****************************************************************************
646 * Curl_cookie_init()
648 * Inits a cookie struct to read data from a local file. This is always
649 * called before any cookies are set. File may be NULL.
651 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
653 ****************************************************************************/
654 struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
655 char *file,
656 struct CookieInfo *inc,
657 bool newsession)
659 struct CookieInfo *c;
660 FILE *fp;
661 bool fromfile=TRUE;
663 if(NULL == inc) {
664 /* we didn't get a struct, create one */
665 c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
666 if(!c)
667 return NULL; /* failed to get memory */
668 c->filename = strdup(file?file:"none"); /* copy the name just in case */
670 else {
671 /* we got an already existing one, use that */
672 c = inc;
674 c->running = FALSE; /* this is not running, this is init */
676 if(file && strequal(file, "-")) {
677 fp = stdin;
678 fromfile=FALSE;
680 else if(file && !*file) {
681 /* points to a "" string */
682 fp = NULL;
684 else
685 fp = file?fopen(file, "r"):NULL;
687 c->newsession = newsession; /* new session? */
689 if(fp) {
690 char *lineptr;
691 bool headerline;
693 char *line = (char *)malloc(MAX_COOKIE_LINE);
694 if(line) {
695 while(fgets(line, MAX_COOKIE_LINE, fp)) {
696 if(checkprefix("Set-Cookie:", line)) {
697 /* This is a cookie line, get it! */
698 lineptr=&line[11];
699 headerline=TRUE;
701 else {
702 lineptr=line;
703 headerline=FALSE;
705 while(*lineptr && my_isspace(*lineptr))
706 lineptr++;
708 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
710 free(line); /* free the line buffer */
712 if(fromfile)
713 fclose(fp);
716 c->running = TRUE; /* now, we're running */
718 return c;
721 /*****************************************************************************
723 * Curl_cookie_getlist()
725 * For a given host and path, return a linked list of cookies that the
726 * client should send to the server if used now. The secure boolean informs
727 * the cookie if a secure connection is achieved or not.
729 * It shall only return cookies that haven't expired.
731 ****************************************************************************/
733 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
734 char *host, char *path, bool secure)
736 struct Cookie *newco;
737 struct Cookie *co;
738 time_t now = time(NULL);
739 struct Cookie *mainco=NULL;
741 if(!c || !c->cookies)
742 return NULL; /* no cookie struct or no cookies in the struct */
744 co = c->cookies;
746 while(co) {
747 /* only process this cookie if it is not expired or had no expire
748 date AND that if the cookie requires we're secure we must only
749 continue if we are! */
750 if( (co->expires<=0 || (co->expires> now)) &&
751 (co->secure?secure:TRUE) ) {
753 /* now check if the domain is correct */
754 if(!co->domain ||
755 (co->tailmatch && tailmatch(co->domain, host)) ||
756 (!co->tailmatch && strequal(host, co->domain)) ) {
757 /* the right part of the host matches the domain stuff in the
758 cookie data */
760 /* now check the left part of the path with the cookies path
761 requirement */
762 if(!co->path ||
763 /* not using checkprefix() because matching should be
764 case-sensitive */
765 !strncmp(co->path, path, strlen(co->path)) ) {
767 /* and now, we know this is a match and we should create an
768 entry for the return-linked-list */
770 newco = (struct Cookie *)malloc(sizeof(struct Cookie));
771 if(newco) {
772 /* first, copy the whole source cookie: */
773 memcpy(newco, co, sizeof(struct Cookie));
775 /* then modify our next */
776 newco->next = mainco;
778 /* point the main to us */
779 mainco = newco;
781 else {
782 /* failure, clear up the allocated chain and return NULL */
783 while(mainco) {
784 co = mainco->next;
785 free(mainco);
786 mainco = co;
789 return NULL;
794 co = co->next;
797 return mainco; /* return the new list */
800 /*****************************************************************************
802 * Curl_cookie_clearall()
804 * Clear all existing cookies and reset the counter.
806 ****************************************************************************/
807 void Curl_cookie_clearall(struct CookieInfo *cookies)
809 if(cookies) {
810 Curl_cookie_freelist(cookies->cookies);
811 cookies->cookies = NULL;
812 cookies->numcookies = 0;
816 /*****************************************************************************
818 * Curl_cookie_freelist()
820 * Free a list of cookies previously returned by Curl_cookie_getlist();
822 ****************************************************************************/
824 void Curl_cookie_freelist(struct Cookie *co)
826 struct Cookie *next;
827 if(co) {
828 while(co) {
829 next = co->next;
830 free(co); /* we only free the struct since the "members" are all
831 just copied! */
832 co = next;
838 /*****************************************************************************
840 * Curl_cookie_clearsess()
842 * Free all session cookies in the cookies list.
844 ****************************************************************************/
845 void Curl_cookie_clearsess(struct CookieInfo *cookies)
847 struct Cookie *first, *curr, *next, *prev = NULL;
849 if(!cookies->cookies)
850 return;
852 first = curr = prev = cookies->cookies;
854 for(; curr; curr = next) {
855 next = curr->next;
856 if(!curr->expires) {
857 if(first == curr)
858 first = next;
860 if(prev == curr)
861 prev = next;
862 else
863 prev->next = next;
865 free(curr);
866 cookies->numcookies--;
868 else
869 prev = curr;
872 cookies->cookies = first;
876 /*****************************************************************************
878 * Curl_cookie_cleanup()
880 * Free a "cookie object" previous created with cookie_init().
882 ****************************************************************************/
883 void Curl_cookie_cleanup(struct CookieInfo *c)
885 struct Cookie *co;
886 struct Cookie *next;
887 if(c) {
888 if(c->filename)
889 free(c->filename);
890 co = c->cookies;
892 while(co) {
893 next = co->next;
894 freecookie(co);
895 co = next;
897 free(c); /* free the base struct as well */
901 /* get_netscape_format()
903 * Formats a string for Netscape output file, w/o a newline at the end.
905 * Function returns a char * to a formatted line. Has to be free()d
907 static char *get_netscape_format(const struct Cookie *co)
909 return aprintf(
910 "%s%s\t" /* domain */
911 "%s\t" /* tailmatch */
912 "%s\t" /* path */
913 "%s\t" /* secure */
914 "%" FORMAT_OFF_T "\t" /* expires */
915 "%s\t" /* name */
916 "%s", /* value */
917 /* Make sure all domains are prefixed with a dot if they allow
918 tailmatching. This is Mozilla-style. */
919 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
920 co->domain?co->domain:"unknown",
921 co->tailmatch?"TRUE":"FALSE",
922 co->path?co->path:"/",
923 co->secure?"TRUE":"FALSE",
924 co->expires,
925 co->name,
926 co->value?co->value:"");
930 * Curl_cookie_output()
932 * Writes all internally known cookies to the specified file. Specify
933 * "-" as file name to write to stdout.
935 * The function returns non-zero on write failure.
937 int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
939 struct Cookie *co;
940 FILE *out;
941 bool use_stdout=FALSE;
943 if((NULL == c) || (0 == c->numcookies))
944 /* If there are no known cookies, we don't write or even create any
945 destination file */
946 return 0;
948 if(strequal("-", dumphere)) {
949 /* use stdout */
950 out = stdout;
951 use_stdout=TRUE;
953 else {
954 out = fopen(dumphere, "w");
955 if(!out)
956 return 1; /* failure */
959 if(c) {
960 char *format_ptr;
962 fputs("# Netscape HTTP Cookie File\n"
963 "# http://curlm.haxx.se/rfc/cookie_spec.html\n"
964 "# This file was generated by libcurl! Edit at your own risk.\n\n",
965 out);
966 co = c->cookies;
968 while(co) {
969 format_ptr = get_netscape_format(co);
970 if (format_ptr == NULL) {
971 fprintf(out, "#\n# Fatal libcurl error\n");
972 return 1;
974 fprintf(out, "%s\n", format_ptr);
975 free(format_ptr);
976 co=co->next;
980 if(!use_stdout)
981 fclose(out);
983 return 0;
986 struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
988 struct curl_slist *list = NULL;
989 struct curl_slist *beg;
990 struct Cookie *c;
991 char *line;
993 if ((data->cookies == NULL) ||
994 (data->cookies->numcookies == 0))
995 return NULL;
997 c = data->cookies->cookies;
999 beg = list;
1000 while (c) {
1001 /* fill the list with _all_ the cookies we know */
1002 line = get_netscape_format(c);
1003 if (line == NULL) {
1004 /* get_netscape_format returns null only if we run out of memory */
1006 curl_slist_free_all(beg); /* free some memory */
1007 return NULL;
1009 list = curl_slist_append(list, line);
1010 free(line);
1011 c = c->next;
1014 return list;
1017 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */