MEDIUM: pattern: add sample lookup function.

Some functions needs to change the sample associated to pattern. This
new pointer permit to return the a pointer to the sample pointer. The
caller can use or change the value.
diff --git a/src/acl.c b/src/acl.c
index c424189..f110269 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -356,6 +356,7 @@
 	expr->pat.match = aclkw ? aclkw->match : NULL;
 	expr->pat.delete = aclkw ? aclkw->delete : NULL;
 	expr->pat.prune = aclkw ? aclkw->prune : NULL;
+	expr->pat.find_smp = aclkw ? aclkw->find_smp : NULL;
 	expr->smp = smp;
 	smp = NULL;
 
@@ -369,6 +370,7 @@
 			expr->pat.match = pat_match_fcts[PAT_MATCH_BOOL];
 			expr->pat.delete = pat_delete_fcts[PAT_MATCH_BOOL];
 			expr->pat.prune = pat_prune_fcts[PAT_MATCH_BOOL];
+			expr->pat.find_smp = pat_find_smp_fcts[PAT_MATCH_BOOL];
 			break;
 		case SMP_T_SINT:
 		case SMP_T_UINT:
@@ -377,6 +379,7 @@
 			expr->pat.match = pat_match_fcts[PAT_MATCH_INT];
 			expr->pat.delete = pat_delete_fcts[PAT_MATCH_INT];
 			expr->pat.prune = pat_prune_fcts[PAT_MATCH_INT];
+			expr->pat.find_smp = pat_find_smp_fcts[PAT_MATCH_INT];
 			break;
 		case SMP_T_IPV4:
 		case SMP_T_IPV6:
@@ -385,6 +388,7 @@
 			expr->pat.match = pat_match_fcts[PAT_MATCH_IP];
 			expr->pat.delete = pat_delete_fcts[PAT_MATCH_IP];
 			expr->pat.prune = pat_prune_fcts[PAT_MATCH_IP];
+			expr->pat.find_smp = pat_find_smp_fcts[PAT_MATCH_IP];
 			break;
 		}
 	}
@@ -447,6 +451,7 @@
 			expr->pat.match = pat_match_fcts[idx];
 			expr->pat.delete = pat_delete_fcts[idx];
 			expr->pat.prune = pat_prune_fcts[idx];
+			expr->pat.find_smp = pat_find_smp_fcts[idx];
 			args++;
 		}
 		else if ((*args)[1] == '-') {
diff --git a/src/dumpstats.c b/src/dumpstats.c
index ddba615..aecce5f 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -1561,8 +1561,7 @@
 			stats_sock_table_request(si, args, STAT_CLI_O_SET);
 		}
 		else if (strcmp(args[1], "map") == 0) {
-			struct pattern_list *pat_elt;
-			struct pattern_tree *idx_elt;
+			struct sample_storage **smp;
 			char *value = NULL;
 
 			/* Expect three parameters: map name, key and new value. */
@@ -1612,11 +1611,9 @@
 			for (stats_map_lookup_next(si);
 			     appctx->ctx.map.desc;
 			     stats_map_lookup_next(si)) {
-				pattern_lookup(args[3], appctx->ctx.map.desc->pat, &pat_elt, &idx_elt, NULL);
-				if (pat_elt != NULL)
-					appctx->ctx.map.desc->parse(value, pat_elt->pat.smp);
-				if (idx_elt != NULL)
-					appctx->ctx.map.desc->parse(value, idx_elt->smp);
+				smp = pattern_find_smp(args[3], appctx->ctx.map.desc->pat, NULL);
+				if (smp)
+					appctx->ctx.map.desc->parse(value, *smp);
 			}
 
 			/* The set is done, send message. */
diff --git a/src/map.c b/src/map.c
index 0f2db28..b595b02 100644
--- a/src/map.c
+++ b/src/map.c
@@ -414,6 +414,7 @@
 		desc->pat->index = pat_index_fcts[conv->private];
 		desc->pat->delete = pat_delete_fcts[conv->private];
 		desc->pat->prune = pat_prune_fcts[conv->private];
+		desc->pat->find_smp = pat_find_smp_fcts[conv->private];
 
 		/* parse each line of the file */
 		list_for_each_entry(ent, &ref->entries, list)
diff --git a/src/pattern.c b/src/pattern.c
index 170955f..48cec0d 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -88,6 +88,23 @@
 	[PAT_MATCH_REG]   = pat_del_list_reg,
 };
 
