|
| 1 | +from django.utils.cache import cc_delim_re, get_conditional_response, set_response_etag |
| 2 | +from django.utils.http import parse_http_date_safe |
| 3 | + |
| 4 | +from django_async_extensions.amiddleware.base import AsyncMiddlewareMixin |
| 5 | + |
| 6 | + |
| 7 | +class AsyncConditionalGetMiddleware(AsyncMiddlewareMixin): |
| 8 | + """ |
| 9 | + Handle conditional GET operations. If the response has an ETag or |
| 10 | + Last-Modified header and the request has If-None-Match or If-Modified-Since, |
| 11 | + replace the response with HttpNotModified. Add an ETag header if needed. |
| 12 | + """ |
| 13 | + |
| 14 | + async def process_response(self, request, response): |
| 15 | + # It's too late to prevent an unsafe request with a 412 response, and |
| 16 | + # for a HEAD request, the response body is always empty so computing |
| 17 | + # an accurate ETag isn't possible. |
| 18 | + if request.method != "GET": |
| 19 | + return response |
| 20 | + |
| 21 | + if self.needs_etag(response) and not response.has_header("ETag"): |
| 22 | + set_response_etag(response) |
| 23 | + |
| 24 | + etag = response.get("ETag") |
| 25 | + last_modified = response.get("Last-Modified") |
| 26 | + last_modified = last_modified and parse_http_date_safe(last_modified) |
| 27 | + |
| 28 | + if etag or last_modified: |
| 29 | + return get_conditional_response( |
| 30 | + request, |
| 31 | + etag=etag, |
| 32 | + last_modified=last_modified, |
| 33 | + response=response, |
| 34 | + ) |
| 35 | + |
| 36 | + return response |
| 37 | + |
| 38 | + def needs_etag(self, response): |
| 39 | + """Return True if an ETag header should be added to response.""" |
| 40 | + cache_control_headers = cc_delim_re.split(response.get("Cache-Control", "")) |
| 41 | + return all(header.lower() != "no-store" for header in cache_control_headers) |
0 commit comments