def test_plain_views_are_cacheable(self, mocked_api_session): mocked_api_session().get().json.return_value = { 'count': 1, 'results': [{ 'nomis_id': 'AAA', 'short_name': 'Prison', 'name': 'HMP Prison' }], } view_names = [ 'help_area:help', 'help_area:help-new-payment', 'help_area:help-sent-payment', 'help_area:prison_list', 'terms', 'privacy', 'js-i18n', 'sitemap_xml', 'accessibility' ] for view_name in view_names: response = self.client.get(reverse(view_name)) self.assertGreaterEqual(get_max_age(response), 3600, msg=f'{view_name} should be cacheable') with override_lang('cy'): response = self.client.get(reverse(view_name)) self.assertGreaterEqual(get_max_age(response), 3600, msg=f'{view_name} should be cacheable')
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if request.method != 'GET': # This is a stronger requirement than above. It is needed # because of interactions between this middleware and the # HTTPMiddleware, which throws the body of a HEAD-request # away before this middleware gets a chance to cache it. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix) cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Set the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if response.streaming or response.status_code not in (200, 304): return response # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'): return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout and response.status_code == 200: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout) ) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" #if not self._should_update_cache(request, response): # # We don't need to update the cache, just return. # return response if response.streaming or response.status_code != 200: return response # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'): return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = "%s-%s" % (self.key_prefix, request.get_full_path()) #raise ValueError(cache_key) if hasattr(response, 'render') and isinstance(response.render, collections.Callable): response.add_post_render_callback( lambda r: cache._cache.set(cache_key.encode("utf-8"), zlib.compress(r.content, 9), timeout) ) else: # we use the highest compression level, because since it is cached we hope for it to pay off cache._cache.set(cache_key.encode("utf-8"), zlib.compress(response.content, 9), timeout) return response
def process_response(self, request, response): # Get the path (do it early since we do conditionals on it) path = request.get_full_path() anon_only = getattr(settings,"CACHE_MIDDLEWARE_ANONYMOUS_ONLY",False) # A few conditions that cause us not to cache. if request.method != "GET" \ or not response.status_code == 200: return response # The cache key prefix (should match what is in the site's nginx config) prefix = getattr(settings,"NGINX_CACHE_PREFIX","NG") # See the value of max-age and set timer on that. If not set, # use CACHE_MIDDLEWARE_SECONDS. If 0, do not cache. timeout = get_max_age(response) if timeout == None: timeout = getattr(settings,"CACHE_MIDDLEWARE_SECONDS",300) elif timeout == 0: return response # Set the item in cache. key = "%s:%s" % (prefix, path) cache.set(key, response.content, timeout) return response
def wrapped_view(request, *args, **kwargs): # Build a cache key using only the view function and the arguments; # nothing related to the request or current site. view_path = '.'.join((view_func.__module__, view_func.__name__)) signature = HashableTuple((args, kwargs)).hash cache_key = ':'.join((view_path, signature)) # Retrieve the response from the cache, or generate a new one. if getattr(request, '_purging', False): response = None else: response = cache.get(cache_key) if response is None: response = view_func(request, *args, **kwargs) max_age = get_max_age(response) if max_age is not None: cache.set(cache_key, response, max_age) else: response['X-From-Cache'] = True # Stop the middleware from caching it too. request._cache_update_cache = False return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not hasattr( request, '_cache_update_cache') or not request._cache_update_cache: # We don't need to update the cache, just return. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) self.cache.set(cache_key, response, timeout) return response
def test(self): request = RequestFactory().get('/') response = my_view(request) patch_response_headers(response, cache_timeout=3600) self.assertEqual(get_max_age(response), 3600) expires = response._headers["expires"][1] print(expires)
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout) ) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if response.streaming or response.status_code != 200: return response # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'): return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout) ) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if response.streaming or response.status_code != 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response # patch_response_headers(response, timeout) if timeout: cache_key = hashlib.md5( force_bytes( re.sub(r'^https?://', '', request.build_absolute_uri()))).hexdigest() if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response.content, timeout) return response
def process_response(self, request, response): """ Rewrite the "Cache-control" and "Expires headers" in the response if needed. """ max_ttl = getattr(settings, "MAX_BROWSER_CACHE_TTL", 600) if max_ttl: try: max_ttl = int(max_ttl) if max_ttl < 0: raise ValueError( "MAX_BROWSER_CACHE_TTL must be a positive integer") except (ValueError, TypeError) as err: logger.error(err) return response max_age = get_max_age(response) if max_age is not None and max_age > max_ttl: if response.has_header("Expires"): # Remove the Expires response Header because patch_response_headers() # adds it only if it isn't already set del response["Expires"] patch_response_headers(response, cache_timeout=max_ttl) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache: # We don't need to update the cache, just return. return response if request.method != 'GET': # This is a stronger requirement than above. It is needed # because of interactions between this middleware and the # HTTPMiddleware, which throws the body of a HEAD-request # away before this middleware gets a chance to cache it. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response if self.patch_headers: patch_response_headers(response, timeout) if timeout: if callable(self.key_prefix): key_prefix = self.key_prefix(request) else: key_prefix = self.key_prefix cache_key = learn_cache_key(request, response, timeout, key_prefix) cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): if not self._should_update_cache(request, response): return response if response.streaming or response.status_code != 200: return response if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'): return response if (request.path.startswith('/admin/') or request.path.startswith('/sitemap') or request.path[-12:] == '/rss/yandex/' or request.path == 'sidebar.json'): return response timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: return response #patch_response_headers(response, 5) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback(lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): # Cache the response if all the required conditions are met. # Response must be marked for updating by the # ``FetchFromCacheMiddleware`` having a cache get miss, the # user must not be authenticated, the HTTP status must be OK # and the response mustn't include an expiry age, incicating it # shouldn't be cached. marked_for_update = getattr(request, "_update_cache", False) anon = hasattr(request, "user") and not request.user.is_authenticated() valid_status = response.status_code == 200 timeout = get_max_age(response) if timeout is None: timeout = settings.CACHE_MIDDLEWARE_SECONDS if anon and valid_status and marked_for_update and timeout: cache_key = cache_key_prefix(request) + request.get_full_path() _cache_set = lambda r: cache_set(cache_key, r.content, timeout) if callable(getattr(response, "render", None)): response.add_post_render_callback(_cache_set) else: _cache_set(response) # Second phase rendering for non-cached template code and # content. Split on the delimiter the ``nevercache`` tag # wrapped its contents in, and render only the content # enclosed by it, to avoid possible template code injection. token = nevercache_token() try: token = token.encode('utf-8') except AttributeError: pass parts = response.content.split(token) content_type = response.get("content-type", "") if content_type.startswith("text") and len(parts) > 1: # Restore csrf token from cookie - check the response # first as it may be being set for the first time. csrf_token = None try: csrf_token = response.cookies[settings.CSRF_COOKIE_NAME].value except KeyError: try: csrf_token = request.COOKIES[settings.CSRF_COOKIE_NAME] except KeyError: pass if csrf_token: request.META["CSRF_COOKIE"] = csrf_token context = RequestContext(request) for i, part in enumerate(parts): if i % 2: part = Template(part).render(context).encode("utf-8") parts[i] = part response.content = b"".join(parts) response["Content-Length"] = len(response.content) if hasattr(request, '_messages'): # Required to clear out user messages. request._messages.update(response) return response
def process_response(self, request, response): if COUNT_UPDATE_CACHE: self._count_response(request) if getattr(response, "_from_cache", False) == True: if COUNT_UPDATE_CACHE: self._count_hit() logger.debug( "response comes from the cache, no need to update the cache") return response else: # used e.g. in unittests response._from_cache = False if not self.use_cache(request, response): if EXTRA_DEBUG: logger.debug("Don't put to cache: %s" % request.get_full_path()) return response # get the timeout from the "max-age" section of the "Cache-Control" header timeout = get_max_age(response) if timeout == None: # use default cache_timeout timeout = settings.CACHE_MIDDLEWARE_SECONDS elif timeout == 0: logger.debug("Don't cache this page (timeout == 0)") return response # Create a new HttpResponse for the cache, so we can skip existing # cookies and attributes like response.csrf_processing_done response2 = HttpResponse( content=response._container, status=200, content_type=response['Content-Type'], ) if response.has_header("Content-Language"): response2['Content-Language'] = response['Content-Language'] if settings.DEBUG or RUN_WITH_DEV_SERVER or request.META.get( 'REMOTE_ADDR') in settings.INTERNAL_IPS: # Check if we store a {% csrf_token %} into the cache, this should never happen! for content in response._container: if "csrfmiddlewaretoken" in content: raise AssertionError( "csrf_token would be put into the cache! content: %r" % content) # Adds ETag, Last-Modified, Expires and Cache-Control headers patch_response_headers(response2, timeout) cache_key = get_cache_key(request) cache.set(cache_key, response2, timeout) logger.debug("Put to cache: %r" % cache_key) return response
def test_invalid_date_params(self): with responses.RequestsMock(), silence_logger(name='django.request'): response = self.client.get( reverse_lazy('performance_data_csv') + '?from=invalid') self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST) self.assertIn( 'Date "invalid" could not be parsed - use YYYY-MM-DD format', response.json()['errors']) self.assertEqual(0, get_max_age(response)) with responses.RequestsMock(), silence_logger(name='django.request'): response = self.client.get( reverse_lazy('performance_data_csv') + '?from=2021-01-01&to=invalid') self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST) self.assertIn( 'Date "invalid" could not be parsed - use YYYY-MM-DD format', response.json()['errors']) self.assertEqual(0, get_max_age(response))
def process_response(self, request, response): if request.COOKIES.get( 'view_uncached') == 'true' and request.user.is_authenticated: return response else: middleware_cache_tags = self.cache_tags if self.cache_tags else [] if not self._should_update_cache(request, response): return response if response.streaming or response.status_code not in (200, 304): return response # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if not request.COOKIES and response.cookies and has_vary_header( response, 'Cookie'): return response # Don't cache a response with 'Cache-Control: private' if 'private' in response.get('Cache-Control', ()): return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if response.has_header('X-Additional-Cache-Tags'): middleware_cache_tags = response.__getitem__( 'X-Additional-Cache-Tags').split(",") + self.cache_tags if timeout and response.status_code == 200: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) # add this cache_key to a cache_keys cache with tags cache.add_cache_key(request, cache_key, tags=middleware_cache_tags) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def test_caching(self): self.assertTrue(self.response.has_header('Cache-Control'), msg='response has no Cache-Control header') self.assertIn('public', self.response['Cache-Control'], msg='response is private') expected_max_age = 7 * 24 * 60 * 60 # 7 days in seconds self.assertGreaterEqual(get_max_age(self.response), expected_max_age, msg='max-age is less than a week')
def _assert_not_cached(response): """ Assert that the the max-age header is defined and set to 0, or that has a custom vary-on-view header. Good decorator to use: from django.views.decorators.cache import never_cache """ max_age_header = get_max_age(response) assert (max_age_header == 0) or ('X-Vary-On-View' in response)
def _should_cache(self, request, response): if response.streaming or response.status_code != 200: return False # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'): return False if get_max_age(response) == 0: return False return True
def __call__(self, request): response = self.get_response(request) request_conditions = (request.is_api and request.method in ('GET', 'HEAD') and 'HTTP_AUTHORIZATION' not in request.META and 'disable_caching' not in request.GET) response_conditions = (not response.cookies and response.status_code >= 200 and response.status_code < 400 and get_max_age(response) is None) if request_conditions and response_conditions: patch_cache_control(response, max_age=settings.API_CACHE_DURATION) return response
def process_response(req, res, prefix, cache_time=60 * 60): # update the cache using the django's CacheMiddleware cache_middleware = CacheMiddleware(cache_timeout=cache_time, key_prefix=prefix) response = cache_middleware.process_response(req, res) # update some header to prevent wrong client caching max_age = get_max_age(response) if max_age and max_age < max_age: # Remove headers so patch_response works for header in ("ETag", "Last-Modified", "Expires"): if response.has_header(header): del response[header] patch_response_headers(response, max_age) return response
def process_response(self, request, response): if (request.method in self.allowed_methods and response.status_code in self.allowed_statuses and request.REQUEST.get('cache') == '1'): timeout = get_max_age(response) if timeout is None: timeout = settings.CACHE_MIDDLEWARE_SECONDS or 0 if timeout != 0: # Only if max-age is 0 should we bother with caching. patch_response_headers(response, timeout) patch_cache_control(response, must_revalidate=True) return response
def process_response(self, request, response): if COUNT_UPDATE_CACHE: self._count_response(request) if getattr(response, "_from_cache", False) == True: if COUNT_UPDATE_CACHE: self._count_hit() logger.debug("response comes from the cache, no need to update the cache") return response else: # used e.g. in unittests response._from_cache = False if not self.use_cache(request, response): if EXTRA_DEBUG: logger.debug("Don't put to cache: %s" % request.get_full_path()) return response # get the timeout from the "max-age" section of the "Cache-Control" header timeout = get_max_age(response) if timeout == None: # use default cache_timeout timeout = settings.CACHE_MIDDLEWARE_SECONDS elif timeout == 0: logger.debug("Don't cache this page (timeout == 0)") return response # Create a new HttpResponse for the cache, so we can skip existing # cookies and attributes like response.csrf_processing_done response2 = HttpResponse( content=response._container, status=200, content_type=response['Content-Type'], ) if response.has_header("Content-Language"): response2['Content-Language'] = response['Content-Language'] if settings.DEBUG or RUN_WITH_DEV_SERVER or request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS: # Check if we store a {% csrf_token %} into the cache, this should never happen! for content in response._container: if "csrfmiddlewaretoken" in content: raise AssertionError("csrf_token would be put into the cache! content: %r" % content) # Adds ETag, Last-Modified, Expires and Cache-Control headers patch_response_headers(response2, timeout) cache_key = get_cache_key(request) cache.set(cache_key, response2, timeout) logger.debug("Put to cache: %r" % cache_key) return response
def process_response(self, request, response): """ RUS: Возвращает ответ сервера, если пользователь идентифицирован. """ if request.user.is_authenticated(): return response """Sets the cache, if needed.""" if not self._should_update_cache(request, response): return response # RUS: Возвращает ответ сервера, если не было обновления кэша. if response.streaming or response.status_code != 200: return response # RUS: Возвращает ответ сервера, если, у атрибута HttpResponse.streaming статус False # или код ответа не равен 200. # Не кэширует ответы сервера, которые устанавливают специфичные для пользователя (и, возможно, # чувствительные к безопасности ) cookie в ответ на запрос без cookie # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if not request.COOKIES and response.cookies and has_vary_header( response, 'Cookie'): return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response # Возвращает максимальный возраст из заголовка Cache-Control ответа в виде целого числа ( # Пытается получить время хранения кэша из заголовка Cache-Control. # При его отсутствии, время хранения кэша равно значению по умолчанию, # если же установлено равным 0, возвращается некэшированный ответ сервера patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" # TODO if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response # 不是流响应,不是200码 if response.streaming or response.status_code != 200: return response # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. # 请求没有cookie,但是处理过程中设置了cookie,并且Vary包含了Cookie,直接返回 # 分析:因为缓存服务器收到请求是没有Cookie的,然后返回的告诉他类似的请求根据Cookie # 来判断是否使用缓存,这样,下一个没有Cookie的人访问该URL则会拿到之前的人 # 的Cookie中的数据 if not request.COOKIES and response.cookies and has_vary_header( response, 'Cookie'): return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. # 首先使用response中设置的max_age(根据Cache-Control部分),如果没有设置 # 则使用setting中的. # 分析:setting中的是最后的依据,如果设置过则按照设置过的来 timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response # 设置ETag, Last-Modified, Expires 和 Cache-Control的max-age部分,都用于缓存控制 patch_response_headers(response, timeout) if timeout: # 拿到cache——key,该方法设置了header_key,返回的是page_key cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) # 如果有render,则设置回调,在render之后缓存. if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def _should_cache(self, request, response): if response.streaming or response.status_code != 200: return False # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if not request.COOKIES and response.cookies and has_vary_header( response, 'Cookie'): return False if get_max_age(response) == 0: return False return True
def template_response_callback(self, response): if self.cache_middleware: response = self.cache_middleware.process_response( self.request, response) # We might want to cache for longer internally than we tell clients max_age = get_max_age(response) if max_age and self.max_age < max_age: # Remove headers so patch_response works for header in ('ETag', 'Last-Modified', 'Expires'): if response.has_header(header): del response[header] patch_response_headers(response, self.max_age) return response
def process_response(req, res, prefix, cache_time=60 * 60): # update the cache using the django's CacheMiddleware cache_middleware = CacheMiddleware(cache_timeout=cache_time, key_prefix=prefix) response = cache_middleware.process_response(req, res) # update some header to prevent wrong client caching max_age = get_max_age(response) if max_age and max_age < max_age: # Remove headers so patch_response works for header in ('ETag', 'Last-Modified', 'Expires'): if response.has_header(header): del response[header] patch_response_headers(response, max_age) return response
def process_response(self, request, response): # TODO if cache length gets long (like over 10 minutes), set a shorter # cache time by default on those. # # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3 # if response.status_code == 302: # return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length inside patch_response_headers. timeout = get_max_age(response) patch_response_headers(response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if (not hasattr(request, '_cache_update_cache') or not request._cache_update_cache): # We don't need to update the cache, just return. return response if request.method != 'GET': # This is a stronger requirement than above. It is needed # because of interactions between this middleware and the # HTTPMiddleware, which throws the body of a HEAD-request # away before this middleware gets a chance to cache it. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response if self.patch_headers: patch_response_headers(response, timeout) if timeout: if callable(self.key_prefix): key_prefix = self.key_prefix(request) else: key_prefix = self.key_prefix if self.post_process_response: response = self.post_process_response(response, request) with RequestPath(request, self.only_get_keys, self.forget_get_keys): cache_key = learn_cache_key(request, response, timeout, key_prefix) if self.remember_all_urls: self.remember_url(request, cache_key, timeout) self.cache.set(cache_key, response, timeout) if self.post_process_response_always: response = self.post_process_response_always(response, request) return response
def process_response(self, request, response): if getattr(response, "_from_cache", False) == True: # Current response comes from the cache, no need to update the cache return response else: # used e.g. in unittests response._from_cache = False if response.status_code != 200: # Don't cache e.g. error pages return response if not self.use_cache(request): #print "Don't put to cache." return response # get the timeout from the "max-age" section of the "Cache-Control" header timeout = get_max_age(response) if timeout == None: # use default cache_timeout timeout = settings.CACHE_MIDDLEWARE_SECONDS elif timeout == 0: logger.debug("Don't cache this page (timeout == 0)") return response # Create a new HttpResponse for the cache, so we can skip existing # cookies and attributes like response.csrf_processing_done response2 = HttpResponse( content=response._container, status=200, content_type=response['Content-Type'], ) if response.has_header("Content-Language"): response2['Content-Language'] = response['Content-Language'] if settings.DEBUG or settings.RUN_WITH_DEV_SERVER: # Check if we store a {% csrf_token %} into the cache # This can't work ;) for content in response._container: if "csrfmiddlewaretoken" in content: raise AssertionError("csrf_token would be put into the cache! content: %r" % content) # Adds ETag, Last-Modified, Expires and Cache-Control headers patch_response_headers(response2, timeout) cache_key = self.get_cache_key(request) cache.set(cache_key, response2, timeout) logger.debug("Put to cache: %r" % cache_key) return response
def _assert_has_headers(response): """ Assert that we have the standard caching headers. Good decorators to use: from django_cache_middleware.decorators import add_cache_headers from django.views.decorators.cache import never_cache """ # A max-age value must be set. # A value of 0 is acceptable. max_age_header = get_max_age(response) assert max_age_header is not None # And check for the other ones too. for header in ('ETag', 'Last-Modified', 'Expires'): assert header in response
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) user = request.user try: github_prefix = user.social_auth.get( provider='github').extra_data['username'] except: github_prefix = '' try: bitbucket_prefix = user.social_auth.get( provider='bitbucket').extra_data['username'] except: bitbucket_prefix = '' custom_prefix = '.'.join((hashlib.md5(github_prefix).hexdigest(), hashlib.md5(bitbucket_prefix).hexdigest())) if timeout: cache_key = learn_cache_key(request, response, timeout, custom_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if getattr(response, 'streaming', None) or response.status_code != 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response # patch start patch_response_headers(response, timeout) tags = set() if self.tags: # Usefull to bind view, args and kwargs to request. # See https://bitbucket.org/emacsway/django-ext/src/d8b55d86680e/django_ext/middleware/view_args_to_request.py tags = self.tags(request) tags = set(tags) # Adds tags from request, see templatetag {% cache_add_tags ... %} if hasattr(request, 'cache_tagging'): tags.update(request.cache_tagging) if timeout: cache_key = learn_cache_key(request, response, tags, timeout, self.key_prefix, cache=self.cache) # patched if hasattr(response, 'render') and isinstance( response.render, collections.Callable): response.add_post_render_callback(lambda r: self.cache.set( cache_key, r, tags, timeout) # patched ) else: self.cache.set(cache_key, response, tags, timeout) # patched # patch end return response
def process_response(self, request, response): if request.path != '/status': cache_entry = Model('cache').facade.get_or_create( request.build_absolute_uri()) cache_entry.requests += 1 cache_entry.save() if not (hasattr(request, '_cache_update_cache') and request._cache_update_cache): return response response['Object-Cache'] = 'MISS' if response.streaming or response.status_code not in (200, 304): return response if not request.COOKIES and response.cookies and has_vary_header( response, 'Cookie'): return response if 'private' in response.get('Cache-Control', ()): return response timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: return response patch_response_headers(response, timeout) if timeout and response.status_code == 200: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Set the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if response.streaming or response.status_code not in (200, 304): return response # Don't cache responses that set a user-specific (and maybe security # sensitive) cookie in response to a cookie-less request. if (not request.COOKIES and response.cookies and has_vary_header(response, "Cookie")): return response # Don't cache a response with 'Cache-Control: private' if "private" in response.get("Cache-Control", ()): return response # Page timeout takes precedence over the "max-age" and the default # cache timeout. timeout = self.page_timeout if timeout is None: # The timeout from the "max-age" section of the "Cache-Control" # header takes precedence over the default cache timeout. timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't cache. return response patch_response_headers(response, timeout) if timeout and response.status_code == 200: cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache) if hasattr(response, "render") and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout)) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): if (request.method in self.allowed_methods and response.status_code in self.allowed_statuses and request.GET.get('cache', '').isdigit()): # If there's already a `Cache-Control` header with a `max-age`, # use that TTL before falling back to what the client requested. timeout = get_max_age(response) if timeout is None: timeout = int(request.GET['cache']) # Never allow clients to choose positive timeouts below # settings.CACHE_MIDDLEWARE_SECONDS. if timeout > 0 and timeout < settings.CACHE_MIDDLEWARE_SECONDS: timeout = settings.CACHE_MIDDLEWARE_SECONDS # Send caching headers, but only timeout is not 0. if timeout != 0: patch_response_headers(response, timeout) patch_cache_control(response, must_revalidate=True) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache: # We don't need to update the cache, just return. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix) self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) user = request.user try: github_prefix = user.social_auth.get(provider='github').extra_data['username'] except: github_prefix = '' try: bitbucket_prefix=user.social_auth.get(provider='bitbucket').extra_data['username'] except: bitbucket_prefix = '' custom_prefix = '.'.join((hashlib.md5(github_prefix).hexdigest(),hashlib.md5(bitbucket_prefix).hexdigest())) if timeout: cache_key = learn_cache_key(request, response, timeout, custom_prefix, cache=self.cache) if hasattr(response, 'render') and callable(response.render): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, timeout) ) else: self.cache.set(cache_key, response, timeout) return response
def process_response(self, request, response): """Sets the cache, if needed.""" if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if not response.status_code == 200: return response # Try to get the timeout from the "max-age" section of the "Cache- # Control" header before reverting to using the default cache_timeout # length. timeout = get_max_age(response) if timeout == None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response # patch start patch_response_headers(response, timeout) tags = set() if self.tags: # Usefull to bind view, args and kwargs to request. # See https://bitbucket.org/emacsway/django-ext/src/d8b55d86680e/django_ext/middleware/view_args_to_request.py tags = self.tags(request) tags = set(tags) # Adds tags from request, see templatetag {% cache_add_tags ... %} if hasattr(request, 'cache_tagging'): tags.update(request.cache_tagging) if timeout: cache_key = learn_cache_key(request, response, tags, timeout, self.key_prefix, cache=self.cache) # patched if hasattr(response, 'render') and isinstance(response.render, collections.Callable): response.add_post_render_callback( lambda r: self.cache.set(cache_key, r, tags, timeout) # patched ) else: self.cache.set(cache_key, response, tags, timeout) # patched # patch end return response
def process_response(self, request, response): if getattr(request, 'response_has_esi', False): response['Has-ESI'] = True if response.has_header('ETag') and not response['ETag']: del response['ETag'] if not self._should_update_cache(request, response): # We don't need to update the cache, just return. return response if request.method != 'GET': return response if response.status_code != 200: return response if not response._is_string: # Cannot cache iterable/streamed responses. return response timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout elif timeout == 0: # max-age was set to 0, don't bother caching. return response patch_response_headers(response, timeout) if timeout: cache_key = learn_cache_key(request, response, timeout, self.key_prefix) cache_backend.set(cache_key, response, timeout) return response
"""
def process_response(self, request, response): if request.path.startswith('/admin/'): if get_max_age(response) is None: add_never_cache_headers(response) return response
def process_response(self, request, response): # Caching is only applicable for text-based, non-streaming # responses. We also skip it for non-200 statuses during # development, so that stack traces are correctly rendered. is_text = response.get("content-type", "").startswith("text") valid_status = response.status_code == 200 streaming = getattr(response, "streaming", False) if not is_text or streaming or (settings.DEBUG and not valid_status): return response # Cache the response if all the required conditions are met. # Response must be marked for updating by the # ``FetchFromCacheMiddleware`` having a cache get miss, the # user must not be authenticated, the HTTP status must be OK # and the response mustn't include an expiry age, indicating it # shouldn't be cached. marked_for_update = getattr(request, "_update_cache", False) anon = hasattr(request, "user") and not request.user.is_authenticated() timeout = get_max_age(response) if timeout is None: timeout = settings.CACHE_MIDDLEWARE_SECONDS if anon and valid_status and marked_for_update and timeout: cache_key = cache_key_prefix(request) + request.get_full_path() _cache_set = lambda r: cache_set(cache_key, r.content, timeout) if callable(getattr(response, "render", None)): response.add_post_render_callback(_cache_set) else: _cache_set(response) # Second phase rendering for non-cached template code and # content. Split on the delimiter the ``nevercache`` tag # wrapped its contents in, and render only the content # enclosed by it, to avoid possible template code injection. token = nevercache_token() try: token = token.encode('utf-8') except AttributeError: pass parts = response.content.split(token) # Restore csrf token from cookie - check the response # first as it may be being set for the first time. csrf_token = None try: csrf_token = response.cookies[settings.CSRF_COOKIE_NAME].value except KeyError: try: csrf_token = request.COOKIES[settings.CSRF_COOKIE_NAME] except KeyError: pass if csrf_token: request.META["CSRF_COOKIE"] = csrf_token context = RequestContext(request) for i, part in enumerate(parts): if i % 2: part = Template(part).render(context).encode("utf-8") parts[i] = part response.content = b"".join(parts) response["Content-Length"] = len(response.content) if hasattr(request, '_messages'): # Required to clear out user messages. request._messages.update(response) # Response needs to be run-through the CSRF middleware again so # that if there was a {% csrf_token %} inside of the nevercache # the cookie will be correctly set for the the response csrf_mw_name = "django.middleware.csrf.CsrfViewMiddleware" if csrf_mw_name in MIDDLEWARE_SETTING: response.csrf_processing_done = False csrf_mw = CsrfViewMiddleware() csrf_mw.process_response(request, response) return response
def _get_timeout(self, response): timeout = get_max_age(response) if timeout is None: timeout = self.cache_timeout return timeout
def process_response(self, request, response): # Some built in django views have no caching headers. Ignore them. for path in self.ignored_paths: if request.path.startswith(path): return response if response.status_code == 304: # Not Modified responses don't need to be checked. They will # sometimes have unwanted headers at this point, which Django # will remove later on in the base handler. return response if not self._typical_get_request(request, response): # These types of requests/responses should never be cached, and # thus should not have caching headers in the response. # If they do have cache headers, then they must be "never cache" # headers (a max-age of 0). if get_max_age(response) not in (0, None): raise InvalidHeadersWarning('Only non-secure GET/HEAD requests should have caching headers.') else: return response if response.status_code != 200: # We generally only cache responses with a status code of 200, # but there are exceptions. As long as the other checks are done # then this is OK to let through. return response # All typical GET requests must have some caching headers defined. try: self._assert_has_headers(response) except AssertionError: message = ( "This URL does not have the required caching headers. " "Typical GET requests must return a response with caching headers defined at the view level. " "The current headers are: %s" ) header_list = [': '.join(header) for header in response._headers.values()] headers = ', '.join(header_list) raise InvalidHeadersWarning(message % headers) session_was_accessed = hasattr(request, 'session') and request.session.accessed if session_was_accessed or has_vary_header(response, 'Cookie'): if settings.CACHE_MIDDLEWARE_ANONYMOUS_ONLY: # When using this setting, all of the requirements for headers # have changed. This is just for Finda Social, which has very # different caching rules than the other sites. try: self._assert_cache_anonymous_only(request, response) except AssertionError, error: raise InvalidHeadersWarning('CACHE_MIDDLEWARE_ANONYMOUS_ONLY is enabled and the following occurred: %s' % error) else: return response if session_was_accessed: message_info = "accessed the user's session (probably by simply accessing request.user)" else: message_info = "returned a response with the Vary: Cookie header" message = "This URL has %s, but the response still has standard caching headers. You can't do both!" % message_info # If the session has been accessed and/or the "Vary: Cookie" header # exists, then the HTTP headers should specify that the response # is not to be cached. try: self._assert_not_cached(response) except AssertionError: raise InvalidHeadersWarning(message)