]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: acl: report parsing errors to the caller
authorWilly Tarreau <w@1wt.eu>
Fri, 27 Apr 2012 10:38:15 +0000 (12:38 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 8 May 2012 18:57:20 +0000 (20:57 +0200)
All parsing errors were known but impossible to return. Now by making use
of memprintf(), we're able to build meaningful error messages that the
caller can display.

include/proto/acl.h
src/acl.c
src/cfgparse.c
src/proto_http.c
src/proto_tcp.c

index 3a7606b8e34c470e0b8fa480d594a4b7ca868d7f..2c74e2db331f5c4faa4162af20306c81e6fed12a 100644 (file)
@@ -59,7 +59,7 @@ struct acl_keyword *find_acl_kw(const char *kw);
  * Right now, the only accepted syntax is :
  * <subject> [<value>...]
  */
-struct acl_expr *parse_acl_expr(const char **args);
+struct acl_expr *parse_acl_expr(const char **args, char **err);
 
 /* Purge everything in the acl <acl>, then return <acl>. */
 struct acl *prune_acl(struct acl *acl);
@@ -70,7 +70,7 @@ struct acl *prune_acl(struct acl *acl);
  *
  * args syntax: <aclname> <acl_expr>
  */
-struct acl *parse_acl(const char **args, struct list *known_acl);
+struct acl *parse_acl(const char **args, struct list *known_acl, char **err);
 
 /* Purge everything in the acl_cond <cond>, then return <cond>. */
 struct acl_cond *prune_acl_cond(struct acl_cond *cond);
@@ -79,15 +79,16 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond);
  * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
  * case of low memory). Supports multiple conditions separated by "or".
  */
-struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol);
+struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err);
 
 /* Builds an ACL condition starting at the if/unless keyword. The complete
  * condition is returned. NULL is returned in case of error or if the first
  * word is neither "if" nor "unless". It automatically sets the file name and
  * the line number in the condition for better error reporting, and adds the
- * ACL requirements to the proxy's acl_requires.
+ * ACL requirements to the proxy's acl_requires. If <err> is not NULL, it will
+ * be set to an error message upon errors, that the caller will have to free.
  */
-struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args);
+struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err);
 
 /* Execute condition <cond> and return either ACL_PAT_FAIL, ACL_PAT_MISS or
  * ACL_PAT_PASS depending on the test results. This function only computes the
index 433a2667e972771f39b1d7a5411c32ecc0b96bc8..a040d872b9401553727347ad8c322621b347d9b3 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -1224,11 +1224,14 @@ static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
        return ret;
 }
 
-/* Parse an ACL expression starting at <args>[0], and return it.
+/* Parse an ACL expression starting at <args>[0], and return it. If <err> is
+ * not NULL, it will be filled with a pointer to an error message in case of
+ * error. This pointer must be freeable or NULL.
+ *
  * Right now, the only accepted syntax is :
  * <subject> [<value>...]
  */
-struct acl_expr *parse_acl_expr(const char **args)
+struct acl_expr *parse_acl_expr(const char **args, char **err)
 {
        __label__ out_return, out_free_expr, out_free_pattern;
        struct acl_expr *expr;
@@ -1238,12 +1241,18 @@ struct acl_expr *parse_acl_expr(const char **args)
        const char *arg;
 
        aclkw = find_acl_kw(args[0]);
-       if (!aclkw || !aclkw->parse)
+       if (!aclkw || !aclkw->parse) {
+               if (err)
+                       memprintf(err, "unknown ACL keyword '%s'", *args);
                goto out_return;
+       }
 
        expr = (struct acl_expr *)calloc(1, sizeof(*expr));
-       if (!expr)
+       if (!expr) {
+               if (err)
+                       memprintf(err, "out of memory when parsing ACL expression");
                goto out_return;
+       }
 
        expr->kw = aclkw;
        aclkw->use_cnt++;
@@ -1259,8 +1268,11 @@ struct acl_expr *parse_acl_expr(const char **args)
                        /* there are 0 or more arguments in the form "subject(arg[,arg]*)" */
                        arg++;
                        end = strchr(arg, ')');
-                       if (!end)
+                       if (!end) {
+                               if (err)
+                                       memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", aclkw->kw);
                                goto out_free_expr;
+                       }
 
                        /* Parse the arguments. Note that currently we have no way to
                         * report parsing errors, hence the NULL in the error pointers.
@@ -1268,12 +1280,22 @@ struct acl_expr *parse_acl_expr(const char **args)
                         * missing.
                         */
                        nbargs = make_arg_list(arg, end - arg, aclkw->arg_mask, &expr->args,
-                                              NULL, NULL, NULL);
-                       if (nbargs < 0)
+                                              err, NULL, NULL);
+                       if (nbargs < 0) {
+                               /* note that make_arg_list will have set <err> here */
+                               if (err)
+                                       memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
                                goto out_free_expr;
+                       }
 
