7

Preface

I'm very much a neophyte regarding webservers. I'm setting up an Apache2 server and currently poring over the documentation.

I noticed that the <Directory>, <Location>, and <Files> directives each have a corresponding <*Match> directive: <DirectoryMatch>, <LocationMatch> and <FilesMatch> respectively. The difference on the surface is apparent enough:

  • <*Match> directives take a regular expression as an argument
  • Non-Match directives take a plain string or shell-style glob as their argument.

Curiously, the non-Match directives can also be given a regular expression as their argument if it is preceded by a '~'. Thus, the following two lines ought to be identical:

# From the Apache2 docs
<Directory ~ "^/www/[0-9]{3}"> ... </Directory>
<DirectoryMatch "^/www/[0-9]{3}"> ... </DirectoryMatch>

Questions

What I'd like to know is whether or not there are any subtle or key differences to be aware of that Apache's core docs do not mention. The <DirectoryMatch> section does mention one subtle difference:

Compatibility

Prior to 2.3.9, this directive implicitly applied to sub-directories (like <Directory>) and could not match the end of line symbol ($). In 2.3.9 and later, only directories that match the expression are affected by the enclosed directives.

Beyond that, I would like to know:

  • Are there any other differences between the Match and non-Match directives?
  • Which directive is more preferable when a regular expression is required?
  • Any other information you feel is pertinent?

Notes

  • <DirectoryMatch> and <Directory "~"> are on the same merge level
  • While not explicitly mentioned, <Directory "~"> can use named groups and backreferences, just like <DirectoryMatch>.
2

The difference is in the parameter type allowed:

<Directory directory-path> ... </Directory>

vs

<DirectoryMatch regex> ... </DirectoryMatch>

DirectoryMatch is a superset, feature wise as you will be able to code any path as a regex. The opposite is not true.

Directory ~ is probably a late addition. Based on a commit found in repository (commit 07b82419b59d1bb7ba8860b86a2d381d5d1090bc on November 1996), this case was added in Apache 1.2

DirectoryMatch was then added in Apache 1.3 (commit a318749e61fda612e883a9ea594459a4517166b8 on July 1997) with a richer set of features.

And the documentation updated in that commit clearly said you should favor the match version when using a regex:

    &lt;Directory ~ &quot;^/www/.*/[0-9]{3}&quot;&gt;
 </pre>

-would match directories in /www/ that consisted of three numbers.<p>
+would match directories in /www/ that consisted of three numbers. In
+Apache 1.3 and later, it is reccomended to use
+<a href="#directorymatch">&lt;DirectoryMatch&gt;</a> instead.<p>

(this "it is recommended to use DirectoryMatch" statement was removed later in a commit on August 1997)

DirectoryMatch is still superior because Directory ~ are handled only after "normal" Directory statements, and DirectoryMatch allows you to capture data that you can subsequently use.

When you are using a regex, I would favor the Match variant as it makes it clearer that you are using a regular expression, and not a specific case of the non match variant. Besides the small differences above, it would however not make a huge difference.

UPDATE in fact probably no changes in result since the code does the same:

static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
{

...

    if (!strcmp(cmd->path, "~")) {
        cmd->path = ap_getword_conf(cmd->pool, &arg);
        if (!cmd->path)
            return "<Directory ~ > block must specify a path";
        r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
        if (!r) {
            return "Regex could not be compiled";
        }
    }
    else if (thiscmd->cmd_data) { /* <DirectoryMatch> */
        r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
        if (!r) {
            return "Regex could not be compiled";
        }
    }

So exact same call to r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE); in both cases.

  • 2
    "DirectoryMatch is a superset" - although the OP is specifically comparing <Directory ~ and <DirectoryMatch, not <Directory. Until Apache 2.3.9, <Directory ~ was arguably the superset because it supported the $ regex anchor, whereas <DirectoryMatch did not. (This may have also been why the recommendation to use DirectoryMatch was removed in the earlier docs?) – MrWhite Mar 22 '18 at 20:04
  • 2
    "DirectoryMatch is still superior because Directory ~ are handled only after "normal" Directory statements, and DirectoryMatch allows you to capture data that you can subsequently use." - but as noted by the OP, these directives are the same in both these respects. – MrWhite Mar 22 '18 at 20:07
  • 1
    I agree that DirectoryMatch is easier to read and therefore preferable (over Directory ~). Whilst the docs don't explicitly state this, DirectoryMatch is used in all recent examples (eg. on the Config Sections page) and Directory ~ never gets a mention. The docs do, however, explicitly state that the similarly named LocationMatch and FilesMatch are preferable over the corresponding ~ version of these directives. – MrWhite Mar 22 '18 at 20:20
  • @MrWhite DirectoryMatch did not support the $ anchor before Apache 2.3.9? The commits I found are related to Apache 1.2/1.3, so far before. – Patrick Mevzek Mar 22 '18 at 20:30
  • 1
    Yes, as stated by the OP (from the 2.4 docs), whereas early examples of <Directory ~ even included the end-of-string anchor. Yes, I see those commits are from 1.2/1.3 - good digging! :) It's also stated in the Apache 1.3 docs when DirectoryMatch was introduced. There were also changes in Apache 1.3 (from 1.2) with regards to how the regex containers (ie. <Directory ~ and the just introduced <DirectoryMatch) were merged. – MrWhite Mar 22 '18 at 20:45
1

Are there any other differences between the Match and non-Match directives?

Not strictly a difference between the two regex versions (<Directory ~ and <DirectoryMatch), but some directives, such as AllowOverride and AllowOverrideList, are only permitted in a plain (non-regex) <Directory> container. So, that excludes both <Directory ~ and <DirectoryMatch.

Reference:
https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride

Only available in <Directory> sections
AllowOverride is valid only in <Directory> sections specified without regular expressions, not in <Location>, <DirectoryMatch> or <Files> sections.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.