Proposal: conditional DELETE (If-Match) on DeleteObject for general-purpose buckets #2602
tomsanbear
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
AWS shipped conditional DELETE for S3 general-purpose buckets on 2025-09-16 — clients can send
If-Match: <etag>(or*) onDeleteObject, and the service returns 412PreconditionFailedon mismatch or 404NoSuchKeywhen the object's absent andIf-Matchwas sent.RustFS already parses the
If-Matchheader on DELETE (viafill_conditional_writes_opts_from_header, landed yesterday in #2592) but doesn't honor it indelete_object, so clients that send it silently lose the precondition check. There's not much of a client-side workaround — the alternative is HEAD-then-DELETE, which costs an extra GET-class request per op (DELETE is free on AWS).AWS refs: conditional-deletes guide, launch announcement.
Proposed behavior
Honor
If-MatchonDeleteObject, matching the AWS status-code matrix:<Code>PreconditionFailedIf-Matchsent (any value, incl.*)NoSuchKeyIf-MatchabsentIf-Match: *+ live objectIf-Match: *+ current version is delete markerPreconditionFailedVerified against
83bac394(current main):rustfs/src/storage/options.rs::del_optsstoresIf-Matchintoopts.http_preconditions.StorageError::PreconditionFailed→ 412,StorageError::ObjectNotFound→ 404 inrustfs/src/error.rs.SetDisks::delete_objectatcrates/ecstore/src/set_disk.rs:1725— it doesn't readopts.http_preconditions.Proposed shape: add a sibling helper
check_delete_preconditionincrates/ecstore/src/set_disk/write.rs, mirroringcheck_write_precondition(async,no_lock = true, returnsOption<StorageError>). Wire it at a single call site indelete_object, gated onopts.http_preconditions.is_some(). Delete-marker semantics invert vs. the PUT helper — on DELETE withIf-Match, a delete-marker current version should returnPreconditionFailed, because the current-version view is "not there."A note on scope
Sticking to what AWS ships for general-purpose buckets, so leaving these out:
If-None-Match/If-Modified-Since/If-Unmodified-Sinceon DELETE — AWS doesn't accept them here.x-amz-if-match-last-modified-time/x-amz-if-match-size— directory-bucket-only.If-Matchin batchDeleteObjects— AWS's batch XML body doesn't accept it.Alternatives I considered
check_write_preconditionwith a flag. Rejected because the delete-marker branch inverts and the PUT helper'sshould_prevent_writeencodes PUT-specific semantics — a flag would fork the body enough that a sibling is cleaner. The sibling also mirrors the existing PUT helper pattern.Open questions
versionId + If-Match— AWS docs explicitly scope conditional DELETE to the current version and are silent on the combination. Current plan: check against the named version's ETag (inherit whateverget_object_infoversion resolution returns). Any preference, or should I just flag it in the PR as "our interpretation"?Prior work I looked at
DeleteObject → PreconditionFailed (412)as a motivation in the PR body — but only wired the helper into the read path. This PR would finish that work.del_opts(yesterday).Verification plan
No unit tests exist in
set_disk/write.rstoday so I'm deferring unit coverage (helper is a straightforward composition ofget_object_info+ etag comparison — happy to add scaffolding if you'd rather). E2e coverage in a newconditional_deletes.rsmirroringconditional_writes.rs,make pre-commitgate before push.Happy to hold off on the PR if anyone wants to weigh in first, or redirect me if someone else has already tackled this or you'd prefer a different shape. Let me know how you'd like me to proceed.
All reactions