Regex in Apache 'if' directive … what'

2019-07-14 19:13发布

问题:

(A possible bug in Apache is now suspected ... see below.)

Here's the statements: (Apache 2.4)

<IfDefine !SERVER_TYPE>
    Define SERVER_TYPE prod
</IfDefine>
<If "${SERVER_TYPE} !~ /prod|demo|test/">   <===error here===
    Error "Define 'SERVER_TYPE' is hosed'"
</If>

Apache complains about the IF:

Cannot parse condition clause: syntax error, unexpected T_OP_NRE, expecting '('

I can guess that T_OP_NRE refers to "negated regular-expression" i.e. "!~" but I can't for the life of me figure out what's the syntax-error in that statement! (And, incidentally, "=~" produces [almost] the same message.)

Apache is recognizing the ${SERVER_TYPE} syntax as I can confirm if I misspell the identifier. The documentation for <DEFINE> expressly states that "${ident}" not "%{ident}" syntax should be used, as I have done.

What's wrong with my syntax, and why does Apache expect a left-parenthesis?


I am cautiously beginning to believe that this is actually a BUG(!) in Apache/2.4.12 because the parse-error only occurs when "${DEFINED_SYMBOL}" is used. It will complain and do all the right things if the symbol is not defined (so, it knows what it's looking at ...), but it gives a nonsensical (to me ...) message as-shown if, and only if, this construct is on the left-hand side.

An apparent workaround is to put the symbol in single quotes, e.g.:

<If "'${SERVER_TYPE}' != /prod/demo/test/">

... but so-far in my testing I don't think that it is matching the regex correctly. In fact, I'm not yet sure what is going on, because the following is considered to be a non-match ("true"):

<If "'prod' !~ /prod|demo|test/">

The regex syntax can be shown to be correct via this Perl one-liner:

perl -e 'my $var = "prod"; if ($var =~ /prod|demo|test/) {print "yes\n";}'

... which prints "yes."


P.S. The "${IDENT}" syntax is correct (versus "%{}", which is not) in the case of a Defined symbol.

回答1:

Try this syntax:

<If "'${SERVER_TYPE}' !~ m#(prod|demo|test)#">
    #Error "Define 'SERVER_TYPE' is hosed"
    RedirectMatch /old /new/
</If>