Mobile app version of vmapp.org
Login or Join
Tiffany637

: Conflicting mod_rewrite rules The Background I run a university club website which has multiple domains, let's say meow.co.uk, foo.uni.ac.uk/bar/meow/ as two relevant cases. (When I upload files

@Tiffany637

Posted in: #Htaccess #ModRewrite

The Background

I run a university club website which has multiple domains, let's say meow.co.uk, foo.uni.ac.uk/bar/meow/ as two relevant cases. (When I upload files using an FTP client, it's the latter that I navigate to.) With my htaccess file, I'm trying to:


Redirect from all other domains to meow.co.uk, the preferred domain, e.g. foo.uni.ac.uk/bar/meow/page.html --> meow.co.uk/page.html
Remove a trailing slash from files that aren't directories, otherwise the user will get an internal server error, e.g. meow.co.uk/page/ --> meow.co.uk/page
Clean the URLs:


Display the contents of the html file if the .html extension is left out, e.g. navigating to meow.co.uk/page shows the same page as navigating to meow.co.uk/page.html
Remove the .html extension from the address bar, e.g. meow.co.uk/page.html --> meow.co.uk/page



The .htaccess

ErrorDocument 404 /errors/404.html
#redirect from the other domains to meow.co.uk
RewriteCond %{HTTP_HOST} !^(www.)?meow.co.uk$ [NC]
RewriteRule ^(.*)$ meow.co.uk/ [R=302]
#remove trailing slash if not a directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ / [R=302]
#meow .co.uk/page will display the contents of meow.co.uk/page.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ .html [L,QSA]

#302 from meow.co.uk/page.html to meow.co.uk/page
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9} /.*.html HTTP/
RewriteRule ^(.*).html$ / [R=302,L]


What works


foo.uni.ac.uk/bar/meow/page --> meow.co.uk/page
meow.co.uk/page/ --> meow.co.uk/page
meow.co.uk/page shows page.html and meow.co.uk/page.html --> meow.co.uk/page


What doesn't work


Expected: foo.uni.ac.uk/bar/meow/page/ --> meow.co.uk/page


Actual: --> foo.uni.ac.uk/http://meow.co.uk/page/

Expected: foo.uni.ac.uk/bar/meow/page.html --> meow.co.uk/page


Actual: --> foo.uni.ac.uk/http://meow.co.uk/page



Why don't these work?

10.01% popularity Vote Up Vote Down


Login to follow query

More posts by @Tiffany637

1 Comments

Sorted by latest first Latest Oldest Best

 

@Ann8826881

tl;dr You need the L flag on your redirects, ie. [R=302,L].


RewriteRule ^(.*)$ meow.co.uk/ [R=302]


Bit of an aside, but... the RewriteRule pattern should be ^bar/meow/(.*) (as mentioned in my answer on your other question), otherwise you won't get the working redirects that you've stated.

For external redirects you generally want to use the L (LAST) flag (briefly mentioned in comments on the other question). Since when you redirect you normally want the rewrite processing to stop and redirect immediately.

This would seem to be the problem here, without the L flag, the rewriting continues and matches the next RewriteRule which further rewrites the request, resulting in a malformed redirect.

This is what's happening in the cases that do not work:

Request: foo.uni.ac.uk/bar/meow/page/
The first RewriteRule matches against the URL-path (less the directory prefix, which is simply the / - slash)

bar/meow/page/ >>> meow.co.uk/page/ (should stop here)

But the second RewriteRule matches the result of the previous rewrite:
meow.co.uk/page/ >>> foo.uni.ac.uk/http://meow.co.uk/page/

Request: foo.uni.ac.uk/bar/meow/page.html
bar/meow/page.html >>> meow.co.uk/page.html (should stop here)

But the last RewriteRule now matches...
meow.co.uk/page.html >>> foo.uni.ac.uk/http://meow.co.uk/page

So, both your earlier redirects need the L flag ie. [R=302,L]. Ironically, the only place you don't need the L flag is where you have used it - in your last redirect! But it is good practise to include it anyway.



Note also, that generally, external redirects should always come before internal rewrites. Whilst your rules work ok, they would be slightly more efficient (and more logical) if you had your internal rewrite last. Currently the last RewriteRule will always match, but the RewriteCond directive prevents it being triggered.

If you reverse these rules then the RewriteRule will only match when needed:
#302 from meow.co.uk/page.html to meow.co.uk/page
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9} /.*.html HTTP/
RewriteRule ^(.*).html$ / [R=302,L]
#meow .co.uk/page will display the contents of meow.co.uk/page.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule (.+) .html [L]





#redirect from the other domains to meow.co.uk
RewriteCond %{HTTP_HOST} !^(www.)?meow.co.uk$ [NC]
RewriteRule ^(.*)$ meow.co.uk/ [R=302]


Another slight problem is that your site would seem to still be accessible by both meow.co.uk and meow.co.uk. You should probably have a second rule to resolve this and redirect one to the other:

RewriteCond %{HTTP_HOST} =www.meow.co.uk [NC]
RewriteRule (.*) meow.co.uk/ [R=302,L]


The = prefix on the CondPattern makes it an exact string match, it is no longer a regex (which is why the dots are not escaped).

10% popularity Vote Up Vote Down


Back to top | Use Dark Theme