-                       if (aclkw->val_args && !aclkw->val_args(expr->args, NULL))
-                               goto out_free_expr; /* invalid keyword argument */
+                       if (aclkw->val_args && !aclkw->val_args(expr->args, err)) {
+                               /* invalid keyword argument, error must have been
+                                * set by val_args().
+                                */
+                               if (err)
+                                       memprintf(err, "in argument to '%s', %s", aclkw->kw, *err);
+                               goto out_free_expr;
+                       }
                }
                else if (ARGM(aclkw->arg_mask) == 1) {
                        int type = (aclkw->arg_mask >> 4) & 15;
@@ -1282,8 +1304,11 @@ struct acl_expr *parse_acl_expr(const char **args)
                         * 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)
+                       if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) {
+                               if (err)
+                                       memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->arg_mask));
                                goto out_free_expr;
+                       }
 
                        /* Build an arg list containing the type as an empty string
                         * and the usual STOP.
@@ -1297,12 +1322,16 @@ struct acl_expr *parse_acl_expr(const char **args)
                }
                else if (ARGM(aclkw->arg_mask)) {
                        /* there were some mandatory arguments */
+                       if (err)
+                               memprintf(err, "ACL keyword '%s' expects %d arguments", aclkw->kw, ARGM(aclkw->arg_mask));
                        goto out_free_expr;
                }
        }
        else {
                if (arg) {
                        /* no argument expected */
+                       if (err)
+                               memprintf(err, "ACL keyword '%s' takes no argument", aclkw->kw);
                        goto out_free_expr;
                }
        }
@@ -1319,8 +1348,11 @@ struct acl_expr *parse_acl_expr(const char **args)
                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))
