diff options
Diffstat (limited to 'django/http')
| -rw-r--r-- | django/http/response.py | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/django/http/response.py b/django/http/response.py index 866b3480e7..0cc14d1346 100644 --- a/django/http/response.py +++ b/django/http/response.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import datetime import json +import re import sys import time from email.header import Header @@ -83,6 +84,9 @@ REASON_PHRASES = { } +_charset_from_content_type_re = re.compile(r';\s*charset=(?P<charset>[^\s;]+)', re.I) + + class BadHeaderError(ValueError): pass @@ -98,19 +102,15 @@ class HttpResponseBase(six.Iterator): status_code = 200 reason_phrase = None # Use default reason phrase for status code. - def __init__(self, content_type=None, status=None, reason=None): + def __init__(self, content_type=None, status=None, reason=None, charset=None): # _headers is a mapping of the lower-case name to the original case of # the header (required for working with legacy systems) and the header # value. Both the name of the header and its value are ASCII strings. self._headers = {} - self._charset = settings.DEFAULT_CHARSET self._closable_objects = [] # This parameter is set by the handler. It's necessary to preserve the # historical behavior of request_finished. self._handler_class = None - if not content_type: - content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, - self._charset) self.cookies = SimpleCookie() if status is not None: self.status_code = status @@ -119,8 +119,27 @@ class HttpResponseBase(six.Iterator): elif self.reason_phrase is None: self.reason_phrase = REASON_PHRASES.get(self.status_code, 'UNKNOWN STATUS CODE') + self._charset = charset + if content_type is None: + content_type = '%s; charset=%s' % (settings.DEFAULT_CONTENT_TYPE, + self.charset) self['Content-Type'] = content_type + @property + def charset(self): + if self._charset is not None: + return self._charset + content_type = self.get('Content-Type', '') + matched = _charset_from_content_type_re.search(content_type) + if matched: + # Extract the charset and strip its double quotes + return matched.group('charset').replace('"', '') + return settings.DEFAULT_CHARSET + + @charset.setter + def charset(self, value): + self._charset = value + def serialize_headers(self): """HTTP headers as a bytestring.""" def to_bytes(val, encoding): @@ -278,10 +297,10 @@ class HttpResponseBase(six.Iterator): if isinstance(value, bytes): return bytes(value) if isinstance(value, six.text_type): - return bytes(value.encode(self._charset)) + return bytes(value.encode(self.charset)) # Handle non-string types (#16494) - return force_bytes(value, self._charset) + return force_bytes(value, self.charset) # These methods partially implement the file-like object interface. # See http://docs.python.org/lib/bltin-file-objects.html |
