You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(cache): support conditional requests on Cache.Open and Stat (#344)
## 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](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .claude/rules/base.md
-1Lines changed: 0 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,6 @@ DO NOT ASSUME I AM RIGHT, VERIFY WHAT I ASSERT
7
7
- When working on a list of tasks in a README.md bullet list `- [ ] ...`, pick the next incomplete one and implement that, mark it as complete, then stop.
8
8
- If you are in read-only "Ask" mode, and are asked to modify something, immediately abort saying you can't modify anything.
9
9
- Do exactly what I ask, no more. Don't add extra scripts, documentation, etc.
10
-
- Always run tests to verify correctness.
11
10
- Always write tests for updated/new code.
12
11
- Be succinct.
13
12
- Don't write comments if the related code itself is simple.
Copy file name to clipboardExpand all lines: .claude/rules/go.md
-1Lines changed: 0 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,7 +16,6 @@
16
16
- Where it makes sense, update existing test rather than creating new ones.
17
17
- ALWAYS run tests with `-timeout 30s` to ensure that wedged tests don't last forever.
18
18
- Don't run tests with `-v` in general, as it produces a large amount of output.
19
-
- Once the change is complete and working, run `golangci-lint run` and fix any linter errors introduced before adding the files to git. Do NOT EVER run `golangci-lint` on individual files.
20
19
- For "unparam" linter warnings about "XXX is unused", remove the parameter unless the type is part of an interface implementation or callback system.
21
20
- ALWAYS respect encapsulation of struct fields, even between types in the same package.
22
21
- ALWAYS apply the Go proverb "align the happy path to the left", to avoid deep nesting.
0 commit comments