Ticket #6447: ticket_6447.diff

File ticket_6447.diff, 7.4 KB (added by carljm, 5 years ago)

updated patch, applies to trunk

  • django/core/cache/backends/base.py

    diff --git a/django/core/cache/backends/base.py b/django/core/cache/backends/base.py
    a b  
    55class InvalidCacheBackendError(ImproperlyConfigured):
    66    pass
    77
     8class InvalidCacheKeyError(Exception):
     9    pass
     10
     11# memcached does not accept keys longer than 250 characters
     12MAX_KEY_LENGTH = 250
     13
    814class BaseCache(object):
    915    def __init__(self, params):
    1016        timeout = params.get('timeout', 300)
     
    116122    def clear(self):
    117123        """Remove *all* values from the cache at once."""
    118124        raise NotImplementedError
     125
     126    def _validate_key(self, key):
     127        """
     128        Enforce keys that would be valid on all backends, to keep cache code portable.
     129
     130        """
     131        if len(key) > MAX_KEY_LENGTH:
     132            raise InvalidCacheKeyError('Key is too long (max length %s)' % MAX_KEY_LENGTH)
     133        for char in key:
     134            if ord(char) < 33 or ord(char) == 127:
     135                raise InvalidCacheKeyError('Key contains control character')
     136       
  • django/core/cache/backends/db.py

    diff --git a/django/core/cache/backends/db.py b/django/core/cache/backends/db.py
    a b  
    4646            self._cull_frequency = 3
    4747
    4848    def get(self, key, default=None):
     49        self._validate_key(key)
    4950        db = router.db_for_read(self.cache_model_class)
    5051        table = connections[db].ops.quote_name(self._table)
    5152        cursor = connections[db].cursor()
     
    6566        return pickle.loads(base64.decodestring(value))
    6667
    6768    def set(self, key, value, timeout=None):
     69        self._validate_key(key)
    6870        self._base_set('set', key, value, timeout)
    6971
    7072    def add(self, key, value, timeout=None):
     73        self._validate_key(key)
    7174        return self._base_set('add', key, value, timeout)
    7275
    7376    def _base_set(self, mode, key, value, timeout=None):
     
    103106            return True
    104107
    105108    def delete(self, key):
     109        self._validate_key(key)
    106110        db = router.db_for_write(self.cache_model_class)
    107111        table = connections[db].ops.quote_name(self._table)
    108112        cursor = connections[db].cursor()
     
    111115        transaction.commit_unless_managed(using=db)
    112116
    113117    def has_key(self, key):
     118        self._validate_key(key)
    114119        db = router.db_for_read(self.cache_model_class)
    115120        table = connections[db].ops.quote_name(self._table)
    116121        cursor = connections[db].cursor()
  • django/core/cache/backends/dummy.py

    diff --git a/django/core/cache/backends/dummy.py b/django/core/cache/backends/dummy.py
    a b  
    66    def __init__(self, *args, **kwargs):
    77        pass
    88
    9     def add(self, *args, **kwargs):
     9    def add(self, key, *args, **kwargs):
     10        self._validate_key(key)
    1011        return True
    1112
    1213    def get(self, key, default=None):
     14        self._validate_key(key)
    1315        return default
    1416
    15     def set(self, *args, **kwargs):
    16         pass
     17    def set(self, key, *args, **kwargs):
     18        self._validate_key(key)
    1719
    18     def delete(self, *args, **kwargs):
    19         pass
     20    def delete(self, key, *args, **kwargs):
     21        self._validate_key(key)
    2022
    2123    def get_many(self, *args, **kwargs):
    2224        return {}
    2325
    24     def has_key(self, *args, **kwargs):
     26    def has_key(self, key, *args, **kwargs):
     27        self._validate_key(key)
    2528        return False
    2629
    2730    def set_many(self, *args, **kwargs):
  • django/core/cache/backends/filebased.py

    diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
    a b  
    3232            self._createdir()
    3333
    3434    def add(self, key, value, timeout=None):
     35        self._validate_key(key)
    3536        if self.has_key(key):
    3637            return False
    3738
     
    3940        return True
    4041
    4142    def get(self, key, default=None):
     43        self._validate_key(key)
    4244        fname = self._key_to_file(key)
    4345        try:
    4446            f = open(fname, 'rb')
     
    5658        return default
    5759
    5860    def set(self, key, value, timeout=None):
     61        self._validate_key(key)
    5962        fname = self._key_to_file(key)
    6063        dirname = os.path.dirname(fname)
    6164
     
    7982            pass
    8083
    8184    def delete(self, key):
     85        self._validate_key(key)
    8286        try:
    8387            self._delete(self._key_to_file(key))
    8488        except (IOError, OSError):
     
    9599            pass
    96100
    97101    def has_key(self, key):
     102        self._validate_key(key)
    98103        fname = self._key_to_file(key)
    99104        try:
    100105            f = open(fname, 'rb')
  • django/core/cache/backends/locmem.py

    diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py
    a b  
    3030        self._lock = RWLock()
    3131
    3232    def add(self, key, value, timeout=None):
     33        self._validate_key(key)
    3334        self._lock.writer_enters()
    3435        try:
    3536            exp = self._expire_info.get(key)
     
    4445            self._lock.writer_leaves()
    4546
    4647    def get(self, key, default=None):
     48        self._validate_key(key)
    4749        self._lock.reader_enters()
    4850        try:
    4951            exp = self._expire_info.get(key)
     
    7678        self._expire_info[key] = time.time() + timeout
    7779
    7880    def set(self, key, value, timeout=None):
     81        self._validate_key(key)
    7982        self._lock.writer_enters()
    8083        # Python 2.4 doesn't allow combined try-except-finally blocks.
    8184        try:
     
    8790            self._lock.writer_leaves()
    8891
    8992    def has_key(self, key):
     93        self._validate_key(key)
    9094        self._lock.reader_enters()
    9195        try:
    9296            exp = self._expire_info.get(key)
     
    127131            pass
    128132
    129133    def delete(self, key):
     134        self._validate_key(key)
    130135        self._lock.writer_enters()
    131136        try:
    132137            self._delete(key)
  • docs/topics/cache.txt

    diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt
    a b  
    537537    >>> cache.get('my_key')
    538538    'hello, world!'
    539539
     540.. note::
     541
     542   Cache keys may not be longer than 250 characters, and may not
     543   contain whitespace or control characters.
     544
    540545The ``timeout`` argument is optional and defaults to the ``timeout``
    541546argument in the ``CACHE_BACKEND`` setting (explained above). It's the number of
    542547seconds the value should be stored in the cache.
  • tests/regressiontests/cache/tests.py

    diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
    a b  
    366366                count = count + 1
    367367        self.assertEqual(count, final_count)
    368368
     369    def test_invalid_keys(self):
     370        """
     371        All the builtin backends should refuse keys that would be refused by
     372        memcached, so code using the cache API is portable. Refs #6447.
     373
     374        We assert only that a generic exception is raised because we don't
     375        want to encumber the memcached backend with key-checking code, and the
     376        specific exceptions raised from memcached will depend on the client
     377        library used.
     378       
     379        """
     380        self.assertRaises(Exception, self.cache.set, 'key with spaces', 'value')
     381        # memcached also limits key length to 250
     382        self.assertRaises(Exception, self.cache.set, 'a' * 251, 'value')
     383
    369384class DBCacheTests(unittest.TestCase, BaseCacheTests):
    370385    def setUp(self):
    371386        # Spaces are used in the table name to ensure quoting/escaping is working
Back to Top