Article
mod_rewrite: No More Endless Loops!
RewriteOptions
So our Web server won’t freeze any more… but why did the internal redirections stop after 10 redirects? This is where the RewriteOptions directive and maxredirects option come into play.
By default (i.e. if you don’t declare it), maxredirects is set to:
RewriteOptions maxredirect=10
This directive will force the rewrite engine to stop after 10 internal redirections as, after that time, we’re probably in an endless loop.
If the figure of 10 redirects is too high, you can change it to a lower value. For example:
RewriteOptions maxredirect=3
Our log file would then look like this:
# phase a)
[] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/path/to/ -> path/to/
[] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'path/to/'
[] (2) [per-dir /www/htdocs/] rewrite path/to/ -> /index.php
[] (1) [per-dir /www/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
# phase b)
[redir#1] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/index.php -> index.php
[redir#1] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'index.php'
[redir#1] (2) [per-dir /www/htdocs/] rewrite index.php -> /index.php
[redir#1] (1) [per-dir /www/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
# phase b)
[redir#3] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/index.php -> index.php
[redir#3] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'index.php'
[redir#3] (2) [per-dir /www/htdocs/] rewrite index.php -> /index.php
[redir#3] (1) [per-dir /www/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
...stop
Remember that the maxredirect option helps control a deliberate mistake in the rules we created. It will not fix the mistake, but it will stop it freezing our Web server.
This is good for both hosting companies and mod_rewrite users.
Conclusions
Last but not least, what can we do to correct the rules we used in the example? We need to use this rule instead:
RewriteRule .* index.php [L]
The difference is that, in the amended rule, index.php does not begin with a slash. In the latter case mod_rewrite is clever enough to prevent endless-loops, as it sees that the original request of index.php is the same as the internal redirection to index.php, so it won’t perform the redirection. This can be seen in the following log file:
# phase a)
[] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/path/to/ -> path/to/
[] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'path/to/'
[] (2) [per-dir /www/htdocs/] rewrite path/to/ -> index.php
[] (3) [per-dir /www/htdocs/] add per-dir prefix: index.php -> /www/htdocs/index.php
[] (2) [per-dir /www/htdocs/] strip document_root prefix: /www/htdocs/index.php -> /index.php
[] (1) [per-dir /www/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
# phase b)
[redir#1] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/index.php -> index.php
[redir#1] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'index.php'
[redir#1] (2) [per-dir /www/htdocs/] rewrite index.php -> index.php
[redir#1] (3) [per-dir /www/htdocs/] add per-dir prefix: index.php -> /www/htdocs/index.php
# Smart check that will avoid the endless loops
[redir#1] (1) [per-dir /www/htdocs/] initial URL equal rewritten URL: /www/htdocs/index.php [IGNORING REWRITE]
Interesting, isn't it ?
If you have any questions regarding Apache and/or mod_rewrite please visit SitePoint’s Apache forum.
Bibliography
- Change log for Apache 2.0
- Change log for Apache 1.3
- mod_rewrite RewriteOptions directive
- Apache mod_rewrite FAQ
- SitePoint's Apache forum