[MEDIUM] cookie: set the date in the cookie if needed

If a maxidle or maxlife parameter is set on the persistence cookie in
insert mode and the client did not provide a recent enough cookie,
then we emit a new cookie with a new last_seen date and the same
first_seen (if maxlife is set). Recent enough here designates a
cookie that would be rounded to the same date. That way, we can
refresh a cookie when required without doing it in all responses.

If the request did not contain such parameters, they are set anyway.
This means that a monitoring request that is forced to a server will
get an expiration date anyway, but this should not be a problem given
that the client is able to set its cookie in this case. This also
permits to force an expiration date on visitors who previously did
not have one.

If a request comes with a dated cookie while no date check is performed,
then a new cookie is emitted with no date, so that we don't risk dropping
the user too fast due to a very old date when we re-enable the date check.

All requests that were targetting the correct server and which had their
expiration date added/updated/removed in the response cookie are logged
with the 'U' ("updated") flag instead of the 'I' ("inserted"). So very
often we'll see "VU" instead of "VN".
(cherry picked from commit 8b3c6ecab6d37be5f3655bc3a2d2c0f9f37325eb)
This commit is contained in:
Willy Tarreau 2010-10-07 21:00:29 +02:00
parent f64d1410fc
commit ef4f391cc4

View File

@ -4963,19 +4963,46 @@ int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, s
/*
* 6: add server cookie in the response if needed
*/
if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
if ((t->srv) && (t->be->options & PR_O_COOK_INS) &&
(!(t->flags & SN_DIRECT) ||
((t->be->cookie_maxidle || txn->cookie_last_date) &&
(!txn->cookie_last_date || (txn->cookie_last_date - date.tv_sec) < 0)) ||
(t->be->cookie_maxlife && !txn->cookie_first_date) || // set the first_date
(!t->be->cookie_maxlife && txn->cookie_first_date)) && // remove the first_date
(!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST)) &&
!(t->flags & SN_IGNORE_PRST)) {
int len;
/* the server is known, it's not the one the client requested, we have to
/* the server is known, it's not the one the client requested, or the
* cookie's last seen date needs to be refreshed. We have to
* insert a set-cookie here, except if we want to insert only on POST
* requests and this one isn't. Note that servers which don't have cookies
* (eg: some backup servers) will return a full cookie removal request.
*/
len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
t->be->cookie_name,
t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
if (!t->srv->cookie) {
len = sprintf(trash,
"Set-Cookie: %s=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/",
t->be->cookie_name);
}
else {
len = sprintf(trash, "Set-Cookie: %s=%s", t->be->cookie_name, t->srv->cookie);
if (t->be->cookie_maxidle || t->be->cookie_maxlife) {
/* emit last_date, which is mandatory */
trash[len++] = COOKIE_DELIM_DATE;
s30tob64((date.tv_sec+3) >> 2, trash + len); len += 5;
if (t->be->cookie_maxlife) {
/* emit first_date, which is either the original one or
* the current date.
*/
trash[len++] = COOKIE_DELIM_DATE;
s30tob64(txn->cookie_first_date ?
txn->cookie_first_date >> 2 :
(date.tv_sec+3) >> 2, trash + len);
len += 5;
}
}
len += sprintf(trash + len, "; path=/");
}
if (t->be->cookie_domain)
len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
@ -4983,8 +5010,13 @@ int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, s
if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
trash, len) < 0))
goto return_bad_resp;
txn->flags &= ~TX_SCK_MASK;
txn->flags |= TX_SCK_INSERTED;
if (t->srv->cookie && (t->flags & SN_DIRECT))
/* the server did not change, only the date was updated */
txn->flags |= TX_SCK_UPDATED;
else
txn->flags |= TX_SCK_INSERTED;
/* Here, we will tell an eventual cache on the client side that we don't
* want it to cache this reply because HTTP/1.0 caches also cache cookies !
@ -5998,8 +6030,8 @@ void manage_client_side_cookies(struct session *t, struct buffer *req)
* long.
*/
if (txn->cookie_first_date && t->be->cookie_maxlife &&
((signed)(date.tv_sec - txn->cookie_first_date) > t->be->cookie_maxlife ||
(signed)(txn->cookie_first_date - date.tv_sec) > 86400)) {
(((signed)(date.tv_sec - txn->cookie_first_date) > (signed)t->be->cookie_maxlife) ||
((signed)(txn->cookie_first_date - date.tv_sec) > 86400))) {
txn->flags &= ~TX_CK_MASK;
txn->flags |= TX_CK_OLD;
delim = val_beg; // let's pretend we have not found the cookie
@ -6007,8 +6039,8 @@ void manage_client_side_cookies(struct session *t, struct buffer *req)
txn->cookie_last_date = 0;
}
else if (txn->cookie_last_date && t->be->cookie_maxidle &&
((signed)(date.tv_sec - txn->cookie_last_date) > t->be->cookie_maxidle ||
(signed)(txn->cookie_last_date - date.tv_sec) > 86400)) {
(((signed)(date.tv_sec - txn->cookie_last_date) > (signed)t->be->cookie_maxidle) ||
((signed)(txn->cookie_last_date - date.tv_sec) > 86400))) {
txn->flags &= ~TX_CK_MASK;
txn->flags |= TX_CK_EXPIRED;
delim = val_beg; // let's pretend we have not found the cookie