+struct sample_storage **(*pat_find_smp_fcts[PAT_MATCH_NUM])(struct pattern_expr *,
+                                                            struct pattern *) = {
+	[PAT_MATCH_FOUND] = pat_find_smp_list_val,
+	[PAT_MATCH_BOOL]  = pat_find_smp_list_val,
+	[PAT_MATCH_INT]   = pat_find_smp_list_val,
+	[PAT_MATCH_IP]    = pat_find_smp_tree_ip,
+	[PAT_MATCH_BIN]   = pat_find_smp_list_ptr,
+	[PAT_MATCH_LEN]   = pat_find_smp_list_val,
+	[PAT_MATCH_STR]   = pat_find_smp_tree_str,
+	[PAT_MATCH_BEG]   = pat_find_smp_list_str,
+	[PAT_MATCH_SUB]   = pat_find_smp_list_str,
+	[PAT_MATCH_DIR]   = pat_find_smp_list_str,
+	[PAT_MATCH_DOM]   = pat_find_smp_list_str,
+	[PAT_MATCH_END]   = pat_find_smp_list_str,
+	[PAT_MATCH_REG]   = pat_find_smp_list_reg,
+};
+
 void (*pat_prune_fcts[PAT_MATCH_NUM])(struct pattern_expr *) = {
 	[PAT_MATCH_FOUND] = pat_prune_val,
 	[PAT_MATCH_BOOL]  = pat_prune_val,
@@ -1212,6 +1229,189 @@
 	return 1;
 }
 
