summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2017-09-02 21:09:22 -0400
committerTim Graham <timograham@gmail.com>2017-09-22 12:51:18 -0400
commit48d57788ee56811fa77cd37b9edf40535f82d87e (patch)
tree287dccd8f73cc4ef5d0f57eb5607fa1076a75bc0
parent4502489a466b89cccd9d2c1b8d21b2f153d71b4b (diff)
Refs #26447 -- Removed the USE_ETAGS setting per deprecation timeline.
-rw-r--r--django/conf/global_settings.py5
-rw-r--r--django/middleware/common.py33
-rw-r--r--django/utils/cache.py14
-rw-r--r--docs/ref/middleware.txt16
-rw-r--r--docs/ref/settings.txt18
-rw-r--r--docs/ref/utils.txt6
-rw-r--r--docs/releases/2.1.txt3
-rw-r--r--tests/admin_views/tests.py20
-rw-r--r--tests/cache/tests.py38
-rw-r--r--tests/middleware/tests.py58
10 files changed, 8 insertions, 203 deletions
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 754e6e5cdf..4d7c5854e2 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -21,11 +21,6 @@ DEBUG = False
# on a live site.
DEBUG_PROPAGATE_EXCEPTIONS = False
-# Whether to use the "ETag" header. This saves bandwidth but slows down performance.
-# Deprecated (RemovedInDjango21Warning) in favor of ConditionalGetMiddleware
-# which sets the ETag regardless of this setting.
-USE_ETAGS = False
-
# People who get code error notifications.
# In the format [('Full Name', 'email@example.com'), ('Full Name', 'anotheremail@example.com')]
ADMINS = []
diff --git a/django/middleware/common.py b/django/middleware/common.py
index d8cfb9a8b0..7e520b7061 100644
--- a/django/middleware/common.py
+++ b/django/middleware/common.py
@@ -1,5 +1,4 @@
import re
-import warnings
from urllib.parse import urlparse
from django.conf import settings
@@ -7,10 +6,7 @@ from django.core.exceptions import PermissionDenied
from django.core.mail import mail_managers
from django.http import HttpResponsePermanentRedirect
from django.urls import is_valid_path
-from django.utils.cache import (
- cc_delim_re, get_conditional_response, set_response_etag,
-)
-from django.utils.deprecation import MiddlewareMixin, RemovedInDjango21Warning
+from django.utils.deprecation import MiddlewareMixin
class CommonMiddleware(MiddlewareMixin):
@@ -30,11 +26,6 @@ class CommonMiddleware(MiddlewareMixin):
This behavior can be customized by subclassing CommonMiddleware and
overriding the response_redirect_class attribute.
-
- - ETags: If the USE_ETAGS setting is set, ETags will be calculated from
- the entire page content and Not Modified responses will be returned
- appropriately. USE_ETAGS is deprecated in favor of
- ConditionalGetMiddleware.
"""
response_redirect_class = HttpResponsePermanentRedirect
@@ -114,23 +105,6 @@ 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 and self.needs_etag(response):
- warnings.warn(
- "The USE_ETAGS setting is deprecated in favor of "
- "ConditionalGetMiddleware which sets the ETag regardless of "
- "the setting. CommonMiddleware won't do ETag processing in "
- "Django 2.1.",
- RemovedInDjango21Warning
- )
- if not response.has_header('ETag'):
- set_response_etag(response)
-
- if response.has_header('ETag'):
- return get_conditional_response(
- request,
- etag=response['ETag'],
- response=response,
- )
# Add the Content-Length header to non-streaming responses if not
# already set.
if not response.streaming and not response.has_header('Content-Length'):
@@ -138,11 +112,6 @@ 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/django/utils/cache.py b/django/utils/cache.py
index b1abbf0648..81fc44293e 100644
--- a/django/utils/cache.py
+++ b/django/utils/cache.py
@@ -20,12 +20,10 @@ import hashlib
import logging
import re
import time
-import warnings
from django.conf import settings
from django.core.cache import caches
from django.http import HttpResponse, HttpResponseNotModified
-from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_bytes, force_text, iri_to_uri
from django.utils.http import (
http_date, parse_etags, parse_http_date_safe, quote_etag,
@@ -248,18 +246,6 @@ def patch_response_headers(response, cache_timeout=None):
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
if cache_timeout < 0:
cache_timeout = 0 # Can't have max-age negative
- if settings.USE_ETAGS and not response.has_header('ETag'):
- warnings.warn(
- "The USE_ETAGS setting is deprecated in favor of "
- "ConditionalGetMiddleware which sets the ETag regardless of the "
- "setting. patch_response_headers() won't do ETag processing in "
- "Django 2.1.",
- RemovedInDjango21Warning
- )
- if hasattr(response, 'render') and callable(response.render):
- response.add_post_render_callback(set_response_etag)
- else:
- response = set_response_etag(response)
if not response.has_header('Expires'):
response['Expires'] = http_date(time.time() + cache_timeout)
patch_cache_control(response, max_age=cache_timeout)
diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt
index 5c33d196d3..05f06092aa 100644
--- a/docs/ref/middleware.txt
+++ b/docs/ref/middleware.txt
@@ -61,23 +61,12 @@ Adds a few conveniences for perfectionists:
indexer would treat them as separate URLs -- so it's best practice to
normalize URLs.
-* Handles ETags based on the :setting:`USE_ETAGS` setting. If
- :setting:`USE_ETAGS` is set to ``True``, Django will calculate an ETag
- for each request by MD5-hashing the page content, and it'll take care of
- sending ``Not Modified`` responses, if appropriate.
-
* Sets the ``Content-Length`` header for non-streaming responses.
.. versionchanged:: 1.11
Older versions didn't set the ``Content-Length`` header.
-.. deprecated:: 1.11
-
- The :setting:`USE_ETAGS` setting is deprecated in favor of using
- :class:`~django.middleware.http.ConditionalGetMiddleware` for ETag
- processing.
-
.. attribute:: CommonMiddleware.response_redirect_class
Defaults to :class:`~django.http.HttpResponsePermanentRedirect`. Subclass
@@ -472,11 +461,6 @@ Here are some hints about the ordering of various Django middleware classes:
After ``UpdateCacheMiddleware``: Modifies ``Vary`` header.
-#. :class:`~django.middleware.http.ConditionalGetMiddleware`
-
- Before ``CommonMiddleware``: uses its ``ETag`` header when
- :setting:`USE_ETAGS` = ``True``.
-
#. :class:`~django.contrib.sessions.middleware.SessionMiddleware`
After ``UpdateCacheMiddleware``: Modifies ``Vary`` header.
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 358de5eca0..b9dc61686b 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -2593,23 +2593,6 @@ the correct environment.
.. _list of time zones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
-.. setting:: USE_ETAGS
-
-``USE_ETAGS``
--------------
-
-Default: ``False``
-
-A boolean that specifies whether to output the ``ETag`` header. This saves
-bandwidth but slows down performance. This is used by the
-:class:`~django.middleware.common.CommonMiddleware` and in the :doc:`cache
-framework </topics/cache>`.
-
-.. deprecated:: 1.11
-
- This setting is deprecated in favor of using ``ConditionalGetMiddleware``,
- which sets an ETag regardless of this setting.
-
.. setting:: USE_I18N
``USE_I18N``
@@ -3438,7 +3421,6 @@ HTTP
* :setting:`SECURE_SSL_HOST`
* :setting:`SECURE_SSL_REDIRECT`
* :setting:`SIGNING_BACKEND`
-* :setting:`USE_ETAGS`
* :setting:`USE_X_FORWARDED_HOST`
* :setting:`USE_X_FORWARDED_PORT`
* :setting:`WSGI_APPLICATION`
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index c9fa10e0e5..596edaa09a 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -52,7 +52,6 @@ need to distinguish caches by the ``Accept-language`` header.
Adds some useful headers to the given ``HttpResponse`` object:
- * ``ETag``
* ``Expires``
* ``Cache-Control``
@@ -65,11 +64,6 @@ need to distinguish caches by the ``Accept-language`` header.
In older versions, the ``Last-Modified`` header was also set.
- .. deprecated:: 1.11
-
- Since the ``USE_ETAGS`` setting is deprecated, this function won't set
- the ``ETag`` header when the deprecation ends in Django 2.1.
-
.. function:: add_never_cache_headers(response)
Adds a ``Cache-Control: max-age=0, no-cache, no-store, must-revalidate``
diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt
index 5effa6eba9..de7150b7b7 100644
--- a/docs/releases/2.1.txt
+++ b/docs/releases/2.1.txt
@@ -251,3 +251,6 @@ how to remove usage of these features.
as the first positional argument.
* The ``django.db.models.permalink()`` decorator is removed.
+
+* The ``USE_ETAGS`` setting is removed. ``CommonMiddleware`` and
+ ``django.utils.cache.patch_response_headers()`` no longer set ETags.
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 10e1303659..ff06dbae19 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -25,14 +25,12 @@ from django.core.files import temp as tempfile
from django.forms.utils import ErrorList
from django.template.response import TemplateResponse
from django.test import (
- SimpleTestCase, TestCase, ignore_warnings, modify_settings,
- override_settings, skipUnlessDBFeature,
+ TestCase, modify_settings, override_settings, skipUnlessDBFeature,
)
from django.test.utils import override_script_prefix, patch_logger
from django.urls import NoReverseMatch, resolve, reverse
from django.utils import formats, translation
from django.utils.cache import get_max_age
-from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_bytes, force_text, iri_to_uri
from django.utils.html import escape
from django.utils.http import urlencode
@@ -5810,22 +5808,6 @@ class InlineAdminViewOnSiteTest(TestCase):
@override_settings(ROOT_URLCONF='admin_views.urls')
-class TestETagWithAdminView(SimpleTestCase):
- # The admin is compatible with ETags (#16003).
-
- def test_admin(self):
- with self.settings(USE_ETAGS=False):
- response = self.client.get(reverse('admin:index'))
- self.assertEqual(response.status_code, 302)
- self.assertFalse(response.has_header('ETag'))
-
- with self.settings(USE_ETAGS=True), ignore_warnings(category=RemovedInDjango21Warning):
- response = self.client.get(reverse('admin:index'))
- self.assertEqual(response.status_code, 302)
- self.assertTrue(response.has_header('ETag'))
-
-
-@override_settings(ROOT_URLCONF='admin_views.urls')
class GetFormsetsWithInlinesArgumentTest(TestCase):
"""
#23934 - When adding a new model instance in the admin, the 'obj' argument
diff --git a/tests/cache/tests.py b/tests/cache/tests.py
index d3c9513303..57e4ec15b4 100644
--- a/tests/cache/tests.py
+++ b/tests/cache/tests.py
@@ -32,15 +32,13 @@ from django.template.context_processors import csrf
from django.template.response import TemplateResponse
from django.test import (
RequestFactory, SimpleTestCase, TestCase, TransactionTestCase,
- ignore_warnings, override_settings,
+ override_settings,
)
from django.test.signals import setting_changed
from django.utils import timezone, translation
from django.utils.cache import (
- get_cache_key, learn_cache_key, patch_cache_control,
- patch_response_headers, patch_vary_headers,
+ get_cache_key, learn_cache_key, patch_cache_control, patch_vary_headers,
)
-from django.utils.deprecation import RemovedInDjango21Warning
from django.views.decorators.cache import cache_page
from .models import Poll, expensive_calculation
@@ -1838,11 +1836,9 @@ class CacheI18nTest(TestCase):
"Cache keys should include the time zone name when time zones are active"
)
- @ignore_warnings(category=RemovedInDjango21Warning) # USE_ETAGS=True
@override_settings(
CACHE_MIDDLEWARE_KEY_PREFIX="test",
CACHE_MIDDLEWARE_SECONDS=60,
- USE_ETAGS=True,
USE_I18N=True,
)
def test_middleware(self):
@@ -1884,14 +1880,6 @@ class CacheI18nTest(TestCase):
# The cache can be recovered
self.assertIsNotNone(get_cache_data)
self.assertEqual(get_cache_data.content, en_message.encode())
- # ETags are used.
- self.assertTrue(get_cache_data.has_header('ETag'))
- # ETags can be disabled.
- with self.settings(USE_ETAGS=False):
- request._cache_update_cache = True
- set_cache(request, 'en', en_message)
- get_cache_data = FetchFromCacheMiddleware().process_request(request)
- self.assertFalse(get_cache_data.has_header('ETag'))
# change the session language and set content
request = self.factory.get(self.path)
request._cache_update_cache = True
@@ -1911,7 +1899,6 @@ class CacheI18nTest(TestCase):
@override_settings(
CACHE_MIDDLEWARE_KEY_PREFIX="test",
CACHE_MIDDLEWARE_SECONDS=60,
- USE_ETAGS=True,
)
def test_middleware_doesnt_cache_streaming_response(self):
request = self.factory.get(self.path)
@@ -2232,27 +2219,6 @@ class TestWithTemplateResponse(SimpleTestCase):
'0f1c2d56633c943073c4569d9a9502fe.d41d8cd98f00b204e9800998ecf8427e'
)
- @override_settings(USE_ETAGS=False)
- def test_without_etag(self):
- template = engines['django'].from_string("This is a test")
- response = TemplateResponse(HttpRequest(), template)
- self.assertFalse(response.has_header('ETag'))
- patch_response_headers(response)
- self.assertFalse(response.has_header('ETag'))
- response = response.render()
- self.assertFalse(response.has_header('ETag'))
-
- @ignore_warnings(category=RemovedInDjango21Warning)
- @override_settings(USE_ETAGS=True)
- def test_with_etag(self):
- template = engines['django'].from_string("This is a test")
- response = TemplateResponse(HttpRequest(), template)
- self.assertFalse(response.has_header('ETag'))
- patch_response_headers(response)
- self.assertFalse(response.has_header('ETag'))
- response = response.render()
- self.assertTrue(response.has_header('ETag'))
-
class TestMakeTemplateFragmentKey(SimpleTestCase):
def test_without_vary_on(self):
diff --git a/tests/middleware/tests.py b/tests/middleware/tests.py
index 8006938a5e..f3c8b9ca06 100644
--- a/tests/middleware/tests.py
+++ b/tests/middleware/tests.py
@@ -18,10 +18,7 @@ from django.middleware.common import (
)
from django.middleware.gzip import GZipMiddleware
from django.middleware.http import ConditionalGetMiddleware
-from django.test import (
- RequestFactory, SimpleTestCase, ignore_warnings, override_settings,
-)
-from django.utils.deprecation import RemovedInDjango21Warning
+from django.test import RequestFactory, SimpleTestCase, override_settings
int2byte = struct.Struct(">B").pack
@@ -265,57 +262,6 @@ class CommonMiddlewareTest(SimpleTestCase):
self.assertEqual(r.status_code, 301)
self.assertEqual(r.url, 'http://www.testserver/customurlconf/slash/')
- # ETag + If-Not-Modified support tests
-
- @ignore_warnings(category=RemovedInDjango21Warning)
- @override_settings(USE_ETAGS=True)
- def test_etag(self):
- req = HttpRequest()
- res = HttpResponse('content')
- self.assertTrue(CommonMiddleware().process_response(req, res).has_header('ETag'))
-
- @ignore_warnings(category=RemovedInDjango21Warning)
- @override_settings(USE_ETAGS=True)
- def test_etag_streaming_response(self):
- req = HttpRequest()
- res = StreamingHttpResponse(['content'])
- res['ETag'] = 'tomatoes'
- self.assertEqual(CommonMiddleware().process_response(req, res).get('ETag'), 'tomatoes')
-
- @ignore_warnings(category=RemovedInDjango21Warning)
- @override_settings(USE_ETAGS=True)
- def test_no_etag_streaming_response(self):
- req = HttpRequest()
- res = StreamingHttpResponse(['content'])
- self.assertFalse(CommonMiddleware().process_response(req, res).has_header('ETag'))
-
- @ignore_warnings(category=RemovedInDjango21Warning)
- @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'))
-
- @ignore_warnings(category=RemovedInDjango21Warning)
- @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'))
-
- @ignore_warnings(category=RemovedInDjango21Warning)
- @override_settings(USE_ETAGS=True)
- def test_if_none_match(self):
- first_req = HttpRequest()
- first_res = CommonMiddleware().process_response(first_req, HttpResponse('content'))
- second_req = HttpRequest()
- second_req.method = 'GET'
- second_req.META['HTTP_IF_NONE_MATCH'] = first_res['ETag']
- second_res = CommonMiddleware().process_response(second_req, HttpResponse('content'))
- self.assertEqual(second_res.status_code, 304)
-
# Tests for the Content-Length header
def test_content_length_header_added(self):
@@ -855,8 +801,6 @@ class GZipMiddlewareTest(SimpleTestCase):
self.assertEqual(self.get_mtime(r2.content), 0)
-@ignore_warnings(category=RemovedInDjango21Warning)
-@override_settings(USE_ETAGS=True)
class ETagGZipMiddlewareTest(SimpleTestCase):
"""
ETags are handled properly by GZipMiddleware.