I have a problem that it seems should be simple. I want to apply a group of configuration directives to a single file (in this case myfile.html
in the DocumentRoot). There may also be subdirectories containing myfile.html
, these should not get the configuration. I also want to do it without using Location
or LocationMatch
.
I came up with the following
DocumentRoot "/home/amoe/opt/httpd/htdocs"
<DirectoryMatch "^/home/amoe/opt/httpd/htdocs$">
<Files "myfile.html">
ExpiresActive on
ExpiresDefault A10
</Files>
</DirectoryMatch>
However, the Expires
header doesn't get set when requesting /myfile.html
. Adding a trailing slash on the DirectoryMatch
seems to make no difference.
You can assume that I want to do this without Location
for academic reasons. (Edit: Also, to quote the documentation, It is important to never use when trying to restrict access to objects in the filesystem.)
The only way I have found to make this work is by using the following:
I believe that the extra
[^/]+
shouldn't be required to get this to work, see below for the full explanation of how I came to this conclusion, and as such I believe this is a bug in Apache.All of the following is based on an Ubuntu 16.04.1 LTS environment running Apache 2.4.23 with test files in these locations:
/path/test/test.html
/path/test/noheader-test.html
/path/test/child/test.html
/path/test/child/grandchild/test.html
Firstly I tried a number of different regex variants, all of which failed to match:
I found however that if you omit the EOL anchor (
$
) then it matches:However this ofcourse matches the
test.html
files in all the subdirectories:/path/test/test.html
- Expires header sent/path/test/noheader-test.html
- no Expires header sent/path/test/child/test.html
- Expires header sent/path/test/child/grandchild/test.html
- Expires header sentIt was as though there was something else in the path that the regex wasn't matching because when I changed the regex to
^/your/path/test/.+$
it matched.Wanting to know what this missing part of the path was I used a regex capture group and the
Header
directive to get Apache to tell me what was missing, like so:This gave the following headers:
/path/test/test.html
-x-test:"test.html"
/path/test/noheader-test.html
- no header sent/path/test/child/test.html
-x-test:"child/test.html"
/path/test/child/grandchild/test.html
-x-test:"child/grandchild/test.html"
This suggests that
DirectoryMatch
is matching the file name too?!On the Apache bug tracker bug 41867 somewhat fits this description so may explain this (I also tested this without the nested
<Files>
directive and the header values remained the same)So to prove it I tried substituting
test.html
into the regex like so:No
X-TEST
header was returned.This did however mean that the regex could be made to match anything that isn't a directory after the directory we're interested in matching, like so:
This gives the header in all the desired places:
/path/test/test.html
- Expires header sent/path/test/noheader-test.html
- no Expires header sent/path/test/child/test.html
- no Expires header sent/path/test/child/grandchild/test.html
- no Expires header sent