Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | n/a |
0 / 0 |
n/a |
0 / 0 |
CRAP | n/a |
0 / 0 |
|||
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * SPDX-License-Identifier: EUPL-1.2 |
| 5 | * |
| 6 | * This file is part of icap-flow. |
| 7 | * |
| 8 | * Licensed under the EUPL, Version 1.2 only (the "Licence"); |
| 9 | * you may not use this work except in compliance with the Licence. |
| 10 | * You may obtain a copy of the Licence at: |
| 11 | * |
| 12 | * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 |
| 13 | * |
| 14 | * Unless required by applicable law or agreed to in writing, software |
| 15 | * distributed under the Licence is distributed on an "AS IS" basis, |
| 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 17 | */ |
| 18 | |
| 19 | declare(strict_types=1); |
| 20 | |
| 21 | namespace Ndrstmr\Icap\Cache; |
| 22 | |
| 23 | use Ndrstmr\Icap\DTO\IcapResponse; |
| 24 | |
| 25 | /** |
| 26 | * Storage for cached ICAP OPTIONS responses (RFC 3507 §4.10.2). |
| 27 | * |
| 28 | * The library ships a process-local implementation ({@see InMemoryOptionsCache}) and adapters for PSR-6 and PSR-16 |
| 29 | * ({@see Psr6OptionsCache}, {@see Psr16OptionsCache}) for caches that processes share. |
| 30 | * |
| 31 | * The contract: |
| 32 | * - An entry is valid for the `$ttlSeconds` of {@see set()}, counted from when it is stored, for at most the |
| 33 | * `Options-TTL` of the response if it has one, and for at most {@see MAX_TTL_SECONDS}. Reading never extends it; |
| 34 | * {@see get()} returns null once it ended. A change of the service |
| 35 | * (its ISTag, `Preview`, `Allow`) shows when the entry ends at the latest, which is the only consistency promised: |
| 36 | * nothing invalidates an entry earlier, and processes that share a backend are not told. Writers of one key replace |
| 37 | * the entry as a whole; the last one wins. |
| 38 | * - The client stores a response only if it has status 200, fits a budget (64 KiB of fields and body in at most 100 |
| 39 | * field values) and does not contradict itself (`Options-TTL`, `ISTag`, `Preview`). It uses what {@see get()} |
| 40 | * returns only if that passes the same check and the limits of the client (`maxResponseSize`, `maxHeaderCount`, |
| 41 | * `maxHeaderLineLength`) would have taken it from the server. An entry that is none, however a custom cache came |
| 42 | * by it, is a miss. |
| 43 | * - The ISTag (RFC 3507 §4.7) belongs to the service that `$key` names. It never invalidates the entry of another key, |
| 44 | * and an implementation must not use it for that. |
| 45 | * - The key names the endpoint, the service (path and query) and the TLS profile of the client, so that a plain and |
| 46 | * a TLS client, or clients with other TLS settings, do not share an entry. It does not know a tenant, a proxy or |
| 47 | * anything else your transport does: give each security domain its own cache, or its own prefix with the PSR |
| 48 | * adapters. |
| 49 | * - How many entries a cache holds is the cache's to bound ({@see InMemoryOptionsCache} does; the PSR adapters bound |
| 50 | * the lifetime and size of an entry, and leave the total to the backend). |
| 51 | * |
| 52 | * A failure of the backend is reported as an {@see \Ndrstmr\Icap\Exception\IcapStorageException} with the cause as its |
| 53 | * previous exception, as the PSR adapters do; anything else passes unchanged. |
| 54 | * |
| 55 | * The client names an entry with a key of 64 hex digits ({@see OptionsCacheKey::forService()}). Treat the key as |
| 56 | * opaque: it holds nothing a PSR-6 or PSR-16 backend, a file name or a Redis key space could refuse. |
| 57 | */ |
| 58 | interface OptionsCacheInterface |
| 59 | { |
| 60 | /** |
| 61 | * The longest time in seconds that an entry is valid, whatever the server says: its `Options-TTL` can only shorten |
| 62 | * it. An hour is the value of the example in RFC 3507 §4.10.2 and the longest a changed service goes unnoticed. |
| 63 | */ |
| 64 | public const int MAX_TTL_SECONDS = 3600; |
| 65 | |
| 66 | /** |
| 67 | * Return the cached response for $key, or null on cache miss |
| 68 | * (entry absent or expired). |
| 69 | */ |
| 70 | public function get(string $key): ?IcapResponse; |
| 71 | |
| 72 | /** |
| 73 | * Store $response under $key for at most $ttlSeconds, and never for longer than its `Options-TTL` or |
| 74 | * {@see MAX_TTL_SECONDS}. A value <= 0 means "do not cache". |
| 75 | * |
| 76 | * $istag is the ISTag of the service $key names, if the response has one. It informs; it invalidates nothing. |
| 77 | */ |
| 78 | public function set(string $key, IcapResponse $response, int $ttlSeconds, ?string $istag = null): void; |
| 79 | |
| 80 | /** |
| 81 | * Remove the cached entry for $key. Idempotent. |
| 82 | */ |
| 83 | public function delete(string $key): void; |
| 84 | } |