]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: pattern: create pattern expression
authorThierry FOURNIER <tfournier@exceliance.fr>
Thu, 28 Nov 2013 10:41:23 +0000 (11:41 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 2 Dec 2013 22:31:33 +0000 (23:31 +0100)
This new structure contains the data needed for pattern matching. It's
the first step to the complete independance of the pattern matching.

include/proto/pattern.h
include/types/acl.h
include/types/pattern.h
src/acl.c
src/pattern.c

index 9898eb3e7e06fada352d0e985c4f67b53dde46ce..d085196fdf7b8ec30ebd5c3d8969a300731dc719 100644 (file)
  * fails, with <err> message filled. It returns -2 in "out of memory"
  * error case.
  */
-int acl_register_pattern(struct acl_expr *expr, char *text, struct sample_storage *smp, struct acl_pattern **pattern, int patflags, char **err);
+int acl_register_pattern(struct pattern_expr *expr, char *text, struct sample_storage *smp, struct acl_pattern **pattern, int patflags, char **err);
 
 /* 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
  * ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
  */
-inline int acl_exec_match(struct acl_expr *expr, struct sample *smp, struct sample_storage **sample);
+inline int acl_exec_match(struct pattern_expr *expr, struct sample *smp, struct sample_storage **sample);
 
 /*
  *
@@ -128,9 +128,9 @@ int acl_match_ip(struct sample *smp, struct acl_pattern *pattern);
  */
 int acl_match_reg(struct sample *smp, struct acl_pattern *pattern);
 
-int acl_read_patterns_from_file(struct acl_expr *expr, const char *filename, int patflags, char **err);
+int acl_read_patterns_from_file(struct pattern_expr *expr, const char *filename, int patflags, char **err);
 void free_pattern(struct acl_pattern *pat);
-void free_pattern_list(struct list *head);
-void free_pattern_tree(struct eb_root *root);
+void prune_pattern_expr(struct pattern_expr *expr);
+void init_pattern_expr(struct pattern_expr *expr);
 
 #endif
index e479f9bc62abcffd2ef04426ef2698a329d1c6e7..50a89f3506b45c2bf59dca9f2932644db3a90f8c 100644 (file)
@@ -105,17 +105,13 @@ struct acl_kw_list {
 /*
  * Description of an ACL expression.
  * 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.
+ * sample fetch descriptor which defaults to the keyword's, and the associated
+ * pattern matching. The structure is organized so that the hot parts are
+ * grouped together in order to optimize caching.
  */
 struct acl_expr {
-       int (*parse)(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
-       int (*match)(struct sample *smp, struct acl_pattern *pattern);
        struct sample_expr *smp;      /* the sample expression we depend on */
-       struct list patterns;         /* list of acl_patterns */
-       struct eb_root pattern_tree;  /* may be used for lookup in large datasets */
+       struct pattern_expr pat;      /* the pattern matching expression */
        struct list list;             /* chaining */
        const char *kw;               /* points to the ACL kw's name or fetch's name (must not free) */
 };
index 68ed4621b4370e866a587aaad042439f4ab02a87..2023b1aa412de32717d13626825c798cbf7e6280 100644 (file)
@@ -121,6 +121,18 @@ struct acl_pattern {
 
 };
 
+/* Description of a pattern expression.
+ * It contains pointers to the parse and match functions, 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 pattern_expr {
+       int (*parse)(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
+       int (*match)(struct sample *smp, struct acl_pattern *pattern);
+       struct list patterns;         /* list of acl_patterns */
+       struct eb_root pattern_tree;  /* may be used for lookup in large datasets */
+};
+
 extern char *acl_match_names[ACL_MATCH_NUM];
 extern int (*acl_parse_fcts[ACL_MATCH_NUM])(const char **, struct acl_pattern *, struct sample_storage *, int *, char **);
 extern int (*acl_match_fcts[ACL_MATCH_NUM])(struct sample *, struct acl_pattern *);
index 1bb3e9f807004fa8979aa6eceaaad297b3feeff0..1e0daa3eb2736575a707edf2e949b64f812be666 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -107,9 +107,7 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
 {
        struct arg *arg;
 
-       free_pattern_list(&expr->patterns);
-       free_pattern_tree(&expr->pattern_tree);
-       LIST_INIT(&expr->patterns);
+       prune_pattern_expr(&expr->pat);
 
        for (arg = expr->smp->arg_p; arg; arg++) {
                if (arg->type == ARGT_STOP)
@@ -171,30 +169,30 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
                goto out_return;
        }
 
+       init_pattern_expr(&expr->pat);
+
        expr->kw = aclkw ? aclkw->kw : smp->fetch->kw;
-       LIST_INIT(&expr->patterns);
-       expr->pattern_tree = EB_ROOT_UNIQUE;
-       expr->parse = aclkw ? aclkw->parse : NULL;
-       expr->match = aclkw ? aclkw->match : NULL;
+       expr->pat.parse = aclkw ? aclkw->parse : NULL;
+       expr->pat.match = aclkw ? aclkw->match : NULL;
        expr->smp = aclkw ? NULL : smp;
 
-       if (!expr->parse) {
+       if (!expr->pat.parse) {
                /* some types can be automatically converted */
 
                switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) {
                case SMP_T_BOOL:
-                       expr->parse = acl_parse_fcts[ACL_MATCH_BOOL];
-                       expr->match = acl_match_fcts[ACL_MATCH_BOOL];
+                       expr->pat.parse = acl_parse_fcts[ACL_MATCH_BOOL];
+                       expr->pat.match = acl_match_fcts[ACL_MATCH_BOOL];
                        break;
                case SMP_T_SINT:
                case SMP_T_UINT:
-                       expr->parse = acl_parse_fcts[ACL_MATCH_INT];
-                       expr->match = acl_match_fcts[ACL_MATCH_INT];
+                       expr->pat.parse = acl_parse_fcts[ACL_MATCH_INT];
+                       expr->pat.match = acl_match_fcts[ACL_MATCH_INT];
                        break;
                case SMP_T_IPV4:
                case SMP_T_IPV6:
-                       expr->parse = acl_parse_fcts[ACL_MATCH_IP];
-                       expr->match = acl_match_fcts[ACL_MATCH_IP];
+                       expr->pat.parse = acl_parse_fcts[ACL_MATCH_IP];
+                       expr->pat.match = acl_match_fcts[ACL_MATCH_IP];
                        break;
                }
        }
@@ -430,7 +428,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
 
        /* Additional check to protect against common mistakes */
        cur_type = smp_expr_output_type(expr->smp);
-       if (expr->parse && cur_type != SMP_T_BOOL && !*args[1]) {
+       if (expr->pat.parse && cur_type != SMP_T_BOOL && !*args[1]) {
                Warning("parsing acl keyword '%s' :\n"
                        "  no pattern to match against were provided, so this ACL will never match.\n"
                        "  If this is what you intended, please add '--' to get rid of this warning.\n"
@@ -453,19 +451,19 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
                if ((*args)[1] == 'i')
                        patflags |= ACL_PAT_F_IGNORE_CASE;
                else if ((*args)[1] == 'f') {
-                       if (!expr->parse) {
+                       if (!expr->pat.parse) {
                                memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
                                goto out_free_expr;
                        }
 
-                       if (!acl_read_patterns_from_file(expr, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
+                       if (!acl_read_patterns_from_file(&expr->pat, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
                                goto out_free_expr;
                        args++;
                }
                else if ((*args)[1] == 'm') {
                        int idx;
 
-                       if (!LIST_ISEMPTY(&expr->patterns) || !eb_is_empty(&expr->pattern_tree)) {
+                       if (!LIST_ISEMPTY(&expr->pat.patterns) || !eb_is_empty(&expr->pat.pattern_tree)) {
                                memprintf(err, "'-m' must only be specified before patterns and files in parsing ACL expression");
                                goto out_free_expr;
                        }
@@ -492,8 +490,8 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
                              cur_type == SMP_T_BIN ||
                              cur_type == SMP_T_CSTR ||
                              cur_type == SMP_T_CBIN))) {
-                               expr->parse = acl_parse_fcts[idx];
-                               expr->match = acl_match_fcts[idx];
+                               expr->pat.parse = acl_parse_fcts[idx];
+                               expr->pat.match = acl_match_fcts[idx];
                        }
                        else {
                                memprintf(err, "matching method '%s' cannot be used with fetch keyword '%s'", args[1], expr->kw);
@@ -510,7 +508,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
                args++;
        }
 
-       if (!expr->parse) {
+       if (!expr->pat.parse) {
                memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
                goto out_free_expr;
        }
@@ -527,11 +525,11 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
                pattern->flags = patflags;
 
                pattern->type = SMP_TYPES; /* unspecified type */
-               ret = expr->parse(args, pattern, NULL, &opaque, err);
+               ret = expr->pat.parse(args, pattern, NULL, &opaque, err);
                if (!ret)
                        goto out_free_pattern;
 
-               LIST_ADDQ(&expr->patterns, &pattern->list);
+               LIST_ADDQ(&expr->pat.patterns, &pattern->list);
                args += ret;
        }
 
@@ -1012,7 +1010,7 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, v
                                        continue;
                                }
 
-                               acl_res |= acl_exec_match(expr, &smp, NULL);
+                               acl_res |= acl_exec_match(&expr->pat, &smp, NULL);
                                /*
                                 * OK now acl_res holds the result of this expression
                                 * as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
@@ -1136,14 +1134,14 @@ int acl_find_targets(struct proxy *p)
                                        continue;
                                }
 
-                               if (LIST_ISEMPTY(&expr->patterns)) {
+                               if (LIST_ISEMPTY(&expr->pat.patterns)) {
                                        Alert("proxy %s: acl %s %s(): no groups specified.\n",
                                                p->id, acl->name, expr->kw);
                                        cfgerr++;
                                        continue;
                                }
 
-                               list_for_each_entry(pattern, &expr->patterns, list) {
+                               list_for_each_entry(pattern, &expr->pat.patterns, list) {
                                        /* this keyword only has one argument */
                                        pattern->val.group_mask = auth_resolve_groups(expr->smp->arg_p->data.usr, pattern->ptr.str);
 
index 6bf7d1d6bab963467b80eb21180cb17ea3299fc2..7e9c69ef8f6b723832dba24915123202d3caf598 100644 (file)
@@ -117,7 +117,7 @@ int acl_match_bin(struct sample *smp, struct acl_pattern *pattern)
 /* Lookup a string in the expression's pattern tree. The node is returned if it
  * exists, otherwise NULL.
  */
-static void *acl_lookup_str(struct sample *smp, struct acl_expr *expr)
+static void *acl_lookup_str(struct sample *smp, struct pattern_expr *expr)
 {
        /* data are stored in a tree */
        struct ebmb_node *node;
@@ -389,7 +389,7 @@ int acl_match_ip(struct sample *smp, struct acl_pattern *pattern)
 /* Lookup an IPv4 address in the expression's pattern tree using the longest
  * match method. The node is returned if it exists, otherwise NULL.
  */
-static void *acl_lookup_ip(struct sample *smp, struct acl_expr *expr)
+static void *acl_lookup_ip(struct sample *smp, struct pattern_expr *expr)
 {
        struct in_addr *s;
 
@@ -807,11 +807,24 @@ void free_pattern_tree(struct eb_root *root)
        }
 }
 
+void prune_pattern_expr(struct pattern_expr *expr)
+{
+       free_pattern_list(&expr->patterns);
+       free_pattern_tree(&expr->pattern_tree);
+       LIST_INIT(&expr->patterns);
+}
+
+void init_pattern_expr(struct pattern_expr *expr)
+{
+       LIST_INIT(&expr->patterns);
+       expr->pattern_tree = EB_ROOT_UNIQUE;
+}
+
 /* return 1 if the process is ok
  * return -1 if the parser fail. The err message is filled.
  * return -2 if out of memory
  */
-int acl_register_pattern(struct acl_expr *expr, char *text,
+int acl_register_pattern(struct pattern_expr *expr, char *text,
                          struct sample_storage *smp,
                          struct acl_pattern **pattern,
                          int patflags, char **err)
@@ -856,7 +869,7 @@ int acl_register_pattern(struct acl_expr *expr, char *text,
 /* 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.
  */
-int acl_read_patterns_from_file(struct acl_expr *expr,
+int acl_read_patterns_from_file(struct pattern_expr *expr,
                                 const char *filename, int patflags,
                                 char **err)
 {
@@ -926,7 +939,7 @@ int acl_read_patterns_from_file(struct acl_expr *expr,
  * is not NULL. The function return ACL_PAT_FAIL, ACL_PAT_MISS or
  * ACL_PAT_PASS
  */
-inline int acl_exec_match(struct acl_expr *expr, struct sample *smp,
+inline int acl_exec_match(struct pattern_expr *expr, struct sample *smp,
                           struct sample_storage **sample)
 {
        int acl_res = ACL_PAT_FAIL;