diff --git a/doc/configuration.txt b/doc/configuration.txt index a66350fd1..1b42a3c39 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -811,6 +811,7 @@ expression made of any combination of: - the integer zero ('0'), always returns "false" - a non-nul integer (e.g. '1'), always returns "true". - a predicate optionally followed by argument(s) in parenthesis. + - a condition placed between a pair of parenthesis '(' and ')' - a question mark ('!') preceeding any of the non-empty elements above, and which will negate its status. - expressions combined with a logical AND ('&&'), which will be evaluated @@ -861,7 +862,7 @@ Example: .endif .endif - .if streq("$WITH_SSL",yes) && feature(OPENSSL) + .if feature(OPENSSL) && (streq("$WITH_SSL",yes) || streq("$SSL_ONLY",yes)) bind :443 ssl crt ... .endif diff --git a/include/haproxy/cfgcond-t.h b/include/haproxy/cfgcond-t.h index f4f2796f0..bb1961234 100644 --- a/include/haproxy/cfgcond-t.h +++ b/include/haproxy/cfgcond-t.h @@ -58,6 +58,7 @@ enum cfg_cond_term_type { CCTT_FALSE, CCTT_TRUE, CCTT_PRED, + CCTT_PAREN, // '(' EXPR ')' }; /* keyword for a condition predicate */ @@ -74,6 +75,7 @@ struct cfg_cond_term { int neg; // 0: direct result; 1: negate union { const struct cond_pred_kw *pred; // predicate (function) + struct cfg_cond_expr *expr; // expression for CCTT_PAREN }; }; diff --git a/src/cfgcond.c b/src/cfgcond.c index a96832ff2..fd03196a7 100644 --- a/src/cfgcond.c +++ b/src/cfgcond.c @@ -51,6 +51,9 @@ void cfg_free_cond_term(struct cfg_cond_term **term) if (!term || !*term) return; + if ((*term)->type == CCTT_PAREN) + cfg_free_cond_expr(&(*term)->expr); + free_args((*term)->args); free((*term)->args); ha_free(term); @@ -104,6 +107,32 @@ int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **e return 1; } + /* Try to parse '(' EXPR ')' */ + if (*in == '(') { + int ret; + + t->type = CCTT_PAREN; + t->args = NULL; + + do { in++; } while (*in == ' ' || *in == '\t'); + ret = cfg_parse_cond_expr(&in, &t->expr, err, errptr); + if (ret == -1) + goto fail2; + if (ret == 0) + goto fail0; + + /* find the closing ')' */ + while (*in == ' ' || *in == '\t') + in++; + if (*in != ')') { + memprintf(err, "expected ')' after conditional expression '%s'", *text); + goto fail1; + } + do { in++; } while (*in == ' ' || *in == '\t'); + *text = in; + return 1; + } + /* below we'll likely all make_arg_list() so we must return only via * the label which frees the arg list. */ @@ -123,6 +152,7 @@ int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **e return 1; } + fail0: memprintf(err, "unparsable conditional expression '%s'", *text); fail1: if (errptr) @@ -196,6 +226,9 @@ int cfg_eval_cond_term(const struct cfg_cond_term *term, char **err) break; } } + else if (term->type == CCTT_PAREN) { + ret = cfg_eval_cond_expr(term->expr, err); + } else { memprintf(err, "internal error: unhandled condition term type %d", (int)term->type); }