The only way I have found to make this work is by using the following:
<DirectoryMatch ^/home/amoe/opt/httpd/htdocs/[^/]+$>
<Files "test.html">
ExpiresActive on
ExpiresDefault A10
</Files>
</DirectoryMatch>
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:
<DirectoryMatch ^/path/test$>
<DirectoryMatch ^/path/test/$>
<DirectoryMatch /path/test/$>
<Directory ~ ^/path/test$>
<Directory ~ ^/path/test/$>
<Directory ~ /path/test/$>
I found however that if you omit the EOL anchor ($
) then it matches:
<DirectoryMatch ^/path/test/>
<Files "test.html">
ExpiresActive on
ExpiresDefault A10
</Files>
</Directory>
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 sent
It 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:
<DirectoryMatch ^/path/test/(?<MISSINGPART>.+)$>
<Files "test.html">
Header add X-TEST "expr=%{env:MATCH_MISSINGPART}"
</Files>
</DirectoryMatch>
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:
<DirectoryMatch "^/path/test/test.html$">
<Files "test.html">
Header add X-TEST "Match"
</Files>
</DirectoryMatch>
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:
<DirectoryMatch "^/path/test/[^/]+$">
<Files "test.html">
ExpiresActive on
ExpiresDefault A10
</Files>
</DirectoryMatch>
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