mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							2a6f45e08e
						
					
				
				
					commit
					ed112fadc1
				
			| @@ -19,6 +19,7 @@ An example: i18n middleware would need to distinguish caches by the | ||||
| import hashlib | ||||
| import re | ||||
| import time | ||||
| from collections import defaultdict | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.core.cache import caches | ||||
| @@ -53,17 +54,21 @@ def patch_cache_control(response, **kwargs): | ||||
|         else: | ||||
|             return (t[0].lower(), True) | ||||
|  | ||||
|     def dictvalue(t): | ||||
|     def dictvalue(*t): | ||||
|         if t[1] is True: | ||||
|             return t[0] | ||||
|         else: | ||||
|             return '%s=%s' % (t[0], t[1]) | ||||
|  | ||||
|     cc = defaultdict(set) | ||||
|     if response.get('Cache-Control'): | ||||
|         cc = cc_delim_re.split(response['Cache-Control']) | ||||
|         cc = dict(dictitem(el) for el in cc) | ||||
|     else: | ||||
|         cc = {} | ||||
|         for field in cc_delim_re.split(response['Cache-Control']): | ||||
|             directive, value = dictitem(field) | ||||
|             if directive == 'no-cache': | ||||
|                 # no-cache supports multiple field names. | ||||
|                 cc[directive].add(value) | ||||
|             else: | ||||
|                 cc[directive] = value | ||||
|  | ||||
|     # 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 | ||||
| @@ -78,8 +83,23 @@ def patch_cache_control(response, **kwargs): | ||||
|         del cc['public'] | ||||
|  | ||||
|     for (k, v) in kwargs.items(): | ||||
|         cc[k.replace('_', '-')] = v | ||||
|     cc = ', '.join(dictvalue(el) for el in cc.items()) | ||||
|         directive = k.replace('_', '-') | ||||
|         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 | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -43,6 +43,11 @@ need to distinguish caches by the ``Accept-language`` header. | ||||
|     * All other parameters are added with their value, after applying | ||||
|       ``str()`` to it. | ||||
|  | ||||
|     .. versionchanged:: 3.1 | ||||
|  | ||||
|         Support for multiple field names in the ``no-cache`` directive was | ||||
|         added. | ||||
|  | ||||
| .. function:: get_max_age(response) | ||||
|  | ||||
|     Returns the max-age from the response Cache-Control header as an integer | ||||
|   | ||||
| @@ -104,7 +104,10 @@ Minor features | ||||
| 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 | ||||
| ~~~~ | ||||
|   | ||||
| @@ -1277,6 +1277,7 @@ Here are some more examples: | ||||
| * ``no_transform=True`` | ||||
| * ``must_revalidate=True`` | ||||
| * ``stale_while_revalidate=num_seconds`` | ||||
| * ``no_cache=True`` | ||||
|  | ||||
| The full list of known directives can be found in the `IANA registry`_ | ||||
| (note that not all of them apply to responses). | ||||
|   | ||||
							
								
								
									
										6
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							| @@ -1705,6 +1705,12 @@ class CacheUtils(SimpleTestCase): | ||||
|             ('', {'no-cache': 'Set-Cookie'}, {'no-cache=Set-Cookie'}), | ||||
|             ('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=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 | ||||
|             ('private', {'private': True}, {'private'}), | ||||
|             ('private', {'public': True}, {'public'}), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user