This article is the anticipated sequel of “Exploding myths about mod_rewrite. Part 1” published more than a year ago. In this two-volume work (which may well become a three-volume one soon) we try to thoroughly explain each tiny issue/option of Helicon Ape mod_rewrite (also true for Apache) to give you all the knowledge necessary to master it in its full. Part 2 devotes itself to contexts processing order.
So, let’s start the story…
Request processing contexts
In the simplest case there are only two request processing contexts:
- server context (httpd.conf), and
- “root folder” context (.htaccess)
Server context is executed first and after that, if further processing is allowed (no redirect or proxy happened), root folder config is processed (if present).
Picture 1. Server-wide configuration (httpd.conf)
Picture 2. Per-site configuration (.htaccess)
Picture 3. Processing order for the configs on Pictures 1 and 2
***
Now let’s make it more complicated—we’ll have the rules in the root folder and in Directory1. The processing order then becomes:
- /.htaccess
DirectiveA
- /Directory1/.htaccess
DirectiveB
Picture 4. Processing order in case of several .htaccess files
For the request to http://localhost/index.html only the first context is applied, while for http://localhost/Directory1/index.html (and other requests to deeper subfolders) the merged context 1+2 is executed. In our case it’s:
DirectiveA
DirectiveB
Thus, the child context complements and refines the parent one (but not the server one). This is true for nearly all Apache/Ape modules EXCEPT mod_rewrite. It’s one of a kind and behaves differently.
mod_rewrite behavior
Historically, or for convenience purposes, mod_rewrite contexts do not complement but COMPLETELY OVERRIDE each other. So, if we have two configs
- /.htaccess
RewriteRule a b
- /Directory1/.htaccess
RewriteRule b с
the resulting config to be applied to the request will be
RewriteRule b c
and NOT
RewriteRule a b
RewriteRule b с
which may be unobvious for newbies.
For experts! mod_rewrite has an option allowing to change this behavior and inherit the parent rules:
- /.htaccess
RewriteRule a b
- /Directory1/.htaccess
# inherit parent rules RewriteOptions inherit RewriteRule b с
makes up the following merged config:
RewriteRule b с # parent rules are appended to the end of the merged config! RewriteRule a b
<Directory> section
<Directory> section is equivalent in meaning to writing rules in the .htaccess located inside this directory. The only difference is that <Directory> lives in httpd.conf.
If there are both <Directory> section and .htaccess for the same directory, they are merged; if the directives inside them interfere, the .htaccess directives are preferred.
Picture 5. Processing order when there are both .htaccess and <Directory> for the same location
Let’s see how the configs are merged for the request to http://localhost/Directory1/Directory2/index.html if each directory has both <Directory> section and corresponding .htaccess file.
Picture 6. Processing order when there are several .htaccess files and several <Directory> sections which are applicable for the same request
httpd.conf
<Directory C:/inetpub/wwwroot/>
DirectiveDirectoryA
</Directory>
<Directory C:/inetpub/wwwroot/Directory1/>
DirectiveDirectoryB
</Directory>
<Directory C:/inetpub/wwwroot/Directory1/Directory2/>
DirectiveDirectoryС
</Directory>
/.htaccess
DirectiveA
/Directory1/.htaccess
DirectiveB
/Directory1/Directory2/.htaccess
DirectiveC
The following logics is applied to form the merged config:
- First to execute is httpd.conf except for tagged sections:
<Directory>
<DirectoryMatch>
<Files>
<FilesMatch>
<Location>
<LocationMatch>
<VirtualHost> - Distributed config is built up from the following parts:
a. empty context is created;
b. requested URL is divided into parts like:
/
/Directory1/
/Directory1/Directory2/
c. physical path is defined for each virtual directory:
/ —> C:/inetpub/wwwroot/
/Directory1/ —> C:/inetpub/wwwroot/ Directory1/
/Directory1/Directory2/—> C:/inetpub/wwwroot/ Directory1/ Directory2/
d. corresponding section is found for each path;
e. corresponding .htaccess is found for each path
The resulting sequence of directives will be:
DirectiveDirectoryA
DirectiveA
DirectiveDirectoryB
DirectiveB
DirectiveDirectoryC
DirectiveC
Usually directives’ order is not so important, but not in case with mod_rewrite; that’s why understanding the principles of configs merging may dramatically reduce development and debugging times.
Note! <DirectoryMatch> sections are applied not to all parts of the request (see above) but only to the deepest part, and all matches are searched for, for example, if there are two sections:
<DirectoryMatch C:/inetpub/wwwroot/Directory1/Directory*/>
and
<DirectoryMatch C:/inetpub/wwwroot/Directory1/*/>
then both of them get into the merged config.
<VirtualHost> directive
One should remember that everything written inside server context is applied to all requests and for all sites. Sometimes it may be necessary to limit the scope of directive to one or several sites and that’s the case to use <VirtualHost> section.
<VirtualHost> can reside in httpd.conf only. It is merged with server config, i.e. complements it. In case of both .htaccess and <VirtualHost> section for the specific location, the latter has higher priority and can reject server settings for the specific site (in our case localhost).
#httpd.conf
ServerDirective
<VirtualHost localhost>
VirtualHostDirectiveA
</VirtualHost>
Note! mod_rewrite offers another way to restrict scope for the rules to specific host – RewriteCond %{HTTP_HOST}.
The difference is that RewriteCond %{HTTP_HOST} must appear before each RewriteRule, while <VirtualHost localhost> groups all rules for localhost together and affects all of them. Compare:
RewriteCond %{HTTP_HOST} localhost
RewriteRule . index.php [L]
RewriteCond %{HTTP_HOST} localhost
RewriteRule about$ about.php [L]
and
<VirtualHost localhost>
RewriteRule . index.php [L]
RewriteRule about$ about.php [L]
</VirtualHost>
On the other hand, the limitation of <VirtualHost> is that it can’t be used in .htaccess.
Picture 7. Processing order when <VirtualHost> section is present in httpd.conf
Note! <VirtualHost> sections are NOT merged together – if there are several <VirtualHost>s matching the request, the one with the best match is applied. E.g.:
<VirtualHost localhost> <VirtualHost localhost:80> <VirtualHost *>
For request to localhost:80/page.html the second line will be executed, whereas for localhost/page.html the first one will fire.
If <Directory> section is specified inside <VirtualHost> (which is possible), the processing order is as follows: <Directory> section of the main server config is accounted first, then <Directory> inside <VirtualHost> and after all – .htaccess.
Thus, the use of <Directory> section outside <VirtualHost> will lead to application of its (<Directory>) rules to all sites (in case they use this shared folder).
Picture 8. Processing order when there are <VirtualHost> and <Directory> sections as well as .htaccess
<Files> and <FilesMatch> sections
These two behave similar to <DirectoryMatch> but are used for file names, not for the full path.
E.g., for http://localhost/Directory1/index.html#top they will find the correspondence in file system C:\inetpub\wwwroot\Directory1\index.html and will merge all <FilesMatch> sections valid for this file name (e.g. <FilesMatch *.html> and <FilesMatch index.*> will be merged).
Note! <Files> and <FilesMatch> may reside in .htaccess as well!
<Location> and <LocationMatch> sections
Are applied to the corresponding virtual path, which for http://localhost/Directory1/index.html#top is /Directory1/index.html.
Summary
Let’s now put it all together. Here’s the final sequence of sections:
- httpd.conf <Directory>
- httpd.conf <VirtualHost><Directory>
- .htaccess
- .htaccess <Files>
- httpd.conf <DirectoryMatch>
- httpd.conf <VirtualHost><DirectoryMatch>
- httpd.conf <Files>
- httpd.conf <FilesMatch>
- httpd.conf <VirtualHost><Files>
- httpd.conf <VirtualHost><FilesMatch>
- httpd.conf <Location>
- httpd.conf <LocationMatch>
- httpd.conf <VirtualHost><Location>
- httpd.conf <VirtualHost><LocationMatch>
***
Seems every aspect of configs processing has been covered. We understand that this article may look somewhat sophisticated, but we are sure there are enthusiasts who’ll find it helpful.
The that you look over my thoughts! You peer to know a lot of with this, all night . gave them it in the basket as well. There’s no doubt that that you might actually do some photos they are driving the material residential a little, but could, that is amazing web site. An outstanding go through. I’ll easily be back again.
I’m all over this because of this write-up, I absolutely assume this site preferences much more concern. I’ll more than likely wind up being again to find out much more, nice one for that important information.
You’ve made i am detained to get give good results listed here. Very good blog, basically unspent it to get more detailed personal reference!
Thank you for any other informative web site. Where else may I get that kind of info written in such an ideal approach? I have a project that I am just now operating on, and I have been on the look out for such info.
Really nice post. I just stumbled upon your weblog and wanted to say that I’ve genuinely enjoyed surfing around your blog posts. After all I will likely be subscribing to your rss feed and I hope you write once more soon!
I loved your blog and eapecially your post about Exploding myths about mod_rewrite. Part 2. | Helicon Tech Blog. Thank you very very much for your work.
Hello! This is my 1st comment here so I just wanted to give a quick shout out and say I truly enjoy reading your posts. Can you recommend any other blogs/websites/forums that go over the same topics? Thanks for your time!
You have really interesting blog, keep up posting such informative posts!
I just added this web site to my feed reader, excellent stuff. Can not get enough!
Excellent post, just what the doctor ordered.
Great blog. It’s nice to see such an accurate articulation, I’m definitely bookmarking this. Keep up the good work!