diff --git a/imagekit/cachefiles/backends.py b/imagekit/cachefiles/backends.py index 5a57c20..18c8e70 100644 --- a/imagekit/cachefiles/backends.py +++ b/imagekit/cachefiles/backends.py @@ -1,4 +1,4 @@ -from ..utils import get_singleton +from ..utils import get_singleton, sanitize_cache_key from django.core.cache import get_cache from django.core.exceptions import ImproperlyConfigured @@ -57,7 +57,8 @@ class CachedFileBackend(object): def get_key(self, file): from django.conf import settings - return '%s%s-state' % (settings.IMAGEKIT_CACHE_PREFIX, file.name) + return sanitize_cache_key('%s%s-state' % + (settings.IMAGEKIT_CACHE_PREFIX, file.name)) def get_state(self, file): key = self.get_key(file) diff --git a/imagekit/conf.py b/imagekit/conf.py index 3e454c0..dd082e7 100644 --- a/imagekit/conf.py +++ b/imagekit/conf.py @@ -13,6 +13,7 @@ class ImageKitConf(AppConf): CACHE_BACKEND = None CACHE_PREFIX = 'imagekit:' + USE_MEMCACHED_SAFE_CACHE_KEY = True def configure_cache_backend(self, value): if value is None: diff --git a/imagekit/utils.py b/imagekit/utils.py index ae81760..6590a8a 100644 --- a/imagekit/utils.py +++ b/imagekit/utils.py @@ -1,10 +1,16 @@ import logging from tempfile import NamedTemporaryFile +from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.core.files import File from django.utils.importlib import import_module +from hashlib import md5 from pilkit.utils import * +import re + + +bad_memcached_key_chars = re.compile(ur'[\u0000-\u0031\s]+') def get_nonabstract_descendants(model): @@ -123,3 +129,17 @@ def call_strategy_method(generator, method_name, *args, **kwargs): fn = getattr(strategy, method_name, None) if fn is not None: fn(*args, **kwargs) + + +def sanitize_cache_key(key): + if settings.IMAGEKIT_USE_MEMCACHED_SAFE_CACHE_KEY: + # Memcached keys can't contain whitespace or control characters. + new_key = bad_memcached_key_chars.sub('', key) + + # The also can't be > 250 chars long. Since we don't know what the + # user's cache ``KEY_FUNCTION`` setting is like, we'll limit it to 200. + if len(new_key) >= 200: + new_key = '%s:%s' % (new_key[:200-33], md5(key).hexdigest()) + + key = new_key + return key