1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
26 RECEIVING COOKIE INFORMATION
27 ============================
29 struct CookieInfo *cookie_init(char *file);
31 Inits a cookie struct to store data in a local file. This is always
32 called before any cookies are set.
34 int cookies_set(struct CookieInfo *cookie, char *cookie_line);
36 The 'cookie_line' parameter is a full "Set-cookie:" line as
37 received from a server.
39 The function need to replace previously stored lines that this new
42 It may remove lines that are expired.
44 It should return an indication of success/error.
47 SENDING COOKIE INFORMATION
48 ==========================
50 struct Cookies *cookie_getlist(struct CookieInfo *cookie,
51 char *host, char *path, bool secure);
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
58 It shall only return cookies that haven't expired.
61 Example set of cookies:
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
75 Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
76 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
82 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
84 #define _MPRINTF_REPLACE
85 #include <curl/mprintf.h>
92 #include "curl_memory.h"
94 #include "strtoofft.h"
96 #include "curl_memrchr.h"
98 /* The last #include file should be: */
101 static void freecookie(struct Cookie *co)
121 static bool tailmatch(const char *little, const char *bigone)
123 size_t littlelen = strlen(little);
124 size_t biglen = strlen(bigone);
126 if(littlelen > biglen)
129 return Curl_raw_equal(little, bigone+biglen-littlelen) ? TRUE : FALSE;
133 * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
135 void Curl_cookie_loadfiles(struct SessionHandle *data)
137 struct curl_slist *list = data->change.cookielist;
139 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
141 data->cookies = Curl_cookie_init(data,
144 data->set.cookiesession);
147 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
148 curl_slist_free_all(data->change.cookielist); /* clean up list */
149 data->change.cookielist = NULL; /* don't do this again! */
154 * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
155 * that will be freed before the allocated string is stored there.
157 * It is meant to easily replace strdup()
159 static void strstore(char **str, const char *newstr)
163 *str = strdup(newstr);
167 /****************************************************************************
171 * Add a single cookie line to the cookie keeping object.
173 ***************************************************************************/
176 Curl_cookie_add(struct SessionHandle *data,
177 /* The 'data' pointer here may be NULL at times, and thus
178 must only be used very carefully for things that can deal
179 with data being NULL. Such as infof() and similar */
181 struct CookieInfo *c,
182 bool httpheader, /* TRUE if HTTP header-style line */
183 char *lineptr, /* first character of the line */
184 const char *domain, /* default domain */
185 const char *path) /* full path used when this cookie is set,
186 used to get default path for the cookie
189 struct Cookie *clist;
192 struct Cookie *lastc=NULL;
193 time_t now = time(NULL);
194 bool replace_old = FALSE;
195 bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
197 #ifdef CURL_DISABLE_VERBOSE_STRINGS
201 /* First, alloc and init a new struct for it */
202 co = calloc(1, sizeof(struct Cookie));
204 return NULL; /* bail out if we're this low on memory */
207 /* This line was read off a HTTP-header */
212 what = malloc(MAX_COOKIE_LINE);
218 semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
220 while(*lineptr && ISBLANK(*lineptr))
225 /* we have a <what>=<this> pair or a stand-alone word here */
226 name[0]=what[0]=0; /* init the buffers */
227 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =]=%"
228 MAX_COOKIE_LINE_TXT "[^;\r\n]",
230 /* Use strstore() below to properly deal with received cookie
231 headers that have the same string property set more than once,
232 and then we use the last one. */
236 size_t len=strlen(what);
237 const char *endofn = &ptr[ strlen(name) ];
239 /* skip trailing spaces in name */
240 while(*endofn && ISBLANK(*endofn))
243 /* name ends with a '=' ? */
244 sep = (*endofn == '=')?TRUE:FALSE;
246 /* Strip off trailing whitespace from the 'what' */
247 while(len && ISBLANK(what[len-1])) {
252 /* Skip leading whitespace from the 'what' */
254 while(*whatptr && ISBLANK(*whatptr))
258 /* this was a "<name>=" with no content, and we must allow
259 'secure' and 'httponly' specified this weirdly */
261 if(Curl_raw_equal("secure", name))
263 else if(Curl_raw_equal("httponly", name))
266 /* there was a '=' so we're not done parsing this field */
271 else if(Curl_raw_equal("path", name)) {
272 strstore(&co->path, whatptr);
274 badcookie = TRUE; /* out of memory bad */
278 else if(Curl_raw_equal("domain", name)) {
279 /* note that this name may or may not have a preceding dot, but
280 we don't care about that, we treat the names the same anyway */
282 const char *domptr=whatptr;
286 /* Count the dots, we need to make sure that there are enough
289 if('.' == whatptr[0])
290 /* don't count the initial dot, assume it */
294 nextptr = strchr(domptr, '.');
296 if(domptr != nextptr)
302 /* The original Netscape cookie spec defined that this domain name
303 MUST have three dots (or two if one of the seven holy TLDs),
304 but it seems that these kinds of cookies are in use "out there"
305 so we cannot be that strict. I've therefore lowered the check
306 to not allow less than two dots. */
309 /* Received and skipped a cookie with a domain using too few
311 badcookie=TRUE; /* mark this as a bad cookie */
312 infof(data, "skipped cookie with illegal dotcount domain: %s\n",
316 /* Now, we make sure that our host is within the given domain,
317 or the given domain is not valid and thus cannot be set. */
319 if('.' == whatptr[0])
320 whatptr++; /* ignore preceding dot */
322 if(!domain || tailmatch(whatptr, domain)) {
323 const char *tailptr=whatptr;
324 if(tailptr[0] == '.')
326 strstore(&co->domain, tailptr); /* don't prefix w/dots
332 co->tailmatch=TRUE; /* we always do that if the domain name was
336 /* we did not get a tailmatch and then the attempted set domain
337 is not a domain to which the current host belongs. Mark as
340 infof(data, "skipped cookie with bad tailmatch domain: %s\n",
345 else if(Curl_raw_equal("version", name)) {
346 strstore(&co->version, whatptr);
352 else if(Curl_raw_equal("max-age", name)) {
353 /* Defined in RFC2109:
355 Optional. The Max-Age attribute defines the lifetime of the
356 cookie, in seconds. The delta-seconds value is a decimal non-
357 negative integer. After delta-seconds seconds elapse, the
358 client should discard the cookie. A value of zero means the
359 cookie should be discarded immediately.
362 strstore(&co->maxage, whatptr);
368 strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10)
371 else if(Curl_raw_equal("expires", name)) {
372 strstore(&co->expirestr, whatptr);
377 /* Note that if the date couldn't get parsed for whatever reason,
378 the cookie will be treated as a session cookie */
379 co->expires = curl_getdate(what, &now);
381 /* Session cookies have expires set to 0 so if we get that back
382 from the date parser let's add a second to make it a
383 non-session cookie */
386 else if(co->expires < 0)
390 co->name = strdup(name);
391 co->value = strdup(whatptr);
392 if(!co->name || !co->value) {
398 else this is the second (or more) name we don't know
402 /* this is an "illegal" <what>=<this> pair */
405 if(!semiptr || !*semiptr) {
406 /* we already know there are no more cookies */
412 while(*ptr && ISBLANK(*ptr))
414 semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
417 /* There are no more semicolons, but there's a final name=value pair
419 semiptr=strchr(ptr, '\0');
422 if(!badcookie && !co->domain) {
424 /* no domain was given in the header line, set the default */
425 co->domain=strdup(domain);
431 if(!badcookie && !co->path && path) {
432 /* No path was given in the header line, set the default.
433 Note that the passed-in path to this function MAY have a '?' and
434 following part that MUST not be stored as part of the path. */
435 char *queryp = strchr(path, '?');
437 /* queryp is where the interesting part of the path ends, so now we
438 want to the find the last */
441 endslash = strrchr(path, '/');
443 endslash = memrchr(path, '/', (size_t)(queryp - path));
445 size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
446 co->path=malloc(pathlen+1); /* one extra for the zero byte */
448 memcpy(co->path, path, pathlen);
449 co->path[pathlen]=0; /* zero terminate */
458 if(badcookie || !co->name) {
459 /* we didn't get a cookie name or a bad one,
460 this is an illegal line, bail out */
467 /* This line is NOT a HTTP header style line, we do offer support for
468 reading the odd netscape cookies-file format here */
474 /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
475 marked with httpOnly after the domain name are not accessible
476 from javascripts, but since curl does not operate at javascript
477 level, we include them anyway. In Firefox's cookie files, these
478 lines are preceded with #HttpOnly_ and then everything is
479 as usual, so we skip 10 characters of the line..
481 if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
486 if(lineptr[0]=='#') {
487 /* don't even try the comments */
491 /* strip off the possible end-of-line characters */
492 ptr=strchr(lineptr, '\r');
494 *ptr=0; /* clear it */
495 ptr=strchr(lineptr, '\n');
497 *ptr=0; /* clear it */
499 firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
501 /* Here's a quick check to eliminate normal HTTP-headers from this */
502 if(!firstptr || strchr(firstptr, ':')) {
507 /* Now loop through the fields and init the struct we already have
509 for(ptr=firstptr, fields=0; ptr && !badcookie;
510 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
513 if(ptr[0]=='.') /* skip preceding dots */
515 co->domain = strdup(ptr);
520 /* This field got its explanation on the 23rd of May 2001 by
523 flag: A TRUE/FALSE value indicating if all machines within a given
524 domain can access the variable. This value is set automatically by
525 the browser, depending on the value you set for the domain.
527 As far as I can see, it is set to true when the cookie says
528 .domain.com and to false when the domain is complete www.domain.com
530 co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
533 /* It turns out, that sometimes the file format allows the path
534 field to remain not filled in, we try to detect this and work
535 around it! Andrés GarcÃa made us aware of this... */
536 if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
537 /* only if the path doesn't look like a boolean option! */
538 co->path = strdup(ptr);
543 /* this doesn't look like a path, make one up! */
544 co->path = strdup("/");
547 fields++; /* add a field and fall down to secure */
550 co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
553 co->expires = curlx_strtoofft(ptr, NULL, 10);
556 co->name = strdup(ptr);
561 co->value = strdup(ptr);
568 /* we got a cookie with blank contents, fix it */
569 co->value = strdup("");
576 if(!badcookie && (7 != fields))
577 /* we did not find the sufficient number of fields */
587 if(!c->running && /* read from a file */
588 c->newsession && /* clean session cookies */
589 !co->expires) { /* this is a session cookie since it doesn't expire! */
594 co->livecookie = c->running;
596 /* now, we have parsed the incoming line, we must now check if this
597 superceeds an already existing cookie, which it may if the previous have
598 the same domain and path as this */
603 if(Curl_raw_equal(clist->name, co->name)) {
604 /* the names are identical */
606 if(clist->domain && co->domain) {
607 if(Curl_raw_equal(clist->domain, co->domain))
608 /* The domains are identical */
611 else if(!clist->domain && !co->domain)
615 /* the domains were identical */
617 if(clist->path && co->path) {
618 if(Curl_raw_equal(clist->path, co->path)) {
624 else if(!clist->path && !co->path)
631 if(replace_old && !co->livecookie && clist->livecookie) {
632 /* Both cookies matched fine, except that the already present
633 cookie is "live", which means it was set from a header, while
634 the new one isn't "live" and thus only read from a file. We let
635 live cookies stay alive */
637 /* Free the newcomer and get out of here! */
643 co->next = clist->next; /* get the next-pointer first */
645 /* then free all the old pointers */
654 free(clist->expirestr);
657 free(clist->version);
661 *clist = *co; /* then store all the new data */
663 free(co); /* free the newly alloced memory */
664 co = clist; /* point to the previous struct instead */
666 /* We have replaced a cookie, now skip the rest of the list but
667 make sure the 'lastc' pointer is properly set */
680 /* Only show this when NOT reading the cookies from a file */
681 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
682 "expire %" FORMAT_OFF_T "\n",
683 replace_old?"Replaced":"Added", co->name, co->value,
684 co->domain, co->path, co->expires);
687 /* then make the last item point on this new one */
694 c->numcookies++; /* one more cookie in the jar */
698 /*****************************************************************************
702 * Inits a cookie struct to read data from a local file. This is always
703 * called before any cookies are set. File may be NULL.
705 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
707 ****************************************************************************/
708 struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
710 struct CookieInfo *inc,
713 struct CookieInfo *c;
718 /* we didn't get a struct, create one */
719 c = calloc(1, sizeof(struct CookieInfo));
721 return NULL; /* failed to get memory */
722 c->filename = strdup(file?file:"none"); /* copy the name just in case */
725 /* we got an already existing one, use that */
728 c->running = FALSE; /* this is not running, this is init */
730 if(file && strequal(file, "-")) {
734 else if(file && !*file) {
735 /* points to a "" string */
739 fp = file?fopen(file, "r"):NULL;
741 c->newsession = newsession; /* new session? */
747 char *line = malloc(MAX_COOKIE_LINE);
749 while(fgets(line, MAX_COOKIE_LINE, fp)) {
750 if(checkprefix("Set-Cookie:", line)) {
751 /* This is a cookie line, get it! */
759 while(*lineptr && ISBLANK(*lineptr))
762 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
764 free(line); /* free the line buffer */
770 c->running = TRUE; /* now, we're running */
775 /* sort this so that the longest path gets before the shorter path */
776 static int cookie_sort(const void *p1, const void *p2)
778 struct Cookie *c1 = *(struct Cookie **)p1;
779 struct Cookie *c2 = *(struct Cookie **)p2;
781 size_t l1 = c1->path?strlen(c1->path):0;
782 size_t l2 = c2->path?strlen(c2->path):0;
784 return (l2 > l1) ? 1 : (l2 < l1) ? -1 : 0 ;
787 /*****************************************************************************
789 * Curl_cookie_getlist()
791 * For a given host and path, return a linked list of cookies that the
792 * client should send to the server if used now. The secure boolean informs
793 * the cookie if a secure connection is achieved or not.
795 * It shall only return cookies that haven't expired.
797 ****************************************************************************/
799 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
800 const char *host, const char *path,
803 struct Cookie *newco;
805 time_t now = time(NULL);
806 struct Cookie *mainco=NULL;
809 if(!c || !c->cookies)
810 return NULL; /* no cookie struct or no cookies in the struct */
815 /* only process this cookie if it is not expired or had no expire
816 date AND that if the cookie requires we're secure we must only
817 continue if we are! */
818 if((!co->expires || (co->expires > now)) &&
819 (co->secure?secure:TRUE)) {
821 /* now check if the domain is correct */
823 (co->tailmatch && tailmatch(co->domain, host)) ||
824 (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) {
825 /* the right part of the host matches the domain stuff in the
828 /* now check the left part of the path with the cookies path
831 /* not using checkprefix() because matching should be
833 !strncmp(co->path, path, strlen(co->path)) ) {
835 /* and now, we know this is a match and we should create an
836 entry for the return-linked-list */
838 newco = malloc(sizeof(struct Cookie));
840 /* first, copy the whole source cookie: */
841 memcpy(newco, co, sizeof(struct Cookie));
843 /* then modify our next */
844 newco->next = mainco;
846 /* point the main to us */
853 /* failure, clear up the allocated chain and return NULL */
869 /* Now we need to make sure that if there is a name appearing more than
870 once, the longest specified path version comes first. To make this
871 the swiftest way, we just sort them all based on path length. */
872 struct Cookie **array;
875 /* alloc an array and store all cookie pointers */
876 array = malloc(sizeof(struct Cookie *) * matches);
882 for(i=0; co; co = co->next)
885 /* now sort the cookie pointers in path lenth order */
886 qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
888 /* remake the linked list order according to the new order */
890 mainco = array[0]; /* start here */
891 for(i=0; i<matches-1; i++)
892 array[i]->next = array[i+1];
893 array[matches-1]->next = NULL; /* terminate the list */
895 free(array); /* remove the temporary data again */
898 return mainco; /* return the new list */
901 /*****************************************************************************
903 * Curl_cookie_clearall()
905 * Clear all existing cookies and reset the counter.
907 ****************************************************************************/
908 void Curl_cookie_clearall(struct CookieInfo *cookies)
911 Curl_cookie_freelist(cookies->cookies, TRUE);
912 cookies->cookies = NULL;
913 cookies->numcookies = 0;
917 /*****************************************************************************
919 * Curl_cookie_freelist()
921 * Free a list of cookies previously returned by Curl_cookie_getlist();
923 * The 'cookiestoo' argument tells this function whether to just free the
924 * list or actually also free all cookies within the list as well.
926 ****************************************************************************/
928 void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
937 free(co); /* we only free the struct since the "members" are all just
938 pointed out in the main cookie list! */
945 /*****************************************************************************
947 * Curl_cookie_clearsess()
949 * Free all session cookies in the cookies list.
951 ****************************************************************************/
952 void Curl_cookie_clearsess(struct CookieInfo *cookies)
954 struct Cookie *first, *curr, *next, *prev = NULL;
956 if(!cookies || !cookies->cookies)
959 first = curr = prev = cookies->cookies;
961 for(; curr; curr = next) {
973 cookies->numcookies--;
979 cookies->cookies = first;
983 /*****************************************************************************
985 * Curl_cookie_cleanup()
987 * Free a "cookie object" previous created with cookie_init().
989 ****************************************************************************/
990 void Curl_cookie_cleanup(struct CookieInfo *c)
1004 free(c); /* free the base struct as well */
1008 /* get_netscape_format()
1010 * Formats a string for Netscape output file, w/o a newline at the end.
1012 * Function returns a char * to a formatted line. Has to be free()d
1014 static char *get_netscape_format(const struct Cookie *co)
1017 "%s" /* httponly preamble */
1018 "%s%s\t" /* domain */
1019 "%s\t" /* tailmatch */
1022 "%" FORMAT_OFF_T "\t" /* expires */
1025 co->httponly?"#HttpOnly_":"",
1026 /* Make sure all domains are prefixed with a dot if they allow
1027 tailmatching. This is Mozilla-style. */
1028 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
1029 co->domain?co->domain:"unknown",
1030 co->tailmatch?"TRUE":"FALSE",
1031 co->path?co->path:"/",
1032 co->secure?"TRUE":"FALSE",
1035 co->value?co->value:"");
1041 * Writes all internally known cookies to the specified file. Specify
1042 * "-" as file name to write to stdout.
1044 * The function returns non-zero on write failure.
1046 static int cookie_output(struct CookieInfo *c, const char *dumphere)
1050 bool use_stdout=FALSE;
1052 if((NULL == c) || (0 == c->numcookies))
1053 /* If there are no known cookies, we don't write or even create any
1057 if(strequal("-", dumphere)) {
1063 out = fopen(dumphere, "w");
1065 return 1; /* failure */
1071 fputs("# Netscape HTTP Cookie File\n"
1072 "# http://curl.haxx.se/rfc/cookie_spec.html\n"
1073 "# This file was generated by libcurl! Edit at your own risk.\n\n",
1078 format_ptr = get_netscape_format(co);
1079 if(format_ptr == NULL) {
1080 fprintf(out, "#\n# Fatal libcurl error\n");
1085 fprintf(out, "%s\n", format_ptr);
1097 struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
1099 struct curl_slist *list = NULL;
1100 struct curl_slist *beg;
1104 if((data->cookies == NULL) ||
1105 (data->cookies->numcookies == 0))
1108 c = data->cookies->cookies;
1111 /* fill the list with _all_ the cookies we know */
1112 line = get_netscape_format(c);
1114 curl_slist_free_all(list);
1117 beg = curl_slist_append(list, line);
1120 curl_slist_free_all(list);
1130 void Curl_flush_cookies(struct SessionHandle *data, int cleanup)
1132 if(data->set.str[STRING_COOKIEJAR]) {
1133 if(data->change.cookielist) {
1134 /* If there is a list of cookie files to read, do it first so that
1135 we have all the told files read before we write the new jar.
1136 Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
1137 Curl_cookie_loadfiles(data);
1140 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1142 /* if we have a destination file for all the cookies to get dumped to */
1143 if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
1144 infof(data, "WARNING: failed to save cookies in %s\n",
1145 data->set.str[STRING_COOKIEJAR]);
1148 if(cleanup && data->change.cookielist) {
1149 /* since nothing is written, we can just free the list of cookie file
1151 curl_slist_free_all(data->change.cookielist); /* clean up list */
1152 data->change.cookielist = NULL;
1154 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1157 if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
1158 Curl_cookie_cleanup(data->cookies);
1160 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
1163 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */