summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/cookie.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/cookie.c')
-rw-r--r--Utilities/cmcurl/lib/cookie.c276
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;