diff --git a/backend/common.go b/backend/common.go index 01dfd40a..de8d7efd 100644 --- a/backend/common.go +++ b/backend/common.go @@ -643,6 +643,7 @@ type PreConditions struct { // - if-modified-since // - if-unmodified-since // if-match and if-none-match are ETag comparisons +// if-match "*" matches any ETag, and if-none-match "*" matches no ETag // if-modified-since and if-unmodified-since are last modifed time comparisons func EvaluatePreconditions(etag string, modTime time.Time, preconditions PreConditions) error { if preconditions.IfMatch == nil && preconditions.IfNoneMatch == nil && preconditions.IfModSince == nil && preconditions.IfUnmodeSince == nil { @@ -654,10 +655,10 @@ func EvaluatePreconditions(etag string, modTime time.Time, preconditions PreCond // convert all conditions to *bool to evaluate the conditions var ifMatch, ifNoneMatch, ifModSince, ifUnmodeSince *bool if preconditions.IfMatch != nil { - ifMatch = getBoolPtr(*preconditions.IfMatch == etag) + ifMatch = getBoolPtr(*preconditions.IfMatch == "*" || *preconditions.IfMatch == etag) } if preconditions.IfNoneMatch != nil { - ifNoneMatch = getBoolPtr(*preconditions.IfNoneMatch != etag) + ifNoneMatch = getBoolPtr(*preconditions.IfNoneMatch != "*" && *preconditions.IfNoneMatch != etag) } if preconditions.IfModSince != nil { ifModSince = getBoolPtr(preconditions.IfModSince.UTC().Before(modTime.UTC())) diff --git a/tests/integration/CopyObject.go b/tests/integration/CopyObject.go index 90b781a7..63d09bac 100644 --- a/tests/integration/CopyObject.go +++ b/tests/integration/CopyObject.go @@ -1208,6 +1208,19 @@ func CopyObject_conditional_reads(s *S3Conf) error { {nil, &etagTrimmed, nil, &before, errCond}, {nil, &etagTrimmed, nil, &after, errMod}, {nil, &etagTrimmed, nil, nil, errMod}, + + // if-match and if-none-match with asterisk + {getPtr("*"), nil, nil, nil, nil}, + {getPtr("*"), nil, &after, nil, errMod}, + {getPtr("*"), getPtr("invalid_etag"), nil, nil, nil}, + {getPtr("*"), etag, nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, &before, errMod}, + {nil, getPtr("*"), nil, nil, errMod}, + {nil, getPtr("*"), &before, nil, errMod}, + {nil, getPtr("*"), nil, &after, errMod}, + {nil, getPtr("*"), nil, &before, errCond}, + {getPtr("invalid_etag"), getPtr("*"), nil, nil, errCond}, } { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.CopyObject(ctx, &s3.CopyObjectInput{ diff --git a/tests/integration/GetObject.go b/tests/integration/GetObject.go index 3a3ca7c0..fb15b633 100644 --- a/tests/integration/GetObject.go +++ b/tests/integration/GetObject.go @@ -539,6 +539,19 @@ func GetObject_conditional_reads(s *S3Conf) error { {nil, &etagTrimmed, nil, &before, errCond}, {nil, &etagTrimmed, nil, &after, errMod}, {nil, &etagTrimmed, nil, nil, errMod}, + + // if-match and if-none-match with asterisk + {getPtr("*"), nil, nil, nil, nil}, + {getPtr("*"), nil, &after, nil, errMod}, + {getPtr("*"), getPtr("invalid_etag"), nil, nil, nil}, + {getPtr("*"), etag, nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, &before, errMod}, + {nil, getPtr("*"), nil, nil, errMod}, + {nil, getPtr("*"), &before, nil, errMod}, + {nil, getPtr("*"), nil, &after, errMod}, + {nil, getPtr("*"), nil, &before, errCond}, + {getPtr("invalid_etag"), getPtr("*"), nil, nil, errCond}, } { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.GetObject(ctx, &s3.GetObjectInput{ diff --git a/tests/integration/HeadObject.go b/tests/integration/HeadObject.go index 6fa68af4..0f5ca82d 100644 --- a/tests/integration/HeadObject.go +++ b/tests/integration/HeadObject.go @@ -534,6 +534,19 @@ func HeadObject_conditional_reads(s *S3Conf) error { {nil, &etagTrimmed, nil, &before, errCond}, {nil, &etagTrimmed, nil, &after, errMod}, {nil, &etagTrimmed, nil, nil, errMod}, + + // if-match and if-none-match with asterisk + {getPtr("*"), nil, nil, nil, nil}, + {getPtr("*"), nil, &after, nil, errMod}, + {getPtr("*"), getPtr("invalid_etag"), nil, nil, nil}, + {getPtr("*"), etag, nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, &before, errMod}, + {nil, getPtr("*"), nil, nil, errMod}, + {nil, getPtr("*"), &before, nil, errMod}, + {nil, getPtr("*"), nil, &after, errMod}, + {nil, getPtr("*"), nil, &before, errCond}, + {getPtr("invalid_etag"), getPtr("*"), nil, nil, errCond}, } { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.HeadObject(ctx, &s3.HeadObjectInput{ diff --git a/tests/integration/UploadPartCopy.go b/tests/integration/UploadPartCopy.go index 3e405fa8..677c0b36 100644 --- a/tests/integration/UploadPartCopy.go +++ b/tests/integration/UploadPartCopy.go @@ -804,6 +804,19 @@ func UploadPartCopy_conditional_reads(s *S3Conf) error { {nil, &etagTrimmed, nil, &before, errCond}, {nil, &etagTrimmed, nil, &after, errMod}, {nil, &etagTrimmed, nil, nil, errMod}, + + // if-match and if-none-match with asterisk + {getPtr("*"), nil, nil, nil, nil}, + {getPtr("*"), nil, &after, nil, errMod}, + {getPtr("*"), getPtr("invalid_etag"), nil, nil, nil}, + {getPtr("*"), etag, nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, nil, errMod}, + {getPtr("*"), getPtr("*"), nil, &before, errMod}, + {nil, getPtr("*"), nil, nil, errMod}, + {nil, getPtr("*"), &before, nil, errMod}, + {nil, getPtr("*"), nil, &after, errMod}, + {nil, getPtr("*"), nil, &before, errCond}, + {getPtr("invalid_etag"), getPtr("*"), nil, nil, errCond}, } { mpKey := "mp-key" mp, err := createMp(s3client, bucket, mpKey)