DirectoryMatch treats $ as literal instead of an anchor for EOL. This dates back to the initial DirectoryMatch support in 1.3. This is highly unexpected and somewhat limiting, whereas an escaped $ works fine and is natural in PCRE. I intend to remove this behavior in trunk and document it in all releases (when $ is EOL, getting the trailing slash right is not so intuitive wrt e.g. DirectorySlash)
Here is a short httpd.conf to reproduce this bug/feature: Alias /test/ /var/www/test/ <Directory "/var/www/test/projects"> Options Indexes Order deny,allow Deny from all </Directory> <Directory ~ "/var/www/test/projects/$"> Allow from all </Directory> Expected results: - requesting http://localhost/test/projects would give an autoindex - requesting http://localhost/test/projects/subdir would give a 403 Forbidden Actual results: - requesting http://localhost/test/projects gives a 403 Forbidden - requesting http://localhost/test/projects/subdir gives a 403 Forbidden
I may actually understand this now. The operative part of the documentation is this "and sub-directories" part: <DirectoryMatch> and </DirectoryMatch> are used to enclose a group of directives which will apply only to the named directory and sub-directories of that directory, the same as <Directory>. However, it takes as an argument a regular expression. For example: Which is why the $ cannot be matched, since we tell PCRE the string we pass in is not really a string with an end-of-line in it. This is a side of efffect of expecting it to match sub-directories as well. Still seems sensless, as with a reasonable default behavior one can just include subdirectories with the regex itself.
fixed in trunk in r990091, documented in 2.2.x
I've tested the bug in apache 2.2.22 and it has not been fixed. Here is my config file : ====================================================== <FilesMatch ".(php)$"> deny from all </FilesMatch> <Directory ~ "^/home/domain/public_html/en$"> <Files "index.php"> allow from all </Files> </Directory> ====================================================== Expected result : http://domain.com/en/index.php -> 200 OK http://domain.com/en/includes/index.php -> 403 Forbidden http://domain.com/en/hacked-shell/index.php -> 403 Forbidden Actual result : http://domain.com/en/index.php -> 403 Forbidden http://domain.com/en/includes/index.php -> 403 Forbidden http://domain.com/en/hacked-shell/index.php -> 403 Forbidden
This is how it has behaved for years, will not change in 2.2 and earlier as it would/could break working config. Resolved in 2.4