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.
This commit is contained in:
Thierry FOURNIER 2014-01-17 15:25:13 +01:00 committed by Willy Tarreau
parent 1432a0c5db
commit 1794fdf37e
5 changed files with 141 additions and 74 deletions

View 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);
/*
*

View File

@ -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.

View 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, ");
/* 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] &&

View File

@ -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;
}

View 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