Return a cached response if it exists in the cache, otherwise return False.
(self, request: PreparedRequest)
| 167 | return result |
| 168 | |
| 169 | def cached_request(self, request: PreparedRequest) -> HTTPResponse | Literal[False]: |
| 170 | """ |
| 171 | Return a cached response if it exists in the cache, otherwise |
| 172 | return False. |
| 173 | """ |
| 174 | assert request.url is not None |
| 175 | cache_url = self.cache_url(request.url) |
| 176 | logger.debug('Looking up "%s" in the cache', cache_url) |
| 177 | cc = self.parse_cache_control(request.headers) |
| 178 | |
| 179 | # Bail out if the request insists on fresh data |
| 180 | if "no-cache" in cc: |
| 181 | logger.debug('Request header has "no-cache", cache bypassed') |
| 182 | return False |
| 183 | |
| 184 | if "max-age" in cc and cc["max-age"] == 0: |
| 185 | logger.debug('Request header has "max_age" as 0, cache bypassed') |
| 186 | return False |
| 187 | |
| 188 | # Check whether we can load the response from the cache: |
| 189 | resp = self._load_from_cache(request) |
| 190 | if not resp: |
| 191 | return False |
| 192 | |
| 193 | # If we have a cached permanent redirect, return it immediately. We |
| 194 | # don't need to test our response for other headers b/c it is |
| 195 | # intrinsically "cacheable" as it is Permanent. |
| 196 | # |
| 197 | # See: |
| 198 | # https://tools.ietf.org/html/rfc7231#section-6.4.2 |
| 199 | # |
| 200 | # Client can try to refresh the value by repeating the request |
| 201 | # with cache busting headers as usual (ie no-cache). |
| 202 | if int(resp.status) in PERMANENT_REDIRECT_STATUSES: |
| 203 | msg = ( |
| 204 | "Returning cached permanent redirect response " |
| 205 | "(ignoring date and etag information)" |
| 206 | ) |
| 207 | logger.debug(msg) |
| 208 | return resp |
| 209 | |
| 210 | headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(resp.headers) |
| 211 | if not headers or "date" not in headers: |
| 212 | if "etag" not in headers: |
| 213 | # Without date or etag, the cached response can never be used |
| 214 | # and should be deleted. |
| 215 | logger.debug("Purging cached response: no date or etag") |
| 216 | self.cache.delete(cache_url) |
| 217 | logger.debug("Ignoring cached response: no date") |
| 218 | return False |
| 219 | |
| 220 | now = time.time() |
| 221 | time_tuple = parsedate_tz(headers["date"]) |
| 222 | assert time_tuple is not None |
| 223 | date = calendar.timegm(time_tuple[:6]) |
| 224 | current_age = max(0, now - date) |
| 225 | logger.debug("Current age based on date: %i", current_age) |
| 226 |