Repository navigation
Conversation
S3Store keeps ETags unquoted in Version (quotes are stripped on read) and put them on the wire as they are: `If-Match: abc` on the manifest CAS and on GETs, `If-None-Match: abc` on the conditional manifest GET. HTTP defines both headers over quoted entity-tags (RFC 9110 sections 8.8.3 and 13.1.1; the S3 API docs defer to RFC 7232), and the ETag header of every S3 response carries that form. AWS S3 (its CLI example sends a bare value) and rustfs accept the bare value too, but that is not documented for S3-compatible stores in general, and Cloudflare R2's docs are silent on it. A store that compares the tag strictly would refuse every manifest CAS (no push could ever commit) and never answer the conditional GET with 304. entity_tag() renders a Version as a quoted entity-tag (once; an already quoted value is left alone) and every conditional header uses it. Versions stay unquoted, so nothing stored or compared changes. Checked: the store contract suite passes against rustfs 1.0.1, which honours both forms; against Cloudflare R2, a quoted If-Match returned 200 on a match and 412 on a mismatch. A new unit test records the headers walgit sends to a fake S3; before this change it saw `If-Match: abc`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 11, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
S3Storestores ETags unquoted inVersionand sends them back unquoted in conditional headers:If-Match: abcon the manifest CAS (PutMode::Update) and on GETs withif_match;If-None-Match: abcon the conditional manifest GET.HTTP defines both headers over quoted entity-tags (RFC 9110 §8.8.3 and §13.1.1; the S3 API reference points to RFC 7232). The
ETagheader of every S3 response carries that quoted form. AWS S3 accepts a bare value (its CLI example sends one), and so does rustfs. Neither behaviour is documented for S3-compatible stores in general, and Cloudflare R2's docs are silent on it. A store that compares the tag strictly would refuse every manifest CAS with 412, so no push could ever commit. It would also never answer the conditional GET with 304.Fix
entity_tag()renders aVersionas a quoted entity-tag. A value that is already quoted is left alone. All three conditional headers use it.Versions stay unquoted, so nothing stored or compared changes. GCS is unaffected because it uses generations.Checked
cargo test -p walgit-store --test contract,s3_contract) passes against rustfs 1.0.1. A curl probe shows rustfs honours both the quoted and the bare form, forIf-Match(200/412) and forIf-None-Match(304).If-Matchreturned 200 on a match and 412 on a mismatch.conditional_headers_carry_quoted_entity_tagsrecords the headers sent to a fake S3. Before this change it seesIf-Match: abc.walgit-store, all targets) and thewalgit-storeunit and contract tests.just cipasses on a merge of this branch with my two other open fixes (Keep a 412'd log segment unless the manifest proves it uncommitted #104, Resolve a {"repo": …} events notify under a store prefix #105).🤖 Generated with Claude Code