mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		| @@ -23,7 +23,7 @@ import time | ||||
|  | ||||
| from django.conf import settings | ||||
| 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.timezone import get_current_timezone_name | ||||
| 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 | ||||
|         cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language()) | ||||
|     if settings.USE_TZ: | ||||
|         # Windows uses non-standard timezone names that may include spaces, | ||||
|         # which triggers CacheKeyWarning. | ||||
|         cache_key += '.%s' % get_current_timezone_name().replace(' ', '_') | ||||
|         # The datetime module doesn't restrict the output of tzname(). | ||||
|         # Windows is known to use non-standard, locale-dependant names. | ||||
|         # 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 | ||||
|  | ||||
| def _generate_cache_key(request, method, headerlist, key_prefix): | ||||
|   | ||||
							
								
								
									
										31
									
								
								tests/regressiontests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								tests/regressiontests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							| @@ -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.cache import (patch_vary_headers, get_cache_key, | ||||
|     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 .models import Poll, expensive_calculation | ||||
| @@ -1270,7 +1271,10 @@ class CacheI18nTest(TestCase): | ||||
|     @override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True) | ||||
|     def test_cache_key_i18n_timezone(self): | ||||
|         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() | ||||
|         key = learn_cache_key(request, response) | ||||
|         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): | ||||
|         request = self._get_request() | ||||
|         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() | ||||
|         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(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( | ||||
|             CACHE_MIDDLEWARE_KEY_PREFIX="test", | ||||
|             CACHE_MIDDLEWARE_SECONDS=60, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user