mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-12-24 11:01:00 +01:00
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:
parent
1432a0c5db
commit
1794fdf37e
@ -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);
|
||||
|
||||
/*
|
||||
*
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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] &&
|
||||
|
||||
34
src/map.c
34
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user