]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: pattern: The match function browse itself the list or the tree.
authorThierry FOURNIER <tfournier@exceliance.fr>
Mon, 16 Dec 2013 13:22:13 +0000 (14:22 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 17 Mar 2014 17:06:07 +0000 (18:06 +0100)
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".

include/proto/auth.h
include/proto/pattern.h
include/types/acl.h
include/types/pattern.h
src/auth.c
src/pattern.c
src/proto_http.c

index a9606134b542457f0a9a9c4f2329cdd7a6bc0a9e..eea5df54c919ecb73ac94c64a14153666100ae0b 100644 (file)
@@ -22,7 +22,7 @@ struct userlist *auth_find_userlist(char *name);
 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);
 
index 1daf3bbb4d135010e79e787c1fefd98f5af696fc..e2801a0b6a128d7f10fbe86715868a837c96a814 100644 (file)
@@ -114,48 +114,48 @@ int pat_parse_reg(const char *text, struct pattern *pattern, char **err);
 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);
index 722bfe6744bd334e062ef6bcee5d5fddd4124ad1..49c03cfe06a3a33864a3c09389fd409d61189cd0 100644 (file)
@@ -94,7 +94,7 @@ struct acl_keyword {
        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 */
 };
index 665925c1840ce80cd55bf6ef11e8981eb9f56ad2..7a281716c924e0c54a6f4e9093802a55bc0a8847 100644 (file)
@@ -157,7 +157,7 @@ struct pattern_list {
 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 @@ struct pattern_expr {
 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 */
index 961c2886672e8071157f7d4d119516dd396f1dc8..ad606afb8c128a85e4d173c08d2d6e28a3912630 100644 (file)
@@ -256,12 +256,14 @@ check_user(struct userlist *ul, const char *user, const char *pass)
                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 @@ pat_match_auth(struct sample *smp, struct pattern *pattern)
                        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;
 }
index aa6a3d43bcc31aa142b89f3ac14240df63dd8ce4..d6ae8d9f7f5caa123ef70cf185d74a1730220ff2 100644 (file)
@@ -72,7 +72,7 @@ int (*pat_index_fcts[PAT_MATCH_NUM])(struct pattern_expr *, struct pattern *, ch
        [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 @@ static struct pattern static_pattern;
  *
  */
 
-/* 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 @@ int pat_parse_ip(const char *text, struct pattern *pattern, char **err)
  */
 
 /* 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;
+
+       /* convert input to string */
+       if (!sample_convert(smp, SMP_T_STR))
+               return NULL;
+
+       /* 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;
+               }
+       }
 
-       if (pattern->len != smp->data.str.len)
-               return PAT_NOMATCH;
+       /* look in the list */
+       list_for_each_entry(lst, &expr->patterns, list) {
+               pattern = &lst->pat;
 
-       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;
+               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 @@ static int match_word(struct sample *smp, struct pattern *pattern, unsigned int
  * 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 @@ int pattern_read_from_file(struct pattern_expr *expr,
  */
 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
index dcf91ede462d85a8947fbfb0e6bc3ec17c2a681a..0ae2e876140ede442e55e09a19677834b573b628 100644 (file)
@@ -9046,27 +9046,33 @@ smp_fetch_meth(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
 }
 
 /* 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