]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: pattern: The function pattern_exec_match() returns "struct pattern" if the...
authorThierry FOURNIER <tfournier@exceliance.fr>
Fri, 17 Jan 2014 14:25:13 +0000 (15:25 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 17 Mar 2014 17:06:07 +0000 (18:06 +0100)
Before this commit, the pattern_exec_match() function returns the
associate sample, the associate struct pattern or the associate struct
pattern_tree. This is complex to use, because we can check the type of
information returned.

Now the function return always a "struct pattern". If <fill> is not set,
only the value of the pointer can be used as boolean (NULL or other). If
<fill> is set, you can use the <smp> pointer and the pattern
information.

If information must be duplicated, it is stored in trash buffer.
Otherwise, the pattern can point on existing strings.

include/proto/pattern.h
src/acl.c
src/dumpstats.c
src/map.c
src/pattern.c

index c49f53d5834b42e9b333577c552558678093ce3d..1daf3bbb4d135010e79e787c1fefd98f5af696fc 100644 (file)
@@ -54,11 +54,12 @@ static inline int pat_find_match_name(const char *name)
 }
 
 /* This function executes a pattern match on a sample. It applies pattern <expr>
- * to sample <smp>. If <sample> is not NULL, a pointer to an optional sample
- * associated to the matching patterned will be put there. The function returns
- * PAT_MATCH or PAT_NOMATCH.
+ * to sample <smp>. The function returns NULL if the sample dont match. It returns
+ * non-null if the sample match. If <fill> is true and the sample match, the
+ * function returns the matched pattern. In many cases, this pattern can be a
+ * static buffer.
  */
-enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *smp, struct sample_storage **sample, struct pattern **pat, struct pattern_tree **elt);
+struct pattern *pattern_exec_match(struct pattern_expr *expr, struct sample *smp, int fill);
 
 /*
  *
index 78c3f307d5e0a893455e69585381ebbea7695c56..37fd8f4b6898dce3c8dab730117025427a52ac18 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -39,9 +39,12 @@ static struct acl_kw_list acl_keywords = {
 };
 
 /* input values are 0 or 3, output is the same */
-static inline enum acl_test_res pat2acl(enum pat_match_res res)
+static inline enum acl_test_res pat2acl(struct pattern *pat)
 {
-       return (enum acl_test_res)res;
+       if (pat)
+               return ACL_TEST_PASS;
+       else
+               return ACL_TEST_FAIL;
 }
 
 /*
@@ -1053,7 +1056,7 @@ enum acl_test_res acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct
                                        continue;
                                }
 
-                               acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, NULL, NULL, NULL));
+                               acl_res |= pat2acl(pattern_exec_match(&expr->pat, &smp, 0));
                                /*
                                 * OK now acl_res holds the result of this expression
                                 * as one of ACL_TEST_FAIL, ACL_TEST_MISS or ACL_TEST_PASS.
index afd333cf8ceae21587c9df2ed169d18b2bb47f7f..01f5d37e26ab8856414e6d5f812f084a8c41113c 100644 (file)
@@ -4827,10 +4827,10 @@ static int stats_map_lookup(struct stream_interface *si)
        struct sample_storage *smp;
        struct sample sample;
        struct pattern *pat;
-       struct pattern_tree *elt;
-       enum pat_match_res res;
-       struct sockaddr_in addr;
-       char addr_str[INET_ADDRSTRLEN];
+       struct sockaddr_storage addr;
+       char s_addr[INET_ADDRSTRLEN];
+       char s_mask[INET_ADDRSTRLEN];
+       char s_addr6[INET6_ADDRSTRLEN];
 
        switch (appctx->st2) {
        case STAT_ST_INIT:
@@ -4850,9 +4850,7 @@ static int stats_map_lookup(struct stream_interface *si)
                        sample.flags |= SMP_F_CONST;
                        sample.data.str.len = appctx->ctx.map.chunk.len;
                        sample.data.str.str = appctx->ctx.map.chunk.str;
-                       pat = NULL;
-                       elt = NULL;
-                       res = pattern_exec_match(appctx->ctx.map.desc->pat, &sample, &smp, &pat, &elt);
+                       pat = pattern_exec_match(appctx->ctx.map.desc->pat, &sample, 1);
 
                        /* build return message: set type of match */
                        /**/ if (appctx->ctx.map.desc->pat->match == NULL)
@@ -4885,9 +4883,8 @@ static int stats_map_lookup(struct stream_interface *si)
                                chunk_appendf(&trash, "unknown(%p), ", appctx->ctx.map.desc->pat->match);
 
                        /* Display no match, and set default value */
