Skip to content

feat(cache): support conditional requests on Cache.Open and Stat#344

Merged
alecthomas merged 1 commit into
mainfrom
aat/open-options
Jun 23, 2026
Merged

feat(cache): support conditional requests on Cache.Open and Stat#344
alecthomas merged 1 commit into
mainfrom
aat/open-options

Conversation

@alecthomas

Copy link
Copy Markdown
Collaborator

Summary

Unifies conditional-request handling into a single option set shared by the client wire protocol, the cache backends, and the server handlers. Previously If-Match/If-None-Match were only evaluated at the HTTP layer (httputil.ServeCacheHit), and Cache.Open/Stat had no way to express preconditions — so the Remote tier couldn't forward them upstream and backends always read the body before a 304/412 could be decided.

This pushes precondition evaluation down into the cache, establishing the option plumbing for forthcoming Range / If-Range support.

Changes

  • client: replace the http.Request-based RequestOption with an inspectable RequestOptions struct (IfMatch/IfNoneMatch) plus a Check(etag) evaluator, so non-HTTP backends can evaluate preconditions locally. The matching logic (etagListMatches) moves here from httputil.
  • internal/cache: Cache.Open/Stat accept variadic Option args (an idiomatic alias of client.RequestOption). Disk/Memory/S3 short-circuit with ErrNotModified/ErrPreconditionFailed before reading the body; Remote forwards opts to upstream (zero translation — same type); Tiered treats the sentinels as definitive (no backfill, headers preserved for 304).
  • internal/httputil: ServeCacheHit/ServeCacheStat now serve the Open/Stat outcome, mapping sentinels to 304/412; CheckConditionals delegates to the unified client logic (still used by the git snapshot path).
  • handlers: apiv1 and the generic caching handler parse request conditionals and push them into Open/Stat.

Note on S3

S3's native conditional options (SetMatchETag etc.) match against S3's object ETag, but cachew advertises a SHA256 content-hash ETag stored in the companion .meta object — a different value. So preconditions are evaluated locally against the stored ETag rather than delegated to S3.

Tests

  • Reworked httputil/conditional_test.go for the outcome-based serve helpers.
  • Added a Conditional case to the shared cache suite, exercising If-Match/If-None-Match on Open and Stat across all backends (including Remote end-to-end).

🤖 Generated with Claude Code

Unify conditional-request handling into a single option set shared by the
client wire protocol, the cache backends, and the server handlers.

- client: replace the http.Request-based RequestOption with an inspectable
  RequestOptions struct (IfMatch/IfNoneMatch) plus Check(etag) evaluation,
  so non-HTTP backends can evaluate preconditions locally.
- cache: Cache.Open/Stat accept variadic Option args (alias of the client
  type). Disk/Memory/S3 short-circuit with ErrNotModified/ErrPreconditionFailed
  before reading the body; Remote forwards to upstream; Tiered treats the
  sentinels as definitive.
- httputil: matching logic moves to client; ServeCacheHit/ServeCacheStat now
  serve the Open/Stat outcome, mapping sentinels to 304/412.
- handlers: apiv1 and the generic caching handler push request conditionals
  down into Open/Stat.

This establishes the option plumbing for forthcoming Range/If-Range support.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alecthomas alecthomas requested a review from a team as a code owner June 23, 2026 05:11
@alecthomas alecthomas requested review from worstell and removed request for a team June 23, 2026 05:11
@alecthomas alecthomas merged commit e140d32 into main Jun 23, 2026
8 checks passed
@alecthomas alecthomas deleted the aat/open-options branch June 23, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant