diff --git a/django/middleware/cache.py b/django/middleware/cache.py index 8af0c9db7c..6b320f1db5 100644 --- a/django/middleware/cache.py +++ b/django/middleware/cache.py @@ -85,6 +85,10 @@ class UpdateCacheMiddleware(MiddlewareMixin): if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'): return response + # Don't cache a response with 'Cache-Control: private' + if 'private' in response.get('Cache-Control', ()): + return response + # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. diff --git a/tests/cache/tests.py b/tests/cache/tests.py index 79c49edd7e..86f5bdce38 100644 --- a/tests/cache/tests.py +++ b/tests/cache/tests.py @@ -39,7 +39,7 @@ from django.utils import timezone, translation from django.utils.cache import ( get_cache_key, learn_cache_key, patch_cache_control, patch_vary_headers, ) -from django.views.decorators.cache import cache_page +from django.views.decorators.cache import cache_control, cache_page from .models import Poll, expensive_calculation @@ -2163,6 +2163,15 @@ class CacheMiddlewareTest(SimpleTestCase): response = other_with_prefix_view(request, '16') self.assertEqual(response.content, b'Hello World 16') + def test_cached_control_private_not_cached(self): + """Responses with 'Cache-Control: private' are not cached.""" + view_with_private_cache = cache_page(3)(cache_control(private=True)(hello_world_view)) + request = self.factory.get('/view/') + response = view_with_private_cache(request, '1') + self.assertEqual(response.content, b'Hello World 1') + response = view_with_private_cache(request, '2') + self.assertEqual(response.content, b'Hello World 2') + def test_sensitive_cookie_not_cached(self): """ Django must prevent caching of responses that set a user-specific (and