Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RewriteCond REQUEST_URI - ^ doesn't work as expected

I'm building a site in codeigniter. I have a series of rewrite conditions & rules in the .htaccess file. The first set of rules turns SSL on or off depending on the first segment of the uri.

Then it loops through again & if it finds a match, redirects the page appropriately. If there is no match, and the uri does NOT start with any of the strings listed, it redirects you to another page. If no conditions are met, it goes to the index page.

The problem is with my first set of rules that turn SSL on & off. I want to specify that the uri must START with admin or secure. But if I add the ^ to the beginning of the string, everything breaks. Here's what I have:

RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/?(admin|secure)
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

RewriteCond %{HTTPS} on 
RewriteCond %{REQUEST_URI} !^/?(admin|secure)
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]

...specific rewrites here
RewriteRule ^secure-form1$ secure/contract/secure-form1 [L]
RewriteRule ^secure$ secure/article/secure [L]

RewriteCond %{HTTP_HOST} ^www.example.com$ 
RewriteCond %{REQUEST_URI} !^/(admin|form|secure|page)/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/page/article/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

If I keep the ^ symbol in the first 2 rewrite conditions (https on & off) then http://www.example.com/secure rewrites to https://www.example.com/index.php/secure/article/secure which is the last rewrite rule. The url actually changes to this in the browser.

If I take the ^ symbol out of the first 2 rewrite conditions, then it goes to the right page. But I do need to specify the beginning of the uri because there are other pages that have "secure" in the middle of the uri (and following a slash) that should NOT use SSL.

I can't figure this one out.

like image 815
user1669830 Avatar asked Sep 17 '12 19:09

user1669830


2 Answers

Try this one:

RewriteCond %{HTTPS} off 
RewriteCond %{HTTP_HOST} ^(.*)$ 
RewriteRule ^/?(admin|secure)$ https://%1/$1 [R=301,L]
like image 117
Ωmega Avatar answered Oct 06 '22 01:10

Ωmega


Old question, I know, but there's another solution that might work better if you really want to stick with the %{REQUEST_URI} condition:

RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_URI} ^/?(admin|secure)$
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

The key difference versus the OP is the inclusion of /? to check for the presence of a forward slash at the beginning of the URI. AFAIK, different Apache installations may or may not include the opening slash in %{REQUEST_URI}.

One benefit of doing it this way is that you can apply the rule to multiple conditions:

RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_URI} ^/?admin$ [OR]
RewriteCond %{REQUEST_URI} ^/?secure$ [OR]
RewriteCond %{REQUEST_URI} ^/?top-secret$
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

For the way I think, this is easier to work with than a long chain of pipe-delimited strings. This comes at the cost of a potential efficiency loss versus a single regex, but there are some other improvements you can make to offset this:

  • Use the lexographically equal operator !=on. If you just use off it gets treated as a regex.

  • Eliminate the RewriteRule pattern, replacing it with a single caret, then use the environment vars %{HTTP_HOST} and %{REQUEST_URI}. This saves the overhead of a longer regex pattern as well as the backrefs.

like image 25
njbair Avatar answered Oct 06 '22 00:10

njbair