Fixed #23755 -- Added support for multiple field names in the no-cache Cache-Control directive to patch_cache_control().
https://tools.ietf.org/html/rfc7234#section-5.2.2.2
This commit is contained in:
parent
2a6f45e08e
commit
ed112fadc1
|
@ -19,6 +19,7 @@ An example: i18n middleware would need to distinguish caches by the
|
||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import caches
|
from django.core.cache import caches
|
||||||
|
@ -53,17 +54,21 @@ def patch_cache_control(response, **kwargs):
|
||||||
else:
|
else:
|
||||||
return (t[0].lower(), True)
|
return (t[0].lower(), True)
|
||||||
|
|
||||||
def dictvalue(t):
|
def dictvalue(*t):
|
||||||
if t[1] is True:
|
if t[1] is True:
|
||||||
return t[0]
|
return t[0]
|
||||||
else:
|
else:
|
||||||
return '%s=%s' % (t[0], t[1])
|
return '%s=%s' % (t[0], t[1])
|
||||||
|
|
||||||
|
cc = defaultdict(set)
|
||||||
if response.get('Cache-Control'):
|
if response.get('Cache-Control'):
|
||||||
cc = cc_delim_re.split(response['Cache-Control'])
|
for field in cc_delim_re.split(response['Cache-Control']):
|
||||||
cc = dict(dictitem(el) for el in cc)
|
directive, value = dictitem(field)
|
||||||
|
if directive == 'no-cache':
|
||||||
|
# no-cache supports multiple field names.
|
||||||
|
cc[directive].add(value)
|
||||||
else:
|
else:
|
||||||
cc = {}
|
cc[directive] = value
|
||||||
|
|
||||||
# If there's already a max-age header but we're being asked to set a new
|
# If there's already a max-age header but we're being asked to set a new
|
||||||
# max-age, use the minimum of the two ages. In practice this happens when
|
# max-age, use the minimum of the two ages. In practice this happens when
|
||||||
|
@ -78,8 +83,23 @@ def patch_cache_control(response, **kwargs):
|
||||||
del cc['public']
|
del cc['public']
|
||||||
|
|
||||||
for (k, v) in kwargs.items():
|
for (k, v) in kwargs.items():
|
||||||
cc[k.replace('_', '-')] = v
|
directive = k.replace('_', '-')
|
||||||
cc = ', '.join(dictvalue(el) for el in cc.items())
|
if directive == 'no-cache':
|
||||||
|
# no-cache supports multiple field names.
|
||||||
|
cc[directive].add(v)
|
||||||
|
else:
|
||||||
|
cc[directive] = v
|
||||||
|
|
||||||
|
directives = []
|
||||||
|
for directive, values in cc.items():
|
||||||
|
if isinstance(values, set):
|
||||||
|
if True in values:
|
||||||
|
# True takes precedence.
|
||||||
|
values = {True}
|
||||||
|
directives.extend([dictvalue(directive, value) for value in values])
|
||||||
|
else:
|
||||||
|
directives.append(dictvalue(directive, values))
|
||||||
|
cc = ', '.join(directives)
|
||||||
response['Cache-Control'] = cc
|
response['Cache-Control'] = cc
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,11 @@ need to distinguish caches by the ``Accept-language`` header.
|
||||||
* All other parameters are added with their value, after applying
|
* All other parameters are added with their value, after applying
|
||||||
``str()`` to it.
|
``str()`` to it.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.1
|
||||||
|
|
||||||
|
Support for multiple field names in the ``no-cache`` directive was
|
||||||
|
added.
|
||||||
|
|
||||||
.. function:: get_max_age(response)
|
.. function:: get_max_age(response)
|
||||||
|
|
||||||
Returns the max-age from the response Cache-Control header as an integer
|
Returns the max-age from the response Cache-Control header as an integer
|
||||||
|
|
|
@ -104,7 +104,10 @@ Minor features
|
||||||
Cache
|
Cache
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
* ...
|
* The :func:`~django.views.decorators.cache.cache_control` decorator and
|
||||||
|
:func:`~django.utils.cache.patch_cache_control` method now support multiple
|
||||||
|
field names in the ``no-cache`` directive for the ``Cache-Control`` header,
|
||||||
|
according to :rfc:`7234#section-5.2.2.2`.
|
||||||
|
|
||||||
CSRF
|
CSRF
|
||||||
~~~~
|
~~~~
|
||||||
|
|
|
@ -1277,6 +1277,7 @@ Here are some more examples:
|
||||||
* ``no_transform=True``
|
* ``no_transform=True``
|
||||||
* ``must_revalidate=True``
|
* ``must_revalidate=True``
|
||||||
* ``stale_while_revalidate=num_seconds``
|
* ``stale_while_revalidate=num_seconds``
|
||||||
|
* ``no_cache=True``
|
||||||
|
|
||||||
The full list of known directives can be found in the `IANA registry`_
|
The full list of known directives can be found in the `IANA registry`_
|
||||||
(note that not all of them apply to responses).
|
(note that not all of them apply to responses).
|
||||||
|
|
|
@ -1705,6 +1705,12 @@ class CacheUtils(SimpleTestCase):
|
||||||
('', {'no-cache': 'Set-Cookie'}, {'no-cache=Set-Cookie'}),
|
('', {'no-cache': 'Set-Cookie'}, {'no-cache=Set-Cookie'}),
|
||||||
('no-cache=Set-Cookie', {'no_cache': True}, {'no-cache'}),
|
('no-cache=Set-Cookie', {'no_cache': True}, {'no-cache'}),
|
||||||
('no-cache=Set-Cookie,no-cache=Link', {'no_cache': True}, {'no-cache'}),
|
('no-cache=Set-Cookie,no-cache=Link', {'no_cache': True}, {'no-cache'}),
|
||||||
|
('no-cache=Set-Cookie', {'no_cache': 'Link'}, {'no-cache=Set-Cookie', 'no-cache=Link'}),
|
||||||
|
(
|
||||||
|
'no-cache=Set-Cookie,no-cache=Link',
|
||||||
|
{'no_cache': 'Custom'},
|
||||||
|
{'no-cache=Set-Cookie', 'no-cache=Link', 'no-cache=Custom'},
|
||||||
|
),
|
||||||
# Test whether private/public attributes are mutually exclusive
|
# Test whether private/public attributes are mutually exclusive
|
||||||
('private', {'private': True}, {'private'}),
|
('private', {'private': True}, {'private'}),
|
||||||
('private', {'public': True}, {'public'}),
|
('private', {'public': True}, {'public'}),
|
||||||
|
|
Loading…
Reference in New Issue