Karl-André Gagnon Karl-André Gagnon - 7 days ago 7
Apache Configuration Question

RewriteRule changing the URL instead of mapping to a file

I've encounter a weird behavior that I cannot explain nor correct. I need to redirect every

HTTP
request to
HTTPS
. I've use the following code :

RewriteEngine On
RewriteBase /

RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# The query string in the rewrite is for testing purposes
RewriteRule (.*) /index.php?url=$1&%{REQUEST_URI}&http=%{HTTPS} [L]


So far, it works. Then, I need a single page to be
HTTP
, so I added some rewrite conditions :

RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} ^/not-https
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]

RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/not-https
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.php?url=$1&%{REQUEST_URI}&https=%{HTTPS} [L]


Now, here what's happening. For some reasons, when accessing the
/not-https
page, it redirects to
/index.php?url=not-https&/not-https&https=off


Here is a map of GET requests followed by the redirects / displayed URL.

GET: http://example.com/test
-> https://example.com/test with proper $_GET

GET: http://example.com/test.jpg
-> https://example.com/test.jpg with no $_GET (file exists)

GET: https://example.com/not-https
-> http://example.com/not-https
-> http://example.com/index.php?url=not-https&/not-https&https=off


My question is why does the
not-https
change the displayed URL (and therefor, mess up my application)?

Answer

It is happening because value of REQUEST_URI variable is changing to /index.php?... in last rule that makes condition !^/non-https succeed in 2nd rule and makes it execute that rule.

Change your 1st 2 rules to this:

RewriteCond %{HTTPS} on
RewriteCond %{THE_REQUEST} \s/+not-https [NC]
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]

RewriteCond %{HTTPS} off
RewriteCond %{THE_REQUEST} !\s/+not-https [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]

Unlike REQUEST_URI variable THE_REQUEST doesn't change it's value after execution of other internal rewrites.