MEDIUM: pattern: The function pattern_exec_match() returns "struct pattern" if the patten match.
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.
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index c49f53d..1daf3bb 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -54,11 +54,12 @@
}
/* 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);
/*
*
diff --git a/src/acl.c b/src/acl.c
index 78c3f30..37fd8f4 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -39,9 +39,12 @@
};
/* 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 @@
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.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index afd333c..01f5d37 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -4827,10 +4827,10 @@
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 @@
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 @@
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 @@
/* 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, ");
+ /* 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 source */
+ if (pat->flags & PAT_F_FROM_FILE)
+ chunk_appendf(&trash, "from-file, ");
- /* display match expresion */
- if (elt) {
- if (appctx->ctx.map.desc->pat->match == pat_match_str) {
- chunk_appendf(&trash, "match=\"%s\", ", elt->node.key);
+ /* 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);
+ }
+ 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] &&
diff --git a/src/map.c b/src/map.c
index e48408a..c244bb7 100644
--- a/src/map.c
+++ b/src/map.c
@@ -457,24 +457,38 @@
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;
}
diff --git a/src/pattern.c b/src/pattern.c
index d41e086..aa6a3d4 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -105,6 +105,9 @@
[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 @@
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 @@
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;
+ }
}
}
+ 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;
+ }
+
- return pat_res;
+ /* No match */
+ return NULL;
}
/* This function browse the pattern expr <expr> to lookup the key <key>. On