+struct sample_storage **pat_find_smp_list_val(struct pattern_expr *expr, struct pattern *pattern)
+{
+	struct pattern_list *pat;
+	struct pattern_list *safe;
+
+	list_for_each_entry_safe(pat, safe, &expr->patterns, list) {
+
+		/* Check equality. */
+		if (pattern->val.range.min_set != pat->pat.val.range.min_set)
+			continue;
+		if (pattern->val.range.max_set != pat->pat.val.range.max_set)
+			continue;
+		if (pattern->val.range.min_set &&
+		    pattern->val.range.min != pat->pat.val.range.min)
+			continue;
+		if (pattern->val.range.max_set &&
+		    pattern->val.range.max != pat->pat.val.range.max)
+			continue;
+
+		/* Return the pointer on the sample pointer. */
+		return &pat->pat.smp;
+	}
+
+	return NULL;
+}
+
+struct sample_storage **pat_find_smp_tree_ip(struct pattern_expr *expr, struct pattern *pattern)
+{
+	struct ebmb_node *node, *next_node;
+	struct pattern_tree *elt;
+	struct pattern_list *pat;
+	struct pattern_list *safe;
+	unsigned int mask;
+
+	/* browse each node of the tree for IPv4 addresses. */
+	if (pattern->type == SMP_T_IPV4) {
+		/* Convert mask. If the mask is contiguous, browse each node
+		 * of the tree for IPv4 addresses.
+		 */
+		mask = ntohl(pattern->val.ipv4.mask.s_addr);
+		if (mask + (mask & -mask) == 0) {
+			mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
+
+			for (node = ebmb_first(&expr->pattern_tree), next_node = ebmb_next(node);
+			     node;
+			     node = next_node, next_node = next_node ? ebmb_next(next_node) : NULL) {
+				/* Extract container of the tree node. */
+				elt = container_of(node, struct pattern_tree, node);
+
+				/* Check equality. */
+				if (strcmp(pattern->ptr.str, (char *)elt->node.key) != 0)
+					continue;
+
+				/* Return the pointer on the sample pointer. */
+				return &elt->smp;
+			}
+		}
+		else {
+			/* Browse each node of the list for IPv4 addresses. */
+			list_for_each_entry_safe(pat, safe, &expr->patterns, list) {
+				/* Check equality. */
+				if (memcmp(&pattern->val.ipv4.addr, &pat->pat.val.ipv4.addr,
+				           sizeof(pat->pat.val.ipv4.addr)) != 0)
+					continue;
+				if (memcmp(&pattern->val.ipv4.mask, &pat->pat.val.ipv4.mask,
+				           sizeof(pat->pat.val.ipv4.addr)) != 0)
+					continue;
+
+				/* Return the pointer on the sample pointer. */
+				return &pat->pat.smp;
+			}
+		}
+	}
+	else if (pattern->type == SMP_T_IPV6) {
+		/* browse each node of the tree for IPv4 addresses. */
+		for (node = ebmb_first(&expr->pattern_tree_2), next_node = ebmb_next(node);
+		     node;
+		     node = next_node, next_node = next_node ? ebmb_next(next_node) : NULL) {
+			/* Extract container of the tree node. */
+			elt = container_of(node, struct pattern_tree, node);
+
+			/* Check equality. */
+			if (strcmp(pattern->ptr.str, (char *)elt->node.key) != 0)
+				continue;
+
+			/* Return the pointer on the sample pointer. */
+			return &elt->smp;
+		}
+	}
+
+	return NULL;
+}
+
+struct sample_storage **pat_find_smp_list_ptr(struct pattern_expr *expr, struct pattern *pattern)
+{
+	struct pattern_list *pat;
+	struct pattern_list *safe;
+
+	list_for_each_entry_safe(pat, safe, &expr->patterns, list) {
+		/* Check equality. */
+		if (pattern->len != pat->pat.len)
+			continue;
+		if (memcmp(pattern->ptr.ptr, pat->pat.ptr.ptr, pat->pat.len) != 0)
+			continue;
+
+		/* Return the pointer on the sample pointer. */
+		return &pat->pat.smp;
+	}
+
+	return NULL;
+}
+
+struct sample_storage **pat_find_smp_tree_str(struct pattern_expr *expr, struct pattern *pattern)
+{
+	struct ebmb_node *node, *next_node;
+	struct pattern_tree *elt;
+
+	/* browse each node of the tree. */
+	for (node = ebmb_first(&expr->pattern_tree), next_node = ebmb_next(node);
+	     node;
+	     node = next_node, next_node = next_node ? ebmb_next(next_node) : NULL) {
+		/* Extract container of the tree node. */
+		elt = container_of(node, struct pattern_tree, node);
+
+		/* Check equality. */
+		if (strcmp(pattern->ptr.str, (char *)elt->node.key) != 0)
+			continue;
+
+		/* Return the pointer on the sample pointer. */
+		return &elt->smp;
+	}
+
+	return NULL;
+}
+
+struct sample_storage **pat_find_smp_list_str(struct pattern_expr *expr, struct pattern *pattern)
+{
+	struct pattern_list *pat;
+	struct pattern_list *safe;
+
+	list_for_each_entry_safe(pat, safe, &expr->patterns, list) {
+		/* Check equality. */
+		if (pattern->len != pat->pat.len)
+			continue;
+		if (pat->pat.flags & PAT_F_IGNORE_CASE) {
+			if (strncasecmp(pattern->ptr.str, pat->pat.ptr.str, pat->pat.len) != 0)
+				continue;
+		}
+		else {
+			if (strncmp(pattern->ptr.str, pat->pat.ptr.str, pat->pat.len) != 0)
+				continue;
+		}
+
+		/* Return the pointer on the sample pointer. */
+		return &pat->pat.smp;
+	}
+
+	return NULL;
+}
+
+struct sample_storage **pat_find_smp_list_reg(struct pattern_expr *expr, struct pattern *pattern)
+{
+	struct pattern_list *pat;
+	struct pattern_list *safe;
+
+	list_for_each_entry_safe(pat, safe, &expr->patterns, list) {
+		/* Check equality. */
+		if (pat->pat.flags & PAT_F_IGNORE_CASE) {
+			if (strcasecmp(pattern->ptr.reg->regstr, pat->pat.ptr.reg->regstr) != 0)
+				continue;
+		}
+		else {
+			if (strcmp(pattern->ptr.reg->regstr, pat->pat.ptr.reg->regstr) != 0)
+				continue;
+		}
+
+		/* Return the pointer on the sample pointer. */
+		return &pat->pat.smp;
+	}
+
+	return NULL;
+}
+
 void pat_del_list_val(struct pattern_expr *expr, struct pattern *pattern)
 {
 	struct pattern_list *pat;
@@ -1526,6 +1726,20 @@
 	expr->prune(expr);
 }
 
