Skip to content

Support conditional writes (If-Match / If-None-Match) on PutObject and CopyObject - #294

Open
Robothy wants to merge 2 commits into
mainfrom
feat/conditional-requests
Open

Support conditional writes (If-Match / If-None-Match) on PutObject and CopyObject#294
Robothy wants to merge 2 commits into
mainfrom
feat/conditional-requests

Conversation

@Robothy

@Robothy Robothy commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Closes #289

What

Adds support for the S3 conditional write headers on PutObject, CopyObject and CompleteMultipartUpload:

  • If-Match -- write only if the current ETag matches (* requires the object to exist)
  • If-None-Match -- write only if the current ETag does not match (* requires the object to be absent)

Returns 412 PreconditionFailed when a condition does not hold. Reuses the existing S3ErrorCode.PreconditionFailed, no new error code.

How

The check happens in a single place -- PutObjectService#putObject, before content is written to storage, so a failed precondition never leaves a dangling object. CopyObject and CompleteMultipartUpload both route through it and pass the headers along.

ETag comparison tolerates both quoted and unquoted values, because clients echo back the ETag returned by the server verbatim (the server returns "<hex>").

Tests

New ConditionalRequestIntegrationTest with 8 cases covering wildcard and explicit ETags, match/mismatch on both headers, quoted ETags from the server, CopyObject, and 404 precedence on a missing bucket.

Full suite: 640 tests, 0 failures (baseline 632 + 8 new).

…d CopyObject

Evaluate the If-Match and If-None-Match headers before writing to storage so
that a failed precondition never leaves a dangling object behind.

The check is applied in a single place, PutObjectService#putObject, which
CopyObject and CompleteMultipartUpload both route through. ETag comparison
tolerates both quoted and unquoted values, since clients echo back the ETag
returned by the server verbatim.

Closes #289
@codecov

codecov Bot commented Sep 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.74359% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.75%. Comparing base (9b2a02c) to head (70451f1).

Files with missing lines Patch % Lines
.../robothy/s3/core/util/ConditionalRequestUtils.java 81.81% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #294      +/-   ##
============================================
- Coverage     90.76%   90.75%   -0.01%     
- Complexity     1459     1479      +20     
============================================
  Files           248      250       +2     
  Lines          5327     5365      +38     
  Branches        399      407       +8     
============================================
+ Hits           4835     4869      +34     
- Misses          338      340       +2     
- Partials        154      156       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

Support S3 conditional writes (If-Match / If-None-Match)

1 participant