mirror of https://github.com/django/django.git
Fixed #27225 -- Added "Age" header when fetching cached responses.
Co-Authored-By: Author: Alexander Lazarević <laza@e11bits.com>
This commit is contained in:
parent
4b1cd8edc1
commit
3580b47ed3
|
@ -43,6 +43,8 @@ More details about how the caching works:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import DEFAULT_CACHE_ALIAS, caches
|
from django.core.cache import DEFAULT_CACHE_ALIAS, caches
|
||||||
from django.utils.cache import (
|
from django.utils.cache import (
|
||||||
|
@ -53,6 +55,7 @@ from django.utils.cache import (
|
||||||
patch_response_headers,
|
patch_response_headers,
|
||||||
)
|
)
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
|
from django.utils.http import parse_http_date_safe
|
||||||
|
|
||||||
|
|
||||||
class UpdateCacheMiddleware(MiddlewareMixin):
|
class UpdateCacheMiddleware(MiddlewareMixin):
|
||||||
|
@ -171,6 +174,15 @@ class FetchFromCacheMiddleware(MiddlewareMixin):
|
||||||
request._cache_update_cache = True
|
request._cache_update_cache = True
|
||||||
return None # No cache information available, need to rebuild.
|
return None # No cache information available, need to rebuild.
|
||||||
|
|
||||||
|
# Derive the age estimation of the cached response.
|
||||||
|
if (max_age_seconds := get_max_age(response)) is not None and (
|
||||||
|
expires_timestamp := parse_http_date_safe(response["Expires"])
|
||||||
|
) is not None:
|
||||||
|
now_timestamp = int(time.time())
|
||||||
|
remaining_seconds = expires_timestamp - now_timestamp
|
||||||
|
# Use Age: 0 if local clock got turned back.
|
||||||
|
response["Age"] = max(0, max_age_seconds - remaining_seconds)
|
||||||
|
|
||||||
# hit, return cached response
|
# hit, return cached response
|
||||||
request._cache_update_cache = False
|
request._cache_update_cache = False
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -2752,6 +2752,37 @@ class CacheMiddlewareTest(SimpleTestCase):
|
||||||
|
|
||||||
self.assertIsNot(thread_caches[0], thread_caches[1])
|
self.assertIsNot(thread_caches[0], thread_caches[1])
|
||||||
|
|
||||||
|
def test_cache_control_max_age(self):
|
||||||
|
view = cache_page(2)(hello_world_view)
|
||||||
|
request = self.factory.get("/view/")
|
||||||
|
|
||||||
|
# First request. Freshly created response gets returned with no Age
|
||||||
|
# header.
|
||||||
|
with mock.patch.object(
|
||||||
|
time, "time", return_value=1468749600
|
||||||
|
): # Sun, 17 Jul 2016 10:00:00 GMT
|
||||||
|
response = view(request, 1)
|
||||||
|
response.close()
|
||||||
|
self.assertIn("Expires", response)
|
||||||
|
self.assertEqual(response["Expires"], "Sun, 17 Jul 2016 10:00:02 GMT")
|
||||||
|
self.assertIn("Cache-Control", response)
|
||||||
|
self.assertEqual(response["Cache-Control"], "max-age=2")
|
||||||
|
self.assertNotIn("Age", response)
|
||||||
|
|
||||||
|
# Second request one second later. Response from the cache gets
|
||||||
|
# returned with an Age header set to 1 (second).
|
||||||
|
with mock.patch.object(
|
||||||
|
time, "time", return_value=1468749601
|
||||||
|
): # Sun, 17 Jul 2016 10:00:01 GMT
|
||||||
|
response = view(request, 1)
|
||||||
|
response.close()
|
||||||
|
self.assertIn("Expires", response)
|
||||||
|
self.assertEqual(response["Expires"], "Sun, 17 Jul 2016 10:00:02 GMT")
|
||||||
|
self.assertIn("Cache-Control", response)
|
||||||
|
self.assertEqual(response["Cache-Control"], "max-age=2")
|
||||||
|
self.assertIn("Age", response)
|
||||||
|
self.assertEqual(response["Age"], "1")
|
||||||
|
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
CACHE_MIDDLEWARE_KEY_PREFIX="settingsprefix",
|
CACHE_MIDDLEWARE_KEY_PREFIX="settingsprefix",
|
||||||
|
|
Loading…
Reference in New Issue