-                       if (res == PAT_NOMATCH) {
+                       if (!pat) {
                                chunk_appendf(&trash, "no-match, ");
-                               smp = appctx->ctx.map.desc->def;
                        }
 
                        /* Display match and match info */
@@ -4895,46 +4892,61 @@ static int stats_map_lookup(struct stream_interface *si)
                                /* display match */
                                chunk_appendf(&trash, "match, ");
 
-                               /* display search mode */
-                               if (elt)
+                               /* display index mode */
+                               if (pat->flags & PAT_F_TREE)
                                        chunk_appendf(&trash, "tree, ");
                                else
                                        chunk_appendf(&trash, "list, ");
 
-                               /* display search options */
-                               if (pat) {
-                                       /* case sensitive */
-                                       if (pat->flags & PAT_F_IGNORE_CASE)
-                                               chunk_appendf(&trash, "case-insensitive, ");
-                                       else
-                                               chunk_appendf(&trash, "case-sensitive, ");
-
-                                       /* display source */
-                                       if (pat->flags & PAT_F_FROM_FILE)
-                                               chunk_appendf(&trash, "from-file, ");
+                               /* case sensitive */
+                               if (pat->flags & PAT_F_IGNORE_CASE)
+                                       chunk_appendf(&trash, "case-insensitive, ");
+                               else
+                                       chunk_appendf(&trash, "case-sensitive, ");
+
+                               /* display source */
+                               if (pat->flags & PAT_F_FROM_FILE)
+                                       chunk_appendf(&trash, "from-file, ");
+
+                               /* display string */
+                               if (appctx->ctx.map.desc->pat->match == pat_match_str ||
+                                   appctx->ctx.map.desc->pat->match == pat_match_str ||
+                                   appctx->ctx.map.desc->pat->match == pat_match_beg ||
+                                   appctx->ctx.map.desc->pat->match == pat_match_sub ||
+                                   appctx->ctx.map.desc->pat->match == pat_match_dir ||
+                                   appctx->ctx.map.desc->pat->match == pat_match_dom ||
+                                   appctx->ctx.map.desc->pat->match == pat_match_end) {
+                                       chunk_appendf(&trash, "match=\"%s\", ", pat->ptr.str);
                                }
-
-                               /* display match expresion */
-                               if (elt) {
-                                       if (appctx->ctx.map.desc->pat->match == pat_match_str) {
-                                               chunk_appendf(&trash, "match=\"%s\", ", elt->node.key);
+                               else if (appctx->ctx.map.desc->pat->match == pat_match_ip) {
+                                       /* display IPv4/v6 */
+                                       if (pat->type == SMP_T_IPV4) {
+                                               ((struct sockaddr_in *)&addr)->sin_family = AF_INET;
+                                               memcpy(&((struct sockaddr_in *)&addr)->sin_addr, &pat->val.ipv4.addr,
+                                                      sizeof(pat->val.ipv4.addr));
+                                               if (addr_to_str(&addr, s_addr, INET_ADDRSTRLEN)) {
+                                                       memcpy(&((struct sockaddr_in *)&addr)->sin_addr, &pat->val.ipv4.mask,
+                                                              sizeof(pat->val.ipv4.mask));
+                                                       if (addr_to_str(&addr, s_mask, INET_ADDRSTRLEN))
+                                                               chunk_appendf(&trash, "match=\"%s/%s\", ", s_addr, s_mask);
+                                               }
                                        }
-                                       /* only IPv4 */
-                                       else if (appctx->ctx.map.desc->pat->match == pat_match_ip) {
-                                               /* convert ip */
-                                               memcpy(&addr.sin_addr, elt->node.key, 4);
-                                               addr.sin_family = AF_INET;
-                                               if (addr_to_str((struct sockaddr_storage *)&addr, addr_str, INET_ADDRSTRLEN))
-                                                       chunk_appendf(&trash, "match=\"%s/%d\", ", addr_str, elt->node.node.pfx);
+                                       else if (pat->type == SMP_T_IPV6) {
+                                               ((struct sockaddr_in6 *)&addr)->sin6_family = AF_INET6;
+                                               memcpy(&((struct sockaddr_in6 *)&addr)->sin6_addr, &pat->val.ipv6.addr,
+                                                      sizeof(pat->val.ipv6.addr));
+                                               if (addr_to_str(&addr, s_addr6, INET6_ADDRSTRLEN))
+                                                       chunk_appendf(&trash, "match=\"%s/%d\", ", s_addr6, pat->val.ipv6.mask);
                                        }
                                }
                        }
 
                        /* display return value */
-                       if (!smp) {
+                       if (!pat || !pat->smp) {
                                chunk_appendf(&trash, "return=nothing\n");
                        }
                        else {
+                               smp = pat->smp;
                                memcpy(&sample.data, &smp->data, sizeof(sample.data));
                                sample.type = smp->type;
                                if (sample_casts[sample.type][SMP_T_STR] &&
index e48408aa34d4bd5b5c16b9f5db3bfb6979973715..c244bb7d315569dc8dbf16d16b7679b9b757e196 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -457,24 +457,38 @@ static int sample_load_map(struct arg *arg, struct sample_conv *conv, char **err
 static int sample_conv_map(const struct arg *arg_p, struct sample *smp)
 {
        struct map_descriptor *desc;
-       struct sample_storage *sample;
-       enum pat_match_res ret;
+       struct pattern *pat;
 
        /* get config */
        desc = arg_p[0].data.map;
 
        /* Execute the match function. */
-       ret = pattern_exec_match(desc->pat, smp, &sample, NULL, NULL);
-       if (ret != PAT_MATCH) {
-               if (!desc->def)
-                       return 0;
-               sample = desc->def;
+       pat = pattern_exec_match(desc->pat, smp, 1);
+
+       /* Match case. */
+       if (pat) {
+               /* Copy sample. */
+               if (pat->smp) {
+                       smp->type = pat->smp->type;
+                       smp->flags |= SMP_F_CONST;
+                       memcpy(&smp->data, &pat->smp->data, sizeof(smp->data));
+                       return 1;
+               }
+
+               /* Return just int sample containing 1. */
+               smp->type = SMP_T_UINT;
+               smp->data.uint= 1;
+               return 1;
        }
 
-       /* copy new data */
-       smp->type = sample->type;
+       /* If no default value avalaible, the converter fails. */
+       if (!desc->def)
+               return 0;
+
+       /* Return the default value. */
+       smp->type = desc->def->type;
        smp->flags |= SMP_F_CONST;
-       memcpy(&smp->data, &sample->data, sizeof(smp->data));
+       memcpy(&smp->data, &desc->def->data, sizeof(smp->data));
        return 1;
 }
 
index d41e0863315a26aa1a07cef59feb30177137f7a8..aa6a3d43bcc31aa142b89f3ac14240df63dd8ce4 100644 (file)
@@ -105,6 +105,9 @@ int pat_match_types[PAT_MATCH_NUM] = {
        [PAT_MATCH_REG]   = SMP_T_STR,
 };
 
+/* this struct is used to return information */
+static struct pattern static_pattern;
+
 /*
  *
  * The following functions are not exported and are used by internals process
@@ -1059,19 +1062,18 @@ int pattern_read_from_file(struct pattern_expr *expr,
        return ret;
 }
 
-/* This function matches a sample <smp> against a set of patterns presented in
- * pattern expression <expr>. Upon success, if <sample> is not NULL, it is fed
- * with the pointer associated with the matching pattern. This function returns
- * PAT_NOMATCH or PAT_MATCH.
+/* This function executes a pattern match on a sample. It applies pattern <expr>
+ * to sample <smp>. The function returns NULL if the sample dont match. It returns
+ * non-null if the sample match. If <fill> is true and the sample match, the
+ * function returns the matched pattern. In many cases, this pattern can be a
+ * static buffer.
  */
-enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *smp,
-                                      struct sample_storage **sample,
-                                      struct pattern **pat, struct pattern_tree **idx_elt)
+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;
+       struct pattern_list *pattern = NULL;
        struct ebmb_node *node = NULL;
-       struct pattern_tree *elt;
+       struct pattern_tree *elt = NULL;
 
        if (expr->match == pat_match_nothing) {
                if (smp->data.uint)
@@ -1097,27 +1099,62 @@ enum pat_match_res pattern_exec_match(struct pattern_expr *expr, struct sample *
                        if (node) {
                                pat_res |= PAT_MATCH;
                                elt = ebmb_entry(node, struct pattern_tree, node);
-                               if (sample)
-                                       *sample = elt->smp;
-                               if (idx_elt)
-                                       *idx_elt = elt;
                        }
                }
 
                /* call the match() function for all tests on this value */
-               list_for_each_entry(pattern, &expr->patterns, list) {
-                       if (pat_res == PAT_MATCH)
-                               break;
-                       if (sample_convert(smp, pattern->pat.expect_type))
-                               pat_res |= expr->match(smp, &pattern->pat);
-                       if (sample)
-                               *sample = pattern->pat.smp;
-                       if (pat)
-                               *pat = &pattern->pat;
+               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;
+                       }
                }
        }
 
-       return pat_res;
+       if (pat_res == PAT_MATCH) {
+               static_pattern.flags = 0;
+               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;
+               }
+
+               /* Return uninitialized pattern. The content must not be used by the caller */
+               return &static_pattern;
+       }
+
+       /* No match */
+       return NULL;
 }
 
 /* This function browse the pattern expr <expr> to lookup the key <key>. On