diff options
| author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
| commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
| tree | f0506b668a013d0063e5fba3dbf4863b466713ba /django/utils/cache.py | |
| parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'django/utils/cache.py')
| -rw-r--r-- | django/utils/cache.py | 164 |
1 files changed, 95 insertions, 69 deletions
diff --git a/django/utils/cache.py b/django/utils/cache.py index c0e47e0e42..90292ce4da 100644 --- a/django/utils/cache.py +++ b/django/utils/cache.py @@ -23,15 +23,13 @@ from django.conf import settings from django.core.cache import caches from django.http import HttpResponse, HttpResponseNotModified from django.utils.crypto import md5 -from django.utils.http import ( - http_date, parse_etags, parse_http_date_safe, quote_etag, -) +from django.utils.http import http_date, parse_etags, parse_http_date_safe, quote_etag from django.utils.log import log_response from django.utils.regex_helper import _lazy_re_compile from django.utils.timezone import get_current_timezone_name from django.utils.translation import get_language -cc_delim_re = _lazy_re_compile(r'\s*,\s*') +cc_delim_re = _lazy_re_compile(r"\s*,\s*") def patch_cache_control(response, **kwargs): @@ -46,8 +44,9 @@ def patch_cache_control(response, **kwargs): * All other parameters are added with their value, after applying str() to it. """ + def dictitem(s): - t = s.split('=', 1) + t = s.split("=", 1) if len(t) > 1: return (t[0].lower(), t[1]) else: @@ -57,13 +56,13 @@ def patch_cache_control(response, **kwargs): if t[1] is True: return t[0] else: - return '%s=%s' % (t[0], t[1]) + return "%s=%s" % (t[0], t[1]) cc = defaultdict(set) - if response.get('Cache-Control'): - for field in cc_delim_re.split(response.headers['Cache-Control']): + if response.get("Cache-Control"): + for field in cc_delim_re.split(response.headers["Cache-Control"]): directive, value = dictitem(field) - if directive == 'no-cache': + if directive == "no-cache": # no-cache supports multiple field names. cc[directive].add(value) else: @@ -72,18 +71,18 @@ def patch_cache_control(response, **kwargs): # 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 # a decorator and a piece of middleware both operate on a given view. - if 'max-age' in cc and 'max_age' in kwargs: - kwargs['max_age'] = min(int(cc['max-age']), kwargs['max_age']) + if "max-age" in cc and "max_age" in kwargs: + kwargs["max_age"] = min(int(cc["max-age"]), kwargs["max_age"]) # Allow overriding private caching and vice versa - if 'private' in cc and 'public' in kwargs: - del cc['private'] - elif 'public' in cc and 'private' in kwargs: - del cc['public'] + if "private" in cc and "public" in kwargs: + del cc["private"] + elif "public" in cc and "private" in kwargs: + del cc["public"] for (k, v) in kwargs.items(): - directive = k.replace('_', '-') - if directive == 'no-cache': + directive = k.replace("_", "-") + if directive == "no-cache": # no-cache supports multiple field names. cc[directive].add(v) else: @@ -98,8 +97,8 @@ def patch_cache_control(response, **kwargs): directives.extend([dictvalue(directive, value) for value in values]) else: directives.append(dictvalue(directive, values)) - cc = ', '.join(directives) - response.headers['Cache-Control'] = cc + cc = ", ".join(directives) + response.headers["Cache-Control"] = cc def get_max_age(response): @@ -107,18 +106,20 @@ def get_max_age(response): Return the max-age from the response Cache-Control header as an integer, or None if it wasn't found or wasn't an integer. """ - if not response.has_header('Cache-Control'): + if not response.has_header("Cache-Control"): return - cc = dict(_to_tuple(el) for el in cc_delim_re.split(response.headers['Cache-Control'])) + cc = dict( + _to_tuple(el) for el in cc_delim_re.split(response.headers["Cache-Control"]) + ) try: - return int(cc['max-age']) + return int(cc["max-age"]) except (ValueError, TypeError, KeyError): pass def set_response_etag(response): if not response.streaming and response.content: - response.headers['ETag'] = quote_etag( + response.headers["ETag"] = quote_etag( md5(response.content, usedforsecurity=False).hexdigest(), ) return response @@ -127,7 +128,8 @@ def set_response_etag(response): def _precondition_failed(request): response = HttpResponse(status=412) log_response( - 'Precondition Failed: %s', request.path, + "Precondition Failed: %s", + request.path, response=response, request=request, ) @@ -139,7 +141,15 @@ def _not_modified(request, response=None): if response: # Preserve the headers required by Section 4.1 of RFC 7232, as well as # Last-Modified. - for header in ('Cache-Control', 'Content-Location', 'Date', 'ETag', 'Expires', 'Last-Modified', 'Vary'): + for header in ( + "Cache-Control", + "Content-Location", + "Date", + "ETag", + "Expires", + "Last-Modified", + "Vary", + ): if header in response: new_response.headers[header] = response.headers[header] @@ -158,11 +168,13 @@ def get_conditional_response(request, etag=None, last_modified=None, response=No return response # Get HTTP request headers. - if_match_etags = parse_etags(request.META.get('HTTP_IF_MATCH', '')) - if_unmodified_since = request.META.get('HTTP_IF_UNMODIFIED_SINCE') - if_unmodified_since = if_unmodified_since and parse_http_date_safe(if_unmodified_since) - if_none_match_etags = parse_etags(request.META.get('HTTP_IF_NONE_MATCH', '')) - if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE') + if_match_etags = parse_etags(request.META.get("HTTP_IF_MATCH", "")) + if_unmodified_since = request.META.get("HTTP_IF_UNMODIFIED_SINCE") + if_unmodified_since = if_unmodified_since and parse_http_date_safe( + if_unmodified_since + ) + if_none_match_etags = parse_etags(request.META.get("HTTP_IF_NONE_MATCH", "")) + if_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE") if_modified_since = if_modified_since and parse_http_date_safe(if_modified_since) # Step 1 of section 6 of RFC 7232: Test the If-Match precondition. @@ -170,23 +182,26 @@ def get_conditional_response(request, etag=None, last_modified=None, response=No return _precondition_failed(request) # Step 2: Test the If-Unmodified-Since precondition. - if (not if_match_etags and if_unmodified_since and - not _if_unmodified_since_passes(last_modified, if_unmodified_since)): + if ( + not if_match_etags + and if_unmodified_since + and not _if_unmodified_since_passes(last_modified, if_unmodified_since) + ): return _precondition_failed(request) # Step 3: Test the If-None-Match precondition. if if_none_match_etags and not _if_none_match_passes(etag, if_none_match_etags): - if request.method in ('GET', 'HEAD'): + if request.method in ("GET", "HEAD"): return _not_modified(request, response) else: return _precondition_failed(request) # Step 4: Test the If-Modified-Since precondition. if ( - not if_none_match_etags and - if_modified_since and - not _if_modified_since_passes(last_modified, if_modified_since) and - request.method in ('GET', 'HEAD') + not if_none_match_etags + and if_modified_since + and not _if_modified_since_passes(last_modified, if_modified_since) + and request.method in ("GET", "HEAD") ): return _not_modified(request, response) @@ -202,12 +217,12 @@ def _if_match_passes(target_etag, etags): if not target_etag: # If there isn't an ETag, then there can't be a match. return False - elif etags == ['*']: + elif etags == ["*"]: # The existence of an ETag means that there is "a current # representation for the target resource", even if the ETag is weak, # so there is a match to '*'. return True - elif target_etag.startswith('W/'): + elif target_etag.startswith("W/"): # A weak ETag can never strongly match another ETag. return False else: @@ -231,15 +246,15 @@ def _if_none_match_passes(target_etag, etags): if not target_etag: # If there isn't an ETag, then there isn't a match. return True - elif etags == ['*']: + elif etags == ["*"]: # The existence of an ETag means that there is "a current # representation for the target resource", so there is a match to '*'. return False else: # The comparison should be weak, so look for a match after stripping # off any weak indicators. - target_etag = target_etag.strip('W/') - etags = (etag.strip('W/') for etag in etags) + target_etag = target_etag.strip("W/") + etags = (etag.strip("W/") for etag in etags) return target_etag not in etags @@ -264,8 +279,8 @@ 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 not response.has_header('Expires'): - response.headers['Expires'] = http_date(time.time() + cache_timeout) + if not response.has_header("Expires"): + response.headers["Expires"] = http_date(time.time() + cache_timeout) patch_cache_control(response, max_age=cache_timeout) @@ -274,7 +289,9 @@ def add_never_cache_headers(response): Add headers to a response to indicate that a page should never be cached. """ patch_response_headers(response, cache_timeout=-1) - patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True, private=True) + patch_cache_control( + response, no_cache=True, no_store=True, must_revalidate=True, private=True + ) def patch_vary_headers(response, newheaders): @@ -287,28 +304,31 @@ def patch_vary_headers(response, newheaders): # Note that we need to keep the original order intact, because cache # implementations may rely on the order of the Vary contents in, say, # computing an MD5 hash. - if response.has_header('Vary'): - vary_headers = cc_delim_re.split(response.headers['Vary']) + if response.has_header("Vary"): + vary_headers = cc_delim_re.split(response.headers["Vary"]) else: vary_headers = [] # Use .lower() here so we treat headers as case-insensitive. existing_headers = {header.lower() for header in vary_headers} - additional_headers = [newheader for newheader in newheaders - if newheader.lower() not in existing_headers] + additional_headers = [ + newheader + for newheader in newheaders + if newheader.lower() not in existing_headers + ] vary_headers += additional_headers - if '*' in vary_headers: - response.headers['Vary'] = '*' + if "*" in vary_headers: + response.headers["Vary"] = "*" else: - response.headers['Vary'] = ', '.join(vary_headers) + response.headers["Vary"] = ", ".join(vary_headers) def has_vary_header(response, header_query): """ Check to see if the response has a given header name in its Vary header. """ - if not response.has_header('Vary'): + if not response.has_header("Vary"): return False - vary_headers = cc_delim_re.split(response.headers['Vary']) + vary_headers = cc_delim_re.split(response.headers["Vary"]) existing_headers = {header.lower() for header in vary_headers} return header_query.lower() in existing_headers @@ -319,9 +339,9 @@ def _i18n_cache_key_suffix(request, cache_key): # first check if LocaleMiddleware or another middleware added # LANGUAGE_CODE to request, then fall back to the active language # which in turn can also fall back to settings.LANGUAGE_CODE - cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language()) + cache_key += ".%s" % getattr(request, "LANGUAGE_CODE", get_language()) if settings.USE_TZ: - cache_key += '.%s' % get_current_timezone_name() + cache_key += ".%s" % get_current_timezone_name() return cache_key @@ -332,21 +352,27 @@ def _generate_cache_key(request, method, headerlist, key_prefix): value = request.META.get(header) if value is not None: ctx.update(value.encode()) - url = md5(request.build_absolute_uri().encode('ascii'), usedforsecurity=False) - cache_key = 'views.decorators.cache.cache_page.%s.%s.%s.%s' % ( - key_prefix, method, url.hexdigest(), ctx.hexdigest()) + url = md5(request.build_absolute_uri().encode("ascii"), usedforsecurity=False) + cache_key = "views.decorators.cache.cache_page.%s.%s.%s.%s" % ( + key_prefix, + method, + url.hexdigest(), + ctx.hexdigest(), + ) return _i18n_cache_key_suffix(request, cache_key) def _generate_cache_header_key(key_prefix, request): """Return a cache key for the header cache.""" - url = md5(request.build_absolute_uri().encode('ascii'), usedforsecurity=False) - cache_key = 'views.decorators.cache.cache_header.%s.%s' % ( - key_prefix, url.hexdigest()) + url = md5(request.build_absolute_uri().encode("ascii"), usedforsecurity=False) + cache_key = "views.decorators.cache.cache_header.%s.%s" % ( + key_prefix, + url.hexdigest(), + ) return _i18n_cache_key_suffix(request, cache_key) -def get_cache_key(request, key_prefix=None, method='GET', cache=None): +def get_cache_key(request, key_prefix=None, method="GET", cache=None): """ Return a cache key based on the request URL and query. It can be used in the request phase because it pulls the list of headers to take into @@ -388,17 +414,17 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None, cach cache_key = _generate_cache_header_key(key_prefix, request) if cache is None: cache = caches[settings.CACHE_MIDDLEWARE_ALIAS] - if response.has_header('Vary'): + if response.has_header("Vary"): is_accept_language_redundant = settings.USE_I18N # If i18n is used, the generated cache key will be suffixed with the # current locale. Adding the raw value of Accept-Language is redundant # in that case and would result in storing the same content under # multiple keys in the cache. See #18191 for details. headerlist = [] - for header in cc_delim_re.split(response.headers['Vary']): - header = header.upper().replace('-', '_') - if header != 'ACCEPT_LANGUAGE' or not is_accept_language_redundant: - headerlist.append('HTTP_' + header) + for header in cc_delim_re.split(response.headers["Vary"]): + header = header.upper().replace("-", "_") + if header != "ACCEPT_LANGUAGE" or not is_accept_language_redundant: + headerlist.append("HTTP_" + header) headerlist.sort() cache.set(cache_key, headerlist, cache_timeout) return _generate_cache_key(request, request.method, headerlist, key_prefix) @@ -410,7 +436,7 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None, cach def _to_tuple(s): - t = s.split('=', 1) + t = s.split("=", 1) if len(t) == 2: return t[0].lower(), t[1] return t[0].lower(), True |
