Apache logical OR & AND conditions with SetEnvIf

Unfortunately, the Apache SetEnvIf module doesn’t support logical conditions, like OR & AND. More specifically, it is not possible to set a variable only if condition1 AND/OR condition2 are verified.

For example, to log all the POST queries made from the loopback interface in a separate log file, you can’t do this:

CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
SetEnvIf Remote_Addr "^127\.0\.0\.1$" AND Request_Method "POST" posting_myself

The first line is valid, it asks the server to log all the requests to the mentioned file, only if the environment variable posting_myself is set.
The second line attemps to set the posting_myself variable if two conditions are met (use of a logical AND), which is not a supported syntax.

On a first attempt to work around this problem, I came up with this:

CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
SetEnv loopback_ip 0
SetEnvIf Remote_Addr "^127\.0\.0\.1$" loopback_ip=1
SetEnvIf Request_Method "POST" posting_myself
SetEnvIf loopback_ip 0 !posting_myself

The first line is unchanged.
The second line unconditionally sets the variable loopback_ip to zero (meaning : false).
The third line sets the same variable to one (“true”) if the requests indeed comes from the loopback IP.
The fourth line sets the variable posting_myself to true if the request method is POST.
Note that at this stage, the posting_myself variable can be true, even if somebody else made the request.
This is taken care of at the last line, where posting_myself is unset if the variable posting_myself is equal to zero (false).
After the last line, we will have the posting_myself variable set only if the request comes from the loopback IP **and** if the request is a POST.

Unfortunately, this doesn’t work either, for a subtle reason : the SetEnv directive is executed after the SetEnvIf directives, according to the Apache documentation. This means that when SetEnv sets loopback_ip to zero, it’s way too late.

So, I came up with this other version to emulate a SetEnvIf logical AND:

CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
SetEnvIf Remote_Addr "^" loopback_ip=0
SetEnvIf Remote_Addr "^127\.0\.0\.1$" loopback_ip=1
SetEnvIf Request_Method "POST" posting_myself
SetEnvIf loopback_ip 0 !posting_myself

This is similar to the previous attempt, only the second line changes: I have to use SetEnIfv, to artificially set loopback_ip to zero, unconditionally. To do this, I use a regex that will always match : “^”. Note that I used Remote_Addr, but I could have used Request_Protocol, Request_URI or anything else: the only important thing is that it always matches and does set loopback_ip to zero.

Now, to emulate a SetEnvIf logical OR, this is way easier:

SetEnvIf Remote_Addr "^192\.168\.0\." my_networks
SetEnvIf Remote_Addr "^127\.0\.0\.1$" my_networks

Here, the variable my_networks will be set if the remote address starts with “192.168.0.” or is “127.0.0.1”. It’s that simple.
Well, I could have used a smarter regex to do this in one line, but it would have ruined my logical OR example! 🙂