MINOR: proxy/http-ana: Add support of extra attributes for the cookie directive
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.
(cherry picked from commit 2f5339079b884ac8bdde166add1879ebfd9e433b)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit fac50825151ac2abc6b71343e3ffa6e0dc06c53d)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 2e834fb..e65b073 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -3351,7 +3351,7 @@
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
@@ -3510,6 +3510,11 @@
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
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 6aa0de1..9b06955 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -339,6 +339,7 @@
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 */
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index c3fe8b9..5645048 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -473,6 +473,8 @@
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);
@@ -623,6 +625,7 @@
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);
@@ -1136,9 +1139,34 @@
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;
diff --git a/src/haproxy.c b/src/haproxy.c
index db3531d..0355344 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -2212,6 +2212,7 @@
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);
diff --git a/src/proto_http.c b/src/proto_http.c
index 3c16776..6e6d0b0 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -5077,6 +5077,9 @@
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_header_add_tail2(&txn->rsp, &txn->hdr_idx, trash.area, trash.data) < 0))
goto return_bad_resp;
diff --git a/src/proto_htx.c b/src/proto_htx.c
index 1ad4aa8..af73a50 100644
--- a/src/proto_htx.c
+++ b/src/proto_htx.c
@@ -2055,6 +2055,9 @@
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_bad_resp;