Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Rationalised CompatCookie/SimpleCookie into single SimpleCookie class…

… with all fixes.

Since upstream Python has fixed the encoding bug (see
http://bugs.python.org/issue9824), we don't want a separate class for this
bug fix, or several layers for the different fixes.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15298 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 42c31f6bf036efd93c0311bc1f524b1553c20489 1 parent 09a6363
@spookylukey spookylukey authored
View
6 django/contrib/messages/storage/cookie.py
@@ -1,7 +1,7 @@
from django.conf import settings
from django.contrib.messages import constants
from django.contrib.messages.storage.base import BaseStorage, Message
-from django.http import CompatCookie
+from django.http import SimpleCookie
from django.utils import simplejson as json
from django.utils.crypto import salted_hmac, constant_time_compare
@@ -88,9 +88,9 @@ def _store(self, messages, response, remove_oldest=True, *args, **kwargs):
unstored_messages = []
encoded_data = self._encode(messages)
if self.max_cookie_size:
- # data is going to be stored eventually by CompatCookie, which
+ # data is going to be stored eventually by SimpleCookie, which
# adds it's own overhead, which we must account for.
- cookie = CompatCookie() # create outside the loop
+ cookie = SimpleCookie() # create outside the loop
def stored_length(val):
return len(cookie.value_encode(val)[1])
View
120 django/http/__init__.py
@@ -21,38 +21,76 @@
# PendingDeprecationWarning
from cgi import parse_qsl
+import Cookie
# httponly support exists in Python 2.6's Cookie library,
# but not in Python 2.4 or 2.5.
-import Cookie
-if Cookie.Morsel._reserved.has_key('httponly'):
+_morsel_supports_httponly = Cookie.Morsel._reserved.has_key('httponly')
+# Some versions of Python 2.7 and later won't need this encoding bug fix:
+_cookie_encodes_correctly = Cookie.SimpleCookie().value_encode(';') == (';', '"\\073"')
+
+if _morsel_supports_httponly and _cookie_encodes_correctly:
SimpleCookie = Cookie.SimpleCookie
else:
- class Morsel(Cookie.Morsel):
- def __setitem__(self, K, V):
- K = K.lower()
- if K == "httponly":
- if V:
- # The superclass rejects httponly as a key,
- # so we jump to the grandparent.
- super(Cookie.Morsel, self).__setitem__(K, V)
- else:
- super(Morsel, self).__setitem__(K, V)
-
- def OutputString(self, attrs=None):
- output = super(Morsel, self).OutputString(attrs)
- if "httponly" in self:
- output += "; httponly"
- return output
+ if not _morsel_supports_httponly:
+ class Morsel(Cookie.Morsel):
+ def __setitem__(self, K, V):
+ K = K.lower()
+ if K == "httponly":
+ if V:
+ # The superclass rejects httponly as a key,
+ # so we jump to the grandparent.
+ super(Cookie.Morsel, self).__setitem__(K, V)
+ else:
+ super(Morsel, self).__setitem__(K, V)
+
+ def OutputString(self, attrs=None):
+ output = super(Morsel, self).OutputString(attrs)
+ if "httponly" in self:
+ output += "; httponly"
+ return output
class SimpleCookie(Cookie.SimpleCookie):
- def __set(self, key, real_value, coded_value):
- M = self.get(key, Morsel())
- M.set(key, real_value, coded_value)
- dict.__setitem__(self, key, M)
+ if not _morsel_supports_httponly:
+ def __set(self, key, real_value, coded_value):
+ M = self.get(key, Morsel())
+ M.set(key, real_value, coded_value)
+ dict.__setitem__(self, key, M)
+
+ def __setitem__(self, key, value):
+ rval, cval = self.value_encode(value)
+ self.__set(key, rval, cval)
+
+ if not _cookie_encodes_correctly:
+ 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(SimpleCookie, 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 __setitem__(self, key, value):
- rval, cval = self.value_encode(value)
- self.__set(key, rval, cval)
+class CompatCookie(SimpleCookie):
+ def __init__(self, *args, **kwargs):
+ super(CompatCookie, self).__init__(*args, **kwargs)
+ import warnings
+ warnings.warn("CompatCookie is deprecated, use django.http.SimpleCookie instead.",
+ PendingDeprecationWarning)
from django.utils.datastructures import MultiValueDict, ImmutableList
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
@@ -389,40 +427,12 @@ def urlencode(self, safe=None):
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, Cookie.BaseCookie):
try:
- c = CompatCookie()
+ c = SimpleCookie()
c.load(cookie)
except Cookie.CookieError:
# Invalid cookie
@@ -460,7 +470,7 @@ def __init__(self, content='', mimetype=None, status=None,
else:
self._container = [content]
self._is_string = True
- self.cookies = CompatCookie()
+ self.cookies = SimpleCookie()
if status:
self.status_code = status
View
3  docs/internals/deprecation.txt
@@ -155,6 +155,9 @@ their deprecation, as per the :ref:`Django deprecation policy
a :class:`~django.contrib.gis.geos.GEOSException` when called
on a geometry with no SRID value.
+ * :class:`~django.http.CompatCookie` will be removed in favour of
+ :class:`~django.http.SimpleCookie`.
+
* 2.0
* ``django.views.defaults.shortcut()``. This function has been moved
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
View
8 docs/releases/1.3.txt
@@ -609,3 +609,11 @@ Previously this field's ``clean()`` method accepted a second, gender, argument
which allowed stronger validation checks to be made, however since this
argument could never actually be passed from the Django form machinery it is
now pending deprecation.
+
+``CompatCookie``
+~~~~~~~~~~~~~~~~
+
+Previously, ``django.http`` exposed an undocumented ``CompatCookie`` class,
+which was a bug-fix wrapper around the standard library ``SimpleCookie``. As the
+fixes are moving upstream, this is now deprecated - you should use ``from
+django.http import SimpleCookie`` instead.
View
12 tests/regressiontests/httpwrappers/tests.py
@@ -1,7 +1,7 @@
import copy
import pickle
-from django.http import QueryDict, HttpResponse, CompatCookie, BadHeaderError
+from django.http import QueryDict, HttpResponse, SimpleCookie, BadHeaderError
from django.utils import unittest
class QueryDictTests(unittest.TestCase):
@@ -250,7 +250,7 @@ def test_encode(self):
# Python 2.4 compatibility note: Python 2.4's cookie implementation
# always returns Set-Cookie headers terminating in semi-colons.
# That's not the bug this test is looking for, so ignore it.
- c = CompatCookie()
+ c = SimpleCookie()
c['test'] = "An,awkward;value"
self.assert_(";" not in c.output().rstrip(';')) # IE compat
self.assert_("," not in c.output().rstrip(';')) # Safari compat
@@ -259,9 +259,9 @@ def test_decode(self):
"""
Test that we can still preserve semi-colons and commas
"""
- c = CompatCookie()
+ c = SimpleCookie()
c['test'] = "An,awkward;value"
- c2 = CompatCookie()
+ c2 = SimpleCookie()
c2.load(c.output())
self.assertEqual(c['test'].value, c2['test'].value)
@@ -269,8 +269,8 @@ def test_decode_2(self):
"""
Test that we haven't broken normal encoding
"""
- c = CompatCookie()
+ c = SimpleCookie()
c['test'] = "\xf0"
- c2 = CompatCookie()
+ c2 = SimpleCookie()
c2.load(c.output())
self.assertEqual(c['test'].value, c2['test'].value)
Please sign in to comment.
Something went wrong with that request. Please try again.