MINOR: http-ana: Add support for "set-cookie-fmt" option to redirect rules
It is now possible to use a log-format string to define the "Set-Cookie" header value of a response generated by a redirect rule. There is no special check on the result format and it is not possible during the configuration parsing. It is proably not a big deal because already existing "set-cookie" and "clear-cookie" options don't perform any check. Here is an example: http-request redirect location https://someurl.com/ set-cookie haproxy="%[var(txn.var)]" This patch should fix the issue #1784.
This commit is contained in:
parent
b2877db47c
commit
1be7140ade
|
@ -11453,6 +11453,12 @@ redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]
|
|||
that for a browser, a sole cookie name without an equal sign is
|
||||
different from a cookie with an equal sign.
|
||||
|
||||
- "set-cookie-fmt <fmt>"
|
||||
It is equivaliant to the option above, except the "Set-Cookie" header
|
||||
will be filled with the result of the log-format string <fmt>
|
||||
evaluation. Be carefull to respect the "NAME[=value]" format because no
|
||||
special check are performed during the configuration parsing.
|
||||
|
||||
- "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
|
||||
|
|
|
@ -168,6 +168,7 @@ enum {
|
|||
REDIRECT_FLAG_FROM_REQ = 4, /* redirect rule on the request path */
|
||||
REDIRECT_FLAG_IGNORE_EMPTY = 8, /* silently ignore empty location expressions */
|
||||
REDIRECT_FLAG_KEEP_QS = 16, /* append the query string to location, if any */
|
||||
REDIRECT_FLAG_COOKIE_FMT = 32, /* The cookie value is a log-format stirng*/
|
||||
};
|
||||
|
||||
/* Redirect types (location, prefix, extended ) */
|
||||
|
|
|
@ -518,8 +518,10 @@ struct redirect_rule {
|
|||
struct lf_expr rdr_fmt;
|
||||
int code;
|
||||
unsigned int flags;
|
||||
int cookie_len;
|
||||
char *cookie_str;
|
||||
union {
|
||||
struct ist str; /* the cookie is a string */
|
||||
struct lf_expr fmt; /* or a log-format string (possible for set-cookie only) */
|
||||
} cookie;
|
||||
};
|
||||
|
||||
/* some of the most common options which are also the easiest to handle */
|
||||
|
|
|
@ -2518,8 +2518,13 @@ int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struc
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (rule->cookie_len) {
|
||||
if (!htx_add_header(htx, ist("Set-Cookie"), ist2(rule->cookie_str, rule->cookie_len)))
|
||||
if (rule->flags & REDIRECT_FLAG_COOKIE_FMT) {
|
||||
trash.data = build_logline(s, trash.area, trash.size, &rule->cookie.fmt);
|
||||
if (!htx_add_header(htx, ist("Set-Cookie"), ist2(trash.area, trash.data)))
|
||||
goto fail;
|
||||
}
|
||||
else if (isttest(rule->cookie.str)) {
|
||||
if (!htx_add_header(htx, ist("Set-Cookie"), rule->cookie.str))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -322,7 +322,10 @@ void http_free_redirect_rule(struct redirect_rule *rdr)
|
|||
{
|
||||
free_acl_cond(rdr->cond);
|
||||
free(rdr->rdr_str);
|
||||
free(rdr->cookie_str);
|
||||
if ((rdr->flags & REDIRECT_FLAG_COOKIE_FMT))
|
||||
lf_expr_deinit(&rdr->cookie.fmt);
|
||||
else
|
||||
istfree(&rdr->cookie.str);
|
||||
lf_expr_deinit(&rdr->rdr_fmt);
|
||||
free(rdr);
|
||||
}
|
||||
|
@ -342,6 +345,7 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
|
|||
const char *destination = NULL;
|
||||
const char *cookie = NULL;
|
||||
int cookie_set = 0;
|
||||
size_t cookie_len = 0;
|
||||
unsigned int flags = (!dir ? REDIRECT_FLAG_FROM_REQ : REDIRECT_FLAG_NONE);
|
||||
struct acl_cond *cond = NULL;
|
||||
|
||||
|
@ -378,6 +382,14 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
|
|||
cookie = args[cur_arg];
|
||||
cookie_set = 1;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "set-cookie-fmt") == 0) {
|
||||
if (!*args[cur_arg + 1])
|
||||
goto missing_arg;
|
||||
|
||||
cur_arg++;
|
||||
cookie = args[cur_arg];
|
||||
cookie_set = 2;
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "clear-cookie") == 0) {
|
||||
if (!*args[cur_arg + 1])
|
||||
goto missing_arg;
|
||||
|
@ -422,7 +434,8 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
|
|||
}
|
||||
else {
|
||||
memprintf(errmsg,
|
||||
"expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query', 'keep-query', 'ignore-empty' or 'append-slash' (was '%s')",
|
||||
"expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'set-cookie-fmt',"
|
||||
" 'clear-cookie', 'drop-query', 'keep-query', 'ignore-empty' or 'append-slash' (was '%s')",
|
||||
args[cur_arg]);
|
||||
goto err;
|
||||
}
|
||||
|
@ -476,21 +489,38 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
|
|||
/* depending on cookie_set, either we want to set the cookie, or to clear it.
|
||||
* a clear consists in appending "; path=/; Max-Age=0;" at the end.
|
||||
*/
|
||||
rule->cookie_len = strlen(cookie);
|
||||
if (cookie_set) {
|
||||
rule->cookie_str = malloc(rule->cookie_len + 10);
|
||||
if (!rule->cookie_str)
|
||||
cookie_len = strlen(cookie);
|
||||
if (cookie_set == 1) { // set-cookie
|
||||
rule->cookie.str = istalloc(cookie_len+9);
|
||||
if (!isttest(rule->cookie.str))
|
||||
goto out_of_memory;
|
||||
memcpy(rule->cookie_str, cookie, rule->cookie_len);
|
||||
memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
|
||||
rule->cookie_len += 9;
|
||||
} else {
|
||||
rule->cookie_str = malloc(rule->cookie_len + 21);
|
||||
if (!rule->cookie_str)
|
||||
istcpy(&rule->cookie.str, ist2(cookie, cookie_len), cookie_len);
|
||||
istcat(&rule->cookie.str, ist2("; path=/;", 9), cookie_len+10);
|
||||
}
|
||||
else if (cookie_set == 2) { // set-cookie-fmt
|
||||
int cap = 0;
|
||||
|
||||
lf_expr_init(&rule->cookie.fmt);
|
||||
curproxy->conf.args.ctx = ARGC_RDR;
|
||||
if (curproxy->cap & PR_CAP_FE)
|
||||
cap |= (dir ? SMP_VAL_FE_HRS_HDR : SMP_VAL_FE_HRQ_HDR);
|
||||
if (curproxy->cap & PR_CAP_BE)
|
||||
cap |= (dir ? SMP_VAL_BE_HRS_HDR : SMP_VAL_BE_HRQ_HDR);
|
||||
|
||||
chunk_memcpy(&trash, cookie, cookie_len);
|
||||
chunk_strcat(&trash, "; path=/;");
|
||||
if (!parse_logformat_string(trash.area, curproxy, &rule->cookie.fmt, LOG_OPT_HTTP, cap, errmsg)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
flags |= REDIRECT_FLAG_COOKIE_FMT;
|
||||
}
|
||||
else { // clear-cookie
|
||||
rule->cookie.str = istalloc(cookie_len+20);
|
||||
if (!isttest(rule->cookie.str))
|
||||
goto out_of_memory;
|
||||
memcpy(rule->cookie_str, cookie, rule->cookie_len);
|
||||
memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
|
||||
rule->cookie_len += 20;
|
||||
istcpy(&rule->cookie.str, ist2(cookie, cookie_len), cookie_len);
|
||||
istcat(&rule->cookie.str, ist2("; path=/; Max-Age=0;", 20), cookie_len+21);
|
||||
}
|
||||
}
|
||||
rule->type = type;
|
||||
|
|
Loading…
Reference in New Issue