[mod-rewrite] how to use "AND", "OR" for RewriteCond on Apache?

Is this how to use AND, OR for RewriteCond on Apache?

rewritecond A [or]
rewritecond B
rewritecond C [or]
rewritecond D
RewriteRule ... something

becomes if ( (A or B) and (C or D) ) rewrite_it.

So it seems like "OR" is higher precedence than "AND"? Is there a way to easily tell, like in the (A or B) and (C or D) syntax?

This question is related to mod-rewrite apache-config

The answer is


After many struggles and to achive a general, flexible and more readable solution, in my case I ended up saving the ORs results into ENV variables and doing the ANDs of those variables.

# RESULT_ONE = A OR B
RewriteRule ^ - [E=RESULT_ONE:False]
RewriteCond ...A... [OR]
RewriteCond ...B...
RewriteRule ^ - [E=RESULT_ONE:True]

# RESULT_TWO = C OR D
RewriteRule ^ - [E=RESULT_TWO:False]
RewriteCond ...C... [OR]
RewriteCond ...D...
RewriteRule ^ - [E=RESULT_TWO:True]

# if ( RESULT_ONE AND RESULT_TWO ) then ( RewriteRule ...something... )
RewriteCond %{ENV:RESULT_ONE} =True
RewriteCond %{ENV:RESULT_TWO} =True
RewriteRule ...something...

Requirements:


Having trouble wrapping my head around this.

Have a rewrite rule with four conditions.
The first three conditions A, B, C are to be AND which is then OR with D

RewriteCond A       true
RewriteCond B       false
RewriteCond C [OR]  true
RewriteCond D       true
RewriteRule ...

But that seems to be an expression of A and B and (C or D) = false (don't rewrite)

How can I get to the desired expression? (A and B and C) or D = true (rewrite)

Preferably without using the additional steps of setting environment variables.

HELP!!!


This is an interesting question and since it isn't explained very explicitly in the documentation I'll answer this by going through the sourcecode of mod_rewrite; demonstrating a big benefit of open-source.

In the top section you'll quickly spot the defines used to name these flags:

#define CONDFLAG_NONE               1<<0
#define CONDFLAG_NOCASE             1<<1
#define CONDFLAG_NOTMATCH           1<<2
#define CONDFLAG_ORNEXT             1<<3
#define CONDFLAG_NOVARY             1<<4

and searching for CONDFLAG_ORNEXT confirms that it is used based on the existence of the [OR] flag:

else if (   strcasecmp(key, "ornext") == 0
         || strcasecmp(key, "OR") == 0    ) {
    cfg->flags |= CONDFLAG_ORNEXT;
}

The next occurrence of the flag is the actual implementation where you'll find the loop that goes through all the RewriteConditions a RewriteRule has, and what it basically does is (stripped, comments added for clarity):

# loop through all Conditions that precede this Rule
for (i = 0; i < rewriteconds->nelts; ++i) {
    rewritecond_entry *c = &conds[i];

    # execute the current Condition, see if it matches
    rc = apply_rewrite_cond(c, ctx);

    # does this Condition have an 'OR' flag?
    if (c->flags & CONDFLAG_ORNEXT) {
        if (!rc) {
            /* One condition is false, but another can be still true. */
            continue;
        }
        else {
            /* skip the rest of the chained OR conditions */
            while (   i < rewriteconds->nelts
                   && c->flags & CONDFLAG_ORNEXT) {
                c = &conds[++i];
            }
        }
    }
    else if (!rc) {
        return 0;
    }
}

You should be able to interpret this; it means that OR has a higher precedence, and your example indeed leads to if ( (A OR B) AND (C OR D) ). If you would, for example, have these Conditions:

RewriteCond A [or]
RewriteCond B [or]
RewriteCond C
RewriteCond D

it would be interpreted as if ( (A OR B OR C) and D ).