From 9eab31193abb8fbc35ecc26b2b1a93bda7e31882 Mon Sep 17 00:00:00 2001 From: Chris Cahoon Date: Thu, 9 Jul 2009 19:53:18 +0000 Subject: [PATCH] [soc2009/http-wsgi-improvements] Refactor setting 406 status codes in HttpResponse. Accessing HttpResponse.content now evaluates the status_code for side effects. git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/http-wsgi-improvements@11211 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/http/__init__.py | 22 +++++++++++++--------- django/http/charsets.py | 23 +++++++++++++++-------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/django/http/__init__.py b/django/http/__init__.py index 12ef104c39..a67dbdc949 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -13,7 +13,7 @@ except ImportError: from django.utils.datastructures import MultiValueDict, ImmutableList from django.utils.encoding import smart_str, iri_to_uri, force_unicode from django.http.multipartparser import MultiPartParser -from django.http.charsets import get_response_encoding, get_codec +from django.http.charsets import get_response_encoding, get_codec, UnsupportedCharset from django.conf import settings from django.core.files import uploadhandler from utils import * @@ -367,8 +367,15 @@ class HttpResponse(object): self.set_cookie(key, max_age=0, path=path, domain=domain, expires='Thu, 01-Jan-1970 00:00:00 GMT') + def _configure_body_encoding(self): + if not self._codec: + self._codec = get_codec(self._charset) + if not self._codec: + self._codec = UnsupportedCharset + def _get_status_code(self): - if not self._valid_codec(): + self._configure_body_encoding() + if self._codec is UnsupportedCharset: self._status_code = 406 self._container = [''] return self._status_code @@ -378,14 +385,9 @@ class HttpResponse(object): status_code = property(_get_status_code, _set_status_code) - def _valid_codec(self): - if not self._codec: - self._codec = get_codec(self._charset) - if not self._codec: - return False - return True - def _get_content(self): + # Evaluate status_code for side effects + self._get_status_code() if self.has_header('Content-Encoding'): return ''.join(self._container) return smart_str(''.join(self._container), self._codec.name) @@ -397,6 +399,8 @@ class HttpResponse(object): content = property(_get_content, _set_content) def __iter__(self): + # Evaluate status_code for side effects + self._get_status_code() self._iterator = iter(self._container) return self diff --git a/django/http/charsets.py b/django/http/charsets.py index 5ac333ed58..b4a4922e52 100644 --- a/django/http/charsets.py +++ b/django/http/charsets.py @@ -226,6 +226,13 @@ CHARSET_CODECS = { 'windows-936': 'gbk' } +class UnsupportedCharset(object): + """ + Singleton class to indicate that our codec cannot be set due to an + unsupported charset in an Accept-Charset header. + """ + pass + def get_codec(charset): """ Given the name or alias of a character set, find its Python codec if there is one. @@ -285,6 +292,7 @@ def get_response_encoding(content_type, accept_charset_header): if not used_content_type: if not accept_charset_header: # No information to find a charset with. return None, None + # Get list of matches for Accepted-Charsets. # [{ charset : q }, { charset : q }] match_iterator = ACCEPT_CHARSET_RE.finditer(accept_charset_header) @@ -292,7 +300,7 @@ def get_response_encoding(content_type, accept_charset_header): # Remove charsets we cannot encode and whose q values are 0 charsets = _process_accept_charset(accept_charset) - + # Establish the prioritized charsets (ones we know about beforehand) default_charset = settings.DEFAULT_CHARSET fallback_charset = "ISO-8859-1" @@ -309,11 +317,11 @@ def get_response_encoding(content_type, accept_charset_header): # or defaulting) else: charset = max_q_charset - + codec = get_codec(charset) + # We may reach here with no codec or no charset. We will change the status # code in the HttpResponse. - #print charset, codec return charset, codec # NOTE -- make sure we are not duping the processing of q values @@ -324,10 +332,10 @@ def _process_accept_charset(accept_charset): names, and excludes charsets without Python codecs and whose q values are 0. ''' accepted_charsets = {} - + default_value = 1 wildcard = False - + for potential in accept_charset: charset = potential["charset"].strip() # The default quality value is 1 @@ -341,11 +349,10 @@ def _process_accept_charset(accept_charset): elif charset == "*" and q >= 0 and q <= 1: default_value = q wildcard = True - + if settings.DEFAULT_CHARSET not in accepted_charsets: accepted_charsets[settings.DEFAULT_CHARSET] = default_value if "ISO-8859-1" not in accepted_charsets and wildcard: accepted_charsets["ISO-8859-1"] = default_value - - + return accepted_charsets