+                       if (!acl_read_patterns_from_file(aclkw, expr, args[1], patflags | ACL_PAT_F_FROM_FILE)) {
+                               if (err)
+                                       memprintf(err, "failed to load some ACL patterns from file '%s'", args[1]);
                                goto out_free_expr;
+                       }
                        args++;
                }
                else if ((*args)[1] == '-') {
@@ -1337,13 +1369,19 @@ struct acl_expr *parse_acl_expr(const char **args)
        while (**args) {
                int ret;
                pattern = (struct acl_pattern *)calloc(1, sizeof(*pattern));
-               if (!pattern)
+               if (!pattern) {
+                       if (err)
+                               memprintf(err, "out of memory when parsing ACL pattern");
                        goto out_free_expr;
+               }
                pattern->flags = patflags;
 
                ret = aclkw->parse(args, pattern, &opaque);
-               if (!ret)
+               if (!ret) {
+                       if (err)
+                               memprintf(err, "failed to parse some ACL patterns");
                        goto out_free_pattern;
+               }
                LIST_ADDQ(&expr->patterns, &pattern->list);
                args += ret;
        }
@@ -1378,23 +1416,31 @@ struct acl *prune_acl(struct acl *acl) {
 /* Parse an ACL with the name starting at <args>[0], and with a list of already
  * known ACLs in <acl>. If the ACL was not in the list, it will be added.
  * A pointer to that ACL is returned. If the ACL has an empty name, then it's
- * an anonymous one and it won't be merged with any other one.
+ * an anonymous one and it won't be merged with any other one. If <err> is not
+ * NULL, it will be filled with an appropriate error. This pointer must be
+ * freeable or NULL.
  *
  * args syntax: <aclname> <acl_expr>
  */
-struct acl *parse_acl(const char **args, struct list *known_acl)
+struct acl *parse_acl(const char **args, struct list *known_acl, char **err)
 {
        __label__ out_return, out_free_acl_expr, out_free_name;
        struct acl *cur_acl;
        struct acl_expr *acl_expr;
        char *name;
+       const char *pos;
 
-       if (**args && invalid_char(*args))
+       if (**args && (pos = invalid_char(*args))) {
+               if (err)
+                       memprintf(err, "invalid character in ACL name : '%c'", *pos);
                goto out_return;
+       }
 
-       acl_expr = parse_acl_expr(args + 1);
-       if (!acl_expr)
+       acl_expr = parse_acl_expr(args + 1, err);
+       if (!acl_expr) {
+               /* parse_acl_expr will have filled <err> here */
                goto out_return;
+       }
 
        /* Check for args beginning with an opening parenthesis just after the
         * subject, as this is almost certainly a typo. Right now we can only
@@ -1415,11 +1461,17 @@ struct acl *parse_acl(const char **args, struct list *known_acl)
 
        if (!cur_acl) {
                name = strdup(args[0]);
-               if (!name)
+               if (!name) {
+                       if (err)
+                               memprintf(err, "out of memory when parsing ACL");
                        goto out_free_acl_expr;
+               }
                cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
-               if (cur_acl == NULL)
+               if (cur_acl == NULL) {
+                       if (err)
+                               memprintf(err, "out of memory when parsing ACL");
                        goto out_free_name;
+               }
 
                LIST_INIT(&cur_acl->expr);
                LIST_ADDQ(known_acl, &cur_acl->list);
@@ -1470,9 +1522,11 @@ const struct {
 /* Find a default ACL from the default_acl list, compile it and return it.
  * If the ACL is not found, NULL is returned. In theory, it cannot fail,
  * except when default ACLs are broken, in which case it will return NULL.
- * If <known_acl> is not NULL, the ACL will be queued at its tail.
+ * If <known_acl> is not NULL, the ACL will be queued at its tail. If <err> is
+ * not NULL, it will be filled with an error message if an error occurs. This
+ * pointer must be freeable or NULL.
  */
-struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
+struct acl *find_acl_default(const char *acl_name, struct list *known_acl, char **err)
 {
        __label__ out_return, out_free_acl_expr, out_free_name;
        struct acl *cur_acl;
@@ -1485,19 +1539,31 @@ struct acl *find_acl_default(const char *acl_name, struct list *known_acl)
                        break;
        }
 
-       if (default_acl_list[index].name == NULL)
+       if (default_acl_list[index].name == NULL) {
+               if (err)
+                       memprintf(err, "no such ACL : '%s'", acl_name);
                return NULL;
+       }
 
-       acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr);
-       if (!acl_expr)
+       acl_expr = parse_acl_expr((const char **)default_acl_list[index].expr, err);
+       if (!acl_expr) {
+               /* parse_acl_expr must have filled err here */
                goto out_return;
+       }
 
        name = strdup(acl_name);
-       if (!name)
+       if (!name) {
+               if (err)
+                       memprintf(err, "out of memory when building default ACL '%s'", acl_name);
                goto out_free_acl_expr;
+       }
+
        cur_acl = (struct acl *)calloc(1, sizeof(*cur_acl));
-       if (cur_acl == NULL)
+       if (cur_acl == NULL) {
+               if (err)
+                       memprintf(err, "out of memory when building default ACL '%s'", acl_name);
                goto out_free_name;
+       }
 
        cur_acl->name = name;
        cur_acl->requires |= acl_expr->kw->requires;
@@ -1534,9 +1600,12 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond)
 
 /* Parse an ACL condition starting at <args>[0], relying on a list of already
  * known ACLs passed in <known_acl>. The new condition is returned (or NULL in
- * case of low memory). Supports multiple conditions separated by "or".
+ * case of low memory). Supports multiple conditions separated by "or". If
+ * <err> is not NULL, it will be filled with a pointer to an error message in
+ * case of error, that the caller is responsible for freeing. The initial
+ * location must either be freeable or NULL.
  */
-struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol)
+struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int pol, char **err)
 {
        __label__ out_return, out_free_suite, out_free_term;
        int arg, neg;
@@ -1547,8 +1616,11 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
        struct acl_cond *cond;
 
        cond = (struct acl_cond *)calloc(1, sizeof(*cond));
-       if (cond == NULL)
+       if (cond == NULL) {
+               if (err)
+                       memprintf(err, "out of memory when parsing condition");
                goto out_return;
+       }
 
        LIST_INIT(&cond->list);
        LIST_INIT(&cond->suites);
@@ -1588,21 +1660,29 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
                        while (*args[arg_end] && strcmp(args[arg_end], "}") != 0)
                                arg_end++;
 
-                       if (!*args[arg_end])
+                       if (!*args[arg_end]) {
+                               if (err)
+                                       memprintf(err, "missing closing '}' in condition");
                                goto out_free_suite;
+                       }
 
                        args_new = calloc(1, (arg_end - arg + 1) * sizeof(*args_new));
-                       if (!args_new)
+                       if (!args_new) {
+                               if (err)
+                                       memprintf(err, "out of memory when parsing condition");
                                goto out_free_suite;
+                       }
 
                        args_new[0] = "";
                        memcpy(args_new + 1, args + arg + 1, (arg_end - arg) * sizeof(*args_new));
                        args_new[arg_end - arg] = "";
-                       cur_acl = parse_acl(args_new, known_acl);
+                       cur_acl = parse_acl(args_new, known_acl, err);
                        free(args_new);
 
-                       if (!cur_acl)
+                       if (!cur_acl) {
+                               /* note that parse_acl() must have filled <err> here */
                                goto out_free_suite;
+                       }
                        arg = arg_end;
                }
                else {
@@ -1613,15 +1693,20 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
                         */
                        cur_acl = find_acl_by_name(word, known_acl);
                        if (cur_acl == NULL) {
-                               cur_acl = find_acl_default(word, known_acl);
-                               if (cur_acl == NULL)
+                               cur_acl = find_acl_default(word, known_acl, err);
+                               if (cur_acl == NULL) {
+                                       /* note that find_acl_default() must have filled <err> here */
                                        goto out_free_suite;
+                               }
                        }
                }
 
                cur_term = (struct acl_term *)calloc(1, sizeof(*cur_term));
