mirror of
https://github.com/versity/versitygw.git
synced 2026-09-20 06:54:47 +00:00
Merge pull request #1715 from versity/sis/precondition-string-quotes
fix: Makes precondition headers insensitive to whether the value is quoted
This commit is contained in:
@@ -495,6 +495,8 @@ func EvaluatePreconditions(etag string, modTime time.Time, preconditions PreCond
|
||||
return nil
|
||||
}
|
||||
|
||||
etag = strings.Trim(etag, `"`)
|
||||
|
||||
// convert all conditions to *bool to evaluate the conditions
|
||||
var ifMatch, ifNoneMatch, ifModSince, ifUnmodeSince *bool
|
||||
if preconditions.IfMatch != nil {
|
||||
@@ -581,6 +583,7 @@ func EvaluatePreconditions(etag string, modTime time.Time, preconditions PreCond
|
||||
|
||||
// EvaluateMatchPreconditions evaluates if-match and if-none-match preconditions
|
||||
func EvaluateMatchPreconditions(etag string, ifMatch, ifNoneMatch *string) error {
|
||||
etag = strings.Trim(etag, `"`)
|
||||
if ifMatch != nil && *ifMatch != etag {
|
||||
return errPreconditionFailed
|
||||
}
|
||||
|
||||
@@ -67,7 +67,10 @@ func ParsePreconditionMatchHeaders(ctx *fiber.Ctx, opts ...preconditionOpt) (*st
|
||||
if cfg.withCopySource {
|
||||
prefix = "X-Amz-Copy-Source-"
|
||||
}
|
||||
return GetStringPtr(ctx.Get(prefix + "If-Match")), GetStringPtr(ctx.Get(prefix + "If-None-Match"))
|
||||
|
||||
ifMatch := trimQuotes(ctx.Get(prefix + "If-Match"))
|
||||
ifNoneMatch := trimQuotes(ctx.Get(prefix + "If-None-Match"))
|
||||
return GetStringPtr(ifMatch), GetStringPtr(ifNoneMatch)
|
||||
}
|
||||
|
||||
// ParsePreconditionDateHeaders parses the "If-Modified-Since" and "If-Unmodified-Since"
|
||||
@@ -136,3 +139,15 @@ func ParseIfMatchSize(ctx *fiber.Ctx) *int64 {
|
||||
|
||||
return &ifMatchSize
|
||||
}
|
||||
|
||||
func trimQuotes(str string) string {
|
||||
if len(str) < 2 {
|
||||
return str
|
||||
}
|
||||
|
||||
if str[0] == str[len(str)-1] && str[0] == '"' {
|
||||
return str[1 : len(str)-1]
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
@@ -1374,6 +1374,7 @@ func CompleteMultipartUpload_conditional_writes(s *S3Conf) error {
|
||||
obj := "my-obj"
|
||||
|
||||
etag := getPtr("")
|
||||
var etagTrimmed string
|
||||
incorrectEtag := getPtr("incorrect_etag")
|
||||
errPrecond := s3err.GetAPIError(s3err.ErrPreconditionFailed)
|
||||
|
||||
@@ -1399,6 +1400,13 @@ func CompleteMultipartUpload_conditional_writes(s *S3Conf) error {
|
||||
{"obj-3", etag, incorrectEtag, nil},
|
||||
{"obj-4", incorrectEtag, nil, nil},
|
||||
{"obj-5", nil, etag, nil},
|
||||
|
||||
// precondtion headers without quotes
|
||||
{obj, &etagTrimmed, nil, nil},
|
||||
{obj, &etagTrimmed, &etagTrimmed, errPrecond},
|
||||
{obj, &etagTrimmed, incorrectEtag, nil},
|
||||
{obj, incorrectEtag, &etagTrimmed, errPrecond},
|
||||
{obj, nil, &etagTrimmed, errPrecond},
|
||||
} {
|
||||
res, err := putObjectWithData(0, &s3.PutObjectInput{
|
||||
Bucket: &bucket,
|
||||
@@ -1412,6 +1420,7 @@ func CompleteMultipartUpload_conditional_writes(s *S3Conf) error {
|
||||
// the exact same data.
|
||||
// to avoid ETag collision reassign the etag value
|
||||
*etag = *res.res.ETag
|
||||
etagTrimmed = strings.Trim(*etag, `"`)
|
||||
|
||||
mp, err := createMp(s3client, bucket, test.obj)
|
||||
if err != nil {
|
||||
|
||||
@@ -910,6 +910,7 @@ func CopyObject_conditional_reads(s *S3Conf) error {
|
||||
before := time.Now().AddDate(0, 0, -3)
|
||||
after := time.Now()
|
||||
etag := obj.res.ETag
|
||||
etagTrimmed := strings.Trim(*etag, `"`)
|
||||
|
||||
for i, test := range []struct {
|
||||
ifmatch *string
|
||||
@@ -1008,6 +1009,47 @@ func CopyObject_conditional_reads(s *S3Conf) error {
|
||||
{nil, nil, nil, &before, errCond},
|
||||
{nil, nil, nil, &after, nil},
|
||||
{nil, nil, nil, nil, nil},
|
||||
|
||||
// if-match, if-non-match without quotes
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, nil, nil},
|
||||
|
||||
{&etagTrimmed, &etagTrimmed, &before, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, nil, errMod},
|
||||
|
||||
{&etagTrimmed, nil, &before, &before, nil},
|
||||
{&etagTrimmed, nil, &before, &after, nil},
|
||||
{&etagTrimmed, nil, &before, nil, nil},
|
||||
{&etagTrimmed, nil, &after, &before, errMod},
|
||||
{&etagTrimmed, nil, &after, &after, errMod},
|
||||
{&etagTrimmed, nil, &after, nil, errMod},
|
||||
{&etagTrimmed, nil, nil, &before, nil},
|
||||
{&etagTrimmed, nil, nil, &after, nil},
|
||||
{&etagTrimmed, nil, nil, nil, nil},
|
||||
|
||||
{nil, &etagTrimmed, &before, &before, errCond},
|
||||
{nil, &etagTrimmed, &before, &after, errMod},
|
||||
{nil, &etagTrimmed, &before, nil, errMod},
|
||||
{nil, &etagTrimmed, &after, &before, errCond},
|
||||
{nil, &etagTrimmed, &after, &after, errMod},
|
||||
{nil, &etagTrimmed, &after, nil, errMod},
|
||||
{nil, &etagTrimmed, nil, &before, errCond},
|
||||
{nil, &etagTrimmed, nil, &after, errMod},
|
||||
{nil, &etagTrimmed, nil, nil, errMod},
|
||||
} {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
||||
_, err := s3client.CopyObject(ctx, &s3.CopyObjectInput{
|
||||
|
||||
@@ -379,6 +379,7 @@ func GetObject_conditional_reads(s *S3Conf) error {
|
||||
before := time.Now().AddDate(0, 0, -3)
|
||||
after := time.Now()
|
||||
etag := obj.res.ETag
|
||||
etagTrimmed := strings.Trim(*etag, `"`)
|
||||
|
||||
for i, test := range []struct {
|
||||
ifmatch *string
|
||||
@@ -477,6 +478,47 @@ func GetObject_conditional_reads(s *S3Conf) error {
|
||||
{nil, nil, nil, &before, errCond},
|
||||
{nil, nil, nil, &after, nil},
|
||||
{nil, nil, nil, nil, nil},
|
||||
|
||||
// if-match, if-non-match without quotes
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, nil, nil},
|
||||
|
||||
{&etagTrimmed, &etagTrimmed, &before, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, nil, errMod},
|
||||
|
||||
{&etagTrimmed, nil, &before, &before, nil},
|
||||
{&etagTrimmed, nil, &before, &after, nil},
|
||||
{&etagTrimmed, nil, &before, nil, nil},
|
||||
{&etagTrimmed, nil, &after, &before, errMod},
|
||||
{&etagTrimmed, nil, &after, &after, errMod},
|
||||
{&etagTrimmed, nil, &after, nil, errMod},
|
||||
{&etagTrimmed, nil, nil, &before, nil},
|
||||
{&etagTrimmed, nil, nil, &after, nil},
|
||||
{&etagTrimmed, nil, nil, nil, nil},
|
||||
|
||||
{nil, &etagTrimmed, &before, &before, errCond},
|
||||
{nil, &etagTrimmed, &before, &after, errMod},
|
||||
{nil, &etagTrimmed, &before, nil, errMod},
|
||||
{nil, &etagTrimmed, &after, &before, errCond},
|
||||
{nil, &etagTrimmed, &after, &after, errMod},
|
||||
{nil, &etagTrimmed, &after, nil, errMod},
|
||||
{nil, &etagTrimmed, nil, &before, errCond},
|
||||
{nil, &etagTrimmed, nil, &after, errMod},
|
||||
{nil, &etagTrimmed, nil, nil, errMod},
|
||||
} {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
||||
_, err := s3client.GetObject(ctx, &s3.GetObjectInput{
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
@@ -422,6 +423,7 @@ func HeadObject_conditional_reads(s *S3Conf) error {
|
||||
before := time.Now().AddDate(0, 0, -3)
|
||||
after := time.Now()
|
||||
etag := obj.res.ETag
|
||||
etagTrimmed := strings.Trim(*etag, `"`)
|
||||
|
||||
for i, test := range []struct {
|
||||
ifmatch *string
|
||||
@@ -520,6 +522,47 @@ func HeadObject_conditional_reads(s *S3Conf) error {
|
||||
{nil, nil, nil, &before, errCond},
|
||||
{nil, nil, nil, &after, nil},
|
||||
{nil, nil, nil, nil, nil},
|
||||
|
||||
// if-match, if-non-match without quotes
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, nil, nil},
|
||||
|
||||
{&etagTrimmed, &etagTrimmed, &before, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, nil, errMod},
|
||||
|
||||
{&etagTrimmed, nil, &before, &before, nil},
|
||||
{&etagTrimmed, nil, &before, &after, nil},
|
||||
{&etagTrimmed, nil, &before, nil, nil},
|
||||
{&etagTrimmed, nil, &after, &before, errMod},
|
||||
{&etagTrimmed, nil, &after, &after, errMod},
|
||||
{&etagTrimmed, nil, &after, nil, errMod},
|
||||
{&etagTrimmed, nil, nil, &before, nil},
|
||||
{&etagTrimmed, nil, nil, &after, nil},
|
||||
{&etagTrimmed, nil, nil, nil, nil},
|
||||
|
||||
{nil, &etagTrimmed, &before, &before, errCond},
|
||||
{nil, &etagTrimmed, &before, &after, errMod},
|
||||
{nil, &etagTrimmed, &before, nil, errMod},
|
||||
{nil, &etagTrimmed, &after, &before, errCond},
|
||||
{nil, &etagTrimmed, &after, &after, errMod},
|
||||
{nil, &etagTrimmed, &after, nil, errMod},
|
||||
{nil, &etagTrimmed, nil, &before, errCond},
|
||||
{nil, &etagTrimmed, nil, &after, errMod},
|
||||
{nil, &etagTrimmed, nil, nil, errMod},
|
||||
} {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
||||
_, err := s3client.HeadObject(ctx, &s3.HeadObjectInput{
|
||||
|
||||
@@ -313,6 +313,7 @@ func PutObject_conditional_writes(s *S3Conf) error {
|
||||
}
|
||||
|
||||
etag := res.res.ETag
|
||||
etagTrimmed := strings.Trim(*etag, `"`)
|
||||
incorrectEtag := getPtr("incorrect_etag")
|
||||
errPrecond := s3err.GetAPIError(s3err.ErrPreconditionFailed)
|
||||
|
||||
@@ -331,6 +332,14 @@ func PutObject_conditional_writes(s *S3Conf) error {
|
||||
{obj, nil, incorrectEtag, nil},
|
||||
{obj, nil, etag, errPrecond},
|
||||
{obj, nil, nil, nil},
|
||||
|
||||
// precondition headers without quotes
|
||||
{obj, &etagTrimmed, nil, nil},
|
||||
{obj, &etagTrimmed, &etagTrimmed, errPrecond},
|
||||
{obj, &etagTrimmed, incorrectEtag, nil},
|
||||
{obj, incorrectEtag, &etagTrimmed, errPrecond},
|
||||
{obj, nil, &etagTrimmed, errPrecond},
|
||||
|
||||
// should ignore the precondition headers if
|
||||
// an object with the given name doesn't exist
|
||||
{"obj-1", incorrectEtag, etag, nil},
|
||||
@@ -351,6 +360,7 @@ func PutObject_conditional_writes(s *S3Conf) error {
|
||||
// the exact same data.
|
||||
// to avoid ETag collision reassign the etag value
|
||||
*etag = *res.res.ETag
|
||||
etagTrimmed = strings.Trim(*res.res.ETag, `"`)
|
||||
}
|
||||
if test.err == nil && err != nil {
|
||||
return fmt.Errorf("test case %v: expected no error, instead got %w", i, err)
|
||||
|
||||
@@ -17,6 +17,7 @@ package integration
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
@@ -663,6 +664,7 @@ func UploadPartCopy_conditional_reads(s *S3Conf) error {
|
||||
before := time.Now().AddDate(0, 0, -3)
|
||||
after := time.Now()
|
||||
etag := obj.res.ETag
|
||||
etagTrimmed := strings.Trim(*etag, `"`)
|
||||
|
||||
for i, test := range []struct {
|
||||
ifmatch *string
|
||||
@@ -761,6 +763,47 @@ func UploadPartCopy_conditional_reads(s *S3Conf) error {
|
||||
{nil, nil, nil, &before, errCond},
|
||||
{nil, nil, nil, &after, nil},
|
||||
{nil, nil, nil, nil, nil},
|
||||
|
||||
// if-match, if-non-match without quotes
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &before, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), &after, nil, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &before, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, &after, nil},
|
||||
{&etagTrimmed, getPtr("invalid_etag"), nil, nil, nil},
|
||||
|
||||
{&etagTrimmed, &etagTrimmed, &before, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &before, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, &after, nil, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &before, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, &after, errMod},
|
||||
{&etagTrimmed, &etagTrimmed, nil, nil, errMod},
|
||||
|
||||
{&etagTrimmed, nil, &before, &before, nil},
|
||||
{&etagTrimmed, nil, &before, &after, nil},
|
||||
{&etagTrimmed, nil, &before, nil, nil},
|
||||
{&etagTrimmed, nil, &after, &before, errMod},
|
||||
{&etagTrimmed, nil, &after, &after, errMod},
|
||||
{&etagTrimmed, nil, &after, nil, errMod},
|
||||
{&etagTrimmed, nil, nil, &before, nil},
|
||||
{&etagTrimmed, nil, nil, &after, nil},
|
||||
{&etagTrimmed, nil, nil, nil, nil},
|
||||
|
||||
{nil, &etagTrimmed, &before, &before, errCond},
|
||||
{nil, &etagTrimmed, &before, &after, errMod},
|
||||
{nil, &etagTrimmed, &before, nil, errMod},
|
||||
{nil, &etagTrimmed, &after, &before, errCond},
|
||||
{nil, &etagTrimmed, &after, &after, errMod},
|
||||
{nil, &etagTrimmed, &after, nil, errMod},
|
||||
{nil, &etagTrimmed, nil, &before, errCond},
|
||||
{nil, &etagTrimmed, nil, &after, errMod},
|
||||
{nil, &etagTrimmed, nil, nil, errMod},
|
||||
} {
|
||||
mpKey := "mp-key"
|
||||
mp, err := createMp(s3client, bucket, mpKey)
|
||||
|
||||
Reference in New Issue
Block a user