From 6a057e1595dfe45a0411c116f603801266c87395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 25 Feb 2013 16:10:57 -0700 Subject: [PATCH] Fixed #18191 -- Don't consider Accept-Language redundantly in cache key. Thanks to choongmin for the original patch. --- django/utils/cache.py | 14 +++++- tests/regressiontests/cache/tests.py | 67 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/django/utils/cache.py b/django/utils/cache.py index 0fceaa96e6..8f111592c4 100644 --- a/django/utils/cache.py +++ b/django/utils/cache.py @@ -236,8 +236,18 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None, cach if cache is None: cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS) if response.has_header('Vary'): - headerlist = ['HTTP_'+header.upper().replace('-', '_') - for header in cc_delim_re.split(response['Vary'])] + is_accept_language_redundant = settings.USE_I18N or settings.USE_L10N + # If i18n or l10n are used, the generated cache key will be suffixed + # with the current locale. Adding the raw value of Accept-Language is + # redundant in that case and would result in storing the same content + # under multiple keys in the cache. See #18191 for details. + headerlist = [] + for header in cc_delim_re.split(response['Vary']): + header = header.upper().replace('-', '_') + if header == 'ACCEPT_LANGUAGE' and is_accept_language_redundant: + continue + headerlist.append('HTTP_' + header) + headerlist.sort() cache.set(cache_key, headerlist, cache_timeout) return _generate_cache_key(request, request.method, headerlist, key_prefix) else: diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py index d5d538319a..70d33a1ddf 100644 --- a/tests/regressiontests/cache/tests.py +++ b/tests/regressiontests/cache/tests.py @@ -1324,6 +1324,73 @@ class CacheI18nTest(TestCase): key2 = get_cache_key(request) self.assertEqual(key, key2) + def check_accept_language_vary(self, accept_language, vary, reference_key): + request = self._get_request() + request.META['HTTP_ACCEPT_LANGUAGE'] = accept_language + request.META['HTTP_ACCEPT_ENCODING'] = 'gzip;q=1.0, identity; q=0.5, *;q=0' + response = HttpResponse() + response['Vary'] = vary + key = learn_cache_key(request, response) + key2 = get_cache_key(request) + self.assertEqual(key, reference_key) + self.assertEqual(key2, reference_key) + + @override_settings(USE_I18N=True, USE_L10N=False, USE_TZ=False) + def test_cache_key_i18n_translation_accept_language(self): + lang = translation.get_language() + self.assertEqual(lang, 'en') + request = self._get_request() + request.META['HTTP_ACCEPT_ENCODING'] = 'gzip;q=1.0, identity; q=0.5, *;q=0' + response = HttpResponse() + response['Vary'] = 'accept-encoding' + key = learn_cache_key(request, response) + self.assertIn(lang, key, "Cache keys should include the language name when translation is active") + self.check_accept_language_vary( + 'en-us', + 'cookie, accept-language, accept-encoding', + key + ) + self.check_accept_language_vary( + 'en-US', + 'cookie, accept-encoding, accept-language', + key + ) + self.check_accept_language_vary( + 'en-US,en;q=0.8', + 'accept-encoding, accept-language, cookie', + key + ) + self.check_accept_language_vary( + 'en-US,en;q=0.8,ko;q=0.6', + 'accept-language, cookie, accept-encoding', + key + ) + self.check_accept_language_vary( + 'ko-kr,ko;q=0.8,en-us;q=0.5,en;q=0.3 ', + 'accept-encoding, cookie, accept-language', + key + ) + self.check_accept_language_vary( + 'ko-KR,ko;q=0.8,en-US;q=0.6,en;q=0.4', + 'accept-language, accept-encoding, cookie', + key + ) + self.check_accept_language_vary( + 'ko;q=1.0,en;q=0.5', + 'cookie, accept-language, accept-encoding', + key + ) + self.check_accept_language_vary( + 'ko, en', + 'cookie, accept-encoding, accept-language', + key + ) + self.check_accept_language_vary( + 'ko-KR, en-US', + 'accept-encoding, accept-language, cookie', + key + ) + @override_settings(USE_I18N=False, USE_L10N=True, USE_TZ=False) def test_cache_key_i18n_formatting(self): request = self._get_request()