Fixed #17476 -- Ensure timezone-dependant cache keys only use ASCII characters, especially on Windows.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17286 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
ec07a30e82
commit
3367913c3d
|
@ -23,7 +23,7 @@ import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import get_cache
|
from django.core.cache import get_cache
|
||||||
from django.utils.encoding import smart_str, iri_to_uri
|
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
|
||||||
from django.utils.http import http_date
|
from django.utils.http import http_date
|
||||||
from django.utils.timezone import get_current_timezone_name
|
from django.utils.timezone import get_current_timezone_name
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
|
@ -165,9 +165,12 @@ def _i18n_cache_key_suffix(request, cache_key):
|
||||||
# which in turn can also fall back to settings.LANGUAGE_CODE
|
# which in turn can also fall back to settings.LANGUAGE_CODE
|
||||||
cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language())
|
cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language())
|
||||||
if settings.USE_TZ:
|
if settings.USE_TZ:
|
||||||
# Windows uses non-standard timezone names that may include spaces,
|
# The datetime module doesn't restrict the output of tzname().
|
||||||
# which triggers CacheKeyWarning.
|
# Windows is known to use non-standard, locale-dependant names.
|
||||||
cache_key += '.%s' % get_current_timezone_name().replace(' ', '_')
|
# User-defined tzinfo classes may return absolutely anything.
|
||||||
|
# Hence this paranoid conversion to create a valid cache key.
|
||||||
|
tz_name = force_unicode(get_current_timezone_name(), errors='ignore')
|
||||||
|
cache_key += '.%s' % tz_name.encode('ascii', 'ignore').replace(' ', '_')
|
||||||
return cache_key
|
return cache_key
|
||||||
|
|
||||||
def _generate_cache_key(request, method, headerlist, key_prefix):
|
def _generate_cache_key(request, method, headerlist, key_prefix):
|
||||||
|
|
|
@ -28,6 +28,7 @@ from django.test.utils import (get_warnings_state, restore_warnings_state,
|
||||||
from django.utils import timezone, translation, unittest
|
from django.utils import timezone, translation, unittest
|
||||||
from django.utils.cache import (patch_vary_headers, get_cache_key,
|
from django.utils.cache import (patch_vary_headers, get_cache_key,
|
||||||
learn_cache_key, patch_cache_control, patch_response_headers)
|
learn_cache_key, patch_cache_control, patch_response_headers)
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
from django.views.decorators.cache import cache_page
|
from django.views.decorators.cache import cache_page
|
||||||
|
|
||||||
from .models import Poll, expensive_calculation
|
from .models import Poll, expensive_calculation
|
||||||
|
@ -1270,7 +1271,10 @@ class CacheI18nTest(TestCase):
|
||||||
@override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True)
|
@override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True)
|
||||||
def test_cache_key_i18n_timezone(self):
|
def test_cache_key_i18n_timezone(self):
|
||||||
request = self._get_request()
|
request = self._get_request()
|
||||||
tz = timezone.get_current_timezone_name().replace(' ', '_')
|
# This is tightly coupled to the implementation,
|
||||||
|
# but it's the most straightforward way to test the key.
|
||||||
|
tz = force_unicode(timezone.get_current_timezone_name(), errors='ignore')
|
||||||
|
tz = tz.encode('ascii', 'ignore').replace(' ', '_')
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
key = learn_cache_key(request, response)
|
key = learn_cache_key(request, response)
|
||||||
self.assertIn(tz, key, "Cache keys should include the time zone name when time zones are active")
|
self.assertIn(tz, key, "Cache keys should include the time zone name when time zones are active")
|
||||||
|
@ -1281,12 +1285,35 @@ class CacheI18nTest(TestCase):
|
||||||
def test_cache_key_no_i18n (self):
|
def test_cache_key_no_i18n (self):
|
||||||
request = self._get_request()
|
request = self._get_request()
|
||||||
lang = translation.get_language()
|
lang = translation.get_language()
|
||||||
tz = timezone.get_current_timezone_name().replace(' ', '_')
|
tz = force_unicode(timezone.get_current_timezone_name(), errors='ignore')
|
||||||
|
tz = tz.encode('ascii', 'ignore').replace(' ', '_')
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
key = learn_cache_key(request, response)
|
key = learn_cache_key(request, response)
|
||||||
self.assertNotIn(lang, key, "Cache keys shouldn't include the language name when i18n isn't active")
|
self.assertNotIn(lang, key, "Cache keys shouldn't include the language name when i18n isn't active")
|
||||||
self.assertNotIn(tz, key, "Cache keys shouldn't include the time zone name when i18n isn't active")
|
self.assertNotIn(tz, key, "Cache keys shouldn't include the time zone name when i18n isn't active")
|
||||||
|
|
||||||
|
@override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True)
|
||||||
|
def test_cache_key_with_non_ascii_tzname(self):
|
||||||
|
# Regression test for #17476
|
||||||
|
class CustomTzName(timezone.UTC):
|
||||||
|
name = ''
|
||||||
|
def tzname(self, dt):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
request = self._get_request()
|
||||||
|
response = HttpResponse()
|
||||||
|
with timezone.override(CustomTzName()):
|
||||||
|
CustomTzName.name = 'Hora estándar de Argentina' # UTF-8 string
|
||||||
|
sanitized_name = 'Hora_estndar_de_Argentina'
|
||||||
|
self.assertIn(sanitized_name, learn_cache_key(request, response),
|
||||||
|
"Cache keys should include the time zone name when time zones are active")
|
||||||
|
|
||||||
|
CustomTzName.name = u'Hora estándar de Argentina' # unicode
|
||||||
|
sanitized_name = 'Hora_estndar_de_Argentina'
|
||||||
|
self.assertIn(sanitized_name, learn_cache_key(request, response),
|
||||||
|
"Cache keys should include the time zone name when time zones are active")
|
||||||
|
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
CACHE_MIDDLEWARE_KEY_PREFIX="test",
|
CACHE_MIDDLEWARE_KEY_PREFIX="test",
|
||||||
CACHE_MIDDLEWARE_SECONDS=60,
|
CACHE_MIDDLEWARE_SECONDS=60,
|
||||||
|
|
Loading…
Reference in New Issue