Using FallbackResource with Apache Header Expressions Causes Weirdness

Recently we needed to set one of our Apache servers to output a HTTP header for a specific URL, a simple task right? Well it turns out it can be a right pain...

The server is pretty standard, it's running Apache 2.4.43 passing requests to a PHP application.

Apache has in built functionality to conditionally set headers it's as simple as:

header set X-Header-Name "Header Value" "expr=%{REQUEST_URI} =~ m#^/matching/uri$#"

This simply put this says output a header named X-Header-Name with the value "Header Value" only if the requested URI matches the regex ^/matching/uri$. This didn't nothing though, I changed the regex and replaced it with a straight == but the only time I could get it to match and set a header was with broad patterns like .* or ^/.+.

Next I wanted to know what Apache thought the value of %{REQUEST_URI} was, clearly it was matching against something but maybe mod_rewrite was changing something. So I got Apache to send a header, non conditionally, which contained the value of %{REQUEST_URI} so I could see what it was:

Header set X-Request-URI "%{REQUEST_URI}e"

This returned exactly what I expected the.. requested URI, this made no sense! At this point I started looking at alternatives to %{REQUEST_URI}, and found that I could match against %{THE_REQUEST} but this felt like a work around that probably had issues I hadn't yet run into.

In an attempt to reduce the number of variables I disabled mod_rewrite, this made no difference, so that can be ruled out.

It was as I was putting the kettle on for the third time that something occurred to me. Even with mod_rewrite disabled the application was still being passed requests. And all requests are passed to index.php: low and behold the regex ^/index.php$ matches. This makes for some confusing possibilities. For example with the following code a request to /matching/uri will set the X-Request-URI header:

Header set X-Request-URI "%{REQUEST_URI}e"

So what this all boils down to is that %{REQUEST_URI} != %{REQUEST_URI}e which kind of makes sense (though I'm not exactly sure what the difference is). In an attempt to get the right value I turned my attention to the env function because I knew that the e in %{REQUEST_URI}e stands for environment.

Header set X-Request-URI "%{REQUEST_URI}e"

This didn't work either, it turns out that when using an <if> env('REQUEST_URI') != %{REQUEST_URI}e however this isn't the case when using an inline expression:

Header set X-Header-Name "Header Value" "expr=env('REQUEST_URI'') =~ m#^/matching/uri$#"

This finally works! The docs allude to being treated slightly specially with regard to environment variables:

When environment variables are looked up within an <If> condition, it's important to consider how extremely early in request processing that this resolution occurs.

I am no expert on the order of Apaches request processing so I'll leave working that one out as an exercise to the reader

Conclusion

Apache is weird.

If you are using mod_dir's FallbackResource to pass requests to your application and want to access REQUEST_URI in expressions (which now I write it sounds really niche) you need to use env('REQUEST_URI') otherwise you will get the value of the application entry point (eg index.php)

Popular Reads

Subscribe

Keep up to date

Please provide your email address
Please provide your name
Please provide your name
No thanks