MEDIUM: pattern: The match function browse itself the list or the tree.

The match function known the format of the pattern. The pattern can be
stored in a list or in a tree. The pattern matching function use itself
the good entry point and indexation type.

Each pattern matching function return the struct pattern that match. If
the flag "fill" is set, the struct pattern is filled, otherwise the
content of this struct must not be used.

With this feature, the general pattern matching function cannot have
exceptions for building the "struct pattern".
diff --git a/include/proto/auth.h b/include/proto/auth.h
index a960613..eea5df5 100644
--- a/include/proto/auth.h
+++ b/include/proto/auth.h
@@ -22,7 +22,7 @@
 unsigned int auth_resolve_groups(struct userlist *l, char *groups);
 int userlist_postinit();
 void userlist_free(struct userlist *ul);
-enum pat_match_res pat_match_auth(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill);
 int check_user(struct userlist *ul, const char *user, const char *pass);
 int check_group(struct userlist *ul, char *name);
 
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index 1daf3bb..e2801a0 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -114,48 +114,48 @@
 int pat_parse_ip(const char *text, struct pattern *pattern, char **err);
 
 /* NB: For two strings to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_str(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_str(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* NB: For two binary buffers to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_bin(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Checks that the length of the pattern in <test> is included between min and max */
-enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_len(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Checks that the integer in <test> is included between min and max */
-enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_int(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* always return false */
-enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_nothing(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Checks that the pattern matches the end of the tested string. */
-enum pat_match_res pat_match_end(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_end(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Checks that the pattern matches the beginning of the tested string. */
-enum pat_match_res pat_match_beg(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_beg(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Checks that the pattern is included inside the tested string. */
-enum pat_match_res pat_match_sub(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_sub(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Checks that the pattern is included inside the tested string, but enclosed
  * between slashes or at the beginning or end of the string. Slashes at the
  * beginning or end of the pattern are ignored.
  */
-enum pat_match_res pat_match_dir(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_dir(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Checks that the pattern is included inside the tested string, but enclosed
  * between dots or at the beginning or end of the string. Dots at the beginning
  * or end of the pattern are ignored.
  */
-enum pat_match_res pat_match_dom(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_dom(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Check that the IPv4 address in <test> matches the IP/mask in pattern */
-enum pat_match_res pat_match_ip(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_ip(struct sample *smp, struct pattern_expr *expr, int fill);
 
 /* Executes a regex. It temporarily changes the data to add a trailing zero,
  * and restores the previous character when leaving.
  */
-enum pat_match_res pat_match_reg(struct sample *smp, struct pattern *pattern);
+struct pattern *pat_match_reg(struct sample *smp, struct pattern_expr *expr, int fill);
 
 int pattern_read_from_file(struct pattern_expr *expr, const char *filename, int patflags, char **err);
 void pattern_free(struct pattern_list *pat);
diff --git a/include/types/acl.h b/include/types/acl.h
index 722bfe6..49c03cf 100644
--- a/include/types/acl.h
+++ b/include/types/acl.h
@@ -94,7 +94,7 @@
 	char *fetch_kw;
 	int (*parse)(const char *text, struct pattern *pattern, char **err);
 	int (*index)(struct pattern_expr *expr, struct pattern *pattern, char **err);
-	enum pat_match_res (*match)(struct sample *smp, struct pattern *pattern);
+	struct pattern *(*match)(struct sample *smp, struct pattern_expr *expr, int fill);
 	/* must be after the config params */
 	struct sample_fetch *smp; /* the sample fetch we depend on */
 };
diff --git a/include/types/pattern.h b/include/types/pattern.h
index 665925c..7a28171 100644
--- a/include/types/pattern.h
+++ b/include/types/pattern.h
@@ -157,7 +157,7 @@
 struct pattern_expr {
 	int (*parse)(const char *text, struct pattern *pattern, char **err);
 	int (*index)(struct pattern_expr *, struct pattern *, char **);
-	enum pat_match_res (*match)(struct sample *smp, struct pattern *pattern);
+	struct pattern *(*match)(struct sample *, struct pattern_expr *, int);
 	struct list patterns;         /* list of acl_patterns */
 	struct eb_root pattern_tree;  /* may be used for lookup in large datasets */
 };
@@ -165,7 +165,7 @@
 extern char *pat_match_names[PAT_MATCH_NUM];
 extern int (*pat_parse_fcts[PAT_MATCH_NUM])(const char *, struct pattern *, char **);
 extern int (*pat_index_fcts[PAT_MATCH_NUM])(struct pattern_expr *, struct pattern *, char **);
-extern enum pat_match_res (*pat_match_fcts[PAT_MATCH_NUM])(struct sample *, struct pattern *);
+struct pattern *(*pat_match_fcts[PAT_MATCH_NUM])(struct sample *, struct pattern_expr *, int);
 extern int pat_match_types[PAT_MATCH_NUM];
 
 #endif /* _TYPES_PATTERN_H */
diff --git a/src/auth.c b/src/auth.c
index 961c288..ad606af 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -256,12 +256,14 @@
 		return 0;
 }
 
-enum pat_match_res
-pat_match_auth(struct sample *smp, struct pattern *pattern)
+struct pattern *
+pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill)
 {
 	struct userlist *ul = smp->ctx.a[0];
+	struct pattern_list *lst;
 	struct auth_users *u;
 	struct auth_groups_list *agl;
+	struct pattern *pattern;
 
 	/* Check if the userlist is present in the context data. */
 	if (!ul)
@@ -273,14 +275,17 @@
 			break;
 	}
 	if (!u)
-		return 0;
+		return NULL;
 
-	/* Browse each group for searching group name that match the pattern. */
-	for (agl = u->u.groups; agl; agl = agl->next) {
-		if (strcmp(agl->group->name, pattern->ptr.str) == 0)
-			break;
+	/* Browse each pattern. */
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		/* Browse each group for searching group name that match the pattern. */
+		for (agl = u->u.groups; agl; agl = agl->next) {
+			if (strcmp(agl->group->name, pattern->ptr.str) == 0)
+				return pattern;
+		}
 	}
-	if (!agl)
-		return PAT_NOMATCH;
-	return PAT_MATCH;
+	return NULL;
 }
diff --git a/src/pattern.c b/src/pattern.c
index aa6a3d4..d6ae8d9 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -72,7 +72,7 @@
 	[PAT_MATCH_REG]   = pat_idx_list_reg,
 };
 
-enum pat_match_res (*pat_match_fcts[PAT_MATCH_NUM])(struct sample *, struct pattern *) = {
+struct pattern *(*pat_match_fcts[PAT_MATCH_NUM])(struct sample *, struct pattern_expr *, int) = {
 	[PAT_MATCH_FOUND] = NULL,
 	[PAT_MATCH_BOOL]  = pat_match_nothing,
 	[PAT_MATCH_INT]   = pat_match_int,
@@ -115,45 +115,12 @@
  *
  */
 
-/* Lookup an IPv4 address in the expression's pattern tree using the longest
- * match method. The node is returned if it exists, otherwise NULL.
- */
-static void *pat_lookup_ip(struct sample *smp, struct pattern_expr *expr)
-{
-	struct in_addr *s;
-
-	if (smp->type != SMP_T_IPV4)
-		return PAT_NOMATCH;
-
-	s = &smp->data.ipv4;
-	return ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
-}
-
 /* Free data allocated by pat_parse_reg */
 static void pat_free_reg(void *ptr)
 {
 	regex_free(ptr);
 }
 
-/* Lookup a string in the expression's pattern tree. The node is returned if it
- * exists, otherwise NULL.
- */
-static void *pat_lookup_str(struct sample *smp, struct pattern_expr *expr)
-{
-	/* data are stored in a tree */
-	struct ebmb_node *node;
-	char prev;
-
-	/* we may have to force a trailing zero on the test pattern */
-	prev = smp->data.str.str[smp->data.str.len];
-	if (prev)
-		smp->data.str.str[smp->data.str.len] = '\0';
-	node = ebst_lookup(&expr->pattern_tree, smp->data.str.str);
-	if (prev)
-		smp->data.str.str[smp->data.str.len] = prev;
-	return node;
-}
-
 /* Background: Fast way to find a zero byte in a word
  * http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
  * hasZeroByte = (v - 0x01010101UL) & ~v & 0x80808080UL;
@@ -452,107 +419,204 @@
  */
 
 /* always return false */
-enum pat_match_res pat_match_nothing(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_nothing(struct sample *smp, struct pattern_expr *expr, int fill)
 {
-	return PAT_NOMATCH;
+	return NULL;
 }
 
 
 /* NB: For two strings to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_str(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_str(struct sample *smp, struct pattern_expr *expr, int fill)
 {
 	int icase;
+	struct ebmb_node *node;
+	char prev;
+	struct pattern_tree *elt;
+	struct pattern_list *lst;
+	struct pattern *pattern;
 
-	if (pattern->len != smp->data.str.len)
-		return PAT_NOMATCH;
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
 
-	icase = pattern->flags & PAT_F_IGNORE_CASE;
-	if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0) ||
-	    (!icase && strncmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0))
-		return PAT_MATCH;
-	return PAT_NOMATCH;
+	/* Lookup a string in the expression's pattern tree. */
+	if (!eb_is_empty(&expr->pattern_tree)) {
+		/* we may have to force a trailing zero on the test pattern */
+		prev = smp->data.str.str[smp->data.str.len];
+		if (prev)
+			smp->data.str.str[smp->data.str.len] = '\0';
+		node = ebst_lookup(&expr->pattern_tree, smp->data.str.str);
+		if (prev)
+			smp->data.str.str[smp->data.str.len] = prev;
+
+		if (node) {
+			if (fill) {
+				elt = ebmb_entry(node, struct pattern_tree, node);
+				static_pattern.smp = elt->smp;
+				static_pattern.flags = PAT_F_TREE;
+				static_pattern.type = SMP_T_STR;
+				static_pattern.ptr.str = (char *)elt->node.key;
+			}
+			return &static_pattern;
+		}
+	}
+
+	/* look in the list */
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		if (pattern->len != smp->data.str.len)
+			continue;
+
+		icase = pattern->flags & PAT_F_IGNORE_CASE;
+		if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0) ||
+		    (!icase && strncmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0))
+			return pattern;
+	}
+
+	return NULL;
 }
 
 /* NB: For two binaries buf to be identical, it is required that their lengths match */
-enum pat_match_res pat_match_bin(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_bin(struct sample *smp, struct pattern_expr *expr, int fill)
 {
-	if (pattern->len != smp->data.str.len)
-		return PAT_NOMATCH;
+	struct pattern_list *lst;
+	struct pattern *pattern;
 
-	if (memcmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0)
-		return PAT_MATCH;
-	return PAT_NOMATCH;
+	/* Convert input to binary. */
+	if (!sample_convert(smp, SMP_T_BIN))
+		return NULL;
+
+	/* Look in the list. */
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		if (pattern->len != smp->data.str.len)
+			continue;
+
+		if (memcmp(pattern->ptr.str, smp->data.str.str, smp->data.str.len) == 0)
+			return pattern;
+	}
+
+	return NULL;
 }
 
 /* Executes a regex. It temporarily changes the data to add a trailing zero,
  * and restores the previous character when leaving.
  */
-enum pat_match_res pat_match_reg(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_reg(struct sample *smp, struct pattern_expr *expr, int fill)
 {
-	if (regex_exec(pattern->ptr.reg, smp->data.str.str, smp->data.str.len) == 0)
-		return PAT_MATCH;
-	return PAT_NOMATCH;
+	struct pattern_list *lst;
+	struct pattern *pattern;
+
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
+
+	/* look in the list */
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		if (regex_exec(pattern->ptr.reg, smp->data.str.str, smp->data.str.len) == 0)
+			return pattern;
+	}
+	return NULL;
 }
 
 /* Checks that the pattern matches the beginning of the tested string. */
-enum pat_match_res pat_match_beg(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_beg(struct sample *smp, struct pattern_expr *expr, int fill)
 {
 	int icase;
+	struct pattern_list *lst;
+	struct pattern *pattern;
 
-	if (pattern->len > smp->data.str.len)
-		return PAT_NOMATCH;
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
 
-	icase = pattern->flags & PAT_F_IGNORE_CASE;
-	if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0) ||
-	    (!icase && strncmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0))
-		return PAT_NOMATCH;
-	return PAT_MATCH;
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		if (pattern->len > smp->data.str.len)
+			continue;
+
+		icase = pattern->flags & PAT_F_IGNORE_CASE;
+		if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0) ||
+		    (!icase && strncmp(pattern->ptr.str, smp->data.str.str, pattern->len) != 0))
+			continue;
+
+		return pattern;
+	}
+	return NULL;
 }
 
 /* Checks that the pattern matches the end of the tested string. */
-enum pat_match_res pat_match_end(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_end(struct sample *smp, struct pattern_expr *expr, int fill)
 {
 	int icase;
+	struct pattern_list *lst;
+	struct pattern *pattern;
 
-	if (pattern->len > smp->data.str.len)
-		return PAT_NOMATCH;
-	icase = pattern->flags & PAT_F_IGNORE_CASE;
-	if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0) ||
-	    (!icase && strncmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0))
-		return PAT_NOMATCH;
-	return PAT_MATCH;
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
+
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		if (pattern->len > smp->data.str.len)
+			continue;
+
+		icase = pattern->flags & PAT_F_IGNORE_CASE;
+		if ((icase && strncasecmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0) ||
+		    (!icase && strncmp(pattern->ptr.str, smp->data.str.str + smp->data.str.len - pattern->len, pattern->len) != 0))
+			continue;
+
+		return pattern;
+	}
+	return  NULL;
 }
 
 /* Checks that the pattern is included inside the tested string.
  * NB: Suboptimal, should be rewritten using a Boyer-Moore method.
  */
-enum pat_match_res pat_match_sub(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_sub(struct sample *smp, struct pattern_expr *expr, int fill)
 {
 	int icase;
 	char *end;
 	char *c;
+	struct pattern_list *lst;
+	struct pattern *pattern;
 
-	if (pattern->len > smp->data.str.len)
-		return PAT_NOMATCH;
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
 
-	end = smp->data.str.str + smp->data.str.len - pattern->len;
-	icase = pattern->flags & PAT_F_IGNORE_CASE;
-	if (icase) {
-		for (c = smp->data.str.str; c <= end; c++) {
-			if (tolower(*c) != tolower(*pattern->ptr.str))
-				continue;
-			if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
-				return PAT_MATCH;
-		}
-	} else {
-		for (c = smp->data.str.str; c <= end; c++) {
-			if (*c != *pattern->ptr.str)
-				continue;
-			if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
-				return PAT_MATCH;
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		if (pattern->len > smp->data.str.len)
+			continue;
+
+		end = smp->data.str.str + smp->data.str.len - pattern->len;
+		icase = pattern->flags & PAT_F_IGNORE_CASE;
+		if (icase) {
+			for (c = smp->data.str.str; c <= end; c++) {
+				if (tolower(*c) != tolower(*pattern->ptr.str))
+					continue;
+				if (strncasecmp(pattern->ptr.str, c, pattern->len) == 0)
+					return pattern;
+			}
+		} else {
+			for (c = smp->data.str.str; c <= end; c++) {
+				if (*c != *pattern->ptr.str)
+					continue;
+				if (strncmp(pattern->ptr.str, c, pattern->len) == 0)
+					return pattern;
+			}
 		}
 	}
-	return PAT_NOMATCH;
+	return NULL;
 }
 
 /* This one is used by other real functions. It checks that the pattern is
@@ -614,105 +678,183 @@
  * between the delimiters '?' or '/' or at the beginning or end of the string.
  * Delimiters at the beginning or end of the pattern are ignored.
  */
-enum pat_match_res pat_match_dir(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_dir(struct sample *smp, struct pattern_expr *expr, int fill)
 {
-	return match_word(smp, pattern, make_4delim('/', '?', '?', '?'));
+	struct pattern_list *lst;
+	struct pattern *pattern;
+
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
+
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+		if (match_word(smp, pattern, make_4delim('/', '?', '?', '?')))
+			return pattern;
+	}
+	return NULL;
 }
 
 /* Checks that the pattern is included inside the tested string, but enclosed
  * between the delmiters '/', '?', '.' or ":" or at the beginning or end of
  * the string. Delimiters at the beginning or end of the pattern are ignored.
  */
-enum pat_match_res pat_match_dom(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_dom(struct sample *smp, struct pattern_expr *expr, int fill)
 {
-	return match_word(smp, pattern, make_4delim('/', '?', '.', ':'));
+	struct pattern_list *lst;
+	struct pattern *pattern;
+
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
+
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+		if (match_word(smp, pattern, make_4delim('/', '?', '.', ':')))
+			return pattern;
+	}
+	return NULL;
 }
 
 /* Checks that the integer in <test> is included between min and max */
-enum pat_match_res pat_match_int(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_int(struct sample *smp, struct pattern_expr *expr, int fill)
 {
-	if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.uint) &&
-	    (!pattern->val.range.max_set || smp->data.uint <= pattern->val.range.max))
-		return PAT_MATCH;
-	return PAT_NOMATCH;
+	struct pattern_list *lst;
+	struct pattern *pattern;
+
+	/* convert input to integer */
+	if (!sample_convert(smp, SMP_T_UINT))
+		return NULL;
+
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+		if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.uint) &&
+		    (!pattern->val.range.max_set || smp->data.uint <= pattern->val.range.max))
+			return pattern;
+	}
+	return NULL;
 }
 
 /* Checks that the length of the pattern in <test> is included between min and max */
