From 20d39325ca1da57a709f3ba38299dc7b0fc4bdfb Mon Sep 17 00:00:00 2001
From: andrewnester <andrew.nester.dev@gmail.com>
Date: Mon, 20 Jun 2016 22:46:33 +0300
Subject: [PATCH] Fixed #26765 -- Made CommonMiddleware no longer set an ETag
 when response has Cache-Control: no-store.

---
 django/middleware/common.py | 13 +++++++++++--
 tests/middleware/tests.py   | 14 ++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/django/middleware/common.py b/django/middleware/common.py
index b705f72b81..3d55baebde 100644
--- a/django/middleware/common.py
+++ b/django/middleware/common.py
@@ -5,7 +5,9 @@ from django.conf import settings
 from django.core.exceptions import PermissionDenied
 from django.core.mail import mail_managers
 from django.urls import is_valid_path
-from django.utils.cache import get_conditional_response, set_response_etag
+from django.utils.cache import (
+    cc_delim_re, get_conditional_response, set_response_etag,
+)
 from django.utils.deprecation import MiddlewareMixin
 from django.utils.encoding import force_text
 from django.utils.http import unquote_etag
@@ -113,7 +115,7 @@ class CommonMiddleware(MiddlewareMixin):
             if self.should_redirect_with_slash(request):
                 return self.response_redirect_class(self.get_full_path_with_slash(request))
 
-        if settings.USE_ETAGS:
+        if settings.USE_ETAGS and self.needs_etag(response):
             if not response.has_header('ETag'):
                 set_response_etag(response)
 
@@ -130,6 +132,13 @@ class CommonMiddleware(MiddlewareMixin):
 
         return response
 
+    def needs_etag(self, response):
+        """
+        Return True if an ETag header should be added to response.
+        """
+        cache_control_headers = cc_delim_re.split(response.get('Cache-Control', ''))
+        return all(header.lower() != 'no-store' for header in cache_control_headers)
+
 
 class BrokenLinkEmailsMiddleware(MiddlewareMixin):
 
diff --git a/tests/middleware/tests.py b/tests/middleware/tests.py
index f9ef951b44..07e1d4ea5a 100644
--- a/tests/middleware/tests.py
+++ b/tests/middleware/tests.py
@@ -275,6 +275,20 @@ class CommonMiddlewareTest(SimpleTestCase):
         res = StreamingHttpResponse(['content'])
         self.assertFalse(CommonMiddleware().process_response(req, res).has_header('ETag'))
 
+    @override_settings(USE_ETAGS=True)
+    def test_no_etag_no_store_cache(self):
+        req = HttpRequest()
+        res = HttpResponse('content')
+        res['Cache-Control'] = 'No-Cache, No-Store, Max-age=0'
+        self.assertFalse(CommonMiddleware().process_response(req, res).has_header('ETag'))
+
+    @override_settings(USE_ETAGS=True)
+    def test_etag_extended_cache_control(self):
+        req = HttpRequest()
+        res = HttpResponse('content')
+        res['Cache-Control'] = 'my-directive="my-no-store"'
+        self.assertTrue(CommonMiddleware().process_response(req, res).has_header('ETag'))
+
     @override_settings(USE_ETAGS=True)
     def test_if_none_match(self):
         first_req = HttpRequest()