mirror of https://github.com/django/django.git
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
This commit is contained in:
parent
09a63632c5
commit
42c31f6bf0
|
@ -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 @@ class CookieStorage(BaseStorage):
|
|||
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])
|
||||
|
||||
|
|
|
@ -21,38 +21,76 @@ except ImportError:
|
|||
# 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
|
||||
|
@ -389,40 +427,12 @@ class QueryDict(MultiValueDict):
|
|||
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 @@ class HttpResponse(object):
|
|||
else:
|
||||
self._container = [content]
|
||||
self._is_string = True
|
||||
self.cookies = CompatCookie()
|
||||
self.cookies = SimpleCookie()
|
||||
if status:
|
||||
self.status_code = status
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 @@ class CookieTests(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
|
||||
|
@ -259,9 +259,9 @@ class CookieTests(unittest.TestCase):
|
|||
"""
|
||||
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 @@ class CookieTests(unittest.TestCase):
|
|||
"""
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue