diff --git a/doc/configuration.txt b/doc/configuration.txt index d05ad9ea5..ae4827a88 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1675,7 +1675,7 @@ contimeout (deprecated) cookie [ rewrite | insert | prefix ] [ indirect ] [ nocache ] - [ postonly ] [ domain ]* + [ postonly ] [ preserve ] [ domain ]* [ maxidle ] [ maxlife ] Enable cookie-based persistence in a backend. May be used in sections : defaults | frontend | listen | backend @@ -1705,16 +1705,18 @@ cookie [ rewrite | insert | prefix ] [ indirect ] [ nocache ] insert This keyword indicates that the persistence cookie will have to be inserted by haproxy in server responses if the client did not + already have a cookie that would have permitted it to access this - server. If the server emits a cookie with the same name, it will - be remove before processing. For this reason, this mode can be - used to upgrade existing configurations running in the "rewrite" - mode. The cookie will only be a session cookie and will not be - stored on the client's disk. By default, unless the "indirect" - option is added, the server will see the cookies emitted by the - client. Due to caching effects, it is generally wise to add the - "nocache" or "postonly" keywords (see below). The "insert" - keyword is not compatible with "rewrite" and "prefix". + server. When used without the "preserve" option, if the server + emits a cookie with the same name, it will be remove before + processing. For this reason, this mode can be used to upgrade + existing configurations running in the "rewrite" mode. The cookie + will only be a session cookie and will not be stored on the + client's disk. By default, unless the "indirect" option is added, + the server will see the cookies emitted by the client. Due to + caching effects, it is generally wise to add the "nocache" or + "postonly" keywords (see below). The "insert" keyword is not + compatible with "rewrite" and "prefix". prefix This keyword indicates that instead of relying on a dedicated cookie for the persistence, an existing one will be completed. @@ -1731,10 +1733,10 @@ cookie [ rewrite | insert | prefix ] [ indirect ] [ nocache ] indirect When this option is specified, no cookie will be emitted to a client which already has a valid one for the server which has processed the request. If the server sets such a cookie itself, - it will be removed. In "insert" mode, this will additionally - remove cookies from requests transmitted to the server, making - the persistence mechanism totally transparent from an application - point of view. + it will be removed, unless the "preserve" option is also set. In + "insert" mode, this will additionally remove cookies from the + requests transmitted to the server, making the persistence + mechanism totally transparent from an application point of view. nocache This option is recommended in conjunction with the insert mode when there is a cache between the client and HAProxy, as it @@ -1756,6 +1758,17 @@ cookie [ rewrite | insert | prefix ] [ indirect ] [ nocache ] persistence cookie in the cache. See also the "insert" and "nocache" options. + preserve This option may only be used with "insert" and/or "indirect". It + allows the server to emit the persistence cookie itself. In this + case, if a cookie is found in the response, haproxy will leave it + untouched. This is useful in order to end persistence after a + logout request for instance. For this, the server just has to + emit a cookie with an invalid value (eg: empty) or with a date in + the past. By combining this mechanism with the "disable-on-404" + check option, it is possible to perform a completely graceful + shutdown because users will definitely leave the server after + they logout. + domain This option allows to specify the domain at which a cookie is inserted. It requires exactly one parameter: a valid domain name. If the domain begins with a dot, the browser is allowed to diff --git a/include/types/proxy.h b/include/types/proxy.h index 246a9bed8..f4fd4a921 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -148,6 +148,7 @@ #define PR_O2_EXP_RSTR 0x02000000 /* http-check expect rstring */ #define PR_O2_EXP_TYPE 0x03800000 /* mask for http-check expect type */ #define PR_O2_EXP_INV 0x04000000 /* http-check expect ! */ +#define PR_O2_COOK_PSV 0x08000000 /* cookie ... preserve */ /* end of proxy->options2 */ /* bits for sticking rules */ diff --git a/src/cfgparse.c b/src/cfgparse.c index da6ef81a8..a7cdea4d5 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1661,6 +1661,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } curproxy->options &= ~PR_O_COOK_ANY; + curproxy->options2 &= ~PR_O2_COOK_PSV; curproxy->cookie_maxidle = curproxy->cookie_maxlife = 0; free(curproxy->cookie_domain); curproxy->cookie_domain = NULL; free(curproxy->cookie_name); @@ -1684,6 +1685,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) else if (!strcmp(args[cur_arg], "postonly")) { curproxy->options |= PR_O_COOK_POST; } + else if (!strcmp(args[cur_arg], "preserve")) { + curproxy->options2 |= PR_O2_COOK_PSV; + } else if (!strcmp(args[cur_arg], "prefix")) { curproxy->options |= PR_O_COOK_PFX; } @@ -1790,6 +1794,12 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) file, linenum); err_code |= ERR_ALERT | ERR_FATAL; } + + if ((curproxy->options2 & PR_O2_COOK_PSV) && !(curproxy->options & (PR_O_COOK_INS|PR_O_COOK_IND))) { + Alert("parsing [%s:%d] : cookie 'preserve' requires at least 'insert' or 'indirect'.\n", + file, linenum); + err_code |= ERR_ALERT | ERR_FATAL; + } }/* end else if (!strcmp(args[0], "cookie")) */ else if (!strcmp(args[0], "persist")) { /* persist */ if (*(args[1]) == 0) { diff --git a/src/proto_http.c b/src/proto_http.c index 3a2be18f7..a5e6e161e 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -5098,6 +5098,7 @@ 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->be->options & PR_O_COOK_INS) && + !((txn->flags & TX_SCK_FOUND) && (t->be->options2 & PR_O2_COOK_PSV)) && (!(t->flags & SN_DIRECT) || ((t->be->cookie_maxidle || txn->cookie_last_date) && (!txn->cookie_last_date || (txn->cookie_last_date - date.tv_sec) < 0)) || @@ -6780,7 +6781,12 @@ void manage_server_side_cookies(struct session *t, struct buffer *res) * We'll delete it too if the "indirect" option is set and we're in * a direct access. */ - if (((t->srv) && (t->be->options & PR_O_COOK_INS)) || + if (t->be->options2 & PR_O2_COOK_PSV) { + /* The "preserve" flag was set, we don't want to touch the + * server's cookie. + */ + } + else if (((t->srv) && (t->be->options & PR_O_COOK_INS)) || ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) { /* this cookie must be deleted */ if (*prev == ':' && next == hdr_end) {