From c7634cd7fe7dc09338fcec0ca48d816a29d791b0 Mon Sep 17 00:00:00 2001 From: Unai Zalakain Date: Tue, 8 Oct 2013 20:30:29 +0200 Subject: [PATCH] Fixed #7603 -- Added a 'scheme' property to the HttpRequest object `HttpRequest.scheme` is `https` if `settings.SECURE_PROXY_SSL_HEADER` is appropriately set and falls back to `HttpRequest._get_scheme()` (a hook for subclasses to implement) otherwise. `WSGIRequest._get_scheme()` makes use of the `wsgi.url_scheme` WSGI environ variable to determine the request scheme. `HttpRequest.is_secure()` simply checks if `HttpRequest.scheme` is `https`. This provides a way to check the current scheme in templates, for example. It also allows us to deal with other schemes. Thanks nslater for the suggestion. --- django/contrib/admindocs/views.py | 2 +- django/contrib/contenttypes/views.py | 2 +- django/contrib/gis/sitemaps/views.py | 2 +- django/contrib/sitemaps/views.py | 4 ++-- django/core/handlers/wsgi.py | 4 ++-- django/http/request.py | 19 +++++++++++-------- django/middleware/common.py | 2 +- django/middleware/locale.py | 4 ++-- docs/ref/request-response.txt | 7 +++++++ docs/releases/1.7.txt | 6 ++++++ 10 files changed, 34 insertions(+), 18 deletions(-) diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 5515a3eee4..9a3d23a89c 100644 --- a/django/contrib/admindocs/views.py +++ b/django/contrib/admindocs/views.py @@ -38,7 +38,7 @@ def bookmarklets(request): admin_root = urlresolvers.reverse('admin:index') return render_to_response('admin_doc/bookmarklets.html', { 'root_path': admin_root, - 'admin_url': "%s://%s%s" % ('https' if request.is_secure() else 'http', request.get_host(), admin_root), + 'admin_url': "%s://%s%s" % (request.scheme, request.get_host(), admin_root), }, context_instance=RequestContext(request)) @staff_member_required diff --git a/django/contrib/contenttypes/views.py b/django/contrib/contenttypes/views.py index 6d4a719289..d2dc48ea08 100644 --- a/django/contrib/contenttypes/views.py +++ b/django/contrib/contenttypes/views.py @@ -75,7 +75,7 @@ def shortcut(request, content_type_id, object_id): # If all that malarkey found an object domain, use it. Otherwise, fall back # to whatever get_absolute_url() returned. if object_domain is not None: - protocol = 'https' if request.is_secure() else 'http' + protocol = request.scheme return http.HttpResponseRedirect('%s://%s%s' % (protocol, object_domain, absurl)) else: diff --git a/django/contrib/gis/sitemaps/views.py b/django/contrib/gis/sitemaps/views.py index d64691e971..e184f4c6b6 100644 --- a/django/contrib/gis/sitemaps/views.py +++ b/django/contrib/gis/sitemaps/views.py @@ -21,7 +21,7 @@ def index(request, sitemaps): """ current_site = get_current_site(request) sites = [] - protocol = 'https' if request.is_secure() else 'http' + protocol = request.scheme for section, site in sitemaps.items(): if callable(site): pages = site().paginator.num_pages diff --git a/django/contrib/sitemaps/views.py b/django/contrib/sitemaps/views.py index 14983acea9..7418deb533 100644 --- a/django/contrib/sitemaps/views.py +++ b/django/contrib/sitemaps/views.py @@ -22,7 +22,7 @@ def index(request, sitemaps, template_name='sitemap_index.xml', content_type='application/xml', sitemap_url_name='django.contrib.sitemaps.views.sitemap'): - req_protocol = 'https' if request.is_secure() else 'http' + req_protocol = request.scheme req_site = get_current_site(request) sites = [] @@ -44,7 +44,7 @@ def index(request, sitemaps, def sitemap(request, sitemaps, section=None, template_name='sitemap.xml', content_type='application/xml'): - req_protocol = 'https' if request.is_secure() else 'http' + req_protocol = request.scheme req_site = get_current_site(request) if section is not None: diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 7f6d37b3c1..7c7415d330 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -110,8 +110,8 @@ class WSGIRequest(http.HttpRequest): self._read_started = False self.resolver_match = None - def _is_secure(self): - return self.environ.get('wsgi.url_scheme') == 'https' + def _get_scheme(self): + return self.environ.get('wsgi.url_scheme') def _parse_content_type(self, ctype): """ diff --git a/django/http/request.py b/django/http/request.py index 3972151865..1cecbe191a 100644 --- a/django/http/request.py +++ b/django/http/request.py @@ -129,15 +129,16 @@ class HttpRequest(object): if not location: location = self.get_full_path() if not absolute_http_url_re.match(location): - current_uri = '%s://%s%s' % ('https' if self.is_secure() else 'http', + current_uri = '%s://%s%s' % (self.scheme, self.get_host(), self.path) location = urljoin(current_uri, location) return iri_to_uri(location) - def _is_secure(self): - return os.environ.get("HTTPS") == "on" + def _get_scheme(self): + return 'https' if os.environ.get("HTTPS") == "on" else 'http' - def is_secure(self): + @property + def scheme(self): # First, check the SECURE_PROXY_SSL_HEADER setting. if settings.SECURE_PROXY_SSL_HEADER: try: @@ -145,11 +146,13 @@ class HttpRequest(object): except ValueError: raise ImproperlyConfigured('The SECURE_PROXY_SSL_HEADER setting must be a tuple containing two values.') if self.META.get(header, None) == value: - return True - - # Failing that, fall back to _is_secure(), which is a hook for + return 'https' + # Failing that, fall back to _get_scheme(), which is a hook for # subclasses to implement. - return self._is_secure() + return self._get_scheme() + + def is_secure(self): + return self.scheme == 'https' def is_ajax(self): return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' diff --git a/django/middleware/common.py b/django/middleware/common.py index 8f5923ac4a..51fcf1b2af 100644 --- a/django/middleware/common.py +++ b/django/middleware/common.py @@ -85,7 +85,7 @@ class CommonMiddleware(object): return if new_url[0]: newurl = "%s://%s%s" % ( - 'https' if request.is_secure() else 'http', + request.scheme, new_url[0], urlquote(new_url[1])) else: newurl = urlquote(new_url[1]) diff --git a/django/middleware/locale.py b/django/middleware/locale.py index 0611b6044a..cb0bf3f084 100644 --- a/django/middleware/locale.py +++ b/django/middleware/locale.py @@ -51,8 +51,8 @@ class LocaleMiddleware(object): if path_valid: language_url = "%s://%s/%s%s" % ( - 'https' if request.is_secure() else 'http', - request.get_host(), language, request.get_full_path()) + request.scheme, request.get_host(), language, + request.get_full_path()) return self.response_redirect_class(language_url) # Store language back into session if it is not present diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index a4ed6a2645..57222c8ca7 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -32,6 +32,13 @@ Attributes All attributes should be considered read-only, unless stated otherwise below. ``session`` is a notable exception. +.. attribute:: HttpRequest.scheme + + .. versionadded:: 1.7 + + A string representing the scheme of the request (``http`` or ``https`` + usually). + .. attribute:: HttpRequest.body The raw HTTP request body as a byte string. This is useful for processing diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index 5c208e22ac..a3fdc0e9f3 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -386,6 +386,12 @@ Templates ` ``datetime`` instances performing the expected rendering. +Requests +^^^^^^^^ + +* The new :attr:`HttpRequest.scheme ` attribute + specifies the scheme of the request (``http`` or ``https`` normally). + Tests ^^^^^