Update S3-Conditional-Operations.md

Chris Lu committed 2026-05-26 13:19:27 -07:00
1 parent 661df744c8
commit 867ebb3740
1 file changed
+68 -11
+68 -11
@@ -14,12 +14,49 @@ ring changes.
## Supported Conditional Headers
| Header | Applies To | Condition | Use Case |
|--------|------------|-----------|----------|
| **If-Match** | GET, PUT, COPY | ETag matches | Ensure object hasn't changed |
| **If-None-Match** | GET, PUT, COPY | ETag doesn't match | Prevent overwrites, caching |
| **If-Modified-Since** | GET, COPY | Modified after date | Conditional downloads |
| **If-Unmodified-Since** | GET, PUT, COPY | Not modified after date | Safe modifications |
These conditions act on the **target object** (the object being read or
written). All four are supported on GET, HEAD, PUT, POST
(`CompleteMultipartUpload`), and COPY. DELETE supports only `If-Match`.
| Header | Type | Applies to | Special values |
|--------|------|------------|----------------|
| `If-Match` | ETag | GET, HEAD, PUT, POST, COPY, **DELETE** | `*` matches any existing object; comma-separated ETag list is honored |
| `If-None-Match` | ETag | GET, HEAD, PUT, POST, COPY | `*` matches only when the object does **not** exist (compare-and-create); comma-separated ETag list is honored |
| `If-Modified-Since` | RFC 1123 date | GET, HEAD, PUT, POST, COPY | — |
| `If-Unmodified-Since` | RFC 1123 date | GET, HEAD, PUT, POST, COPY | — |
### Copy-source conditionals
`CopyObject` and `UploadPartCopy` accept a second set of headers that
condition on the **source** object. They are independent of the four
standard headers above (which condition on the destination), so a single
copy request can carry conditions for both ends.
| Header | Type |
|--------|------|
| `x-amz-copy-source-if-match` | ETag |
| `x-amz-copy-source-if-none-match` | ETag |
| `x-amz-copy-source-if-modified-since` | RFC 1123 date |
| `x-amz-copy-source-if-unmodified-since` | RFC 1123 date |
### Evaluation order
Per [RFC 7232 §6](https://datatracker.ietf.org/doc/html/rfc7232#section-6)
and AWS S3, the conditions are evaluated in this order; later conditions
are skipped when an earlier one is present:
1. `If-Match`
2. `If-Unmodified-Since` — ignored if `If-Match` is present
([RFC 7232 §3.4](https://datatracker.ietf.org/doc/html/rfc7232#section-3.4))
3. `If-None-Match`
4. `If-Modified-Since` — ignored if `If-None-Match` is present
([RFC 7232 §3.3](https://datatracker.ietf.org/doc/html/rfc7232#section-3.3))
### Not supported
* `If-Range`. A `Range` request without `If-Range` works normally; there is
no header to fall back to a full-object response when the source has
changed.
## HTTP Examples
@@ -78,15 +115,35 @@ curl -X PUT \
-H "x-amz-copy-source: /source-bucket/source-file.txt" \
-H "x-amz-copy-source-if-match: \"source-etag\"" \
"http://localhost:8333/dest-bucket/dest-file.txt"
# Same copy, but also refuse to overwrite the destination
curl -X PUT \
-H "x-amz-copy-source: /source-bucket/source-file.txt" \
-H "x-amz-copy-source-if-match: \"source-etag\"" \
-H "If-None-Match: *" \
"http://localhost:8333/dest-bucket/dest-file.txt"
```
### Conditional DELETE
```bash
# Delete only if the object's ETag still matches what we read
curl -X DELETE \
-H "If-Match: \"d41d8cd98f00b204e9800998ecf8427e\"" \
"http://localhost:8333/mybucket/myfile.txt"
```
DELETE supports `If-Match` only; the other three conditional headers are
ignored on DELETE per the AWS S3 spec.
## HTTP Status Codes
| Status Code | Condition | Meaning |
|-------------|-----------|---------|
| **200 OK** | Condition met | Operation succeeded |
| **304 Not Modified** | If-None-Match matched | Object unchanged (GET only) |
| **412 Precondition Failed** | Condition not met | Operation blocked by condition |
| Status Code | When | Meaning |
|-------------|------|---------|
| **200 OK** | All conditions met | Operation succeeded normally |
| **304 Not Modified** | GET/HEAD with `If-None-Match` match, or `If-Modified-Since` not exceeded | Object unchanged; response carries the ETag header but no body |
| **400 Invalid Request** | `If-Modified-Since` or `If-Unmodified-Since` is not a valid RFC 1123 date | Header is malformed |
| **412 Precondition Failed** | Any other failed condition (all writes; GET/HEAD with `If-Match` mismatch or `If-Unmodified-Since` exceeded) | Operation blocked by condition |
## Atomicity and concurrency