Security hardening.
- Cache backend
get/setfailures (e.g. a Redis outage) are now caught and logged, degrading gracefully to a cache miss / uncached response instead of surfacing a 500 (CWE-703). - Interpolated cache tag values are length-capped (256 chars) before use as Redis key components, so a hostile path segment cannot inflate the tag-key namespace (CWE-770).
Security hardening.
- Corrupt cache entries no longer raise —
decode()failures are logged and treated as a miss so the handler is invoked to repopulate (CWE-502). decode()enforces conservative msgpack size limits (max_bin_len/max_str_len= 10 MiB,max_array_len/max_map_len= 1024) to prevent decompression-style memory blow-ups.- The
@cachedecorator now prependsplugin.key_prefixto the computed cache key — previouslykey_prefixwas ignored, breaking namespacing (CWE-436). - CR / LF characters are stripped from cached header values during decode, closing a response-splitting vector if a corrupt entry was ever served (CWE-444).
- Cached responses carry
Cache-Control: no-storeby default so downstream caches don't re-store our replays. on_startup/on_shutdownnow run the backend coroutine to completion instead of fire-and-forgetting it, so backendclose()actually flushes.- The active-plugin registry uses
WeakKeyDictionaryto eliminate theid(app)ABA hazard.
0.1.0 - 2026-05-16
Initial release.
init_cache(app, *, backend=...)— registersCachePlugin, mounts onapp.state.cache.@cache(ttl=..., tags=..., vary=..., key_func=..., condition=...)decorator.MemoryCacheBackend(max_size=10_000)— LRU + TTL, default.RedisCacheBackend.from_url(...)— multi-process viahawkapi-cache[redis]extra.- Tag-based invalidation:
app.state.cache.invalidate_tags([...]). X-Cache: HIT/MISSresponse header.- Only
GET/HEAD+ 2xx responses are cached; other methods and statuses pass through.