HTTPS detection in Django under PyISAPIe

Created 13th August, 2008 08:23 (UTC), last edited 13th August, 2008 08:41 (UTC)

When I put together the ForceHTTPS Django middleware there was an annoying and not very good work around for a bug between PyISAPIe and Django. The problem was that django.http.Request.is_secure() would always return False — not helpful. Since then I've more or less ignored it hoping that it would go away, but today I tracked down Selenium test failures for Internet Explorer to the same cause so had to come up with a fix. Thankfully it wasn't too hard.

Django uses the following implementation of is_secure()

    def is_secure(self):
        return os.environ.get("HTTPS") == "on"

The problem is that this doesn't work on Windows because it doesn't set an environment variable for this — it sets a server variable which PyISAPIe should expose under Request.META. The problem there is that the HTTPS server variable is missing from PyISAPIe's code.

First django.core.handlers.pyisapie._get_meta() needs to have HTTPS added to the list of names it forwards:

                'CONTENT_TYPE':      Env.CONTENT_TYPE,
                'HTTPS': Env.HTTPS, # Add this line

The best fix for the Django side of things isn't quite so obvious. The code i went for was this:

    def is_secure(self):
        environ = os.environ.get("HTTPS")
        if environ:
            return environ == "on"
        return self.META.get("HTTPS").lower() == "on"

There are plenty of other ways to skin this cat too depending on what you're trading off. I'm assuming that you don't want too many lookups into the environment Dict and that most Django users will be running on some platform where os.environ.get("HTTPS") will work as expected. I'm not certain if the case conversion is required or not.