Scenario
One of those moments again where the search engine did not turn up information which I need. So I hope this article will be helpful to someone out there.
It seems that environment variables in Apache are not being treated equally when SetEnv, SetEnvIf and RewriteRule directives are used. In my case, I want to limit access based on query string but SetEnvIf does not have that attribute to test against. RewriteRule creates an environment variable that is not accessible by Allow/Deny directive (Possibly because Allow/Deny are evaluated before RewriteRule). It makes things complicated when you are going to use environment variables to limit access but it does not work as expected.
Unfortunately, I do not have a solution for you but I hope this information will save you countless hours researching a solution that never exists. But if you do have one, please let me know as I would love to hear from you.
.htaccess Test Configuration
You can skip this part actually. But if you are interested in how the test is done, you can continue reading.
RewriteEngine On # Putting Header before setting the environment variables do not seem to matter. Header always add A_1 "%{A_1}e" Header always add B_1 "%{B_1}e" Header always add C_1 "%{C_1}e" Header always add U_1 "%{U_1}e" Header always add A_2 "%{A_2}e" Header always add B_2 "%{B_2}e" Header always add C_2 "%{C_2}e" Header always add U_2 "%{U_2}e" Header always add A_3 "%{A_3}e" Header always add B_3 "%{B_3}e" Header always add C_3 "%{C_3}e" Header always add U_3 "%{U_3}e" Header always add A_4 "%{A_4}e" Header always add B_4 "%{B_4}e" Header always add C_4 "%{C_4}e" Header always add U_4 "%{U_4}e" Header always add A_5 "%{A_5}e" Header always add B_5 "%{B_5}e" Header always add C_5 "%{C_5}e" Header always add U_5 "%{U_5}e" Header always add S_5 "%{S_5}e" # Test to see if (1) Header can access the environment variables. SetEnv A_1 SetEnv_Works SetEnvIf always_match ^ B_1=SetEnvIf_Works RewriteRule .* - [E=C_1:RewriteRule_Works,NE] # U_1 is not set deliberately. # Test to see if (2) SetEnvIf can access the environment variables. SetEnvIf A_1 ^(.*)$ A_2="$1" SetEnvIf B_1 ^(.*)$ B_2="$1" SetEnvIf C_1 ^(.*)$ C_2="$1" SetEnvIf U_1 ^(.*)$ U_2="$1" # Test to see if (3) RewriteCond can access the environment variables. RewriteCond %{ENV:A_1} ^(.*)$ RewriteRule .* - [E=A_3:"%1",NE] RewriteCond %{ENV:B_1} ^(.*)$ RewriteRule .* - [E=B_3:"%1",NE] RewriteCond %{ENV:C_1} ^(.*)$ RewriteRule .* - [E=C_3:"%1",NE] RewriteCond %{ENV:U_1} ^(.*)$ RewriteRule .* - [E=U_3:"%1",NE] # Test to see if (4) RewriteRule can access the environment variables. RewriteRule .* - [E=A_4:"%{ENV:A_1}",NE] RewriteRule .* - [E=B_4:"%{ENV:B_1}",NE] RewriteRule .* - [E=C_4:"%{ENV:C_1}",NE] RewriteRule .* - [E=U_4:"%{ENV:U_1}",NE] # Test to see if (5) <IfDefine> can access the environment variables. <IfDefine A_1> SetEnv A_5 Can_Access </IfDefine> <IfDefine B_1> SetEnv B_5 Can_Access </IfDefine> <IfDefine C_1> SetEnv C_5 Can_Access </IfDefine> <IfDefine U_1> SetEnv U_5 Can_Access </IfDefine> SetEnv S_5 Unconditionally_Set # Test to see if (6) Allow/Deny can access the environment variables. Options +Indexes Order Deny,Allow Deny from all # To test, only one should be uncommented at any point in time. #Allow from env=A_1 #Allow from env=B_1 #Allow from env=C_1 #Allow from env=U_1 Allow from all # Required for (3) RewriteCond and (4) RewriteRule test to work properly.
Test Result
A_1 SetEnv_Works B_1 SetEnvIf_Works C_1 RewriteRule_Works U_1 (null) A_2 "" B_2 "SetEnvIf_Works" C_2 "" U_2 "" A_3 "" B_3 "SetEnvIf_Works" C_3 "RewriteRule_Works" U_3 "" A_4 "" B_4 "SetEnvIf_Works" C_4 "RewriteRule_Works" U_4 "" A_5 (null) B_5 (null) C_5 (null) U_5 (null) S_5 Unconditionally_Set
Summary
Set Using | (U) Unset Variable |
||||
(A) SetEnv |
(B) SetEnvIf |
(C) RewriteRule |
|||
Accessible By | (1) Header | Yes | Yes | Yes | (null) |
(2) SetEnvIf | No | Yes | No | – | |
(3) RewriteCond* | No | Yes | Yes | – | |
(4) RewriteRule* | No | Yes | Yes | – | |
(5) |
No | No | No | No | |
(6) Allow/Deny |
No | Yes | No | – |
*Will not work if “Deny from all” is in effect.
Excellent References:
http://httpd.apache.org/docs/2.2/env.html
Wow, thanks for this! I was trying to do some advanced variable setting and rewriting and this was extremely useful.
Hey, i feel your pain on this one. I was about to shoot someone until i finally got this working. And you’re right: there’s NO fcking docs on how to PROPERLY do this. So it’s trial and error, and time wasted.
Anyway, i DID find a working example, while trying to setup apache to handle mobile redirects for TheSocialExpo.com and i posted an article about it here:
http://thesocialexpo.com/?a=WCMS_Article_Display&id=13001842310325634&page=1
I came across you while i was trying to solve this problem, so i figured i’d come back and share my findings as well.
Thanks for the information. 🙂
Do you have a copy of that page? It is offline now 🙁 Would like to find a fix for this…
Thanks for this! very useful, exactly what I was looking for.
This was wonderfully useful. It saved me hours. Thanks so much. I’ve brought it to the webfaction community here: http://community.webfaction.com/questions/8694/using-rewritecond-to-simulate-rewritebase-for-hosting-same-app-at-root-and-subdirectory
May be I didn’t get something, but official documentation IMHO clearly explain it.
http://httpd.apache.org/docs/2.2/mod/core.html#ifdefine
“Encloses directives that will be processed only if a test is true >>>at startup<<>>after<<>>If the environment variable you’re setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf.<<<"
May be I didn’t get something, but official documentation IMHO clearly explain it.
http://httpd.apache.org/docs/2.2/mod/core.html#ifdefine
“Encloses directives that will be processed only if a test is true +++at startup+++”
It means any existing system env.vars will be available for IFDefine.
One more way to pass environment variable on start to Apache only instead of setting it system wide it is place file(s) to directory
etc/apache22/envvars.d in the same way as it done in standard Burne shell
#-------------- comments about var ....
MySpecialSuperDuperIP='11.22.33.44'
export MySpecialSuperDuperIP
#=========================
that “MySpecialSuperDuperIP” will be available later for all tests
As of “setenv”:
http://httpd.apache.org/docs/2.2/mod/mod_env.html#setenv
“The internal environment variables set by this directive are set +++after+++ most early request processing directives are run, such as access control and URI-to-filename mapping. +++If the environment variable you’re setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf.+++”
P.S.
Sorry for previous post, forget that wordpress don’t like some characters
Great post. Thanks for it.