6

I am using code igniter, our server is behind some funky config.

I want certian pages to be behind https, certian pages to be behind http, and others I don't care about.

So below is my setup,

  • If I go to http://test.example.com (which has a call to disable_ssl()) the page loads fine
  • If I go to https://test.example.com/login (which has a call to require_ssl()) the page loads fine.
  • If I go the http://test.example.com/login I get redirected to the https version. which is good.
  • If I go to https://test.example.com then I get hit with a redirect loop... For some reason the header keeps getting set to https instead of http, even though I explicitly write http.

My $_SERVER array on an http request looks like looks like

Array
(
    [REDIRECT_STATUS] => 200
    [HTTP_HOST] => test.example.com:80
    [HTTP_X_REAL_IP] => 119.224.22.142
    [HTTP_X_FORWARDED_FOR] => 119.224.22.142
    [HTTP_X_URL_SCHEME] => http
    [HTTP_CONNECTION] => close
    [HTTP_CACHE_CONTROL] => max-age=0
    [HTTP_USER_AGENT] => Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8
    [HTTP_ACCEPT_ENCODING] => gzip,deflate,sdch
    [HTTP_ACCEPT_LANGUAGE] => en-US,en;q=0.8,en-NZ;q=0.6
    [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.3
    [HTTP_COOKIE] => [...]
    [PATH] => /usr/local/bin:/usr/bin:/bin
    [SERVER_SIGNATURE] => 
Apache/2.2.14 (Ubuntu) Server at test.example.com Port 8080


    [SERVER_SOFTWARE] => Apache/2.2.14 (Ubuntu)
    [SERVER_NAME] => test.example.com
    [SERVER_ADDR] => 127.0.0.1
    [SERVER_PORT] => 8080
    [REMOTE_ADDR] => 127.0.0.1
    [DOCUMENT_ROOT] => /var/www
    [SERVER_ADMIN] => webmaster@localhost
    [SCRIPT_FILENAME] => /var/www/index.php
    [REMOTE_PORT] => 54833
    [REDIRECT_URL] => /
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.0
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /
    [SCRIPT_NAME] => /index.php
    [PATH_INFO] => /
    [PATH_TRANSLATED] => redirect:/index.php/
    [PHP_SELF] => /index.php/
    [PHP_AUTH_USER] => ******
    [PHP_AUTH_PW] => ******
    [REQUEST_TIME] => 1308972068
)

and on a https request it looks like

Array
(
    [REDIRECT_STATUS] => 200
    [HTTP_HOST] => test.example.com:443
    [HTTP_X_REAL_IP] => 119.224.22.142
    [HTTP_X_FORWARDED_FOR] => 119.224.22.142
    [HTTP_X_URL_SCHEME] => https
    [HTTP_X_FORWARDED_PROTO] => https
    [HTTP_CONNECTION] => close
    [HTTP_USER_AGENT] => Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8
    [HTTP_ACCEPT_ENCODING] => gzip,deflate,sdch
    [HTTP_ACCEPT_LANGUAGE] => en-US,en;q=0.8,en-NZ;q=0.6
    [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.3
    [HTTP_COOKIE] => [...]
    [PATH] => /usr/local/bin:/usr/bin:/bin
    [SERVER_SIGNATURE] => 
Apache/2.2.14 (Ubuntu) Server at test.example.com Port 8080


    [SERVER_SOFTWARE] => Apache/2.2.14 (Ubuntu)
    [SERVER_NAME] => test.example.com
    [SERVER_ADDR] => 127.0.0.1
    [SERVER_PORT] => 8080
    [REMOTE_ADDR] => 127.0.0.1
    [DOCUMENT_ROOT] => /var/www
    [SERVER_ADMIN] => webmaster@localhost
    [SCRIPT_FILENAME] => /var/www/index.php
    [REMOTE_PORT] => 54841
    [REDIRECT_URL] => /
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.0
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /
    [SCRIPT_NAME] => /index.php
    [PATH_INFO] => /
    [PATH_TRANSLATED] => redirect:/index.php/
    [PHP_SELF] => /index.php/
    [PHP_AUTH_USER] => ********
    [PHP_AUTH_PW] => ********
    [REQUEST_TIME] => 1308972250
)

and my .htaccess looks like

Options +FollowSymlinks
RewriteEngine on

RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ %1/$1 [R=301,L]


RewriteCond $1 !^(index\.php|robots\.txt|favicon\.ico|css|images|js)
RewriteRule ^(.*)$ index.php/$1 [L] 

So at the very top of my index.php I have

$_SERVER['SERVER_PORT'] = explode(':', $_SERVER['HTTP_HOST']);
$_SERVER['HTTP_HOST'] = $_SERVER['SERVER_PORT'][0];
$_SERVER['SERVER_PORT'] = $_SERVER['SERVER_PORT'][1];
if($_SERVER['SERVER_PORT'] == 443)
  $_SERVER['HTTPS'] = 'On';
else
  $_SERVER['HTTPS'] = 'Off';

And on pages where I want HTTPS I call

function require_ssl(){
    if($_SERVER['HTTPS'] == 'Off') {
        $host = explode(':', $_SERVER['HTTP_HOST']);
        header('location: https://' . $host[0] . $_SERVER['REQUEST_URI']);
        exit;
    }
}

And on pages where I want only HTTP I call

function disable_ssl(){
    if($_SERVER['HTTPS'] == 'On') {
        $host = explode(':', $_SERVER['HTTP_HOST']);
        header('location: http://' . $host[0] . $_SERVER['REQUEST_URI']);
        exit;
    }
}
Hailwood
  • 89,623
  • 107
  • 270
  • 423
  • 4
    If you turn on rewrite logging at a 3+ level (http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewritelog) it'll show you exactly what the engine is doing to the requested url. – Marc B Jun 28 '11 at 17:31

4 Answers4

5

So, after hours of painful debugging we finally worked out the issue.

Nginx
Yep, the load balancer was doing it's own redirects.

In the nginx setup this line existed proxy_redirect http:// https://;

So, what was happening?

Well, My code was saying "this page should not be https, redirect"
Then nginx was saying "this request is not https, redirect"
Then my code was...
boom redirect loop.

So, by changing proxy_redirect http:// https://; to proxy_redirect Off; we fixed the problem :)

Hailwood
  • 89,623
  • 107
  • 270
  • 423
  • We've addressed the accurate fix for Nginx here http://www.sonassi.com/knowledge-base/magento-kb/magento-https-redirect-loop/ This avoids the necessity to have that code in your `index.php` file – Ben Lessani Mar 24 '12 at 19:07
  • @Hailwood : I'm facing the same issue. My login page must be https but it is getting redirected to http. But my proxy_redirect is already set to off. Any ideas on how I could further investigate? – nish Oct 17 '13 at 06:12
  • @Hailwood : Hi, I am faing the same issue, after I installed ssl certificate i cannot access the Admin Panel and the page goes in a redirect loop, Can U tell me where do i make the above changes ? – Mohan Nov 12 '14 at 07:58
1

The function that you posted for disable_ssl() shows:

if($_SERVER['HTTPS'] == '0n') {

Is the 0 ('zero') a copy/paste error? I assume that you meant:

if($_SERVER['HTTPS'] == 'On') {

If I'm following your logic correctly, this function is invoked when you goto https://test.example.com, and so if this typo exists, it is probably not doing what you think it should.

johnvey
  • 5,101
  • 1
  • 19
  • 14
1

We've addressed the accurate fix for Nginx (and other reverse proxies) here:

http://www.sonassi.com/knowledge-base/magento-kb/magento-https-redirect-loop/

This avoids the necessity to have that code in your index.php file. All you needed to do was add this to your Nginx config,

fastcgi_param  HTTPS on;
Ben Lessani
  • 2,141
  • 14
  • 16
0

You might consider using .htaccess rules instead, something like:

RewriteCond %{SERVER_PORT} 80 
RewriteCond %{REQUEST_URI} (optional pattern additional url matching)
RewriteRule ^(.*)$ https://test.example.com/$1 [L]

if you want to force http just replace 80 with 443 and https with http.

WebChemist
  • 4,393
  • 6
  • 28
  • 37
  • I had thought about that, but this gives me more control, as I can enable/disable ssl when I need to. – Hailwood Jun 29 '11 at 23:20