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