I recently started this thread on the Django developer's list:
http://groups.google.com/group/django-developers/browse_thread/thread/5af492b48fee4ff0
It seems that django now relies on:
os.environ['HTTPS'] == "on"
in order for HTTPS redirects to work. Previously, redirects were
returned as relative URLs, contrary to the HTTP spec, but satisfactory
for most web browsers. Now that redirects follow the spec in this
regard, they need some way to determine whether a request is secure or
not, and this is the method Django has chosen.
As far as I can tell, this variable is not set when running under
mod_wsgi, and hence HTTPS redirects are broken. I am bringing
attention to the thread here as well, since I really don't know what
the proper solution is.
Thank you,
Jeffrey
--
Jeffrey Froman
OlympusNet Administration
http://www.olympus.net
wsgi.tc...@olympus.net
Graham
The fix is a modification to a single line in django/core/handlers/wsgi.py
Look for the function is_secure() and change the line that says:
return 'HTTPS' in self.environ and self.environ['HTTPS'] == 'on'
to
return 'wsgi.url_scheme' in self.environ and 'https' ==
self.environ['wsgi.url_scheme']
I don't know about the rest of Django but by running grep through the
latest stable version (0.96) there are other places where the HTTPS
environment variable is used to determine if the Django app is
accessed through a secure connection. The CGI 1.1 spec does not
require HTTPS environment variable to be set and some webservers do
not set it so it is not a reliable indicator if you are connected to
the server via HTTPS.
SERVER_PORT is part of the CGI 1.1 spec but you should not rely on
that one either since it's possible that the server is running HTTPS
on a different port from the standard 443 (e.g.,
proxied/load-balanced/chrooted servers come to mind).
--
_nimrod_a_abing_
FWIW, in mod_wsgi the wsgi.url_scheme should be reliable (Apache >=
2.0) as it derives the information from Apache mod_ssl module
directly. It actually sets HTTPS as a side effect as well, but it is
set to "1" and not "on" which is what Django was expecting.
Anyway, the mod_wsgi code first does:
/* Determine whether connection uses HTTPS protocol. */
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
if (!wsgi_is_https)
wsgi_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
if (wsgi_is_https && wsgi_is_https(r->connection))
apr_table_set(r->subprocess_env, "HTTPS", "1");
#endif
I used "1" rather than "on" as the WSGI specification suggests that it
is a value that existing web servers can produce. Ie., since I didn't
need to be setting it anyway, seemed a reasonable value to choose of
the two the WSGI specification gives as an example.
Later on it then constructs wsgi.url_scheme:
scheme = apr_table_get(r->subprocess_env, "HTTPS");
if (scheme && (!strcasecmp(scheme, "On") || !strcmp(scheme, "1"))) {
object = PyString_FromString("https");
PyDict_SetItemString(vars, "wsgi.url_scheme", object);
Py_DECREF(object);
}
else {
object = PyString_FromString("http");
PyDict_SetItemString(vars, "wsgi.url_scheme", object);
Py_DECREF(object);
}
Now I could use "on" instead of "1", but technically that would just
hide the fact that Django is not correct in that it by rights should
use 'wsgi.url_scheme' for a WSGI adapter instead.
BTW, if you don't want to go fiddling Django source code, use a
wrapper around Django entry point:
import os, sys
sys.path.append('/usr/local/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()
def application(environ, start_response):
if environ['wsgi.url_scheme'] == 'https':
environ['HTTPS'] = 'on'
return _application(environ, start_response)
Graham
Yes there are other places in Django where this is handled right (or better)::
modpython.py:49
return self._req.subprocess_env.get('HTTPS', '').lower() in ('on', '1')
django\core\servers\basehttp.py:212 (server side POV)
if environ.get("HTTPS") in ('yes','on','1'):
> [...]
> Now I could use "on" instead of "1", but technically that would just
> hide the fact that Django is not correct in that it by rights should
> use 'wsgi.url_scheme' for a WSGI adapter instead.
>
Since the WSGI spec wording used is "should" for the 'HTTPS'
var and "must" for the 'wsgi.url_scheme' var when talking about
server side implementations of WSGI, IMVHO it would be safe to
just handle the latter case as in the the snippet posted bu Nimrod
and the one-line-patch I posted to the django-devel mailing list.
Regards,
--
Ramiro Morales
Thank you,
Jeffrey