(value: string | null)
| 239 | * `max-age=abc`) or a required value is missing (e.g. bare `max-age`). |
| 240 | */ |
| 241 | export function parseCacheControl(value: string | null): CacheControl { |
| 242 | const result: CacheControl = {}; |
| 243 | if (value === null || value.trim() === "") { |
| 244 | return result as CacheControl; |
| 245 | } |
| 246 | |
| 247 | const seen = new Set<string>(); |
| 248 | const parts = splitDirectives(value); |
| 249 | for (const part of parts) { |
| 250 | const trimmed = part.trim(); |
| 251 | if (trimmed === "") continue; |
| 252 | |
| 253 | const eq = trimmed.indexOf("="); |
| 254 | const name = (eq === -1 ? trimmed : trimmed.slice(0, eq)).trim() |
| 255 | .toLowerCase(); |
| 256 | const rawValue = eq === -1 ? undefined : trimmed.slice(eq + 1).trim(); |
| 257 | |
| 258 | // RFC 9111 §4.2.1: when a directive appears more than once, use the first |
| 259 | // occurrence. Track seen directive names to skip subsequent duplicates. |
| 260 | if (seen.has(name)) continue; |
| 261 | seen.add(name); |
| 262 | |
| 263 | switch (name) { |
| 264 | case "max-age": |
| 265 | if (rawValue === undefined) { |
| 266 | throw new SyntaxError( |
| 267 | `Cache-Control: ${name} requires an integer value`, |
| 268 | ); |
| 269 | } |
| 270 | result.maxAge = parseNonNegativeInt(rawValue, name); |
| 271 | break; |
| 272 | case "max-stale": |
| 273 | result.maxStale = rawValue === undefined |
| 274 | ? true |
| 275 | : parseNonNegativeInt(rawValue, name); |
| 276 | break; |
| 277 | case "min-fresh": |
| 278 | if (rawValue === undefined) { |
| 279 | throw new SyntaxError( |
| 280 | `Cache-Control: ${name} requires an integer value`, |
| 281 | ); |
| 282 | } |
| 283 | result.minFresh = parseNonNegativeInt(rawValue, name); |
| 284 | break; |
| 285 | case "no-cache": { |
| 286 | const noCacheFields = rawValue === undefined |
| 287 | ? undefined |
| 288 | : parseFieldNames(rawValue); |
| 289 | result.noCache = |
| 290 | noCacheFields === undefined || noCacheFields.length === 0 |
| 291 | ? true |
| 292 | : noCacheFields; |
| 293 | break; |
| 294 | } |
| 295 | case "no-store": |
| 296 | result.noStore = true; |
| 297 | break; |
| 298 | case "no-transform": |
no test coverage detected