From 1794fdf37eb4f5d463e866c5aee5233f38157988 Mon Sep 17 00:00:00 2001 From: Thierry FOURNIER Date: Fri, 17 Jan 2014 15:25:13 +0100 Subject: [PATCH] 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 is not set, only the value of the pointer can be used as boolean (NULL or other). If is set, you can use the 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 | 9 +++-- src/acl.c | 9 +++-- src/dumpstats.c | 80 ++++++++++++++++++++++----------------- src/map.c | 34 ++++++++++++----- src/pattern.c | 83 +++++++++++++++++++++++++++++------------ 5 files changed, 141 insertions(+), 74 deletions(-) diff --git a/include/proto/pattern.h b/include/proto/pattern.h index c49f53d58..1daf3bbb4 100644 --- a/include/proto/pattern.h +++ b/include/proto/pattern.h @@ -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 - * to sample . If 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 . The function returns NULL if the sample dont match. It returns + * non-null if the sample match. If 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 78c3f307d..37fd8f4b6 100644 --- 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. diff --git a/src/dumpstats.c b/src/dumpstats.c index afd333cf8..01f5d37e2 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -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, "); + /* 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 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] && diff --git a/src/map.c b/src/map.c index e48408aa3..c244bb7d3 100644 --- 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; } diff --git a/src/pattern.c b/src/pattern.c index d41e08633..aa6a3d43b 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -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 against a set of patterns presented in - * pattern expression . Upon success, if 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 + * to sample . The function returns NULL if the sample dont match. It returns + * non-null if the sample match. If 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 to lookup the key . On