1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | __license__ = "Python"
__copyright__ = "Copyright (C) 2007, Stephen Zabel"
__author__ = "Stephen Zabel - sjzabel@gmail.com"
__contributors__ = "Jay Parlar - parlar@gmail.com"
from django.conf import settings
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect, get_host
SSL = 'SSL'
class SSLRedirect:
def process_view(self, request, view_func, view_args, view_kwargs):
if SSL in view_kwargs:
secure = view_kwargs[SSL]
del view_kwargs[SSL]
else:
secure = False
if not secure == self._is_secure(request):
return self._redirect(request, secure)
def _is_secure(self, request):
if request.is_secure():
return True
#Handle the Webfaction case until this gets resolved in the request.is_secure()
if 'HTTP_X_FORWARDED_SSL' in request.META:
return request.META['HTTP_X_FORWARDED_SSL'] == 'on'
return False
def _redirect(self, request, secure):
protocol = secure and "https" or "http"
newurl = "%s://%s%s" % (protocol,get_host(request),request.get_full_path())
if settings.DEBUG and request.method == 'POST':
raise RuntimeError, \
"""Django can't perform a SSL redirect while maintaining POST data.
Please structure your views so that redirects only occur during GETs."""
return HttpResponsePermanentRedirect(newurl)
|
Comments
This middleware would not work, as is, with Webfaction, do to a problem with is_secure(). So I've slightly modified it, and posted the modified version, along with instructions, at http://www.djangosnippets.org/snippets/240/
#
Cool, I updated my code with your check for the webfaction header. I like the idea of checking both better than having two branches of the code.
Cheers
#
To accept both http and https requests with same view I added "secure!=1 and " to the line 20;
Then marked that view with {'SSL':1} in urls file.
#
Sorry, in my previous comment I forgotten the fact that 1==True in Python. So, the value "1" must be changed with some another value. I changed them with -1.
#
Nice work. I wanted to be able to run the middleware in dev (no ssl cert) and production (ssl cert) so, I made this change to lines 20&21:
I then added this line to my production settings.py and made it false in my dev settings.py:
SSL_ENABLED = True
#
I've found that I only want to explicitly choose a protocol in certain views, I have made a change to process_view that will only redirect when it is explicitly asked for ie:
Now any view with the SSL option included will be forced to the requested protocol but the others will be ignored.
#
Note!
If you are running under IIS with PyISAPIe the example PyISAPIe handler does not include an implementation for the is_secure method and you will end up with a redirect loop. This can be solved by modifying the PyISAPIeRequest class and adding the method:
This solution is not perfect as it is assumed that SSL is configured and working on port 443 but as mentioned in the function there is no other information that allows for a more "informed" decision.
#
Yes, like tim.savage, I find situations, where you should allow both http and https access, and leave them, as is.
That is a matter of taste, which is the default...
#