Determine cache TTL from response headers and URL.
(raw_response: bytes, url: str)
| 222 | |
| 223 | @staticmethod |
| 224 | def parse_ttl(raw_response: bytes, url: str) -> int: |
| 225 | """Determine cache TTL from response headers and URL.""" |
| 226 | hdr_end = raw_response.find(b"\r\n\r\n") |
| 227 | if hdr_end < 0: |
| 228 | return 0 |
| 229 | hdr = raw_response[:hdr_end].decode(errors="replace").lower() |
| 230 | |
| 231 | if b"HTTP/1.1 200" not in raw_response[:20]: |
| 232 | return 0 |
| 233 | # Scope no-store / private checks to the Cache-Control header line so |
| 234 | # URLs like "Location: /api/private/…" or "Server: private-build" |
| 235 | # don't accidentally suppress caching for cacheable responses. |
| 236 | if re.search(r"cache-control:[^\r\n]*\b(?:no-store|private)\b", hdr): |
| 237 | return 0 |
| 238 | if "set-cookie:" in hdr: |
| 239 | return 0 |
| 240 | |
| 241 | max_age_match = re.search(r"max-age=(\d+)", hdr) |
| 242 | if max_age_match: |
| 243 | return min(int(max_age_match.group(1)), CACHE_TTL_MAX) |
| 244 | |
| 245 | path = url.split("?")[0].lower() |
| 246 | for ext in STATIC_EXTS: |
| 247 | if path.endswith(ext): |
| 248 | return CACHE_TTL_STATIC_LONG |
| 249 | |
| 250 | content_type_match = re.search(r"content-type:\s*([^\r\n]+)", hdr) |
| 251 | content_type = content_type_match.group(1) if content_type_match else "" |
| 252 | if "image/" in content_type or "font/" in content_type: |
| 253 | return CACHE_TTL_STATIC_LONG |
| 254 | if "text/css" in content_type or "javascript" in content_type: |
| 255 | return CACHE_TTL_STATIC_MED |
| 256 | if "text/html" in content_type or "application/json" in content_type: |
| 257 | return 0 |
| 258 | |
| 259 | return 0 |
| 260 | |
| 261 | |
| 262 | # ── CORS helpers ────────────────────────────────────────────────────────────── |
no outgoing calls