]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-ana: Add support for "set-cookie-fmt" option to redirect rules
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 18 Nov 2024 17:03:23 +0000 (18:03 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 19 Nov 2024 14:20:02 +0000 (15:20 +0100)
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.

doc/configuration.txt
include/haproxy/http_ana-t.h
include/haproxy/proxy-t.h
src/http_ana.c
src/http_rules.c

index 9bd5d45aefc1580331ac09e725e8bb87223cff44..afe5edb385961494b9fb04082dd955b916c9aa4e 100644 (file)
@@ -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
index 2010aa045b48e7b68b0adf3ebb6601899f29344f..f4f13d0701cfe4ab9f0fdd17091093f30f67ac05 100644 (file)
@@ -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 ) */
index 677eacea0fd08b3003c49211ce7b0ed2abc08e8e..e25e1838b30da31b4cc3518c64537d79d6a89e53 100644 (file)
@@ -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 */
index fea5f1f9a88a8c02cdf9d19275f5303d16a0ab8c..cda4642408c052e8f27cea17cb22ea91365be1fd 100644 (file)
@@ -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;
        }
 
index 86df4cf435817efab71f8f2ab9b40b0476ebf22e..8a3f9ec17eef8e1db360b126f0a87448a77ccdf5 100644 (file)
@@ -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;