summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/http/__init__.py32
-rw-r--r--tests/regressiontests/httpwrappers/tests.py35
2 files changed, 64 insertions, 3 deletions
diff --git a/django/http/__init__.py b/django/http/__init__.py
index 7b0c469c51..6353637a95 100644
--- a/django/http/__init__.py
+++ b/django/http/__init__.py
@@ -248,12 +248,40 @@ class QueryDict(MultiValueDict):
output.extend([urlencode({k: smart_str(v, self.encoding)}) for v in list_])
return '&'.join(output)
+class CompatCookie(SimpleCookie):
+ """
+ Cookie class that handles some issues with browser compatibility.
+ """
+ def value_encode(self, val):
+ # Some browsers do not support quoted-string from RFC 2109,
+ # including some versions of Safari and Internet Explorer.
+ # These browsers split on ';', and some versions of Safari
+ # are known to split on ', '. Therefore, we encode ';' and ','
+
+ # SimpleCookie already does the hard work of encoding and decoding.
+ # It uses octal sequences like '\\012' for newline etc.
+ # and non-ASCII chars. We just make use of this mechanism, to
+ # avoid introducing two encoding schemes which would be confusing
+ # and especially awkward for javascript.
+
+ # NB, contrary to Python docs, value_encode returns a tuple containing
+ # (real val, encoded_val)
+ val, encoded = super(CompatCookie, self).value_encode(val)
+
+ encoded = encoded.replace(";", "\\073").replace(",","\\054")
+ # If encoded now contains any quoted chars, we need double quotes
+ # around the whole string.
+ if "\\" in encoded and not encoded.startswith('"'):
+ encoded = '"' + encoded + '"'
+
+ return val, encoded
+
def parse_cookie(cookie):
if cookie == '':
return {}
if not isinstance(cookie, BaseCookie):
try:
- c = SimpleCookie()
+ c = CompatCookie()
c.load(cookie)
except CookieError:
# Invalid cookie
@@ -288,7 +316,7 @@ class HttpResponse(object):
else:
self._container = [content]
self._is_string = True
- self.cookies = SimpleCookie()
+ self.cookies = CompatCookie()
if status:
self.status_code = status
diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py
index 04099be16e..09da4476b4 100644
--- a/tests/regressiontests/httpwrappers/tests.py
+++ b/tests/regressiontests/httpwrappers/tests.py
@@ -465,7 +465,40 @@ BadHeaderError: Header values can't contain newlines (got 'test\\nstr')
[u'1', u'2', u'3', u'4']
"""
-from django.http import QueryDict, HttpResponse
+from django.http import QueryDict, HttpResponse, CompatCookie
+from django.test import TestCase
+
+
+class Cookies(TestCase):
+
+ def test_encode(self):
+ """
+ Test that we don't output tricky characters in encoded value
+ """
+ c = CompatCookie()
+ c['test'] = "An,awkward;value"
+ self.assert_(";" not in c.output()) # IE compat
+ self.assert_("," not in c.output()) # Safari compat
+
+ def test_decode(self):
+ """
+ Test that we can still preserve semi-colons and commas
+ """
+ c = CompatCookie()
+ c['test'] = "An,awkward;value"
+ c2 = CompatCookie()
+ c2.load(c.output())
+ self.assertEqual(c['test'].value, c2['test'].value)
+
+ def test_decode_2(self):
+ """
+ Test that we haven't broken normal encoding
+ """
+ c = CompatCookie()
+ c['test'] = "\xf0"
+ c2 = CompatCookie()
+ c2.load(c.output())
+ self.assertEqual(c['test'].value, c2['test'].value)
if __name__ == "__main__":
import doctest