Article
mod_rewrite: No More Endless Loops!
If it sounds complicated, don’t worry! Here’s a simplified log file that shows the process:
# 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#2] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/index.php -> index.php
[redir#2] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'index.php'
[redir#2] (2) [per-dir /www/htdocs/] rewrite index.php -> /index.php
[redir#2] (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]
....ad infinitum...
# phase b)
[redir#N] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/index.php -> index.php
[redir#N] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'index.php'
[redir#N] (2) [per-dir /www/htdocs/] rewrite index.php -> /index.php
[redir#N] (1) [per-dir /www/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
This is what happens with versions of Apache prior to the 2.0.45 and 1.3.28 releases.
Maxredirects
The following simplified log file shows what would happen if our example was run under Apache 2.0.45 or 1.3.28:
# 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#2] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/index.php -> index.php
[redir#2] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'index.php'
[redir#2] (2) [per-dir /www/htdocs/] rewrite index.php -> /index.php
[redir#2] (1) [per-dir /www/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
...last...
# phase b)
[redir#10] (3) [per-dir /www/htdocs/] strip per-dir prefix: /www/htdocs/index.php -> index.php
[redir#10] (3) [per-dir /www/htdocs/] applying pattern '(.*)' to uri 'index.php'
[redir#10] (2) [per-dir /www/htdocs/] rewrite index.php -> /index.php
[redir#10] (1) [per-dir /www/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
While the rewrite log may seem the same as before, it’s not. The internal redirections are not continuous, as they stop after 10 attempts. The Web server will not freeze and we will receive a 500 HTTP status error (Internal Server Error).
Our error_log will look like this:
[Mon Jul 21 15:24:27 2003] [error] [client 127.0.0.1] mod_rewrite: maximum number of internal redirects reached. Assuming configuration error. Use 'RewriteOptions MaxRedirects' to increase the limit if neccessary.
This detailed error log will help us to debug our rules quickly and precisely.
Even though we use the same rules as before, our Apache Web server won’t freeze any more. Isn’t it magic?