One common setup is to have a reverse proxy (like Pound, Lighttpd, or Apache) sit in front of CherryPy and handle requests. If you want to handle both http and https protocols, you set up your reverse proxy to deal with the secure communications, and then pass types of both types of requests (secure and insecure) to CherryPy as a normal http request. CherryPy processes the requests, returns them to the proxy, and the proxy passes them on to the client (secure or insecure, depending on the original request).
This causes a problem if you do a HTTPRedirect to a URL in your application. CherryPy thinks that this is an unencrypted request. So, the redirect URL provided by CherryPy will begin with http, regardless of whether or not the original URL scheme was http or https.
One way to work around this is to have the proxy give a hint to CherryPy as to the original protocol. Most proxies have some way to set a custom header to the request before passing it on. So, the general solution is to add a special header to https requests, and then have a CherryPy tool look for that header and modify the base URL to something more appropriate.
Pound is a fairly easy to configure reverse proxy that we can use as an example. In the Pound configuration, we add a custom header called ‘X-Forwarded-Ssl’. The relevant part of the Pound configuration file looks like:
ListenHTTPS Address 127.0.0.1 Port 443 Cert "/Users/plewis/Desktop/Pound-2.0.2/mycert.pem" AddHeader "X-Forwarded-Proto: https" Service BackEnd Address 127.0.0.1 Port 8080 End End End
Apache users can use mod_headers to add a custom header. For example, in your SSL virtualhost section, add the following line:
RequestHeader add X-Forwarded-Proto https
Lighttpd users can set a custom header via setenv.add-request-header.
Regardless of the proxy you are using, you don’t want to add this header on a global basis, but only for https requests.
CherryPy 3 comes with a builtin tool that already does exactly what we want.
It is named
tools.proxy and just needs to be activated.
In your configuration file (e.g. prod.cfg), set the following configuration variable:
[/] tools.proxy.on = True
You should be able to add a method to your controller like:
@turbogears.expose() def test_redirect(self): turbogears.redirect('/') # uses cherrypy.HTTPRedirect
Calling this URL should work over both http and https, and will properly redirect to the base of your application.