# Comportamiento por defecto de la caché

> Qué peticiones tiene en cuenta la caché del borde, qué respuestas guarda, cuánto tiempo las conserva y qué nunca cachea.

La caché decide dos veces: primero con la **petición** (¿es elegible, es decir, se consulta la caché?) y después con la **respuesta** (¿se puede guardar y durante cuánto tiempo?).

## Peticiones elegibles

Una petición solo se busca en la caché si se cumple todo esto. Si no, va directa al origen y se marca como `DYNAMIC`.

- La caché está activada para el nombre y el [modo desarrollo](https://developers.openwaf.dev/es/cache/configure/#development-mode) no.
- El método es `GET` o `HEAD`, sin cabecera `Upgrade` (WebSocket) y sin cuerpo.
- No coincide ninguna [regla de caché](https://developers.openwaf.dev/es/cache/cache-rules/) `bypass`.
- La extensión de la ruta está en la lista por defecto de abajo, o una regla `cache` hace elegible la petición.
- La ruta no es ambigua: sin parámetros de ruta con `;`, sin `/`, `\`, NUL, CR ni LF codificados, sin barra invertida y sin un último segmento que acabe en punto (`/x.css.`).

La `Cache-Control` y el `Pragma` de la propia petición se ignoran, así que un cliente no puede obligar al borde a volver a pedir al origen.

### Extensiones por defecto

```text
7z avi avif apk apng bin bmp bz2 class css csv doc docx dmg ejs eot eps exe flac gif gz ico iso jar
jpeg jpg js jxl m4a m4v mid midi mjs mkv mov mp3 mp4 ogg otf pdf pict pls png ppt pptx ps rar svg
svgz swf tar tif tiff ttf wasm webm webmanifest webp woff woff2 xls xlsx zip zst
```

además de `robots.txt`. El HTML, el JSON, el XML, `txt` y los source maps **no** están en la lista: necesitan una regla `cache`.

## Frescura: cuánto tiempo se guarda una respuesta

El borde toma el TTL de la primera de estas cabeceras que envíe el origen:

1. `OpenWAF-CDN-Cache-Control`: un cache-control solo para el borde de OpenWAF, que nunca se reenvía a los navegadores.
2. `CDN-Cache-Control` (RFC 9213), que se reenvía tal cual.
3. `Cache-Control`: `s-maxage` y después `max-age`.
4. `Expires`.
5. Los valores por defecto de abajo, si no hay ninguna de las anteriores.

La `Cache-Control` siempre llega al navegador tal como la envió el origen, salvo que configures un [TTL del navegador](https://developers.openwaf.dev/es/cache/configure/#browser-ttl).

### TTL por defecto

Sin ninguna cabecera de frescura, y solo para la lista de extensiones por defecto:

| Estado | TTL en el borde |
|---|---|
| `200`, `206`, `301` | 2 horas |
| `302`, `303` | 20 minutos, solo en peticiones sin `Cookie` ni `Authorization` |
| `404`, `410` | 3 minutos |
| Cualquier otro | no se guarda |

Los directorios de build conocidos de los frameworks habituales reciben **7 días** en lugar de 2 horas: `/_next/static/`, `/_nuxt/`, `/_astro/`, `/_app/immutable/`, `/build/assets/` y `/packs/`, salvo los ficheros que cambian a propósito, como `version.json`, `latest.json`, `sw.js`, `service-worker`, `manifest.json`, `page-data/` y `app-data.json`.

Una ruta que una regla hace elegible (HTML, JSON…) no recibe TTL por defecto: necesita frescura del origen o un TTL en la regla.

Ningún objeto se conserva más de 30 días.

## Respuestas que nunca se guardan

Estas respuestas llegan al visitante sin guardarse y se marcan como `BYPASS`:

- `Cache-Control: no-store` o `private`. Con `private="Set-Cookie"`, la respuesta se guarda sin esa cabecera.
- Una cabecera `Set-Cookie`, salvo que una regla fije el TTL del borde (entonces se quita `Set-Cookie` de la copia guardada).
- Una petición con `Authorization` cuya respuesta no diga `public`, `s-maxage` ni `must-revalidate`.
- Un `Vary` que nombre algo distinto de `Accept-Encoding`, `Accept` (solo imágenes) u `Origin`, incluidos `Vary: *` y `Vary: Cookie`. Consulta [Claves de caché](https://developers.openwaf.dev/es/cache/cache-keys/#vary).
- Un código de estado que no se puede cachear, un cuerpo mayor que el [tamaño máximo de objeto](https://developers.openwaf.dev/es/cache/configure/#maximum-object-size) (100 MB por defecto) o una codificación distinta de gzip o Brotli.
- Documentos personales: para `pdf`, `doc(x)`, `xls(x)`, `ppt(x)`, `csv`, `zip`, `7z`, `rar`, `tar` y `gz`, una petición con `Cookie` o `Authorization` solo se guarda si el origen envió frescura explícita.
- Las páginas que genera el propio borde: retos, páginas de bloqueo, la puerta de acceso y las redirecciones.

### Armadura anti-engaño de caché

Activada por defecto. Cuando la extensión de la URL promete un tipo pero el origen responde `text/html`, `application/json`, `application/xhtml+xml` o `text/plain` (salvo `robots.txt` y `.csv`), la respuesta no se guarda. Así se corta el ataque clásico en el que `/account.php/x.css` devuelve una página HTML personal que, si no, se cachearía y se serviría a otros. Se admiten las discrepancias inofensivas, como `application/octet-stream` o un `.jpg` servido como `image/webp`.

## Revalidación y contenido caducado

- `no-cache`, `max-age=0` o `s-maxage=0` con `ETag` o `Last-Modified`: la respuesta se guarda y se revalida con el origen cada vez que se usa (`If-None-Match` / `If-Modified-Since`); un `304` evita volver a enviar el cuerpo.
- Un objeto caducado con validadores se revalida: `REVALIDATED` si llega un `304` y `EXPIRED` si llega un `200` nuevo.
- **Caducado mientras se revalida**: con el `stale-while-revalidate` del origen, el objeto caducado se sirve (`UPDATING`) mientras se actualiza en segundo plano.
- **Caducado si hay error**: cuando el origen falla (error de red, tiempo agotado, `500`, `502`, `503`, `504`), se sirve el objeto caducado (`STALE`) durante el `stale-if-error` del origen o, si no lo envía, hasta 24 horas por defecto.
- `must-revalidate`, `proxy-revalidate`, `no-cache` y `s-maxage` desactivan el contenido caducado.

## Range, HEAD y fallos simultáneos

- Un `GET` con un único `Range` que no está en caché pide el objeto entero una sola vez, lo guarda y responde el rango a medida que llega (`206`), así que los vídeos también se cachean.
- Un `HEAD` se sirve desde la caché si el objeto está; si no, va al origen y no se guarda nada.
- Cuando muchos visitantes piden a la vez el mismo objeto que no está en caché, solo una petición va al origen; las demás esperan hasta 5 segundos y se sirven con el resultado.

## Compresión

El borde pide al origen `br, gzip` y guarda una sola copia por URL en la codificación que eligió el origen. Si el navegador de un visitante no acepta esa codificación, recibe la copia descomprimida al vuelo; `Vary: Accept-Encoding` no divide la caché.
