MEDIUM: http: merge ACL and pattern cookie fetches into a single one
It's easy to merge pattern and ACL fetches of cookies. It allows us
to remove two distinct fetch functions. The new function internally
uses an occurrence number to serve both purposes, but it didn't appear
worth exposing it outside so there is no keyword argument to set it.
However one of the benefits is that the "cookie" fetch for stick tables
now automatically adapts to requests and responses, so there is no more
need for set-cookie().
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 979af63..12fee1e 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -8407,16 +8407,20 @@
cookie(<name>)
This extracts the last occurrence of the cookie name <name> on a
- "Cookie" header line from the request and uses the corresponding
- value to match. A typical use is to get multiple clients sharing
- a same profile use the same server. This can be similar to what
- "appsession" does with the "request-learn" statement, but with
- support for multi-peer synchronization and state keeping across
- restarts.
+ "Cookie" header line from the request, or a "Set-Cookie" header
+ from the response, and uses the corresponding value to match. A
+ typical use is to get multiple clients sharing a same profile
+ use the same server. This can be similar to what "appsession"
+ does with the "request-learn" statement, but with support for
+ multi-peer synchronization and state keeping across restarts.
See also : "appsession"
set-cookie(<name>)
+ This fetch function is deprecated and has been superseded by the
+ "cookie" fetch which is capable of handling both requests and
+ responses. This keyword will disappear soon.
+
This extracts the last occurrence of the cookie name <name> on a
"Set-Cookie" header line from the response and uses the
corresponding value to match. This can be comparable to what
diff --git a/src/proto_http.c b/src/proto_http.c
index a1b7e13..a173f88 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -8139,10 +8139,11 @@
* end-of-header-value, and smp->ctx.a[2] for the hdr_idx. Depending on
* the direction, multiple cookies may be parsed on the same line or not.
* The cookie name is in args and the name length in args->data.str.len.
- * Accepts exactly 1 argument of type string.
+ * Accepts exactly 1 argument of type string. If the input options indicate
+ * that no iterating is desired, then only last value is fetched if any.
*/
static int
-acl_fetch_cookie_value(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
+smp_fetch_cookie_value(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp)
{
struct http_txn *txn = l7;
@@ -8152,6 +8153,8 @@
const char *hdr_name;
int hdr_name_len;
char *sol;
+ int occ = 0;
+ int found = 0;
if (!args || args->type != ARGT_STR)
return 0;
@@ -8168,6 +8171,15 @@
hdr_name_len = 10;
}
+ if (!occ && !(opt & SMP_OPT_ITERATE))
+ /* no explicit occurrence and single fetch => last cookie by default */
+ occ = -1;
+
+ /* OK so basically here, either we want only one value and it's the
+ * last one, or we want to iterate over all of them and we fetch the
+ * next one.
+ */
+
sol = msg->buf->p + msg->sol;
if (!(smp->flags & SMP_F_NOT_LAST)) {
/* search for the header from the beginning, we must first initialize
@@ -8177,6 +8189,8 @@
ctx->idx = 0;
}
+ smp->flags |= SMP_F_VOL_HDR;
+
while (1) {
/* Note: smp->ctx.a[0] == NULL every time we need to fetch a new header */
if (!smp->ctx.a[0]) {
@@ -8197,17 +8211,21 @@
&smp->data.str.str,
&smp->data.str.len);
if (smp->ctx.a[0]) {
- /* one value was returned into smp->data.str.{str,len} */
- smp->flags |= SMP_F_NOT_LAST;
- smp->flags |= SMP_F_VOL_HDR;
- return 1;
+ found = 1;
+ if (occ >= 0) {
+ /* one value was returned into smp->data.str.{str,len} */
+ smp->flags |= SMP_F_NOT_LAST;
+ return 1;
+ }
}
+ /* if we're looking for last occurrence, let's loop */
}
-
+ /* all cookie headers and values were scanned. If we're looking for the
+ * last occurrence, we may return it now.
+ */
out:
smp->flags &= ~SMP_F_NOT_LAST;
- smp->flags |= SMP_F_VOL_HDR;
- return 0;
+ return found;
}
/* Iterate over all cookies present in a request to count how many occurrences
@@ -8388,85 +8406,6 @@
return 1;
}
-/* Try to find in request or response message is in <msg> and whose transaction
- * is in <txn> the last occurrence of a cookie name in all cookie header values
- * whose header name is <hdr_name> with name of length <hdr_name_len>. The
- * pointer and size of the last occurrence of the cookie value is returned into
- * <value> and <value_l>, and the function returns non-zero if the value was
- * found. Otherwise if the cookie was not found, zero is returned and neither
- * value nor value_l are touched. The input hdr string should begin at the
- * header's value, and its size should be in hdr_l. <list> must be non-zero if
- * value may represent a list of values (cookie headers).
- */
-
-static int
-find_cookie_value(struct http_msg *msg, struct http_txn *txn,
- const char *hdr_name, int hdr_name_len,
- char *cookie_name, size_t cookie_name_l, int list,
- char **value, int *value_l)
-{
- struct hdr_ctx ctx;
- int found = 0;
-
- ctx.idx = 0;
- while (http_find_header2(hdr_name, hdr_name_len, msg->buf->p + msg->sol, &txn->hdr_idx, &ctx)) {
- char *hdr, *end;
- if (ctx.vlen < cookie_name_l + 1)
- continue;
-
- hdr = ctx.line + ctx.val;
- end = hdr + ctx.vlen;
- while ((hdr = extract_cookie_value(hdr, end, cookie_name, cookie_name_l, 1, value, value_l)))
- found = 1;
- }
- return found;
-}
-
-static int
-pattern_fetch_cookie(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
- const struct arg *arg_p, struct sample *smp)
-{
- struct http_txn *txn = l7;
- struct http_msg *msg = &txn->req;
- char *cookie_value;
- int cookie_value_l;
- int found = 0;
-
- found = find_cookie_value(msg, txn, "Cookie", 6,
- arg_p->data.str.str, arg_p->data.str.len, 1,
- &cookie_value, &cookie_value_l);
- if (found) {
- smp->type = SMP_T_CSTR;
- smp->data.str.str = cookie_value;
- smp->data.str.len = cookie_value_l;
- }
-
- return found;
-}
-
-
-static int
-pattern_fetch_set_cookie(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
- const struct arg *arg_p, struct sample *smp)
-{
- struct http_txn *txn = l7;
- struct http_msg *msg = &txn->rsp;
- char *cookie_value;
- int cookie_value_l;
- int found = 0;
-
- found = find_cookie_value(msg, txn, "Set-Cookie", 10,
- arg_p->data.str.str, arg_p->data.str.len, 1,
- &cookie_value, &cookie_value_l);
- if (found) {
- smp->type = SMP_T_CSTR;
- smp->data.str.str = cookie_value;
- smp->data.str.len = cookie_value_l;
- }
-
- return found;
-}
-
/* This function is used to validate the arguments passed to any "hdr" fetch
* keyword. These keywords support an optional positive or negative occurrence
* number. We must ensure that the number is greater than -MAX_HDR_HISTORY. It
@@ -8493,15 +8432,15 @@
* Please take care of keeping this list alphabetically sorted.
*/
static struct acl_kw_list acl_kws = {{ },{
- { "cook", acl_parse_str, acl_fetch_cookie_value, acl_match_str, ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP, ARG1(0,STR) },
- { "cook_beg", acl_parse_str, acl_fetch_cookie_value, acl_match_beg, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
+ { "cook", acl_parse_str, smp_fetch_cookie_value, acl_match_str, ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP, ARG1(0,STR) },
+ { "cook_beg", acl_parse_str, smp_fetch_cookie_value, acl_match_beg, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
{ "cook_cnt", acl_parse_int, acl_fetch_cookie_cnt, acl_match_int, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
- { "cook_dir", acl_parse_str, acl_fetch_cookie_value, acl_match_dir, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
- { "cook_dom", acl_parse_str, acl_fetch_cookie_value, acl_match_dom, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
- { "cook_end", acl_parse_str, acl_fetch_cookie_value, acl_match_end, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
- { "cook_len", acl_parse_int, acl_fetch_cookie_value, acl_match_len, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
- { "cook_reg", acl_parse_reg, acl_fetch_cookie_value, acl_match_reg, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
- { "cook_sub", acl_parse_str, acl_fetch_cookie_value, acl_match_sub, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
+ { "cook_dir", acl_parse_str, smp_fetch_cookie_value, acl_match_dir, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
+ { "cook_dom", acl_parse_str, smp_fetch_cookie_value, acl_match_dom, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
+ { "cook_end", acl_parse_str, smp_fetch_cookie_value, acl_match_end, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
+ { "cook_len", acl_parse_int, smp_fetch_cookie_value, acl_match_len, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
+ { "cook_reg", acl_parse_reg, smp_fetch_cookie_value, acl_match_reg, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
+ { "cook_sub", acl_parse_str, smp_fetch_cookie_value, acl_match_sub, ACL_USE_L7REQ_VOLATILE, ARG1(0,STR) },
{ "hdr", acl_parse_str, smp_fetch_hdr, acl_match_str, ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP, ARG2(0,STR,SINT), val_hdr },
{ "hdr_beg", acl_parse_str, smp_fetch_hdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE, ARG2(0,STR,SINT), val_hdr },
@@ -8534,15 +8473,15 @@
{ "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE|ACL_MAY_LOOKUP, 0 },
{ "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE|ACL_MAY_LOOKUP, 0 },
- { "scook", acl_parse_str, acl_fetch_cookie_value, acl_match_str, ACL_USE_L7RTR_VOLATILE|ACL_MAY_LOOKUP, ARG1(0,STR) },
- { "scook_beg", acl_parse_str, acl_fetch_cookie_value, acl_match_beg, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
+ { "scook", acl_parse_str, smp_fetch_cookie_value, acl_match_str, ACL_USE_L7RTR_VOLATILE|ACL_MAY_LOOKUP, ARG1(0,STR) },
+ { "scook_beg", acl_parse_str, smp_fetch_cookie_value, acl_match_beg, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
{ "scook_cnt", acl_parse_int, acl_fetch_cookie_cnt, acl_match_int, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
- { "scook_dir", acl_parse_str, acl_fetch_cookie_value, acl_match_dir, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
- { "scook_dom", acl_parse_str, acl_fetch_cookie_value, acl_match_dom, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
- { "scook_end", acl_parse_str, acl_fetch_cookie_value, acl_match_end, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
- { "scook_len", acl_parse_int, acl_fetch_cookie_value, acl_match_len, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
- { "scook_reg", acl_parse_reg, acl_fetch_cookie_value, acl_match_reg, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
- { "scook_sub", acl_parse_str, acl_fetch_cookie_value, acl_match_sub, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
+ { "scook_dir", acl_parse_str, smp_fetch_cookie_value, acl_match_dir, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
+ { "scook_dom", acl_parse_str, smp_fetch_cookie_value, acl_match_dom, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
+ { "scook_end", acl_parse_str, smp_fetch_cookie_value, acl_match_end, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
+ { "scook_len", acl_parse_int, smp_fetch_cookie_value, acl_match_len, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
+ { "scook_reg", acl_parse_reg, smp_fetch_cookie_value, acl_match_reg, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
+ { "scook_sub", acl_parse_str, smp_fetch_cookie_value, acl_match_sub, ACL_USE_L7RTR_VOLATILE, ARG1(0,STR) },
{ "shdr", acl_parse_str, smp_fetch_hdr, acl_match_str, ACL_USE_L7RTR_VOLATILE|ACL_MAY_LOOKUP, ARG2(0,STR,SINT), val_hdr },
{ "shdr_beg", acl_parse_str, smp_fetch_hdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE, ARG2(0,STR,SINT), val_hdr },
@@ -8589,8 +8528,8 @@
static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
{ "hdr", smp_fetch_hdr, ARG2(1,STR,SINT), val_hdr, SMP_T_CSTR, SMP_CAP_REQ },
{ "url_param", smp_fetch_url_param, ARG1(1,STR), NULL, SMP_T_CSTR, SMP_CAP_REQ },
- { "cookie", pattern_fetch_cookie, ARG1(1,STR), NULL, SMP_T_CSTR, SMP_CAP_REQ },
- { "set-cookie", pattern_fetch_set_cookie, ARG1(1,STR), NULL, SMP_T_CSTR, SMP_CAP_RES },
+ { "cookie", smp_fetch_cookie_value, ARG1(1,STR), NULL, SMP_T_CSTR, SMP_CAP_REQ|SMP_CAP_RES },
+ { "set-cookie", smp_fetch_cookie_value, ARG1(1,STR), NULL, SMP_T_CSTR, SMP_CAP_RES }, /* deprecated */
{ NULL, NULL, 0, 0, 0 },
}};