-               if (cur_term == NULL)
+               if (cur_term == NULL) {
+                       if (err)
+                               memprintf(err, "out of memory when parsing condition");
                        goto out_free_suite;
+               }
 
                cur_term->acl = cur_acl;
                cur_term->neg = neg;
@@ -1629,8 +1714,11 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
 
                if (!cur_suite) {
                        cur_suite = (struct acl_term_suite *)calloc(1, sizeof(*cur_suite));
-                       if (cur_term == NULL)
+                       if (cur_term == NULL) {
+                               if (err)
+                                       memprintf(err, "out of memory when parsing condition");
                                goto out_free_term;
+                       }
                        LIST_INIT(&cur_suite->terms);
                        LIST_ADDQ(&cond->suites, &cur_suite->list);
                }
@@ -1653,13 +1741,19 @@ struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl, int p
  * condition is returned. NULL is returned in case of error or if the first
  * word is neither "if" nor "unless". It automatically sets the file name and
  * the line number in the condition for better error reporting, and adds the
- * ACL requirements to the proxy's acl_requires.
+ * ACL requirements to the proxy's acl_requires. If <err> is not NULL, it will
+ * be filled with a pointer to an error message in case of error, that the
+ * caller is responsible for freeing. The initial location must either be
+ * freeable or NULL.
  */
-struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args)
+struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, const char **args, char **err)
 {
        int pol = ACL_COND_NONE;
        struct acl_cond *cond = NULL;
 
+       if (err)
+               *err = NULL;
+
        if (!strcmp(*args, "if")) {
                pol = ACL_COND_IF;
                args++;
@@ -1668,12 +1762,17 @@ struct acl_cond *build_acl_cond(const char *file, int line, struct proxy *px, co
                pol = ACL_COND_UNLESS;
                args++;
        }
-       else
+       else {
+               if (err)
+                       memprintf(err, "conditions must start with either 'if' or 'unless'");
                return NULL;
+       }
 
-       cond = parse_acl_cond(args, &px->acl, pol);
-       if (!cond)
+       cond = parse_acl_cond(args, &px->acl, pol, err);
+       if (!cond) {
+               /* note that parse_acl_cond must have filled <err> here */
                return NULL;
+       }
 
        cond->file = file;
        cond->line = line;
index a3ac66121ca4710ce0370d4fedc9ab4dee5e5ccc..8b5eae312d69b5792c25a0761ceee6c026fa213c 100644 (file)
@@ -1085,6 +1085,7 @@ static int create_cond_regex_rule(const char *file, int line,
                                  const char **cond_start)
 {
        regex_t *preg = NULL;
+       char *errmsg = NULL;
        const char *err;
        int err_code = 0;
        struct acl_cond *cond = NULL;
@@ -1106,9 +1107,10 @@ static int create_cond_regex_rule(const char *file, int line,
 
        if (cond_start &&
            (strcmp(*cond_start, "if") == 0 || strcmp(*cond_start, "unless") == 0)) {
-               if ((cond = build_acl_cond(file, line, px, cond_start)) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n",
-                             file, line, cmd);
+               if ((cond = build_acl_cond(file, line, px, cond_start, &errmsg)) == NULL) {
+                       Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
+                             file, line, cmd, errmsg);
+                       free(errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto err;
                }
@@ -2073,6 +2075,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                curproxy->bind_proc = set;
        }
        else if (!strcmp(args[0], "acl")) {  /* add an ACL */
+               char *errmsg = NULL;
+
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2086,9 +2090,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        err_code |= ERR_ALERT | ERR_FATAL;
                }
 
-               if (parse_acl((const char **)args + 1, &curproxy->acl) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing ACL '%s'.\n",
-                             file, linenum, args[1]);
+               if (parse_acl((const char **)args + 1, &curproxy->acl, &errmsg) == NULL) {
+                       Alert("parsing [%s:%d] : error detected while parsing ACL '%s' : %s.\n",
+                             file, linenum, args[1], errmsg);
+                       free(errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -2507,6 +2512,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                curproxy->server_id_hdr_len  = strlen(curproxy->server_id_hdr_name);
        }
        else if (!strcmp(args[0], "block")) {  /* early blocking based on ACLs */
+               char *errmsg = NULL;
+
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2520,9 +2527,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
 
-               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n",
-                             file, linenum);
+               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
+                       Alert("parsing [%s:%d] : error detected while parsing blocking condition : %s.\n",
+                             file, linenum, errmsg);
+                       free(errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -2620,10 +2628,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        }
                        else if (strcmp(args[cur_arg], "if") == 0 ||
                                 strcmp(args[cur_arg], "unless") == 0) {
-                               cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg);
+                               char *errmsg = NULL;
+
+                               cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg, &errmsg);
                                if (!cond) {
-                                       Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition.\n",
-                                             file, linenum, args[0]);
+                                       Alert("parsing [%s:%d] : '%s': error detected while parsing redirect condition : %s.\n",
+                                             file, linenum, args[0], errmsg);
+                                       free(errmsg);
                                        err_code |= ERR_ALERT | ERR_FATAL;
                                        goto out;
                                }
@@ -2676,6 +2687,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
        }
        else if (!strcmp(args[0], "use_backend")) {
                struct switching_rule *rule;
+               char *errmsg = NULL;
 
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -2699,9 +2711,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
 
-               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing switching rule.\n",
-                             file, linenum);
+               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
+                       Alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
+                             file, linenum, errmsg);
+                       free(errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -2716,6 +2729,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
        }
        else if (strcmp(args[0], "use-server") == 0) {
                struct server_rule *rule;
+               char *errmsg = NULL;
 
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -2739,9 +2753,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
 
-               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing switching rule.\n",
-                             file, linenum);
+               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
+                       Alert("parsing [%s:%d] : error detected while parsing switching rule : %s.\n",
+                             file, linenum, errmsg);
+                       free(errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -2758,6 +2773,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
        else if ((!strcmp(args[0], "force-persist")) ||
                 (!strcmp(args[0], "ignore-persist"))) {
                struct persist_rule *rule;
+               char *errmsg = NULL;
 
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -2775,9 +2791,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
 
-               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1)) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing a '%s' rule.\n",
-                             file, linenum, args[0]);
+               if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
+                       Alert("parsing [%s:%d] : error detected while parsing a '%s' rule : %s.\n",
+                             file, linenum, args[0], errmsg);
+                       free(errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
@@ -2953,6 +2970,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                struct sticking_rule *rule;
                struct pattern_expr *expr;
                int myidx = 0;
+               char *errmsg = NULL;
                const char *name = NULL;
                int flags;
 
@@ -3028,9 +3046,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                }
 
                if (strcmp(args[myidx], "if") == 0 || strcmp(args[myidx], "unless") == 0) {
-                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + myidx)) == NULL) {
-                               Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition.\n",
-                                     file, linenum, args[0]);
+                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + myidx, &errmsg)) == NULL) {
+                               Alert("parsing [%s:%d] : '%s': error detected while parsing sticking condition : %s.\n",
+                                     file, linenum, args[0], errmsg);
+                               free(errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                free(expr);
                                goto out;
@@ -3070,6 +3089,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        goto stats_error_parsing;
                } else if (!strcmp(args[1], "admin")) {
                        struct stats_admin_rule *rule;
+                       char *errmsg = NULL;
 
                        if (curproxy == &defproxy) {
                                Alert("parsing [%s:%d]: '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
@@ -3089,9 +3109,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
-                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) {
-                               Alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule.\n",
-                               file, linenum, args[0], args[1]);
+                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
+                               Alert("parsing [%s:%d] : error detected while parsing a '%s %s' rule : %s.\n",
+                                     file, linenum, args[0], args[1], errmsg);
+                               free(errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
@@ -3846,6 +3867,8 @@ stats_error_parsing:
                        err_code |= ERR_WARN;
 
                if (strcmp(args[1], "fail") == 0) {
+                       char *errmsg = NULL;
+
                        /* add a condition to fail monitor requests */
                        if (strcmp(args[2], "if") != 0 && strcmp(args[2], "unless") != 0) {
                                Alert("parsing [%s:%d] : '%s %s' requires either 'if' or 'unless' followed by a condition.\n",
@@ -3854,9 +3877,10 @@ stats_error_parsing:
                                goto out;
                        }
 
-                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2)) == NULL) {
-                               Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition.\n",
-                                     file, linenum, args[0], args[1]);
+                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args + 2, &errmsg)) == NULL) {
+                               Alert("parsing [%s:%d] : error detected while parsing a '%s %s' condition : %s.\n",
+                                     file, linenum, args[0], args[1], errmsg);
+                               free(errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
@@ -4987,6 +5011,7 @@ stats_error_parsing:
        }
        else if (!strcmp(args[0], "reqadd")) {  /* add request header */
                struct cond_wordlist *wl;
+               char *errmsg = NULL;
 
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -5003,9 +5028,10 @@ stats_error_parsing:
                }
 
                if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
-                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) {
-                               Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n",
-                                     file, linenum, args[0]);
+                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2, &errmsg)) == NULL) {
+                               Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
+                                     file, linenum, args[0], errmsg);
+                               free(errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
@@ -5082,6 +5108,7 @@ stats_error_parsing:
        }
        else if (!strcmp(args[0], "rspadd")) {  /* add response header */
                struct cond_wordlist *wl;
+               char *errmsg = NULL;
 
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -5098,9 +5125,10 @@ stats_error_parsing:
                }
        
                if ((strcmp(args[2], "if") == 0 || strcmp(args[2], "unless") == 0)) {
-                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2)) == NULL) {
-                               Alert("parsing [%s:%d] : error detected while parsing a '%s' condition.\n",
-                                     file, linenum, args[0]);
+                       if ((cond = build_acl_cond(file, linenum, curproxy, (const char **)args+2, &errmsg)) == NULL) {
+                               Alert("parsing [%s:%d] : error detected while parsing a '%s' condition : %s.\n",
+                                     file, linenum, args[0], errmsg);
+                               free(errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
index a173f8861597cbf92de50ab45bd54a19684a2dec..07e0eb59737523870eddba5fa4eab16fa6914b52 100644 (file)
@@ -7506,10 +7506,12 @@ req_error_parsing:
 
        if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
                struct acl_cond *cond;
+               char *errmsg = NULL;
 
-               if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg)) == NULL) {
-                       Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition.\n",
-                             file, linenum, args[0]);
+               if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg, &errmsg)) == NULL) {
+                       Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
+                             file, linenum, args[0], errmsg);
+                       free(errmsg);
                        return NULL;
                }
                rule->cond = cond;
