[MINOR] redirect: add support for "set-cookie" and "clear-cookie"

It is now possible to set or clear a cookie during a redirection. This
is useful for logout pages, or for protecting against some DoSes. Check
the documentation for the options supported by the "redirect" keyword.

(cherry-picked from commit 4af993822e880d8c932f4ad6920db4c9242b0981)
This commit is contained in:
Willy Tarreau 2008-11-19 21:07:09 +01:00
parent 79da4697ca
commit 0140f2553c
5 changed files with 103 additions and 13 deletions

View File

@ -2336,34 +2336,68 @@ no option transparent
"transparent" option of the "bind" keyword.
redirect location <to> [code <code>] {if | unless} <condition>
redirect prefix <to> [drop-query] [code <code>] {if | unless} <condition>
redirect location <to> [code <code>] <option> {if | unless} <condition>
redirect prefix <to> [code <code>] <option> {if | unless} <condition>
Return an HTTP redirection if/unless a condition is matched
May be used in sections : defaults | frontend | listen | backend
no | yes | yes | yes
If/unless the condition is matched, the HTTP request will lead to a redirect
response. There are currently two types of redirections : "location" and
"prefix". With "location", the exact value in <to> is placed into the HTTP
"Location" header. With "prefix", the "Location" header is built from the
concatenation of <to> and the URI. If the optional "drop-query" keyword is
used in a prefix-based redirection, then the location will be set without any
possible query-string, which is useful for directing users to a non-secure
page for instance. The "prefix" mode is particularly suited for global site
redirections.
response.
The code is optional. It indicates in <code> which type of HTTP redirection
is desired. Only codes 301, 302 and 303 are supported. 302 is used if no code
is specified.
Arguments :
<to> With "redirect location", the exact value in <to> is placed into
the HTTP "Location" header. In case of "redirect prefix", the
"Location" header is built from the concatenation of <to> and the
complete URI, including the query string, unless the "drop-query"
option is specified (see below).
<code> The code is optional. It indicates which type of HTTP redirection
is desired. Only codes 301, 302 and 303 are supported, and 302 is
used if no code is specified. 301 means "Moved permanently", and
a browser may cache the Location. 302 means "Moved permanently"
and means that the browser should not cache the redirection. 303
is equivalent to 302 except that the browser will fetch the
location with a GET method.
<option> There are several options which can be specified to adjust the
expected behaviour of a redirection :
- "drop-query"
When this keyword is used in a prefix-based redirection, then the
location will be set without any possible query-string, which is useful
for directing users to a non-secure page for instance. It has no effect
with a location-type redirect.
- "set-cookie NAME[=value]"
A "Set-Cookie" header will be added with NAME (and optionally "=value")
to the response. This is sometimes used to indicate that a user has
been seen, for instance to protect against some types of DoS. No other
cookie option is added, so the cookie will be a session cookie. Note
that for a browser, a sole cookie name without an equal sign is
different from a cookie with an equal sign.
- "clear-cookie NAME[=]"
A "Set-Cookie" header will be added with NAME (and optionally "="), but
with the "Max-Age" attribute set to zero. This will tell the browser to
delete this cookie. It is useful for instance on logout pages. It is
important to note that clearing the cookie "NAME" will not remove a
cookie set with "NAME=value". You have to clear the cookie "NAME=" for
that, because the browser makes the difference.
Example: move the login URL only to HTTPS.
acl clear dst_port 80
acl secure dst_port 8080
acl login_page url_beg /login
acl logout url_beg /logout
acl uid_given url_reg /login?userid=[^&]+
acl cookie_set hdr_sub(cookie) SEEN=1
redirect prefix https://mysite.com set-cookie SEEN=1 if !cookie_set
redirect prefix https://mysite.com if login_page !secure
redirect prefix http://mysite.com drop-query if login_page !uid_given
redirect location http://mysite.com/ if !login_page secure
redirect location / clear-cookie USERID= if logout
See section 2.3 about ACL usage.

View File

@ -267,6 +267,8 @@ struct redirect_rule {
char *rdr_str;
int code;
unsigned int flags;
int cookie_len;
char *cookie_str;
};
extern struct proxy *proxy;

View File

@ -1118,6 +1118,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
int type = REDIRECT_TYPE_NONE;
int code = 302;
char *destination = NULL;
char *cookie = NULL;
int cookie_set = 0;
unsigned int flags = REDIRECT_FLAG_NONE;
cur_arg = 1;
@ -1144,6 +1146,28 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
cur_arg++;
destination = args[cur_arg];
}
else if (!strcmp(args[cur_arg], "set-cookie")) {
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s': missing argument for '%s'.\n",
file, linenum, args[0], args[cur_arg]);
return -1;
}
cur_arg++;
cookie = args[cur_arg];
cookie_set = 1;
}
else if (!strcmp(args[cur_arg], "clear-cookie")) {
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s': missing argument for '%s'.\n",
file, linenum, args[0], args[cur_arg]);
return -1;
}
cur_arg++;
cookie = args[cur_arg];
cookie_set = 0;
}
else if (!strcmp(args[cur_arg],"code")) {
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s': missing HTTP code.\n",
@ -1202,6 +1226,20 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
rule->cond = cond;
rule->rdr_str = strdup(destination);
rule->rdr_len = strlen(destination);
if (cookie) {
/* depending on cookie_set, either we want to set the cookie, or to clear it.
* a clear consists in appending "; Max-Age=0" at the end.
*/
rule->cookie_len = strlen(cookie);
if (cookie_set)
rule->cookie_str = strdup(cookie);
else {
rule->cookie_str = malloc(rule->cookie_len + 12);
memcpy(rule->cookie_str, cookie, rule->cookie_len);
memcpy(rule->cookie_str + rule->cookie_len, "; Max-Age=0", 12);
rule->cookie_len += 11;
}
}
rule->type = type;
rule->code = code;
rule->flags = flags;

View File

@ -1932,6 +1932,15 @@ int http_process_request(struct session *s, struct buffer *req)
break;
}
if (rule->cookie_len) {
memcpy(rdr.str + rdr.len, "\r\nSet-Cookie: ", 14);
rdr.len += 14;
memcpy(rdr.str + rdr.len, rule->cookie_str, rule->cookie_len);
rdr.len += rule->cookie_len;
memcpy(rdr.str + rdr.len, "\r\n", 2);
rdr.len += 2;
}
/* add end of headers */
memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
rdr.len += 4;

View File

@ -18,10 +18,17 @@ listen sample1
acl url_test1 url_reg test1
acl url_test2 url_reg test2
acl url_test3 url_reg test3
acl url_test4 url_reg test4
acl seen hdr_sub(cookie) SEEN=1
redirect location /abs/test code 301 if url_test1
redirect prefix /pfx/test code 302 if url_test2
redirect prefix /pfx/test code 303 drop-query if url_test3
redirect location /test4 code 302 set-cookie SEEN=1 if url_test4 !seen
redirect location / code 302 clear-cookie SEEN= if url_test4 seen
### unconditional redirection
#redirect location https://example.com/ if TRUE