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