+/* This function lookup for a pattern matching the <key> and return a
+ * pointer to a pointer of the sample stoarge. If the <key> dont match,
+ * the function returns NULL. If the key cannot be parsed, the function
+ * fill <err>.
+ */
+struct sample_storage **pattern_find_smp(const char *key, struct pattern_expr *expr, char **err)
+{
+	struct pattern pattern;
+
+	if (!expr->parse(key, &pattern, err))
+		return NULL;
+	return expr->find_smp(expr, &pattern);
+}
+
 /* This function search all the pattern matching the <key> and delete it.
  * If the parsing of the input key fails, the function returns 0 and the
  * <err> is filled, else return 1;
diff --git a/src/payload.c b/src/payload.c
index 82efe95..2042341 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -681,13 +681,13 @@
  * Please take care of keeping this list alphabetically sorted.
  */
 static struct acl_kw_list acl_kws = {ILH, {
-	{ "payload",            "req.payload",        pat_parse_bin,        pat_idx_list_ptr, pat_del_list_ptr, pat_prune_ptr, pat_match_bin },
-	{ "payload_lv",         "req.payload_lv",     pat_parse_bin,        pat_idx_list_ptr, pat_del_list_ptr, pat_prune_ptr, pat_match_bin },
-	{ "req_rdp_cookie",     "req.rdp_cookie",     pat_parse_str,        pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str },
-	{ "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", pat_parse_int,        pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_int },
-	{ "req_ssl_sni",        "req.ssl_sni",        pat_parse_str,        pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str },
-	{ "req_ssl_ver",        "req.ssl_ver",        pat_parse_dotted_ver, pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_int },
-	{ "req.ssl_ver",        "req.ssl_ver",        pat_parse_dotted_ver, pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_int },
+	{ "payload",            "req.payload",        pat_parse_bin,        pat_idx_list_ptr, pat_del_list_ptr, pat_find_smp_list_ptr, pat_prune_ptr, pat_match_bin },
+	{ "payload_lv",         "req.payload_lv",     pat_parse_bin,        pat_idx_list_ptr, pat_del_list_ptr, pat_find_smp_list_ptr, pat_prune_ptr, pat_match_bin },
+	{ "req_rdp_cookie",     "req.rdp_cookie",     pat_parse_str,        pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str },
+	{ "req_rdp_cookie_cnt", "req.rdp_cookie_cnt", pat_parse_int,        pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_int },
+	{ "req_ssl_sni",        "req.ssl_sni",        pat_parse_str,        pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str },
+	{ "req_ssl_ver",        "req.ssl_ver",        pat_parse_dotted_ver, pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_int },
+	{ "req.ssl_ver",        "req.ssl_ver",        pat_parse_dotted_ver, pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_int },
 	{ /* END */ },
 }};
 
