]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: proxy/http-ana: Add support of extra attributes for the cookie directive
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 21 Jan 2020 10:06:48 +0000 (11:06 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 22 Jan 2020 06:18:31 +0000 (07:18 +0100)
It is now possible to insert any attribute when a cookie is inserted by
HAProxy. Any value may be set, no check is performed except the syntax validity
(CTRL chars and ';' are forbidden). For instance, it may be used to add the
SameSite attribute:

    cookie SRV insert attr "SameSite=Strict"

The attr option may be repeated to add several attributes.

This patch should fix the issue #361.

doc/configuration.txt
include/types/proxy.h
src/cfgparse-listen.c
src/haproxy.c
src/http_ana.c

index 93b9c65434897dd926a0987cd44ba3039b0231b0..0e69b206c2d77d9fe3238e89ec13d726c7e0e83d 100644 (file)
@@ -3340,7 +3340,7 @@ compression offload
 cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
               [ postonly ] [ preserve ] [ httponly ] [ secure ]
               [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
-              [ dynamic ]
+              [ dynamic ] [ attr <value> ]*
   Enable cookie-based persistence in a backend.
   May be used in sections :   defaults | frontend | listen | backend
                                  yes   |    no    |   yes  |   yes
@@ -3499,6 +3499,11 @@ cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
               The cookie will be regenerated each time the IP address change,
               and is only generated for IPv4/IPv6.
 
+    attr      This option tells haproxy to add an extra attribute when a
+              cookie is inserted. The attribute value can contain any
+              characters except control ones or ";". This option may be
+              repeated.
+
   There can be only one persistence cookie per HTTP backend, and it can be
   declared in a defaults section. The value of the cookie will be the value
   indicated after the "cookie" keyword in a "server" statement. If no cookie
index c018c26f8649108b1254605219affc9cb261ecf9..c6b56aa5bcc50254e0225691ec2a4858f7928d24 100644 (file)
@@ -338,6 +338,7 @@ struct proxy {
        int  cookie_len;                        /* strlen(cookie_name), computed only once */
        char *cookie_domain;                    /* domain used to insert the cookie */
        char *cookie_name;                      /* name of the cookie to look for */
+       char *cookie_attrs;                     /* list of attributes to add to the cookie */
        char *dyncookie_key;                    /* Secret key used to generate dynamic persistent cookies */
        unsigned int cookie_maxidle;            /* max idle time for this cookie */
        unsigned int cookie_maxlife;            /* max life time for this cookie */
index 86d1f3366f0ad5b7d4d05f2cffabba6a90aa785a..3f16a2517fcb3ac4ebb2a470f85747163ec96bcd 100644 (file)
@@ -326,6 +326,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                 curproxy->rdp_cookie_name = strdup(defproxy.rdp_cookie_name);
                        curproxy->rdp_cookie_len = defproxy.rdp_cookie_len;
 
+                       if (defproxy.cookie_attrs)
+                               curproxy->cookie_attrs = strdup(defproxy.cookie_attrs);
 
                        if (defproxy.lbprm.arg_str)
                                curproxy->lbprm.arg_str = strdup(defproxy.lbprm.arg_str);
@@ -476,6 +478,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                free(defproxy.rdp_cookie_name);
                free(defproxy.dyncookie_key);
                free(defproxy.cookie_domain);
+               free(defproxy.cookie_attrs);
                free(defproxy.lbprm.arg_str);
                free(defproxy.capture_name);
                free(defproxy.monitor_uri);
@@ -988,9 +991,34 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                        err_code |= ERR_WARN;
                                curproxy->ck_opts |= PR_CK_DYNAMIC;
                        }
+                       else if (!strcmp(args[cur_arg], "attr")) {
+                               char *val;
+                               if (!*args[cur_arg + 1]) {
+                                       ha_alert("parsing [%s:%d]: '%s' expects <value> as argument.\n",
+                                                file, linenum, args[cur_arg]);
+                                       err_code |= ERR_ALERT | ERR_FATAL;
+                                       goto out;
+                               }
+                               val = args[cur_arg + 1];
+                               while (*val) {
+                                       if (iscntrl(*val) || *val == ';') {
+                                               ha_alert("parsing [%s:%d]: character '%%x%02X' is not permitted in attribute value.\n",
+                                                        file, linenum, *val);
+                                               err_code |= ERR_ALERT | ERR_FATAL;
+                                               goto out;
+                                       }
+                                       val++;
+                               }
+                               /* don't add ';' for the first attribute */
+                               if (!curproxy->cookie_attrs)
+                                       curproxy->cookie_attrs = strdup(args[cur_arg + 1]);
+                               else
+                                       memprintf(&curproxy->cookie_attrs, "%s; %s", curproxy->cookie_attrs, args[cur_arg + 1]);
+                               cur_arg++;
+                       }
 
                        else {
-                               ha_alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache', 'postonly', 'domain', 'maxidle', 'dynamic' and 'maxlife' options.\n",
+                               ha_alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache', 'postonly', 'domain', 'maxidle', 'dynamic', 'maxlife' and 'attr' options.\n",
                                         file, linenum, args[0]);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
index 78143d7e73bde2ba094e81cf952c1314776ba156..ef484d8a2ac1d28ae163dd4e4ddde57fbd728899 100644 (file)
@@ -2339,6 +2339,7 @@ void deinit(void)
                free(p->check_req);
                free(p->cookie_name);
                free(p->cookie_domain);
+               free(p->cookie_attrs);
                free(p->lbprm.arg_str);
                free(p->capture_name);
                free(p->monitor_uri);
index 23db04ece5941526746bc559d839a2a57566abaf..2891f056b7469b20e3c7d007dc1d62c01c199fe0 100644 (file)
@@ -2068,6 +2068,9 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
                if (s->be->ck_opts & PR_CK_SECURE)
                        chunk_appendf(&trash, "; Secure");
 
+               if (s->be->cookie_attrs)
+                       chunk_appendf(&trash, "; %s", s->be->cookie_attrs);
+
                if (unlikely(!http_add_header(htx, ist("Set-Cookie"), ist2(trash.area, trash.data))))
                        goto return_int_err;