index 4aa47293fb4cd50ea9e01684a5847ed480c5dae9..dc7812d21c7bd92551dbc2bb39e957fef3cd3288 100644 (file)
@@ -962,10 +962,13 @@ static int tcp_parse_response_rule(char **args, int arg, int section_type,
        }
 
        if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
-               if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
+               char *errmsg = NULL;
+
+               if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) {
                        snprintf(err, errlen,
-                                "error detected in %s '%s' while parsing '%s' condition",
-                                proxy_type_str(curpx), curpx->id, args[arg]);
+                                "error detected in %s '%s' while parsing '%s' condition : %s",
+                                proxy_type_str(curpx), curpx->id, args[arg], errmsg);
+                       free(errmsg);
                        return -1;
                }
        }
@@ -1032,10 +1035,13 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
        }
 
        if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
-               if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg)) == NULL) {
+               char *errmsg = NULL;
+
+               if ((rule->cond = build_acl_cond(NULL, 0, curpx, (const char **)args+arg, &errmsg)) == NULL) {
                        snprintf(err, errlen,
-                                "error detected in %s '%s' while parsing '%s' condition",
-                                proxy_type_str(curpx), curpx->id, args[arg]);
+                                "error detected in %s '%s' while parsing '%s' condition : %s",
+                                proxy_type_str(curpx), curpx->id, args[arg], errmsg);
+                       free(errmsg);
                        return -1;
                }
        }