Forum Moderators: phranque

Message Too Old, No Replies

RewriteRule Redirect Cycle

How to avoid it?

         

enivid

7:44 am on Apr 28, 2009 (gmt 0)

10+ Year Member



I have a redirect cycle problem and I don't know how to solve it.

I have a http://www.example.com/file.php on my site and I want it to be accessible by http://www.example.com/File. At the same time I want all visitors coming by "http://www.example.com/file.php" address to be 301-redirected to http://www.example.com/File.

What I do is:

RewriteEngine On
RewriteRule file.php File [R=301]
RewriteRule File file.php [L]

How do I remove the redirect cycle from here? Is it possible at all?

jdMorgan

4:40 pm on Apr 28, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You need to check to be sure that the request for "file.php" is coming from a client (browser or robot) before you redirect it. Otherwise, the server will re-run mod_rewrite after executing your internal rewrite (second rule) from "File" to "file.php", find that the rewritten request for file.php now matches the first RewriteRule, and redirect the request back to "File". The request now matches the second rule again, so you end up with an 'infinite' loop.

Easiest fix:


RewriteEngine on
#
# Externally redirect only direct client requests for "file.php" back to "File"
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /file\.php(\?[^\ ]*)?\ HTTP/
RewriteRule ^file\.php$ http://www.example.com/File [R=301,L]
#
# Internally rewrite requests for "File" to "file.php"
RewriteRule ^File$ /file.php [L]

Note the several differences between the syntax for external redirects and internal rewrites. Note also that [L] is used on all rules, as it should be unless you know why you don't want to use it. Note that both patterns have been fully-anchored, so that exact matches are required; This may not be what you want, but in most cases, the start anchor "^" should always be used to avoid unexpected matches and the resulting problems. Basically, make the patterns as specific as possible.

The pattern shown for THE_REQUEST matches the request line sent by the client to your server, exactly as it appears in your raw server access log.

A typical request would look like this:

GET /file.php?some_name=some_value&another_name=another-value HTTP/1.1

So, it is necessary to account for the "GET", a space, the URL-path "/file.php" plus an optional query string, then a required space, and finally the "HTTP/" on the end. Note that the pattern is not end-anchored, because the request might contain "HTTP/1.0", "HTTP/1.1", or (at some time in the future) "HTTP/1.2" or "HTTP/2.0", etc.

It is actually not strictly necessary to match anything past the "file.php", but again, I recommend making patterns as specific as possible to avoid unexpected matches and results... And to an extent, including the extra stuff on the end of the request makes the code a bit more 'self-documenting.'

Jim

[edited by: jdMorgan at 4:44 pm (utc) on April 28, 2009]

enivid

5:12 pm on Apr 28, 2009 (gmt 0)

10+ Year Member



Thank you very much!

g1smd

7:14 pm on Apr 28, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



One specific point is that the redirect also fixes the canonical domain name as a part of what it does.

That avoids an unexpected redirection chain.