mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MEDIUM: acl: fix the argument parser to let the lower layer report detailed errors
Just like for the last commit, we need to fix the ACL argument parser so that it lets the lower layer do the job of referencing unresolved arguments and correctly report the type of missing arguments.
This commit is contained in:
parent
689a1df0a1
commit
131b466f98
126
src/acl.c
126
src/acl.c
@ -136,22 +136,28 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
int patflags;
|
int patflags;
|
||||||
const char *arg;
|
const char *arg;
|
||||||
struct sample_expr *smp = NULL;
|
struct sample_expr *smp = NULL;
|
||||||
const char *p;
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
char *ckw = NULL;
|
char *ckw = NULL;
|
||||||
const char *begw;
|
const char *begw;
|
||||||
const char *endw;
|
const char *endw;
|
||||||
|
const char *endt;
|
||||||
unsigned long prev_type;
|
unsigned long prev_type;
|
||||||
int cur_type;
|
int cur_type;
|
||||||
|
int nbargs;
|
||||||
|
|
||||||
/* First, we lookd for an ACL keyword. And if we don't find one, then
|
/* First, we lookd for an ACL keyword. And if we don't find one, then
|
||||||
* we look for a sample fetch keyword.
|
* we look for a sample fetch keyword.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
al->ctx = ARGC_ACL;
|
||||||
|
al->kw = *args;
|
||||||
|
al->conv = NULL;
|
||||||
|
|
||||||
aclkw = find_acl_kw(args[0]);
|
aclkw = find_acl_kw(args[0]);
|
||||||
if (!aclkw || !aclkw->parse) {
|
if (!aclkw || !aclkw->parse) {
|
||||||
smp = sample_parse_expr((char **)args, &idx, err, al);
|
smp = sample_parse_expr((char **)args, &idx, err, al);
|
||||||
if (!smp) {
|
if (!smp) {
|
||||||
memprintf(err, "%s in sample expression '%s'", *err, *args);
|
memprintf(err, "%s in ACL expression '%s'", *err, *args);
|
||||||
goto out_return;
|
goto out_return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,8 +198,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
|
|
||||||
/* now parse the rest of acl only if "find_acl_kw" match */
|
/* now parse the rest of acl only if "find_acl_kw" match */
|
||||||
if (aclkw) {
|
if (aclkw) {
|
||||||
|
/* build new sample expression for this ACL */
|
||||||
/* build new sample expression */
|
|
||||||
expr->smp = calloc(1, sizeof(struct sample_expr));
|
expr->smp = calloc(1, sizeof(struct sample_expr));
|
||||||
if (!expr->smp) {
|
if (!expr->smp) {
|
||||||
memprintf(err, "out of memory when parsing ACL expression");
|
memprintf(err, "out of memory when parsing ACL expression");
|
||||||
@ -204,116 +209,52 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
expr->smp->arg_p = empty_arg_list;
|
expr->smp->arg_p = empty_arg_list;
|
||||||
|
|
||||||
/* look for the begining of the subject arguments */
|
/* look for the begining of the subject arguments */
|
||||||
p = strchr(args[0], ',');
|
for (arg = args[0]; *arg && *arg != '(' && *arg != ','; arg++);
|
||||||
arg = strchr(args[0], '(');
|
|
||||||
if (p && arg && p < arg)
|
|
||||||
arg = NULL;
|
|
||||||
|
|
||||||
if (expr->smp->fetch->arg_mask) {
|
endt = arg;
|
||||||
int nbargs = 0;
|
if (*endt == '(') {
|
||||||
char *end;
|
/* look for the end of this term and skip the opening parenthesis */
|
||||||
|
endt = ++arg;
|
||||||
if (arg != NULL) {
|
while (*endt && *endt != ')')
|
||||||
/* there are 0 or more arguments in the form "subject(arg[,arg]*)" */
|
endt++;
|
||||||
arg++;
|
if (*endt != ')') {
|
||||||
end = strchr(arg, ')');
|
|
||||||
if (!end) {
|
|
||||||
memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", expr->kw);
|
memprintf(err, "missing closing ')' after arguments to ACL keyword '%s'", expr->kw);
|
||||||
goto out_free_expr;
|
goto out_free_expr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse the arguments. Note that currently we have no way to
|
/* At this point, we have :
|
||||||
* report parsing errors, hence the NULL in the error pointers.
|
* - args[0] : beginning of the keyword
|
||||||
* An error is also reported if some mandatory arguments are
|
* - arg : end of the keyword, first character not part of keyword
|
||||||
* missing. We prepare the args list to report unresolved
|
* nor the opening parenthesis (so first character of args
|
||||||
* dependencies.
|
* if present).
|
||||||
|
* - endt : end of the term (=arg or last parenthesis if args are present)
|
||||||
*/
|
*/
|
||||||
al->ctx = ARGC_ACL;
|
nbargs = make_arg_list(arg, endt - arg, expr->smp->fetch->arg_mask, &expr->smp->arg_p,
|
||||||
al->kw = expr->kw;
|
|
||||||
al->conv = NULL;
|
|
||||||
nbargs = make_arg_list(arg, end - arg, expr->smp->fetch->arg_mask, &expr->smp->arg_p,
|
|
||||||
err, NULL, NULL, al);
|
err, NULL, NULL, al);
|
||||||
if (nbargs < 0) {
|
if (nbargs < 0) {
|
||||||
/* note that make_arg_list will have set <err> here */
|
/* note that make_arg_list will have set <err> here */
|
||||||
memprintf(err, "in argument to '%s', %s", expr->kw, *err);
|
memprintf(err, "ACL keyword '%s' : %s", expr->kw, *err);
|
||||||
goto out_free_expr;
|
goto out_free_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expr->smp->arg_p)
|
if (!expr->smp->arg_p) {
|
||||||
expr->smp->arg_p = empty_arg_list;
|
expr->smp->arg_p = empty_arg_list;
|
||||||
|
}
|
||||||
if (expr->smp->fetch->val_args && !expr->smp->fetch->val_args(expr->smp->arg_p, err)) {
|
else if (expr->smp->fetch->val_args && !expr->smp->fetch->val_args(expr->smp->arg_p, err)) {
|
||||||
/* invalid keyword argument, error must have been
|
/* invalid keyword argument, error must have been
|
||||||
* set by val_args().
|
* set by val_args().
|
||||||
*/
|
*/
|
||||||
memprintf(err, "in argument to '%s', %s", expr->kw, *err);
|
memprintf(err, "in argument to '%s', %s", expr->kw, *err);
|
||||||
goto out_free_expr;
|
goto out_free_expr;
|
||||||
}
|
}
|
||||||
arg = end;
|
arg = endt;
|
||||||
}
|
|
||||||
else if (ARGM(expr->smp->fetch->arg_mask) == 1) {
|
|
||||||
int type = (expr->smp->fetch->arg_mask >> 4) & 15;
|
|
||||||
|
|
||||||
/* If a proxy is noted as a mandatory argument, we'll fake
|
/* look for the begining of the converters list. Those directly attached
|
||||||
* an empty one so that acl_find_targets() resolves it as
|
* to the ACL keyword are found just after <arg> which points to the comma.
|
||||||
* the current one later.
|
|
||||||
*/
|
*/
|
||||||
if (type != ARGT_FE && type != ARGT_BE && type != ARGT_TAB) {
|
|
||||||
memprintf(err, "ACL keyword '%s' expects %d arguments", expr->kw, ARGM(expr->smp->fetch->arg_mask));
|
|
||||||
goto out_free_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build an arg list containing the type as an empty string
|
|
||||||
* and the usual STOP.
|
|
||||||
*/
|
|
||||||
expr->smp->arg_p = calloc(2, sizeof(*expr->smp->arg_p));
|
|
||||||
expr->smp->arg_p[0].type = type;
|
|
||||||
expr->smp->arg_p[0].unresolved = 1;
|
|
||||||
expr->smp->arg_p[0].data.str.str = strdup("");
|
|
||||||
expr->smp->arg_p[0].data.str.size = 1;
|
|
||||||
expr->smp->arg_p[0].data.str.len = 0;
|
|
||||||
|
|
||||||
al->ctx = ARGC_ACL;
|
|
||||||
al->kw = expr->kw;
|
|
||||||
al->conv = NULL;
|
|
||||||
arg_list_add(al, &expr->smp->arg_p[0], 0);
|
|
||||||
|
|
||||||
expr->smp->arg_p[1].type = ARGT_STOP;
|
|
||||||
}
|
|
||||||
else if (ARGM(expr->smp->fetch->arg_mask)) {
|
|
||||||
/* there were some mandatory arguments */
|
|
||||||
memprintf(err, "ACL keyword '%s' expects %d arguments", expr->kw, ARGM(expr->smp->fetch->arg_mask));
|
|
||||||
goto out_free_expr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (arg ) {
|
|
||||||
/* no argument expected */
|
|
||||||
memprintf(err, "ACL keyword '%s' takes no argument", expr->kw);
|
|
||||||
goto out_free_expr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now process the converters if any. We have two supported syntaxes
|
|
||||||
* for the converters, which can be combined :
|
|
||||||
* - comma-delimited list of converters just after the keyword and args ;
|
|
||||||
* - one converter per keyword
|
|
||||||
* The combination allows to have each keyword being a comma-delimited
|
|
||||||
* series of converters.
|
|
||||||
*
|
|
||||||
* We want to process the former first, then the latter. For this we start
|
|
||||||
* from the beginning of the supposed place in the exiting conv chain, which
|
|
||||||
* starts at the last comma (endt).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* look for the begining of the converters list */
|
|
||||||
if (arg)
|
|
||||||
arg = strchr(arg, ',');
|
|
||||||
else
|
|
||||||
arg = strchr(args[0], ',');
|
|
||||||
if (arg) {
|
|
||||||
prev_type = expr->smp->fetch->out_type;
|
prev_type = expr->smp->fetch->out_type;
|
||||||
while (1) {
|
while (*arg) {
|
||||||
struct sample_conv *conv;
|
struct sample_conv *conv;
|
||||||
struct sample_conv_expr *conv_expr;
|
struct sample_conv_expr *conv_expr;
|
||||||
|
|
||||||
@ -421,7 +362,6 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Additional check to protect against common mistakes */
|
/* Additional check to protect against common mistakes */
|
||||||
cur_type = smp_expr_output_type(expr->smp);
|
cur_type = smp_expr_output_type(expr->smp);
|
||||||
|
Loading…
Reference in New Issue
Block a user