Refs #26447 -- Removed the USE_ETAGS setting per deprecation timeline.

This commit is contained in:
Tim Graham 2017-09-02 21:09:22 -04:00
parent 4502489a46
commit 48d57788ee
10 changed files with 8 additions and 203 deletions

View File

@ -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 = []

View File

@ -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):

View File

@ -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)

View File

@ -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.

View File

@ -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`

View File

@ -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``

View File

@ -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.

View File

@ -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
@ -5809,22 +5807,6 @@ class InlineAdminViewOnSiteTest(TestCase):
self.assertContains(response, '"/worker_inline/%s/%s/"' % (self.w1.surname, self.w1.name))
@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):
"""

38
tests/cache/tests.py vendored
View File

@ -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):

View File

@ -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.