Skip to content

Commit 1be7140

Browse files
committed
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.
1 parent b2877db commit 1be7140

File tree

5 files changed

+63
-19
lines changed

5 files changed

+63
-19
lines changed

doc/configuration.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11453,6 +11453,12 @@ redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]
1145311453
that for a browser, a sole cookie name without an equal sign is
1145411454
different from a cookie with an equal sign.
1145511455

11456+
- "set-cookie-fmt <fmt>"
11457+
It is equivaliant to the option above, except the "Set-Cookie" header
11458+
will be filled with the result of the log-format string <fmt>
11459+
evaluation. Be carefull to respect the "NAME[=value]" format because no
11460+
special check are performed during the configuration parsing.
11461+
1145611462
- "clear-cookie NAME[=]"
1145711463
A "Set-Cookie" header will be added with NAME (and optionally "="), but
1145811464
with the "Max-Age" attribute set to zero. This will tell the browser to

include/haproxy/http_ana-t.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ enum {
168168
REDIRECT_FLAG_FROM_REQ = 4, /* redirect rule on the request path */
169169
REDIRECT_FLAG_IGNORE_EMPTY = 8, /* silently ignore empty location expressions */
170170
REDIRECT_FLAG_KEEP_QS = 16, /* append the query string to location, if any */
171+
REDIRECT_FLAG_COOKIE_FMT = 32, /* The cookie value is a log-format stirng*/
171172
};
172173

173174
/* Redirect types (location, prefix, extended ) */

include/haproxy/proxy-t.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,10 @@ struct redirect_rule {
518518
struct lf_expr rdr_fmt;
519519
int code;
520520
unsigned int flags;
521-
int cookie_len;
522-
char *cookie_str;
521+
union {
522+
struct ist str; /* the cookie is a string */
523+
struct lf_expr fmt; /* or a log-format string (possible for set-cookie only) */
524+
} cookie;
523525
};
524526

525527
/* some of the most common options which are also the easiest to handle */

src/http_ana.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2518,8 +2518,13 @@ int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struc
25182518
goto fail;
25192519
}
25202520

2521-
if (rule->cookie_len) {
2522-
if (!htx_add_header(htx, ist("Set-Cookie"), ist2(rule->cookie_str, rule->cookie_len)))
2521+
if (rule->flags & REDIRECT_FLAG_COOKIE_FMT) {
2522+
trash.data = build_logline(s, trash.area, trash.size, &rule->cookie.fmt);
2523+
if (!htx_add_header(htx, ist("Set-Cookie"), ist2(trash.area, trash.data)))
2524+
goto fail;
2525+
}
2526+
else if (isttest(rule->cookie.str)) {
2527+
if (!htx_add_header(htx, ist("Set-Cookie"), rule->cookie.str))
25232528
goto fail;
25242529
}
25252530

src/http_rules.c

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,10 @@ void http_free_redirect_rule(struct redirect_rule *rdr)
322322
{
323323
free_acl_cond(rdr->cond);
324324
free(rdr->rdr_str);
325-
free(rdr->cookie_str);
325+
if ((rdr->flags & REDIRECT_FLAG_COOKIE_FMT))
326+
lf_expr_deinit(&rdr->cookie.fmt);
327+
else
328+
istfree(&rdr->cookie.str);
326329
lf_expr_deinit(&rdr->rdr_fmt);
327330
free(rdr);
328331
}
@@ -342,6 +345,7 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
342345
const char *destination = NULL;
343346
const char *cookie = NULL;
344347
int cookie_set = 0;
348+
size_t cookie_len = 0;
345349
unsigned int flags = (!dir ? REDIRECT_FLAG_FROM_REQ : REDIRECT_FLAG_NONE);
346350
struct acl_cond *cond = NULL;
347351

@@ -378,6 +382,14 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
378382
cookie = args[cur_arg];
379383
cookie_set = 1;
380384
}
385+
else if (strcmp(args[cur_arg], "set-cookie-fmt") == 0) {
386+
if (!*args[cur_arg + 1])
387+
goto missing_arg;
388+
389+
cur_arg++;
390+
cookie = args[cur_arg];
391+
cookie_set = 2;
392+
}
381393
else if (strcmp(args[cur_arg], "clear-cookie") == 0) {
382394
if (!*args[cur_arg + 1])
383395
goto missing_arg;
@@ -422,7 +434,8 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
422434
}
423435
else {
424436
memprintf(errmsg,
425-
"expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query', 'keep-query', 'ignore-empty' or 'append-slash' (was '%s')",
437+
"expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'set-cookie-fmt',"
438+
" 'clear-cookie', 'drop-query', 'keep-query', 'ignore-empty' or 'append-slash' (was '%s')",
426439
args[cur_arg]);
427440
goto err;
428441
}
@@ -476,21 +489,38 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
476489
/* depending on cookie_set, either we want to set the cookie, or to clear it.
477490
* a clear consists in appending "; path=/; Max-Age=0;" at the end.
478491
*/
479-
rule->cookie_len = strlen(cookie);
480-
if (cookie_set) {
481-
rule->cookie_str = malloc(rule->cookie_len + 10);
482-
if (!rule->cookie_str)
492+
cookie_len = strlen(cookie);
493+
if (cookie_set == 1) { // set-cookie
494+
rule->cookie.str = istalloc(cookie_len+9);
495+
if (!isttest(rule->cookie.str))
483496
goto out_of_memory;
484-
memcpy(rule->cookie_str, cookie, rule->cookie_len);
485-
memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
486-
rule->cookie_len += 9;
487-
} else {
488-
rule->cookie_str = malloc(rule->cookie_len + 21);
489-
if (!rule->cookie_str)
497+
istcpy(&rule->cookie.str, ist2(cookie, cookie_len), cookie_len);
498+
istcat(&rule->cookie.str, ist2("; path=/;", 9), cookie_len+10);
499+
}
500+
else if (cookie_set == 2) { // set-cookie-fmt
501+
int cap = 0;
502+
503+
lf_expr_init(&rule->cookie.fmt);
504+
curproxy->conf.args.ctx = ARGC_RDR;
505+
if (curproxy->cap & PR_CAP_FE)
506+
cap |= (dir ? SMP_VAL_FE_HRS_HDR : SMP_VAL_FE_HRQ_HDR);
507+
if (curproxy->cap & PR_CAP_BE)
508+
cap |= (dir ? SMP_VAL_BE_HRS_HDR : SMP_VAL_BE_HRQ_HDR);
509+
510+
chunk_memcpy(&trash, cookie, cookie_len);
511+
chunk_strcat(&trash, "; path=/;");
512+
if (!parse_logformat_string(trash.area, curproxy, &rule->cookie.fmt, LOG_OPT_HTTP, cap, errmsg)) {
513+
goto err;
514+
}
515+
516+
flags |= REDIRECT_FLAG_COOKIE_FMT;
517+
}
518+
else { // clear-cookie
519+
rule->cookie.str = istalloc(cookie_len+20);
520+
if (!isttest(rule->cookie.str))
490521
goto out_of_memory;
491-
memcpy(rule->cookie_str, cookie, rule->cookie_len);
492-
memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
493-
rule->cookie_len += 20;
522+
istcpy(&rule->cookie.str, ist2(cookie, cookie_len), cookie_len);
523+
istcat(&rule->cookie.str, ist2("; path=/; Max-Age=0;", 20), cookie_len+21);
494524
}
495525
}
496526
rule->type = type;

0 commit comments

Comments
 (0)