MEDIUM: acl: move the ->parse, ->match and ->smp fields to acl_expr
We'll need each ACL expression to be able to support its own parse and
match methods, so we're moving these fields to the ACL expression.
diff --git a/include/types/acl.h b/include/types/acl.h
index 0da8d6c..65644cc 100644
--- a/include/types/acl.h
+++ b/include/types/acl.h
@@ -165,19 +165,21 @@
/*
* Description of an ACL expression.
- * It contains a subject and a set of patterns to test against it.
- * - the function get() is called to retrieve the subject from the
- * current session or transaction and build a test.
- * - the function test() is called to evaluate the test based on the
- * available patterns and return ACL_PAT_*
- * Both of those functions are available through the keyword.
+ * The expression is part of a list. It contains pointers to the keyword, the
+ * parse and match functions which default to the keyword's, the sample fetch
+ * descriptor which also defaults to the keyword's, and a list or tree of
+ * patterns to test against. The structure is organized so that the hot parts
+ * are grouped together in order to optimize caching.
*/
struct acl_expr {
- struct list list; /* chaining */
- struct acl_keyword *kw; /* back-reference to the keyword */
- struct arg *args; /* optional argument list (eg: header or cookie name) */
- struct list patterns; /* list of acl_patterns */
+ int (*parse)(const char **text, struct acl_pattern *pattern, int *opaque, char **err);
+ int (*match)(struct sample *smp, struct acl_pattern *pattern);
+ struct arg *args; /* optional fetch argument list (eg: header or cookie name) */
+ struct sample_fetch *smp; /* the sample fetch we depend on */
+ struct list patterns; /* list of acl_patterns */
struct eb_root pattern_tree; /* may be used for lookup in large datasets */
+ struct list list; /* chaining */
+ struct acl_keyword *kw; /* back-reference to the keyword */
};
/* The acl will be linked to from the proxy where it is declared */
diff --git a/src/acl.c b/src/acl.c
index a4215fc..3c0d78f 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -878,10 +878,9 @@
/* Reads patterns from a file. If <err_msg> is non-NULL, an error message will
* be returned there on errors and the caller will have to free it.
*/
-static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
- struct acl_expr *expr,
- const char *filename, int patflags,
- char **err)
+static int acl_read_patterns_from_file(struct acl_expr *expr,
+ const char *filename, int patflags,
+ char **err)
{
FILE *file;
char *c;
@@ -938,7 +937,7 @@
pattern->flags = patflags;
if (!(pattern->flags & ACL_PAT_F_IGNORE_CASE) &&
- (aclkw->match == acl_match_str || aclkw->match == acl_match_ip)) {
+ (expr->match == acl_match_str || expr->match == acl_match_ip)) {
/* we pre-set the data pointer to the tree's head so that functions
* which are able to insert in a tree know where to do that.
*/
@@ -947,7 +946,7 @@
}
pattern->type = SMP_TYPES; /* unspecified type by default */
- if (!aclkw->parse(args, pattern, &opaque, err))
+ if (!expr->parse(args, pattern, &opaque, err))
goto out_free_pattern;
/* if the parser did not feed the tree, let's chain the pattern to the list */
@@ -998,10 +997,13 @@
aclkw->use_cnt++;
LIST_INIT(&expr->patterns);
expr->pattern_tree = EB_ROOT_UNIQUE;
+ expr->parse = aclkw->parse;
+ expr->match = aclkw->match;
expr->args = empty_arg_list;
+ expr->smp = aclkw->smp;
arg = strchr(args[0], '(');
- if (aclkw->smp->arg_mask) {
+ if (expr->smp->arg_mask) {
int nbargs = 0;
char *end;
@@ -1010,7 +1012,7 @@
arg++;
end = strchr(arg, ')');
if (!end) {
- memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", aclkw->kw);
+ memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", expr->kw->kw);
goto out_free_expr;
}
@@ -1019,34 +1021,34 @@
* An error is also reported if some mandatory arguments are
* missing.
*/
- nbargs = make_arg_list(arg, end - arg, aclkw->smp->arg_mask, &expr->args,
+ nbargs = make_arg_list(arg, end - arg, expr->smp->arg_mask, &expr->args,
err, NULL, NULL);
if (nbargs < 0) {
/* note that make_arg_list will have set <err> here */
- memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
+ memprintf(err, "in argument to '%s', %s", expr->kw->kw, *err);
goto out_free_expr;
}
if (!expr->args)
expr->args = empty_arg_list;
- if (aclkw->smp->val_args && !aclkw->smp->val_args(expr->args, err)) {
+ if (expr->smp->val_args && !expr->smp->val_args(expr->args, err)) {
/* invalid keyword argument, error must have been
* set by val_args().
*/
- memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
+ memprintf(err, "in argument to '%s', %s", expr->kw->kw, *err);
goto out_free_expr;
}
}
- else if (ARGM(aclkw->smp->arg_mask) == 1) {
- int type = (aclkw->smp->arg_mask >> 4) & 15;
+ else if (ARGM(expr->smp->arg_mask) == 1) {
+ int type = (expr->smp->arg_mask >> 4) & 15;
/* If a proxy is noted as a mandatory argument, we'll fake
* an empty one so that acl_find_targets() resolves it as
* the current one later.
*/
if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) {
- memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->smp->arg_mask));
+ memprintf(err, "ACL keyword '%s' expects %d arguments", expr->kw->kw, ARGM(expr->smp->arg_mask));
goto out_free_expr;
}
@@ -1061,16 +1063,16 @@
expr->args[0].data.str.len = 0;
expr->args[1].type = ARGT_STOP;
}
- else if (ARGM(aclkw->smp->arg_mask)) {
+ else if (ARGM(expr->smp->arg_mask)) {
/* there were some mandatory arguments */
- memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->smp->arg_mask));
+ memprintf(err, "ACL keyword '%s' expects %d arguments", expr->kw->kw, ARGM(expr->smp->arg_mask));
goto out_free_expr;
}
}
else {
if (arg) {
/* no argument expected */
- memprintf(err, "ACL keyword '%s' takes no argument", aclkw->kw);
+ memprintf(err, "ACL keyword '%s' takes no argument", expr->kw->kw);
goto out_free_expr;
}
}
@@ -1087,7 +1089,7 @@
if ((*args)[1] == 'i')
patflags |= ACL_PAT_F_IGNORE_CASE;
else if ((*args)[1] == 'f') {
- if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
+ if (!acl_read_patterns_from_file(expr, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
goto out_free_expr;
args++;
}
@@ -1112,7 +1114,7 @@
pattern->flags = patflags;
pattern->type = SMP_TYPES; /* unspecified type */
- ret = aclkw->parse(args, pattern, &opaque, err);
+ ret = expr->parse(args, pattern, &opaque, err);
if (!ret)
goto out_free_pattern;
@@ -1213,8 +1215,8 @@
* and where it may be used. If an ACL relies on multiple matches, it is
* OK if at least one of them may match in the context where it is used.
*/
- cur_acl->use |= acl_expr->kw->smp->use;
- cur_acl->val |= acl_expr->kw->smp->val;
+ cur_acl->use |= acl_expr->smp->use;
+ cur_acl->val |= acl_expr->smp->val;
LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
return cur_acl;
@@ -1299,8 +1301,8 @@
}
cur_acl->name = name;
- cur_acl->use |= acl_expr->kw->smp->use;
- cur_acl->val |= acl_expr->kw->smp->val;
+ cur_acl->use |= acl_expr->smp->use;
+ cur_acl->val |= acl_expr->smp->val;
LIST_INIT(&cur_acl->expr);
LIST_ADDQ(&cur_acl->expr, &acl_expr->list);
if (known_acl)
@@ -1585,7 +1587,7 @@
/* we need to reset context and flags */
memset(&smp, 0, sizeof(smp));
fetch_next:
- if (!expr->kw->smp->process(px, l4, l7, opt, expr->args, &smp)) {
+ if (!expr->smp->process(px, l4, l7, opt, expr->args, &smp)) {
/* maybe we could not fetch because of missing data */
if (smp.flags & SMP_F_MAY_CHANGE && !(opt & SMP_OPT_FINAL))
acl_res |= ACL_PAT_MISS;
@@ -1601,9 +1603,9 @@
else {
if (!eb_is_empty(&expr->pattern_tree)) {
/* a tree is present, let's check what type it is */
- if (expr->kw->match == acl_match_str)
+ if (expr->match == acl_match_str)
acl_res |= acl_lookup_str(&smp, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
- else if (expr->kw->match == acl_match_ip)
+ else if (expr->match == acl_match_ip)
acl_res |= acl_lookup_ip(&smp, expr) ? ACL_PAT_PASS : ACL_PAT_FAIL;
}
@@ -1611,7 +1613,7 @@
list_for_each_entry(pattern, &expr->patterns, list) {
if (acl_res == ACL_PAT_PASS)
break;
- acl_res |= expr->kw->match(&smp, pattern);
+ acl_res |= expr->match(&smp, pattern);
}
}
/*
@@ -1698,7 +1700,7 @@
list_for_each_entry(suite, &cond->suites, list) {
list_for_each_entry(term, &suite->terms, list) {
list_for_each_entry(expr, &term->acl->expr, list) {
- if (!(expr->kw->smp->val & where)) {
+ if (!(expr->smp->val & where)) {
if (acl)
*acl = term->acl;
if (kw)