1. django
  2. django

Commits

luke...@bcc190cf-cafb-0310-a4f2-bffc1f526a37  committed 0305183

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.

  • Participants
  • Parent commits 04c14e6
  • Branches default

Comments (0)

Files changed (5)

File django/contrib/messages/storage/cookie.py

View file
  • Ignore whitespace
 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
 
         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])
 

File django/http/__init__.py

View file
  • Ignore whitespace
         # 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)
+    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
+            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)
+            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
+
+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
                            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
         else:
             self._container = [content]
             self._is_string = True
-        self.cookies = CompatCookie()
+        self.cookies = SimpleCookie()
         if status:
             self.status_code = status
 

File docs/internals/deprecation.txt

View file
  • Ignore whitespace
           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

File docs/releases/1.3.txt

View file
  • Ignore whitespace
 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.

File tests/regressiontests/httpwrappers/tests.py

View file
  • Ignore whitespace
 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):
         # 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
         """
         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)
 
         """
         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)