Why does redirecting from HTTPS to HTTP fail in th

2019-07-16 12:17发布

问题:

When the user is on HTTP, I can successfully redirect him to a HTTPS (SSL) variant like so:

redirect_to { protocol: 'https://', domain: 'ssl.tld' }

However, when I want to do the reverse, it creates an infinite redirection loop. I've tried several variants. To mention some:

redirect_to { protocol: 'http://', domain: 'nonssl.tld' }

redirect_to "http://nonssl.tld#{request.fullpath}"

The loop, according to the log:

000.000.000.000 - - [21/Apr/2016:18:50:04 -0100] "GET /en HTTP/1.1" 302 887 "https://ssl.tld/en/users/sign_in" "= THE_USER_AGENT_HERE"

Whereas https://ssl.tld/en/users/sign_in apparantly is the referrer/the current page before redirection.

I wonder why the GET shows a path as opposed to a URL - especially given that redirect_to "http://nonssl.tld#{request.fullpath}" should explicitly be considered an absolute URL, according to the docs.


UPDATE Here is the relevant part from the application_controller's before_action:

exceptions = ['errors', 'subscriptions', 'users']
ssl_is_mandatory = ! exceptions.include?(controller_name)
currently_on_ssl = request.ssl?

if currently_on_ssl
  if !current_user && !ssl_is_mandatory
    logger.debug "#{__method__}: Visitor currently on SSL, but SSL not desired. Redirecting to non_ssl"
    redirect_to "http://my.domain#{request.fullpath}"
  end

else
  if current_user || ssl_is_mandatory
    logger.debug "#{__method__}: Currently on no-SSL, but user in session or SSL mandatory. Redirecting to ssl"
    redirect_to { protocol: 'https://', domain: 'my.ssldomain' }
  end
end

UPDATE: As requested by Marc in the comments, here are the request headers:

Request headers for SSL domain

# curl -s -I https://SSL.tld
HTTP/1.1 302 Found
Date: Mon, 02 May 2016 23:33:34 GMT
Server: Apache/2.2.15 (Red Hat)
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: no-cache
X-Request-Id: 8d182c5e-cec6-46c0-b845-eafe2d313fe2
X-Runtime: 0.005948
X-Powered-By: Phusion Passenger 4.0.18
Location: https://SSL.tld/en
Content-Length: 895
Status: 302 Found
Content-Type: text/html; charset=utf-8
Set-Cookie: GEAR=local-554148915973ca816300021b; path=/

# curl -s -I https://SSL.tld/en
HTTP/1.1 200 OK
Date: Mon, 02 May 2016 23:33:52 GMT
Server: Apache/2.2.15 (Red Hat)
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
ETag: "acf44db83201e4da25659ab8545936b3"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 671d9407-0cdd-4401-9537-abff660e1b18
X-Runtime: 0.078496
X-Powered-By: Phusion Passenger 4.0.18
Content-Length: 10964
Status: 200 OK
Content-Type: text/html; charset=utf-8
Cache-control: private
Set-Cookie: GEAR=local-554148915973ca816300021b; path=/
Vary: Accept-Encoding

Request headers for NONSSL domain

# curl -s -I http://NONSSL.tld
HTTP/1.1 302 Found
Date: Mon, 02 May 2016 23:34:16 GMT
Server: Apache/2.2.15 (Red Hat)
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: no-cache
X-Request-Id: 9f7b4341-0489-48fa-b15d-b45f787db690
X-Runtime: 0.007811
X-Powered-By: Phusion Passenger 4.0.18
Location: http://NONSSL.tld/en
Content-Length: 873
Status: 302 Found
Content-Type: text/html; charset=utf-8
Set-Cookie: GEAR=local-554148915973ca816300021b; path=/

# curl -s -I http://NONSSL.tld/en
HTTP/1.1 200 OK
Date: Mon, 02 May 2016 23:34:47 GMT
Server: Apache/2.2.15 (Red Hat)
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
ETag: "05294c86e7f806ebf2e90c5f52fd7497"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 25a0ac8c-6cba-4a83-9a15-b95474436a3e
X-Runtime: 0.290131
X-Powered-By: Phusion Passenger 4.0.18
Content-Length: 10877
Status: 200 OK
Content-Type: text/html; charset=utf-8
Cache-control: private
Set-Cookie: GEAR=local-554148915973ca816300021b; path=/
Vary: Accept-Encoding

UPDATE

I further simplified the redirection code in application_controller's before_action:

def debug_toggle_ssl
  if params[:x].eql?('yes')
    redirect_to "http://NONSSL.tld#{request.fullpath}"
  end
end

So now, to reproduce the issue:

  1. Go to https://SSL.tld
  2. Try to go to https://SSL.tld/?x=yes
  3. Notice how a loop to https://SSL.tld is caused (http://NONSSL.tld is never even requested)