BUG/MEDIUM: acl: correctly compute the output type when a converter is used

Sample expressions involving converters in expression simply do not work
if the converter changes the sample type from the original keyword. Either
the keyword is a sample fetch keyword and its own type is used, or it's an
ACL keyword, and the keyword's parse/index/match functions are used despite
the converters. Thus it causes such a stupid error :

     redirect location / if { date,ltime(%a) -i Fri }

[ALERT] 240/171746 (29127) : parsing [bug-conv.cfg:35] : error detected in proxy 'svc' while parsing redirect rule : error in condition: 'Fri' is not a number.

In fact now in ACLs, the case where the ACL keyword is alone is an exception
(eventhough the most common one). It's an exception to the sample expression
parsing rules since ACLs allow to redefine alternate parsing functions.

This fix does two things :
  - it voids any references to the ACL keyword when a converter is involved
    since we certainly not want to enforce a parser for a wrong data type ;
  - it ensures that for all other cases (sample expressions), the type of
    the expression is used instead of the type of the fetch keyword.

A significant cleanup of the code should be done, but this patch only aims
fixing the bug.

The fix should be backported into 1.5 since this appeared along the redesign
of the acl/pattern processing.
This commit is contained in:
Willy Tarreau 2014-08-29 17:36:40 +02:00
parent 5def8ef786
commit 6f0ddca67a

View File

@ -161,6 +161,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
struct pat_ref *ref;
struct pattern_expr *pattern_expr;
int load_as_map = 0;
int acl_conv_found = 0;
/* First, we look for an ACL keyword. And if we don't find one, then
* we look for a sample fetch expression starting with a sample fetch
@ -229,6 +230,10 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
/* look for the begining of the converters list. Those directly attached
* to the ACL keyword are found just after <arg> which points to the comma.
* If we find any converter, then we don't use the ACL keyword's match
* anymore but the one related to the converter's output type, so we'll
* kill the ACL kw to avoid any future reference to it (since in fact we'll
* only be using it as a sample fetch function).
*/
prev_type = smp->fetch->out_type;
while (*arg) {
@ -302,6 +307,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
LIST_ADDQ(&(smp->conv_exprs), &(conv_expr->list));
conv_expr->conv = conv;
acl_conv_found = 1;
if (arg != endw) {
int err_arg;
@ -347,8 +353,15 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
memprintf(err, "%s in ACL expression '%s'", *err, *args);
goto out_return;
}
prev_type = smp_expr_output_type(smp);
}
/* From now on, prev_type is the expression's output type.
* Stop relying on ACL keyword if a converter is used.
*/
if (acl_conv_found)
aclkw = NULL;
expr = (struct acl_expr *)calloc(1, sizeof(*expr));
if (!expr) {
memprintf(err, "out of memory when parsing ACL expression");
@ -363,7 +376,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
expr->pat.match = aclkw ? aclkw->match : NULL;
expr->pat.delete = aclkw ? aclkw->delete : NULL;
expr->pat.prune = aclkw ? aclkw->prune : NULL;
expr->pat.expect_type = smp->fetch->out_type;
expr->pat.expect_type = prev_type;
expr->smp = smp;
smp = NULL;
@ -388,7 +401,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
if (!expr->pat.parse) {
/* some types can be automatically converted */
switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) {
switch (prev_type) {
case SMP_T_BOOL:
expr->pat.parse = pat_parse_fcts[PAT_MATCH_BOOL];
expr->pat.index = pat_index_fcts[PAT_MATCH_BOOL];