From: Thierry FOURNIER Date: Fri, 17 Jan 2014 14:25:13 +0000 (+0100) Subject: MEDIUM: pattern: The function pattern_exec_match() returns "struct pattern" if the... X-Git-Tag: v1.5-dev23~118 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1794fdf37eb4f5d463e866c5aee5233f38157988;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/include/proto/pattern.h b/include/proto/pattern.h index c49f53d583..1daf3bbb4d 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 78c3f307d5..37fd8f4b68 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 afd333cf8c..01f5d37e26 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, "); - - /* 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] && diff --git a/src/map.c b/src/map.c index e48408aa34..c244bb7d31 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 d41e086331..aa6a3d43bc 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