handle conditional get operations if the response has an etag or lastmodified header and the request has ifnonematch or ifmodifiedsince replace the response with httpnotmodified add an etag header if needed it s too late to prevent an unsafe request with a 412 response and for a head request the response body is always empty so computing an accurate etag isn t possible return true if an etag header should be added to response cachecontrolheaders ccdelimre splitresponse getcachecontrol return allheader lower nostore for header in cachecontrolheaders handle conditional get operations if the response has an etag or last modified header and the request has if none match or if modified since replace the response with httpnotmodified add an etag header if needed it s too late to prevent an unsafe request with a 412 response and for a head request the response body is always empty so computing an accurate etag isn t possible return true if an etag header should be added to response
from django.utils.cache import cc_delim_re, get_conditional_response, set_response_etag
from django.utils.deprecation import MiddlewareMixin
from django.utils.http import parse_http_date_safe


class ConditionalGetMiddleware(MiddlewareMixin):
    

    def process_response(self, request, response):
        
        
        
        if request.method != "GET":
            return response

        if self.needs_etag(response) and not response.has_header("ETag"):
            set_response_etag(response)

        etag = response.get("ETag")
        last_modified = response.get("Last-Modified")
        last_modified = last_modified and parse_http_date_safe(last_modified)

        if etag or last_modified:
            return get_conditional_response(
                request,
                etag=etag,
                last_modified=last_modified,
                response=response,
            )

        return response

    def needs_etag(self, response):
        
        cache_control_headers = cc_delim_re.split(response.get("Cache-Control", ""))
        return all(header.lower() != "no-store" for header in cache_control_headers)