I'm trying to implement the following mod_rewrite rule:

host.com/developer/ => host.com/developer/index.py
host.com/developer/branchX => host.com/developer/index.py?branch=branchX
host.com/developer/branchX/commitY => host.com/developer/index.py?branch=branchX&commit=commitY

Currently, the appropriate config section looks like this:

  Options FollowSymLinks
  AllowOverride None
  RewriteEngine on
  RewriteRule ^([^/]+)$                   /$1/index.py                          [L]
  RewriteRule ^([^/]+)/([^/]+)            /$1/index.py?branch=$2                [L]
  RewriteRule ^([^/]+)/([^/]+)/([^/]+)$   /$1/index.py?branch=$2&commit=$3      [L]

However, after the URL has been initially rewritten, an internal redirect occurs and the URL is being rewritten again, ruining it. The process repeats many times and eventually results into a 500 error. The log (timestamps and perdir parts removed):

[..initial] (3) strip per-dir prefix: /home/www/host.com/master/a -> master/a
[..initial] (3) applying pattern '^([^/]+)$' to uri 'master/a'
[..initial] (3) strip per-dir prefix: /home/www/host.com/master/a -> master/a
[..initial] (3)  applying pattern '^([^/]+)/([^/]+)' to uri 'master/a'
[..initial] (2) rewrite 'master/a' -> '/master/index.py?branch=a'
[..initial] (3) split uri=/master/index.py?branch=a -> uri=/master/index.py, args=branch=a
[..initial] (1) internal redirect with /master/index.py [INTERNAL REDIRECT]
[..initial/redir#1] (3) strip per-dir prefix: /home/www/host.com/master/index.py -> master/index.py
[..initial/redir#1] (3) applying pattern '^([^/]+)$' to uri 'master/index.py'
[..initial/redir#1] (3) strip per-dir prefix: /home/www/host.com/master/index.py -> master/index.py
[..initial/redir#1] (3) applying pattern '^([^/]+)/([^/]+)' to uri 'master/index.py'
[..initial/redir#1] (2) rewrite 'master/index.py' -> '/master/index.py?branch=index.py'
[..initial/redir#1] (3) split uri=/master/index.py?branch=index.py -> uri=/master/index.py, args=branch=index.py

How can I fix my rules to prevent the endless internal redirects? Thanks.

Accepted Answer

The problem is that the url you are rewriting to is matched in the next pass. L specifies the last rule but only for this execution of the rules, URLs are processed again under certain circumstances (in this case, internal redirects). The solution is to add a RewriteCond to prevent looping, like this:

RewriteEngine on
RewriteCond %{REQUEST_URI}              !index\.py
RewriteRule ^([^/]+)$                   /$1/index.py                          [L]
RewriteCond %{REQUEST_URI}              !index\.py
RewriteRule ^([^/]+)/([^/]+)            /$1/index.py?branch=$2                [L]
RewriteCond %{REQUEST_URI}              !index\.py
RewriteRule ^([^/]+)/([^/]+)/([^/]+)$   /$1/index.py?branch=$2&commit=$3      [L]
Written by Vinko Vrsalovic
This page was build to provide you fast access to the question and the direct accepted answer.
The content is written by members of the stackoverflow.com community.
It is licensed under cc-wiki