summaryrefslogtreecommitdiff
path: root/lib/cookie.c
diff options
context:
space:
mode:
authorDaniel Gustafsson <daniel@yesql.se>2021-06-08 09:16:58 +0200
committerDaniel Gustafsson <daniel@yesql.se>2021-06-08 09:31:19 +0200
commit1bd4b3f4e20d366b7e7dcefefbc5cf4ede341e1e (patch)
treeb112fcbbbe9aa2ec85778f835fc7a8f4b7cc57cc /lib/cookie.c
parent3d01b75077708142a66d4f50337c8d8534cce0f4 (diff)
downloadcurl-1bd4b3f4e20d366b7e7dcefefbc5cf4ede341e1e.tar.gz
cookies: track expiration in jar to optimize removals
Removing expired cookies needs to be a fast operation since we want to be able to perform it often and speculatively. By tracking the timestamp of the next known expiration we can exit early in case the timestamp is in the future. Closes: #7172 Reviewed-by: Daniel Stenberg <daniel@haxx.se>
Diffstat (limited to 'lib/cookie.c')
-rw-r--r--lib/cookie.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/lib/cookie.c b/lib/cookie.c
index 537658fc6..4b99813bd 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -371,7 +371,9 @@ static void strstore(char **str, const char *newstr)
*
* Remove expired cookies from the hash by inspecting the expires timestamp on
* each cookie in the hash, freeing and deleting any where the timestamp is in
- * the past.
+ * the past. If the cookiejar has recorded the next timestamp at which one or
+ * more cookies expire, then processing will exit early in case this timestamp
+ * is in the future.
*/
static void remove_expired(struct CookieInfo *cookies)
{
@@ -379,6 +381,20 @@ static void remove_expired(struct CookieInfo *cookies)
curl_off_t now = (curl_off_t)time(NULL);
unsigned int i;
+ /*
+ * If the earliest expiration timestamp in the jar is in the future we can
+ * skip scanning the whole jar and instead exit early as there won't be any
+ * cookies to evict. If we need to evict however, reset the next_expiration
+ * counter in order to track the next one. In case the recorded first
+ * expiration is the max offset, then perform the safe fallback of checking
+ * all cookies.
+ */
+ if(now < cookies->next_expiration &&
+ cookies->next_expiration != CURL_OFF_T_MAX)
+ return;
+ else
+ cookies->next_expiration = CURL_OFF_T_MAX;
+
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
struct Cookie *pv = NULL;
co = cookies->cookies[i];
@@ -395,6 +411,12 @@ static void remove_expired(struct CookieInfo *cookies)
freecookie(co);
}
else {
+ /*
+ * If this cookie has an expiration timestamp earlier than what we've
+ * seen so far then record it for the next round of expirations.
+ */
+ if(co->expires && co->expires < cookies->next_expiration)
+ cookies->next_expiration = co->expires;
pv = co;
}
co = nx;
@@ -1108,6 +1130,13 @@ Curl_cookie_add(struct Curl_easy *data,
c->numcookies++; /* one more cookie in the jar */
}
+ /*
+ * Now that we've added a new cookie to the jar, update the expiration
+ * tracker in case it is the next one to expire.
+ */
+ if(co->expires && (co->expires < c->next_expiration))
+ c->next_expiration = co->expires;
+
return co;
}
@@ -1143,6 +1172,11 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
c->filename = strdup(file?file:"none"); /* copy the name just in case */
if(!c->filename)
goto fail; /* failed to get memory */
+ /*
+ * Initialize the next_expiration time to signal that we don't have enough
+ * information yet.
+ */
+ c->next_expiration = CURL_OFF_T_MAX;
}
else {
/* we got an already existing one, use that */