-enum pat_match_res pat_match_len(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_len(struct sample *smp, struct pattern_expr *expr, int fill)
 {
-	if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.str.len) &&
-	    (!pattern->val.range.max_set || smp->data.str.len <= pattern->val.range.max))
-		return PAT_MATCH;
-	return PAT_NOMATCH;
+	struct pattern_list *lst;
+	struct pattern *pattern;
+
+	/* convert input to string */
+	if (!sample_convert(smp, SMP_T_STR))
+		return NULL;
+
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+		if ((!pattern->val.range.min_set || pattern->val.range.min <= smp->data.str.len) &&
+		    (!pattern->val.range.max_set || smp->data.str.len <= pattern->val.range.max))
+			return pattern;
+	}
+	return NULL;
 }
 
-enum pat_match_res pat_match_ip(struct sample *smp, struct pattern *pattern)
+struct pattern *pat_match_ip(struct sample *smp, struct pattern_expr *expr, int fill)
 {
 	unsigned int v4; /* in network byte order */
 	struct in6_addr *v6;
 	int bits, pos;
 	struct in6_addr tmp6;
+	struct in_addr *s;
+	struct ebmb_node *node;
+	struct pattern_tree *elt;
+	struct pattern_list *lst;
+	struct pattern *pattern;
 
-	if (pattern->type == SMP_T_IPV4) {
-		if (smp->type == SMP_T_IPV4) {
-			v4 = smp->data.ipv4.s_addr;
+	/* convert input to addr */
+	if (!sample_convert(smp, SMP_T_ADDR))
+		return NULL;
+
+	/* Lookup an IPv4 address in the expression's pattern tree using the longest
+	 * match method.
+	 */
+	if (smp->type == SMP_T_IPV4) {
+		s = &smp->data.ipv4;
+		node = ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
+		if (node) {
+			if (fill) {
+				elt = ebmb_entry(node, struct pattern_tree, node);
+				static_pattern.smp = elt->smp;
+				static_pattern.flags = PAT_F_TREE;
+				static_pattern.type = SMP_T_IPV4;
+				memcpy(&static_pattern.val.ipv4.addr.s_addr, elt->node.key, 4);
+				if (!cidr2dotted(elt->node.node.pfx, &static_pattern.val.ipv4.mask))
+					return NULL;
+			}
+			return &static_pattern;
 		}
-		else if (smp->type == SMP_T_IPV6) {
-			/* v4 match on a V6 sample. We want to check at least for
-			 * the following forms :
-			 *   - ::ffff:ip:v4 (ipv4 mapped)
-			 *   - ::0000:ip:v4 (old ipv4 mapped)
-			 *   - 2002:ip:v4:: (6to4)
-			 */
-			if (*(uint32_t*)&smp->data.ipv6.s6_addr[0] == 0 &&
-			    *(uint32_t*)&smp->data.ipv6.s6_addr[4]  == 0 &&
-			    (*(uint32_t*)&smp->data.ipv6.s6_addr[8] == 0 ||
-			     *(uint32_t*)&smp->data.ipv6.s6_addr[8] == htonl(0xFFFF))) {
-				v4 = *(uint32_t*)&smp->data.ipv6.s6_addr[12];
+	}
+
+	/* Lookup in the list */
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
+
+		if (pattern->type == SMP_T_IPV4) {
+			if (smp->type == SMP_T_IPV4) {
+				v4 = smp->data.ipv4.s_addr;
 			}
-			else if (*(uint16_t*)&smp->data.ipv6.s6_addr[0] == htons(0x2002)) {
-				v4 = htonl((ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[2]) << 16) +
-				            ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[4]));
+			else if (smp->type == SMP_T_IPV6) {
+				/* v4 match on a V6 sample. We want to check at least for
+				 * the following forms :
+				 *   - ::ffff:ip:v4 (ipv4 mapped)
+				 *   - ::0000:ip:v4 (old ipv4 mapped)
+				 *   - 2002:ip:v4:: (6to4)
+				 */
+				if (*(uint32_t*)&smp->data.ipv6.s6_addr[0] == 0 &&
+				    *(uint32_t*)&smp->data.ipv6.s6_addr[4]  == 0 &&
+				    (*(uint32_t*)&smp->data.ipv6.s6_addr[8] == 0 ||
+				     *(uint32_t*)&smp->data.ipv6.s6_addr[8] == htonl(0xFFFF))) {
+					v4 = *(uint32_t*)&smp->data.ipv6.s6_addr[12];
+				}
+				else if (*(uint16_t*)&smp->data.ipv6.s6_addr[0] == htons(0x2002)) {
+					v4 = htonl((ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[2]) << 16) +
+					            ntohs(*(uint16_t*)&smp->data.ipv6.s6_addr[4]));
+				}
+				else
+					continue;
 			}
 			else
-				return PAT_NOMATCH;
-		}
-		else
-			return PAT_NOMATCH;
+				continue;
 
-		if (((v4 ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
-			return PAT_MATCH;
-		else
-			return PAT_NOMATCH;
-	}
-	else if (pattern->type == SMP_T_IPV6) {
-		if (smp->type == SMP_T_IPV4) {
-			/* Convert the IPv4 sample address to IPv4 with the
-			 * mapping method using the ::ffff: prefix.
-			 */
-			memset(&tmp6, 0, 10);
-			*(uint16_t*)&tmp6.s6_addr[10] = htons(0xffff);
-			*(uint32_t*)&tmp6.s6_addr[12] = smp->data.ipv4.s_addr;
-			v6 = &tmp6;
-		}
-		else if (smp->type == SMP_T_IPV6) {
-			v6 = &smp->data.ipv6;
-		}
-		else {
-			return PAT_NOMATCH;
+			if (((v4 ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
+				return pattern;
+			else
+				continue;
 		}
+		else if (pattern->type == SMP_T_IPV6) {
+			if (smp->type == SMP_T_IPV4) {
+				/* Convert the IPv4 sample address to IPv4 with the
+				 * mapping method using the ::ffff: prefix.
+				 */
+				memset(&tmp6, 0, 10);
+				*(uint16_t*)&tmp6.s6_addr[10] = htons(0xffff);
+				*(uint32_t*)&tmp6.s6_addr[12] = smp->data.ipv4.s_addr;
+				v6 = &tmp6;
+			}
+			else if (smp->type == SMP_T_IPV6) {
+				v6 = &smp->data.ipv6;
+			}
+			else {
+				continue;
+			}
 
-		bits = pattern->val.ipv6.mask;
-		for (pos = 0; bits > 0; pos += 4, bits -= 32) {
-			v4 = *(uint32_t*)&v6->s6_addr[pos] ^ *(uint32_t*)&pattern->val.ipv6.addr.s6_addr[pos];
-			if (bits < 32)
-				v4 &= htonl((~0U) << (32-bits));
-			if (v4)
-				return PAT_NOMATCH;
+			bits = pattern->val.ipv6.mask;
+			for (pos = 0; bits > 0; pos += 4, bits -= 32) {
+				v4 = *(uint32_t*)&v6->s6_addr[pos] ^ *(uint32_t*)&pattern->val.ipv6.addr.s6_addr[pos];
+				if (bits < 32)
+					v4 &= htonl((~0U) << (32-bits));
+				if (v4)
+					continue;
+			}
+			return pattern;
 		}
-		return PAT_MATCH;
 	}
-	return PAT_NOMATCH;
+	return NULL;
 }
 
 /* NB: does nothing if <pat> is NULL */
@@ -1070,91 +1212,16 @@
  */
 struct pattern *pattern_exec_match(struct pattern_expr *expr, struct sample *smp, int fill)
 {
-	enum pat_match_res pat_res = PAT_NOMATCH;
-	struct pattern_list *pattern = NULL;
-	struct ebmb_node *node = NULL;
-	struct pattern_tree *elt = NULL;
-
-	if (expr->match == pat_match_nothing) {
-		if (smp->data.uint)
-			pat_res |= PAT_MATCH;
-		else
-			pat_res |= PAT_NOMATCH;
-	}
-	else if (!expr->match) {
-		/* just check for existence */
-		pat_res |= PAT_MATCH;
-	}
-	else {
-		if (!eb_is_empty(&expr->pattern_tree)) {
-			/* a tree is present, let's check what type it is */
-			if (expr->match == pat_match_str) {
-				if (sample_convert(smp, SMP_T_STR))
-					node = pat_lookup_str(smp, expr);
-			}
-			else if (expr->match == pat_match_ip) {
-				if (sample_convert(smp, SMP_T_IPV4))
-					node = pat_lookup_ip(smp, expr);
-			}
-			if (node) {
-				pat_res |= PAT_MATCH;
-				elt = ebmb_entry(node, struct pattern_tree, node);
-			}
-		}
-
-		/* call the match() function for all tests on this value */
-		if (pat_res != PAT_MATCH) {
-			list_for_each_entry(pattern, &expr->patterns, list) {
-				if (sample_convert(smp, pattern->pat.expect_type))
-					pat_res |= expr->match(smp, &pattern->pat);
-				if (pat_res == PAT_MATCH)
-					break;
-			}
-		}
-	}
-
-	if (pat_res == PAT_MATCH) {
-		static_pattern.flags = 0;
+	if (!expr->match) {
 		if (fill) {
-			/* fill with boolean */
-			if (expr->match == NULL ||
-			    expr->match == pat_match_nothing) {
-				static_pattern.smp = NULL;
-				static_pattern.type = SMP_T_BOOL;
-				static_pattern.val.i = 1;
-				return &static_pattern;
-			}
-
-			/* fill with ipv4 */
-			if (expr->match == pat_match_ip && elt) {
-				static_pattern.smp = elt->smp;;
-				static_pattern.flags |= PAT_F_TREE;
-				static_pattern.type = SMP_T_IPV4;
-				memcpy(&static_pattern.val.ipv4.addr, &elt->node.key, 4);
-				if (!cidr2dotted(elt->node.node.pfx, &static_pattern.val.ipv4.mask))
-					return NULL;
-				return &static_pattern;
-			}
-
-			/* fill with string */
-			if (expr->match == pat_match_str && elt) {
-				static_pattern.smp = elt->smp;;
-				static_pattern.flags |= PAT_F_TREE;
-				static_pattern.type = SMP_T_STR;
-				static_pattern.ptr.str = (char *)elt->node.key;
-				return &static_pattern;
-			}
-
-			/* return the pattern */
-			return &pattern->pat;
+			static_pattern.smp = NULL;
+			static_pattern.flags = 0;
+			static_pattern.type = SMP_T_UINT;
+			static_pattern.val.i = 1;
 		}
-
-		/* Return uninitialized pattern. The content must not be used by the caller */
 		return &static_pattern;
 	}
-
-	/* No match */
-	return NULL;
+	return expr->match(smp, expr, fill);
 }
 
 /* This function browse the pattern expr <expr> to lookup the key <key>. On
diff --git a/src/proto_http.c b/src/proto_http.c
index dcf91ed..0ae2e87 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -9046,27 +9046,33 @@
 }
 
 /* See above how the method is stored in the global pattern */
-static enum pat_match_res pat_match_meth(struct sample *smp, struct pattern *pattern)
+static struct pattern *pat_match_meth(struct sample *smp, struct pattern_expr *expr, int fill)
 {
 	int icase;
+	struct pattern_list *lst;
+	struct pattern *pattern;
 
-	/* well-known method */
-	if (pattern->val.i != HTTP_METH_OTHER) {
-		if (smp->data.meth.meth == pattern->val.i)
-			return PAT_MATCH;
-		else
-			return PAT_NOMATCH;
-	}
+	list_for_each_entry(lst, &expr->patterns, list) {
+		pattern = &lst->pat;
 
-	/* Other method, we must compare the strings */
-	if (pattern->len != smp->data.meth.str.len)
-		return PAT_NOMATCH;
+		/* well-known method */
+		if (pattern->val.i != HTTP_METH_OTHER) {
+			if (smp->data.meth.meth == pattern->val.i)
+				return pattern;
+			else
+				continue;
+		}
 
-	icase = pattern->flags & PAT_F_IGNORE_CASE;
-	if ((icase && strncasecmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0) ||
-	    (!icase && strncmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0))
-		return PAT_MATCH;
-	return PAT_NOMATCH;
+		/* Other method, we must compare the strings */
+		if (pattern->len != smp->data.meth.str.len)
+			continue;
+
+		icase = pattern->flags & PAT_F_IGNORE_CASE;
+		if ((icase && strncasecmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0) ||
+		    (!icase && strncmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0))
+			return pattern;
+	}
+	return NULL;
 }
 
 static int