diff options
Diffstat (limited to 'Utilities/cmcurl/lib/cookie.c')
-rw-r--r-- | Utilities/cmcurl/lib/cookie.c | 276 |
1 files changed, 183 insertions, 93 deletions
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index 5f0f145..2c028b3 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -143,6 +143,28 @@ static bool tailmatch(const char *cooke_domain, const char *hostname) } /* + * Return true if the given string is an IP(v4|v6) address. + */ +static bool isip(const char *domain) +{ + struct in_addr addr; +#ifdef ENABLE_IPV6 + struct in6_addr addr6; +#endif + + if(Curl_inet_pton(AF_INET, domain, &addr) +#ifdef ENABLE_IPV6 + || Curl_inet_pton(AF_INET6, domain, &addr6) +#endif + ) { + /* domain name given as IP address */ + return TRUE; + } + + return FALSE; +} + +/* * matching cookie path and url path * RFC6265 5.1.4 Paths and Path-Match */ @@ -218,6 +240,62 @@ pathmatched: } /* + * Return the top-level domain, for optimal hashing. + */ +static const char *get_top_domain(const char * const domain, size_t *outlen) +{ + size_t len; + const char *first = NULL, *last; + + if(!domain) + return NULL; + + len = strlen(domain); + last = memrchr(domain, '.', len); + if(last) { + first = memrchr(domain, '.', (size_t) (last - domain)); + if(first) + len -= (size_t) (++first - domain); + } + + if(outlen) + *outlen = len; + + return first? first: domain; +} + +/* + * A case-insensitive hash for the cookie domains. + */ +static size_t cookie_hash_domain(const char *domain, const size_t len) +{ + const char *end = domain + len; + size_t h = 5381; + + while(domain < end) { + h += h << 5; + h ^= Curl_raw_toupper(*domain++); + } + + return (h % COOKIE_HASH_SIZE); +} + +/* + * Hash this domain. + */ +static size_t cookiehash(const char * const domain) +{ + const char *top; + size_t len; + + if(!domain || isip(domain)) + return 0; + + top = get_top_domain(domain, &len); + return cookie_hash_domain(top, len); +} + +/* * cookie path sanitize */ static char *sanitize_cookie_path(const char *cookie_path) @@ -303,48 +381,29 @@ static void remove_expired(struct CookieInfo *cookies) { struct Cookie *co, *nx, *pv; curl_off_t now = (curl_off_t)time(NULL); - - co = cookies->cookies; - pv = NULL; - while(co) { - nx = co->next; - if(co->expires && co->expires < now) { - if(!pv) { - cookies->cookies = co->next; + unsigned int i; + + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + co = cookies->cookies[i]; + pv = NULL; + while(co) { + nx = co->next; + if(co->expires && co->expires < now) { + if(!pv) { + cookies->cookies[i] = co->next; + } + else { + pv->next = co->next; + } + cookies->numcookies--; + freecookie(co); } else { - pv->next = co->next; + pv = co; } - cookies->numcookies--; - freecookie(co); - } - else { - pv = co; + co = nx; } - co = nx; - } -} - -/* - * Return true if the given string is an IP(v4|v6) address. - */ -static bool isip(const char *domain) -{ - struct in_addr addr; -#ifdef ENABLE_IPV6 - struct in6_addr addr6; -#endif - - if(Curl_inet_pton(AF_INET, domain, &addr) -#ifdef ENABLE_IPV6 - || Curl_inet_pton(AF_INET6, domain, &addr6) -#endif - ) { - /* domain name given as IP address */ - return TRUE; } - - return FALSE; } /**************************************************************************** @@ -368,6 +427,7 @@ Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *c, bool httpheader, /* TRUE if HTTP header-style line */ + bool noexpire, /* if TRUE, skip remove_expired() */ char *lineptr, /* first character of the line */ const char *domain, /* default domain */ const char *path) /* full path used when this cookie is set, @@ -380,6 +440,7 @@ Curl_cookie_add(struct Curl_easy *data, time_t now = time(NULL); bool replace_old = FALSE; bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ + size_t myhash; #ifdef USE_LIBPSL const psl_ctx_t *psl; @@ -430,9 +491,6 @@ Curl_cookie_add(struct Curl_easy *data, size_t nlen = strlen(name); const char *endofn = &ptr[ nlen ]; - infof(data, "cookie size: name/val %d + %d bytes\n", - nlen, len); - if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) || ((nlen + len) > MAX_NAME)) { /* too long individual name or contents, or too long combination of @@ -470,10 +528,16 @@ Curl_cookie_add(struct Curl_easy *data, while(*whatptr && ISBLANK(*whatptr)) whatptr++; - if(!co->name && sep) { + if(!co->name) { /* The very first name/value pair is the actual cookie name */ + if(!sep) { + /* Bad name/value pair. */ + badcookie = TRUE; + break; + } co->name = strdup(name); co->value = strdup(whatptr); + done = TRUE; if(!co->name || !co->value) { badcookie = TRUE; break; @@ -822,7 +886,8 @@ Curl_cookie_add(struct Curl_easy *data, the same domain and path as this */ /* at first, remove expired cookies */ - remove_expired(c); + if(!noexpire) + remove_expired(c); #ifdef USE_LIBPSL /* Check if the domain is a Public Suffix and if yes, ignore the cookie. @@ -839,7 +904,8 @@ Curl_cookie_add(struct Curl_easy *data, } #endif - clist = c->cookies; + myhash = cookiehash(co->domain); + clist = c->cookies[myhash]; replace_old = FALSE; while(clist) { if(strcasecompare(clist->name, co->name)) { @@ -925,7 +991,7 @@ Curl_cookie_add(struct Curl_easy *data, if(lastc) lastc->next = co; else - c->cookies = co; + c->cookies[myhash] = co; c->numcookies++; /* one more cookie in the jar */ } @@ -1029,9 +1095,10 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, while(*lineptr && ISBLANK(*lineptr)) lineptr++; - Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); + Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL); } free(line); /* free the line buffer */ + remove_expired(c); /* run this once, not on every cookie */ if(fromfile) fclose(fp); @@ -1137,8 +1204,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, struct Cookie *mainco = NULL; size_t matches = 0; bool is_ip; + const size_t myhash = cookiehash(host); - if(!c || !c->cookies) + if(!c || !c->cookies[myhash]) return NULL; /* no cookie struct or no cookies in the struct */ /* at first, remove expired cookies */ @@ -1147,7 +1215,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* check if host is an IP(v4|v6) address */ is_ip = isip(host); - co = c->cookies; + co = c->cookies[myhash]; while(co) { /* only process this cookie if it is not expired or had no expire @@ -1235,8 +1303,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, void Curl_cookie_clearall(struct CookieInfo *cookies) { if(cookies) { - Curl_cookie_freelist(cookies->cookies); - cookies->cookies = NULL; + unsigned int i; + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + Curl_cookie_freelist(cookies->cookies[i]); + cookies->cookies[i] = NULL; + } cookies->numcookies = 0; } } @@ -1270,31 +1341,37 @@ void Curl_cookie_freelist(struct Cookie *co) void Curl_cookie_clearsess(struct CookieInfo *cookies) { struct Cookie *first, *curr, *next, *prev = NULL; + unsigned int i; - if(!cookies || !cookies->cookies) + if(!cookies) return; - first = curr = prev = cookies->cookies; + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + if(!cookies->cookies[i]) + continue; - for(; curr; curr = next) { - next = curr->next; - if(!curr->expires) { - if(first == curr) - first = next; + first = curr = prev = cookies->cookies[i]; - if(prev == curr) - prev = next; - else - prev->next = next; + for(; curr; curr = next) { + next = curr->next; + if(!curr->expires) { + if(first == curr) + first = next; + + if(prev == curr) + prev = next; + else + prev->next = next; - freecookie(curr); - cookies->numcookies--; + freecookie(curr); + cookies->numcookies--; + } + else + prev = curr; } - else - prev = curr; - } - cookies->cookies = first; + cookies->cookies[i] = first; + } } @@ -1307,9 +1384,12 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies) ****************************************************************************/ void Curl_cookie_cleanup(struct CookieInfo *c) { + unsigned int i; + if(c) { free(c->filename); - Curl_cookie_freelist(c->cookies); + for(i = 0; i < COOKIE_HASH_SIZE; i++) + Curl_cookie_freelist(c->cookies[i]); free(c); /* free the base struct as well */ } } @@ -1358,6 +1438,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) FILE *out; bool use_stdout = FALSE; char *format_ptr; + unsigned int i; if((NULL == c) || (0 == c->numcookies)) /* If there are no known cookies, we don't write or even create any @@ -1367,6 +1448,10 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) /* at first, remove expired cookies */ remove_expired(c); + /* make sure we still have cookies after expiration */ + if(0 == c->numcookies) + return 0; + if(!strcmp("-", dumphere)) { /* use stdout */ out = stdout; @@ -1383,18 +1468,20 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) "# This file was generated by libcurl! Edit at your own risk.\n\n", out); - for(co = c->cookies; co; co = co->next) { - if(!co->domain) - continue; - format_ptr = get_netscape_format(co); - if(format_ptr == NULL) { - fprintf(out, "#\n# Fatal libcurl error\n"); - if(!use_stdout) - fclose(out); - return 1; + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + for(co = c->cookies[i]; co; co = co->next) { + if(!co->domain) + continue; + format_ptr = get_netscape_format(co); + if(format_ptr == NULL) { + fprintf(out, "#\n# Fatal libcurl error\n"); + if(!use_stdout) + fclose(out); + return 1; + } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); } - fprintf(out, "%s\n", format_ptr); - free(format_ptr); } if(!use_stdout) @@ -1409,26 +1496,29 @@ static struct curl_slist *cookie_list(struct Curl_easy *data) struct curl_slist *beg; struct Cookie *c; char *line; + unsigned int i; if((data->cookies == NULL) || (data->cookies->numcookies == 0)) return NULL; - for(c = data->cookies->cookies; c; c = c->next) { - if(!c->domain) - continue; - line = get_netscape_format(c); - if(!line) { - curl_slist_free_all(list); - return NULL; - } - beg = Curl_slist_append_nodup(list, line); - if(!beg) { - free(line); - curl_slist_free_all(list); - return NULL; + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + for(c = data->cookies->cookies[i]; c; c = c->next) { + if(!c->domain) + continue; + line = get_netscape_format(c); + if(!line) { + curl_slist_free_all(list); + return NULL; + } + beg = Curl_slist_append_nodup(list, line); + if(!beg) { + free(line); + curl_slist_free_all(list); + return NULL; + } + list = beg; } - list = beg; } return list; |