diff --git a/src/proto_http.c b/src/proto_http.c
index 421a186..bd7bfff 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -10391,84 +10391,84 @@
  * Please take care of keeping this list alphabetically sorted.
  */
 static struct acl_kw_list acl_kws = {ILH, {
-	{ "base",            "base",     pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "base_beg",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "base_dir",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "base_dom",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "base_end",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "base_len",        "base",     pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "base_reg",        "base",     pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "base_sub",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "base",            "base",     pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "base_beg",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "base_dir",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "base_dom",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "base_end",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "base_len",        "base",     pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "base_reg",        "base",     pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "base_sub",        "base",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
-	{ "cook",            "req.cook", pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "cook_beg",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "cook_dir",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "cook_dom",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "cook_end",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "cook_len",        "req.cook", pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "cook_reg",        "req.cook", pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "cook_sub",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "cook",            "req.cook", pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "cook_beg",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "cook_dir",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "cook_dom",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "cook_end",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "cook_len",        "req.cook", pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "cook_reg",        "req.cook", pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "cook_sub",        "req.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
-	{ "hdr",             "req.hdr",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "hdr_beg",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "hdr_dir",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "hdr_dom",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "hdr_end",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "hdr_len",         "req.hdr",  pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "hdr_reg",         "req.hdr",  pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "hdr_sub",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "hdr",             "req.hdr",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "hdr_beg",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "hdr_dir",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "hdr_dom",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "hdr_end",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "hdr_len",         "req.hdr",  pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "hdr_reg",         "req.hdr",  pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "hdr_sub",         "req.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
-	{ "http_auth_group", NULL,       pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_auth },
+	{ "http_auth_group", NULL,       pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_auth },
 
-	{ "method",          NULL,       pat_parse_meth, pat_idx_list_str, pat_del_meth,   pat_prune_ptr, pat_match_meth },
+	{ "method",          NULL,       pat_parse_meth, pat_idx_list_str, pat_del_meth,   pat_find_smp_list_str, pat_prune_ptr, pat_match_meth },
 
-	{ "path",            "path",     pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "path_beg",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "path_dir",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "path_dom",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "path_end",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "path_len",        "path",     pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "path_reg",        "path",     pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "path_sub",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "path",            "path",     pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "path_beg",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "path_dir",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "path_dom",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "path_end",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "path_len",        "path",     pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "path_reg",        "path",     pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "path_sub",        "path",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
-	{ "req_ver",         "req.ver",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "resp_ver",        "res.ver",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "req_ver",         "req.ver",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "resp_ver",        "res.ver",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
 
-	{ "scook",           "res.cook", pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "scook_beg",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "scook_dir",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "scook_dom",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "scook_end",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "scook_len",       "res.cook", pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "scook_reg",       "res.cook", pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "scook_sub",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "scook",           "res.cook", pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "scook_beg",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "scook_dir",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "scook_dom",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "scook_end",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "scook_len",       "res.cook", pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "scook_reg",       "res.cook", pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "scook_sub",       "res.cook", pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
-	{ "shdr",            "res.hdr",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "shdr_beg",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "shdr_dir",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "shdr_dom",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "shdr_end",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "shdr_len",        "res.hdr",  pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "shdr_reg",        "res.hdr",  pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "shdr_sub",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "shdr",            "res.hdr",  pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "shdr_beg",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "shdr_dir",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "shdr_dom",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "shdr_end",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "shdr_len",        "res.hdr",  pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "shdr_reg",        "res.hdr",  pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "shdr_sub",        "res.hdr",  pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
-	{ "url",             "url",      pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "url_beg",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "url_dir",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "url_dom",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "url_end",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "url_len",         "url",      pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "url_reg",         "url",      pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "url_sub",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "url",             "url",      pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "url_beg",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "url_dir",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "url_dom",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "url_end",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "url_len",         "url",      pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "url_reg",         "url",      pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "url_sub",         "url",      pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
-	{ "urlp",            "urlp",     pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str  },
-	{ "urlp_beg",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_beg  },
-	{ "urlp_dir",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dir  },
-	{ "urlp_dom",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_dom  },
-	{ "urlp_end",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end  },
-	{ "urlp_len",        "urlp",     pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_prune_val, pat_match_len  },
-	{ "urlp_reg",        "urlp",     pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg  },
-	{ "urlp_sub",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_sub  },
+	{ "urlp",            "urlp",     pat_parse_str,  pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str  },
+	{ "urlp_beg",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_beg  },
+	{ "urlp_dir",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dir  },
+	{ "urlp_dom",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_dom  },
+	{ "urlp_end",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end  },
+	{ "urlp_len",        "urlp",     pat_parse_int,  pat_idx_list_val, pat_del_list_val, pat_find_smp_list_val, pat_prune_val, pat_match_len  },
+	{ "urlp_reg",        "urlp",     pat_parse_reg,  pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg  },
+	{ "urlp_sub",        "urlp",     pat_parse_str,  pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_sub  },
 
 	{ /* END */ },
 }};
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index fedcb46..672bdc1 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -3546,31 +3546,31 @@
  * Please take care of keeping this list alphabetically sorted.
  */
 static struct acl_kw_list acl_kws = {ILH, {
-	{ "ssl_c_i_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_c_key_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_c_notafter",         NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_c_notbefore",        NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_c_sig_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_c_s_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_c_serial",           NULL,         pat_parse_bin, pat_idx_list_ptr, pat_del_list_ptr, pat_prune_ptr, pat_match_bin     },
-	{ "ssl_f_i_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_f_key_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_f_notafter",         NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_f_notbefore",        NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_f_sig_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_f_s_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_f_serial",           NULL,         pat_parse_bin, pat_idx_list_ptr, pat_del_list_ptr, pat_prune_ptr, pat_match_bin     },
-	{ "ssl_fc_cipher",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_c_i_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_c_key_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_c_notafter",         NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_c_notbefore",        NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_c_sig_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_c_s_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_c_serial",           NULL,         pat_parse_bin, pat_idx_list_ptr, pat_del_list_ptr, pat_find_smp_list_ptr, pat_prune_ptr, pat_match_bin     },
+	{ "ssl_f_i_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_f_key_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_f_notafter",         NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_f_notbefore",        NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_f_sig_alg",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_f_s_dn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_f_serial",           NULL,         pat_parse_bin, pat_idx_list_ptr, pat_del_list_ptr, pat_find_smp_list_ptr, pat_prune_ptr, pat_match_bin     },
+	{ "ssl_fc_cipher",          NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
 #ifdef OPENSSL_NPN_NEGOTIATED
-	{ "ssl_fc_npn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_fc_npn",             NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
 #endif
 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
-	{ "ssl_fc_alpn",            NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_fc_alpn",            NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
 #endif
-	{ "ssl_fc_protocol",        NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_fc_sni",             "ssl_fc_sni", pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_prune_ptr, pat_match_str     },
-	{ "ssl_fc_sni_end",         "ssl_fc_sni", pat_parse_str, pat_idx_list_str, pat_del_list_str, pat_prune_ptr, pat_match_end     },
-	{ "ssl_fc_sni_reg",         "ssl_fc_sni", pat_parse_reg, pat_idx_list_reg, pat_del_list_reg, pat_prune_reg, pat_match_reg     },
+	{ "ssl_fc_protocol",        NULL,         pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_fc_sni",             "ssl_fc_sni", pat_parse_str, pat_idx_tree_str, pat_del_tree_str, pat_find_smp_tree_str, pat_prune_ptr, pat_match_str     },
+	{ "ssl_fc_sni_end",         "ssl_fc_sni", pat_parse_str, pat_idx_list_str, pat_del_list_str, pat_find_smp_list_str, pat_prune_ptr, pat_match_end     },
+	{ "ssl_fc_sni_reg",         "ssl_fc_sni", pat_parse_reg, pat_idx_list_reg, pat_del_list_reg, pat_find_smp_list_reg, pat_prune_reg, pat_match_reg     },
 	{ /* END */ },
 }};