cbf513d058429f1d31e27e577f385bf902e68fe5
[platform/upstream/curl.git] / lib / cookie.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id$
22  ***************************************************************************/
23
24 /***
25
26
27 RECEIVING COOKIE INFORMATION
28 ============================
29
30 struct CookieInfo *cookie_init(char *file);
31
32         Inits a cookie struct to store data in a local file. This is always
33         called before any cookies are set.
34
35 int 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
48 SENDING COOKIE INFORMATION
49 ==========================
50
51 struct Cookies *cookie_getlist(struct CookieInfo *cookie,
52                                char *host, char *path, bool secure);
53
54         For a given host and path, return a linked list of cookies that
55         the client should send to the server if used now. The secure
56         boolean informs the cookie if a secure connection is achieved or
57         not.
58
59         It shall only return cookies that haven't expired.
60
61
62 Example set of cookies:
63
64     Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
65     Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
66     domain=.fidelity.com; path=/ftgw; secure
67     Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
68     domain=.fidelity.com; path=/; secure
69     Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
70     domain=.fidelity.com; path=/; secure
71     Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
72     domain=.fidelity.com; path=/; secure
73     Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
74     domain=.fidelity.com; path=/; secure
75     Set-cookie:
76     Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
77     13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
78 ****/
79
80
81 #include "setup.h"
82
83 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
84
85 #include <stdlib.h>
86 #include <string.h>
87
88 #define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */
89 #include <curl/mprintf.h>
90
91 #include "urldata.h"
92 #include "cookie.h"
93 #include "strequal.h"
94 #include "strtok.h"
95 #include "sendf.h"
96 #include "curl_memory.h"
97 #include "share.h"
98 #include "strtoofft.h"
99 #include "rawstr.h"
100 #include "curl_memrchr.h"
101
102 /* The last #include file should be: */
103 #include "memdebug.h"
104
105
106 static void freecookie(struct Cookie *co)
107 {
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);
122
123   free(co);
124 }
125
126 static bool tailmatch(const char *little, const char *bigone)
127 {
128   size_t littlelen = strlen(little);
129   size_t biglen = strlen(bigone);
130
131   if(littlelen > biglen)
132     return FALSE;
133
134   return (bool)Curl_raw_equal(little, bigone+biglen-littlelen);
135 }
136
137 /*
138  * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
139  */
140 void Curl_cookie_loadfiles(struct SessionHandle *data)
141 {
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;
151     }
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! */
155   }
156 }
157
158 /*
159  * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
160  * that will be freed before the allocated string is stored there.
161  *
162  * It is meant to easily replace strdup()
163  */
164 static void strstore(char **str, const char *newstr)
165 {
166   if(*str)
167     free(*str);
168   *str = strdup(newstr);
169 }
170
171
172 /****************************************************************************
173  *
174  * Curl_cookie_add()
175  *
176  * Add a single cookie line to the cookie keeping object.
177  *
178  ***************************************************************************/
179
180 struct Cookie *
181 Curl_cookie_add(struct SessionHandle *data,
182                 /* The 'data' pointer here may be NULL at times, and thus
183                    must only be used very carefully for things that can deal
184                    with data being NULL. Such as infof() and similar */
185
186                 struct CookieInfo *c,
187                 bool httpheader, /* TRUE if HTTP header-style line */
188                 char *lineptr,   /* first character of the line */
189                 const char *domain, /* default domain */
190                 const char *path)   /* full path used when this cookie is set,
191                                        used to get default path for the cookie
192                                        unless set */
193 {
194   struct Cookie *clist;
195   char name[MAX_NAME];
196   struct Cookie *co;
197   struct Cookie *lastc=NULL;
198   time_t now = time(NULL);
199   bool replace_old = FALSE;
200   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
201
202 #ifdef CURL_DISABLE_VERBOSE_STRINGS
203   (void)data;
204 #endif
205
206   /* First, alloc and init a new struct for it */
207   co = calloc(1, sizeof(struct Cookie));
208   if(!co)
209     return NULL; /* bail out if we're this low on memory */
210
211   if(httpheader) {
212     /* This line was read off a HTTP-header */
213     const char *ptr;
214     const char *sep;
215     const char *semiptr;
216     char *what;
217
218     what = malloc(MAX_COOKIE_LINE);
219     if(!what) {
220       free(co);
221       return NULL;
222     }
223
224     semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
225
226     while(*lineptr && ISBLANK(*lineptr))
227       lineptr++;
228
229     ptr = lineptr;
230     do {
231       /* we have a <what>=<this> pair or a 'secure' word here */
232       sep = strchr(ptr, '=');
233       if(sep && (!semiptr || (semiptr>sep)) ) {
234         /*
235          * There is a = sign and if there was a semicolon too, which make sure
236          * that the semicolon comes _after_ the equal sign.
237          */
238
239         name[0]=what[0]=0; /* init the buffers */
240         if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
241                        MAX_COOKIE_LINE_TXT "[^;\r\n]",
242                        name, what)) {
243           /* this is a <name>=<what> pair. We use strstore() below to properly
244              deal with received cookie headers that have the same string
245              property set more than once, and then we use the last one. */
246
247           const char *whatptr;
248
249           /* Strip off trailing whitespace from the 'what' */
250           size_t len=strlen(what);
251           while(len && ISBLANK(what[len-1])) {
252             what[len-1]=0;
253             len--;
254           }
255
256           /* Skip leading whitespace from the 'what' */
257           whatptr=what;
258           while(*whatptr && ISBLANK(*whatptr)) {
259             whatptr++;
260           }
261
262           if(Curl_raw_equal("path", name)) {
263             strstore(&co->path, whatptr);
264             if(!co->path) {
265               badcookie = TRUE; /* out of memory bad */
266               break;
267             }
268           }
269           else if(Curl_raw_equal("domain", name)) {
270             /* note that this name may or may not have a preceeding dot, but
271                we don't care about that, we treat the names the same anyway */
272
273             const char *domptr=whatptr;
274             int dotcount=1;
275
276             /* Count the dots, we need to make sure that there are enough
277                of them. */
278
279             if('.' == whatptr[0])
280               /* don't count the initial dot, assume it */
281               domptr++;
282
283             do {
284               domptr = strchr(domptr, '.');
285               if(domptr) {
286                 domptr++;
287                 dotcount++;
288               }
289             } while(domptr);
290
291             /* The original Netscape cookie spec defined that this domain name
292                MUST have three dots (or two if one of the seven holy TLDs),
293                but it seems that these kinds of cookies are in use "out there"
294                so we cannot be that strict. I've therefore lowered the check
295                to not allow less than two dots. */
296
297             if(dotcount < 2) {
298               /* Received and skipped a cookie with a domain using too few
299                  dots. */
300               badcookie=TRUE; /* mark this as a bad cookie */
301               infof(data, "skipped cookie with illegal dotcount domain: %s\n",
302                     whatptr);
303             }
304             else {
305               /* Now, we make sure that our host is within the given domain,
306                  or the given domain is not valid and thus cannot be set. */
307
308               if('.' == whatptr[0])
309                 whatptr++; /* ignore preceeding dot */
310
311               if(!domain || tailmatch(whatptr, domain)) {
312                 const char *tailptr=whatptr;
313                 if(tailptr[0] == '.')
314                   tailptr++;
315                 strstore(&co->domain, tailptr); /* don't prefix w/dots
316                                                    internally */
317                 if(!co->domain) {
318                   badcookie = TRUE;
319                   break;
320                 }
321                 co->tailmatch=TRUE; /* we always do that if the domain name was
322                                        given */
323               }
324               else {
325                 /* we did not get a tailmatch and then the attempted set domain
326                    is not a domain to which the current host belongs. Mark as
327                    bad. */
328                 badcookie=TRUE;
329                 infof(data, "skipped cookie with bad tailmatch domain: %s\n",
330                       whatptr);
331               }
332             }
333           }
334           else if(Curl_raw_equal("version", name)) {
335             strstore(&co->version, whatptr);
336             if(!co->version) {
337               badcookie = TRUE;
338               break;
339             }
340           }
341           else if(Curl_raw_equal("max-age", name)) {
342             /* Defined in RFC2109:
343
344                Optional.  The Max-Age attribute defines the lifetime of the
345                cookie, in seconds.  The delta-seconds value is a decimal non-
346                negative integer.  After delta-seconds seconds elapse, the
347                client should discard the cookie.  A value of zero means the
348                cookie should be discarded immediately.
349
350              */
351             strstore(&co->maxage, whatptr);
352             if(!co->maxage) {
353               badcookie = TRUE;
354               break;
355             }
356             co->expires =
357               atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) +
358               (long)now;
359           }
360           else if(Curl_raw_equal("expires", name)) {
361             strstore(&co->expirestr, whatptr);
362             if(!co->expirestr) {
363               badcookie = TRUE;
364               break;
365             }
366             /* Note that if the date couldn't get parsed for whatever reason,
367                the cookie will be treated as a session cookie */
368             co->expires = curl_getdate(what, &now);
369
370             /* Session cookies have expires set to 0 so if we get that back
371                from the date parser let's add a second to make it a
372                non-session cookie */
373             if (co->expires == 0)
374               co->expires = 1;
375             else if( co->expires < 0 )
376                 co->expires = 0;
377           }
378           else if(!co->name) {
379             co->name = strdup(name);
380             co->value = strdup(whatptr);
381             if(!co->name || !co->value) {
382               badcookie = TRUE;
383               break;
384             }
385           }
386           /*
387             else this is the second (or more) name we don't know
388             about! */
389         }
390         else {
391           /* this is an "illegal" <what>=<this> pair */
392         }
393       }
394       else {
395         if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
396                   what)) {
397           if(Curl_raw_equal("secure", what)) {
398             co->secure = TRUE;
399           }
400           else if (Curl_raw_equal("httponly", what)) {
401             co->httponly = TRUE;
402           }
403           /* else,
404              unsupported keyword without assign! */
405
406         }
407       }
408       if(!semiptr || !*semiptr) {
409         /* we already know there are no more cookies */
410         semiptr = NULL;
411         continue;
412       }
413
414       ptr=semiptr+1;
415       while(*ptr && ISBLANK(*ptr))
416         ptr++;
417       semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
418
419       if(!semiptr && *ptr)
420         /* There are no more semicolons, but there's a final name=value pair
421            coming up */
422         semiptr=strchr(ptr, '\0');
423     } while(semiptr);
424
425     if(!badcookie && !co->domain) {
426       if(domain) {
427         /* no domain was given in the header line, set the default */
428         co->domain=strdup(domain);
429         if(!co->domain)
430           badcookie = TRUE;
431       }
432     }
433
434     if(!badcookie && !co->path && path) {
435       /* No path was given in the header line, set the default.
436          Note that the passed-in path to this function MAY have a '?' and
437          following part that MUST not be stored as part of the path. */
438       char *queryp = strchr(path, '?');
439
440       /* queryp is where the interesting part of the path ends, so now we
441          want to the find the last */
442       char *endslash;
443       if(!queryp)
444         endslash = strrchr(path, '/');
445       else
446         endslash = memrchr(path, '/', (size_t)(queryp - path));
447       if(endslash) {
448         size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
449         co->path=malloc(pathlen+1); /* one extra for the zero byte */
450         if(co->path) {
451           memcpy(co->path, path, pathlen);
452           co->path[pathlen]=0; /* zero terminate */
453         }
454         else
455           badcookie = TRUE;
456       }
457     }
458
459     free(what);
460
461     if(badcookie || !co->name) {
462       /* we didn't get a cookie name or a bad one,
463          this is an illegal line, bail out */
464       freecookie(co);
465       return NULL;
466     }
467
468   }
469   else {
470     /* This line is NOT a HTTP header style line, we do offer support for
471        reading the odd netscape cookies-file format here */
472     char *ptr;
473     char *firstptr;
474     char *tok_buf=NULL;
475     int fields;
476
477     /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
478        marked with httpOnly after the domain name are not accessible
479        from javascripts, but since curl does not operate at javascript
480        level, we include them anyway. In Firefox's cookie files, these
481        lines are preceeded with #HttpOnly_ and then everything is
482        as usual, so we skip 10 characters of the line..
483     */
484     if (strncmp(lineptr, "#HttpOnly_", 10) == 0) {
485       lineptr += 10;
486       co->httponly = TRUE;
487     }
488
489     if(lineptr[0]=='#') {
490       /* don't even try the comments */
491       free(co);
492       return NULL;
493     }
494     /* strip off the possible end-of-line characters */
495     ptr=strchr(lineptr, '\r');
496     if(ptr)
497       *ptr=0; /* clear it */
498     ptr=strchr(lineptr, '\n');
499     if(ptr)
500       *ptr=0; /* clear it */
501
502     firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
503
504     /* Here's a quick check to eliminate normal HTTP-headers from this */
505     if(!firstptr || strchr(firstptr, ':')) {
506       free(co);
507       return NULL;
508     }
509
510     /* Now loop through the fields and init the struct we already have
511        allocated */
512     for(ptr=firstptr, fields=0; ptr && !badcookie;
513         ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
514       switch(fields) {
515       case 0:
516         if(ptr[0]=='.') /* skip preceeding dots */
517           ptr++;
518         co->domain = strdup(ptr);
519         if(!co->domain)
520           badcookie = TRUE;
521         break;
522       case 1:
523         /* This field got its explanation on the 23rd of May 2001 by
524            Andrés García:
525
526            flag: A TRUE/FALSE value indicating if all machines within a given
527            domain can access the variable. This value is set automatically by
528            the browser, depending on the value you set for the domain.
529
530            As far as I can see, it is set to true when the cookie says
531            .domain.com and to false when the domain is complete www.domain.com
532         */
533         co->tailmatch=(bool)Curl_raw_equal(ptr, "TRUE"); /* store information */
534         break;
535       case 2:
536         /* It turns out, that sometimes the file format allows the path
537            field to remain not filled in, we try to detect this and work
538            around it! Andrés García made us aware of this... */
539         if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
540           /* only if the path doesn't look like a boolean option! */
541           co->path = strdup(ptr);
542           if(!co->path)
543             badcookie = TRUE;
544           break;
545         }
546         /* this doesn't look like a path, make one up! */
547         co->path = strdup("/");
548         if(!co->path)
549           badcookie = TRUE;
550         fields++; /* add a field and fall down to secure */
551         /* FALLTHROUGH */
552       case 3:
553         co->secure = (bool)Curl_raw_equal(ptr, "TRUE");
554         break;
555       case 4:
556         co->expires = curlx_strtoofft(ptr, NULL, 10);
557         break;
558       case 5:
559         co->name = strdup(ptr);
560         if(!co->name)
561           badcookie = TRUE;
562         break;
563       case 6:
564         co->value = strdup(ptr);
565         if(!co->value)
566           badcookie = TRUE;
567         break;
568       }
569     }
570     if(6 == fields) {
571       /* we got a cookie with blank contents, fix it */
572       co->value = strdup("");
573       if(!co->value)
574         badcookie = TRUE;
575       else
576         fields++;
577     }
578
579     if(!badcookie && (7 != fields))
580       /* we did not find the sufficient number of fields */
581       badcookie = TRUE;
582
583     if(badcookie) {
584       freecookie(co);
585       return NULL;
586     }
587
588   }
589
590   if(!c->running &&    /* read from a file */
591      c->newsession &&  /* clean session cookies */
592      !co->expires) {   /* this is a session cookie since it doesn't expire! */
593     freecookie(co);
594     return NULL;
595   }
596
597   co->livecookie = c->running;
598
599   /* now, we have parsed the incoming line, we must now check if this
600      superceeds an already existing cookie, which it may if the previous have
601      the same domain and path as this */
602
603   clist = c->cookies;
604   replace_old = FALSE;
605   while(clist) {
606     if(Curl_raw_equal(clist->name, co->name)) {
607       /* the names are identical */
608
609       if(clist->domain && co->domain) {
610         if(Curl_raw_equal(clist->domain, co->domain))
611           /* The domains are identical */
612           replace_old=TRUE;
613       }
614       else if(!clist->domain && !co->domain)
615         replace_old = TRUE;
616
617       if(replace_old) {
618         /* the domains were identical */
619
620         if(clist->path && co->path) {
621           if(Curl_raw_equal(clist->path, co->path)) {
622             replace_old = TRUE;
623           }
624           else
625             replace_old = FALSE;
626         }
627         else if(!clist->path && !co->path)
628           replace_old = TRUE;
629         else
630           replace_old = FALSE;
631
632       }
633
634       if(replace_old && !co->livecookie && clist->livecookie) {
635         /* Both cookies matched fine, except that the already present
636            cookie is "live", which means it was set from a header, while
637            the new one isn't "live" and thus only read from a file. We let
638            live cookies stay alive */
639
640         /* Free the newcomer and get out of here! */
641         freecookie(co);
642         return NULL;
643       }
644
645       if(replace_old) {
646         co->next = clist->next; /* get the next-pointer first */
647
648         /* then free all the old pointers */
649         free(clist->name);
650         if(clist->value)
651           free(clist->value);
652         if(clist->domain)
653           free(clist->domain);
654         if(clist->path)
655           free(clist->path);
656         if(clist->expirestr)
657           free(clist->expirestr);
658
659         if(clist->version)
660           free(clist->version);
661         if(clist->maxage)
662           free(clist->maxage);
663
664         *clist = *co;  /* then store all the new data */
665
666         free(co);   /* free the newly alloced memory */
667         co = clist; /* point to the previous struct instead */
668
669         /* We have replaced a cookie, now skip the rest of the list but
670            make sure the 'lastc' pointer is properly set */
671         do {
672           lastc = clist;
673           clist = clist->next;
674         } while(clist);
675         break;
676       }
677     }
678     lastc = clist;
679     clist = clist->next;
680   }
681
682   if(c->running)
683     /* Only show this when NOT reading the cookies from a file */
684     infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
685           "expire %" FORMAT_OFF_T "\n",
686           replace_old?"Replaced":"Added", co->name, co->value,
687           co->domain, co->path, co->expires);
688
689   if(!replace_old) {
690     /* then make the last item point on this new one */
691     if(lastc)
692       lastc->next = co;
693     else
694       c->cookies = co;
695   }
696
697   c->numcookies++; /* one more cookie in the jar */
698   return co;
699 }
700
701 /*****************************************************************************
702  *
703  * Curl_cookie_init()
704  *
705  * Inits a cookie struct to read data from a local file. This is always
706  * called before any cookies are set. File may be NULL.
707  *
708  * If 'newsession' is TRUE, discard all "session cookies" on read from file.
709  *
710  ****************************************************************************/
711 struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
712                                     const char *file,
713                                     struct CookieInfo *inc,
714                                     bool newsession)
715 {
716   struct CookieInfo *c;
717   FILE *fp;
718   bool fromfile=TRUE;
719
720   if(NULL == inc) {
721     /* we didn't get a struct, create one */
722     c = calloc(1, sizeof(struct CookieInfo));
723     if(!c)
724       return NULL; /* failed to get memory */
725     c->filename = strdup(file?file:"none"); /* copy the name just in case */
726   }
727   else {
728     /* we got an already existing one, use that */
729     c = inc;
730   }
731   c->running = FALSE; /* this is not running, this is init */
732
733   if(file && strequal(file, "-")) {
734     fp = stdin;
735     fromfile=FALSE;
736   }
737   else if(file && !*file) {
738     /* points to a "" string */
739     fp = NULL;
740   }
741   else
742     fp = file?fopen(file, "r"):NULL;
743
744   c->newsession = newsession; /* new session? */
745
746   if(fp) {
747     char *lineptr;
748     bool headerline;
749
750     char *line = malloc(MAX_COOKIE_LINE);
751     if(line) {
752       while(fgets(line, MAX_COOKIE_LINE, fp)) {
753         if(checkprefix("Set-Cookie:", line)) {
754           /* This is a cookie line, get it! */
755           lineptr=&line[11];
756           headerline=TRUE;
757         }
758         else {
759           lineptr=line;
760           headerline=FALSE;
761         }
762         while(*lineptr && ISBLANK(*lineptr))
763           lineptr++;
764
765         Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
766       }
767       free(line); /* free the line buffer */
768     }
769     if(fromfile)
770       fclose(fp);
771   }
772
773   c->running = TRUE;          /* now, we're running */
774
775   return c;
776 }
777
778 /* sort this so that the longest path gets before the shorter path */
779 static int cookie_sort(const void *p1, const void *p2)
780 {
781   struct Cookie *c1 = *(struct Cookie **)p1;
782   struct Cookie *c2 = *(struct Cookie **)p2;
783
784   size_t l1 = c1->path?strlen(c1->path):0;
785   size_t l2 = c2->path?strlen(c2->path):0;
786
787   return (l2 > l1) ? 1 : (l2 < l1) ? -1 : 0 ;
788 }
789
790 /*****************************************************************************
791  *
792  * Curl_cookie_getlist()
793  *
794  * For a given host and path, return a linked list of cookies that the
795  * client should send to the server if used now. The secure boolean informs
796  * the cookie if a secure connection is achieved or not.
797  *
798  * It shall only return cookies that haven't expired.
799  *
800  ****************************************************************************/
801
802 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
803                                    const char *host, const char *path,
804                                    bool secure)
805 {
806   struct Cookie *newco;
807   struct Cookie *co;
808   time_t now = time(NULL);
809   struct Cookie *mainco=NULL;
810   size_t matches = 0;
811
812   if(!c || !c->cookies)
813     return NULL; /* no cookie struct or no cookies in the struct */
814
815   co = c->cookies;
816
817   while(co) {
818     /* only process this cookie if it is not expired or had no expire
819        date AND that if the cookie requires we're secure we must only
820        continue if we are! */
821     if( (!co->expires || (co->expires > now)) &&
822         (co->secure?secure:TRUE) ) {
823
824       /* now check if the domain is correct */
825       if(!co->domain ||
826          (co->tailmatch && tailmatch(co->domain, host)) ||
827          (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) {
828         /* the right part of the host matches the domain stuff in the
829            cookie data */
830
831         /* now check the left part of the path with the cookies path
832            requirement */
833         if(!co->path ||
834            /* not using checkprefix() because matching should be
835               case-sensitive */
836            !strncmp(co->path, path, strlen(co->path)) ) {
837
838           /* and now, we know this is a match and we should create an
839              entry for the return-linked-list */
840
841           newco = malloc(sizeof(struct Cookie));
842           if(newco) {
843             /* first, copy the whole source cookie: */
844             memcpy(newco, co, sizeof(struct Cookie));
845
846             /* then modify our next */
847             newco->next = mainco;
848
849             /* point the main to us */
850             mainco = newco;
851
852             matches++;
853           }
854           else {
855             fail:
856             /* failure, clear up the allocated chain and return NULL */
857             while(mainco) {
858               co = mainco->next;
859               free(mainco);
860               mainco = co;
861             }
862
863             return NULL;
864           }
865         }
866       }
867     }
868     co = co->next;
869   }
870
871   if(matches) {
872     /* Now we need to make sure that if there is a name appearing more than
873        once, the longest specified path version comes first. To make this
874        the swiftest way, we just sort them all based on path length. */
875     struct Cookie **array;
876     size_t i;
877
878     /* alloc an array and store all cookie pointers */
879     array = (struct Cookie **)malloc(sizeof(struct Cookie *) * matches);
880     if(!array)
881       goto fail;
882
883     co = mainco;
884
885     for(i=0; co; co = co->next)
886       array[i++] = co;
887
888     /* now sort the cookie pointers in path lenth order */
889     qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
890
891     /* remake the linked list order according to the new order */
892
893     mainco = array[0]; /* start here */
894     for(i=0; i<matches-1; i++)
895       array[i]->next = array[i+1];
896     array[matches-1]->next = NULL; /* terminate the list */
897
898     free(array); /* remove the temporary data again */
899   }
900
901   return mainco; /* return the new list */
902 }
903
904 /*****************************************************************************
905  *
906  * Curl_cookie_clearall()
907  *
908  * Clear all existing cookies and reset the counter.
909  *
910  ****************************************************************************/
911 void Curl_cookie_clearall(struct CookieInfo *cookies)
912 {
913   if(cookies) {
914     Curl_cookie_freelist(cookies->cookies, TRUE);
915     cookies->cookies = NULL;
916     cookies->numcookies = 0;
917   }
918 }
919
920 /*****************************************************************************
921  *
922  * Curl_cookie_freelist()
923  *
924  * Free a list of cookies previously returned by Curl_cookie_getlist();
925  *
926  * The 'cookiestoo' argument tells this function whether to just free the
927  * list or actually also free all cookies within the list as well.
928  *
929  ****************************************************************************/
930
931 void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
932 {
933   struct Cookie *next;
934   if(co) {
935     while(co) {
936       next = co->next;
937       if(cookiestoo)
938         freecookie(co);
939       else
940         free(co); /* we only free the struct since the "members" are all just
941                      pointed out in the main cookie list! */
942       co = next;
943     }
944   }
945 }
946
947
948 /*****************************************************************************
949  *
950  * Curl_cookie_clearsess()
951  *
952  * Free all session cookies in the cookies list.
953  *
954  ****************************************************************************/
955 void Curl_cookie_clearsess(struct CookieInfo *cookies)
956 {
957   struct Cookie *first, *curr, *next, *prev = NULL;
958
959   if(!cookies || !cookies->cookies)
960     return;
961
962   first = curr = prev = cookies->cookies;
963
964   for(; curr; curr = next) {
965     next = curr->next;
966     if(!curr->expires) {
967       if(first == curr)
968         first = next;
969
970       if(prev == curr)
971         prev = next;
972       else
973         prev->next = next;
974
975       freecookie(curr);
976       cookies->numcookies--;
977     }
978     else
979       prev = curr;
980   }
981
982   cookies->cookies = first;
983 }
984
985
986 /*****************************************************************************
987  *
988  * Curl_cookie_cleanup()
989  *
990  * Free a "cookie object" previous created with cookie_init().
991  *
992  ****************************************************************************/
993 void Curl_cookie_cleanup(struct CookieInfo *c)
994 {
995   struct Cookie *co;
996   struct Cookie *next;
997   if(c) {
998     if(c->filename)
999       free(c->filename);
1000     co = c->cookies;
1001
1002     while(co) {
1003       next = co->next;
1004       freecookie(co);
1005       co = next;
1006     }
1007     free(c); /* free the base struct as well */
1008   }
1009 }
1010
1011 /* get_netscape_format()
1012  *
1013  * Formats a string for Netscape output file, w/o a newline at the end.
1014  *
1015  * Function returns a char * to a formatted line. Has to be free()d
1016 */
1017 static char *get_netscape_format(const struct Cookie *co)
1018 {
1019   return aprintf(
1020     "%s"     /* httponly preamble */
1021     "%s%s\t" /* domain */
1022     "%s\t"   /* tailmatch */
1023     "%s\t"   /* path */
1024     "%s\t"   /* secure */
1025     "%" FORMAT_OFF_T "\t"   /* expires */
1026     "%s\t"   /* name */
1027     "%s",    /* value */
1028     co->httponly?"#HttpOnly_":"",
1029     /* Make sure all domains are prefixed with a dot if they allow
1030        tailmatching. This is Mozilla-style. */
1031     (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
1032     co->domain?co->domain:"unknown",
1033     co->tailmatch?"TRUE":"FALSE",
1034     co->path?co->path:"/",
1035     co->secure?"TRUE":"FALSE",
1036     co->expires,
1037     co->name,
1038     co->value?co->value:"");
1039 }
1040
1041 /*
1042  * Curl_cookie_output()
1043  *
1044  * Writes all internally known cookies to the specified file. Specify
1045  * "-" as file name to write to stdout.
1046  *
1047  * The function returns non-zero on write failure.
1048  */
1049 int Curl_cookie_output(struct CookieInfo *c, const char *dumphere)
1050 {
1051   struct Cookie *co;
1052   FILE *out;
1053   bool use_stdout=FALSE;
1054
1055   if((NULL == c) || (0 == c->numcookies))
1056     /* If there are no known cookies, we don't write or even create any
1057        destination file */
1058     return 0;
1059
1060   if(strequal("-", dumphere)) {
1061     /* use stdout */
1062     out = stdout;
1063     use_stdout=TRUE;
1064   }
1065   else {
1066     out = fopen(dumphere, "w");
1067     if(!out)
1068       return 1; /* failure */
1069   }
1070
1071   if(c) {
1072     char *format_ptr;
1073
1074     fputs("# Netscape HTTP Cookie File\n"
1075           "# http://curl.haxx.se/rfc/cookie_spec.html\n"
1076           "# This file was generated by libcurl! Edit at your own risk.\n\n",
1077           out);
1078     co = c->cookies;
1079
1080     while(co) {
1081       format_ptr = get_netscape_format(co);
1082       if(format_ptr == NULL) {
1083         fprintf(out, "#\n# Fatal libcurl error\n");
1084         if(!use_stdout)
1085           fclose(out);
1086         return 1;
1087       }
1088       fprintf(out, "%s\n", format_ptr);
1089       free(format_ptr);
1090       co=co->next;
1091     }
1092   }
1093
1094   if(!use_stdout)
1095     fclose(out);
1096
1097   return 0;
1098 }
1099
1100 struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
1101 {
1102   struct curl_slist *list = NULL;
1103   struct curl_slist *beg;
1104   struct Cookie *c;
1105   char *line;
1106
1107   if((data->cookies == NULL) ||
1108       (data->cookies->numcookies == 0))
1109     return NULL;
1110
1111   c = data->cookies->cookies;
1112
1113   beg = list;
1114   while(c) {
1115     /* fill the list with _all_ the cookies we know */
1116     line = get_netscape_format(c);
1117     if(line == NULL) {
1118       curl_slist_free_all(beg);
1119       return NULL;
1120     }
1121     list = curl_slist_append(list, line);
1122     free(line);
1123     if(list == NULL) {
1124       curl_slist_free_all(beg);
1125       return NULL;
1126     }
1127     else if(beg == NULL) {
1128       beg = list;
1129     }
1130     c = c->next;
1131   }
1132
1133   return list;
1134 }
1135
1136 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */