fix: reject an empty start-after and continuation-token in ListObjects (V1)
This commit is contained in:
1 parent
613c71290f
commit
276128b42b
4 files changed
+74
-7
No files matched your search
@@ -615,8 +615,17 @@ func (c S3ApiController) ListObjects(ctx fiber.Ctx) (*Response, error) {
|
|||||||
region = defaultRegion
|
region = defaultRegion
|
||||||
}
|
}
|
||||||
|
|
||||||
// start-after is a ListObjectsV2 argument, S3 rejects it on a V1 listing
|
// continuation-token and start-after are ListObjectsV2 arguments, S3
|
||||||
if ctx.Query("start-after") != "" {
|
// rejects either one on a V1 listing, with or without a value
|
||||||
|
queryArgs := ctx.Request().URI().QueryArgs()
|
||||||
|
if queryArgs.Has("continuation-token") {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, s3err.GetInvalidArgumentErr(s3err.InvalidArgContinuationToken, "")
|
||||||
|
}
|
||||||
|
if queryArgs.Has("start-after") {
|
||||||
return &Response{
|
return &Response{
|
||||||
MetaOpts: &MetaOptions{
|
MetaOpts: &MetaOptions{
|
||||||
BucketOwner: parsedAcl.Owner,
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
|||||||
@@ -1213,6 +1213,42 @@ func TestS3ApiController_ListObjects(t *testing.T) {
|
|||||||
err: s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, ""),
|
err: s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, ""),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "empty start-after is not supported",
|
||||||
|
input: testInput{
|
||||||
|
locals: defaultLocals,
|
||||||
|
beRes: listResult,
|
||||||
|
queries: map[string]string{
|
||||||
|
"start-after": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: testOutput{
|
||||||
|
response: &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: "root",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "continuation-token is not supported",
|
||||||
|
input: testInput{
|
||||||
|
locals: defaultLocals,
|
||||||
|
beRes: listResult,
|
||||||
|
queries: map[string]string{
|
||||||
|
"continuation-token": "my-token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: testOutput{
|
||||||
|
response: &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: "root",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: s3err.GetInvalidArgumentErr(s3err.InvalidArgContinuationToken, ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "invalid max keys",
|
name: "invalid max keys",
|
||||||
input: testInput{
|
input: testInput{
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const (
|
|||||||
InvalidArgMaxBuckets InvalidArgErrorCode = iota
|
InvalidArgMaxBuckets InvalidArgErrorCode = iota
|
||||||
InvalidArgNegativeMaxKeys
|
InvalidArgNegativeMaxKeys
|
||||||
InvalidArgStartAfter
|
InvalidArgStartAfter
|
||||||
|
InvalidArgContinuationToken
|
||||||
InvalidArgObjectAttributes
|
InvalidArgObjectAttributes
|
||||||
InvalidArgPartNumber
|
InvalidArgPartNumber
|
||||||
InvalidArgCompleteMpPartNumber
|
InvalidArgCompleteMpPartNumber
|
||||||
@@ -95,6 +96,10 @@ var invalidArgErrResponses = map[InvalidArgErrorCode]InvalidArgumentError{
|
|||||||
Description: "startAfter only supported in REST.GET.BUCKET with list-type=2",
|
Description: "startAfter only supported in REST.GET.BUCKET with list-type=2",
|
||||||
ArgumentName: "start-after",
|
ArgumentName: "start-after",
|
||||||
},
|
},
|
||||||
|
InvalidArgContinuationToken: {
|
||||||
|
Description: "continuation-token only supported in REST.GET.BUCKET with list-type=2",
|
||||||
|
ArgumentName: "continuation-token",
|
||||||
|
},
|
||||||
InvalidArgObjectAttributes: {
|
InvalidArgObjectAttributes: {
|
||||||
Description: "Invalid attribute name specified.",
|
Description: "Invalid attribute name specified.",
|
||||||
ArgumentName: "x-amz-object-attributes",
|
ArgumentName: "x-amz-object-attributes",
|
||||||
|
|||||||
@@ -195,9 +195,9 @@ func ListObjects_invalid_max_keys(s *S3Conf) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// start-after belongs to ListObjectsV2, so S3 rejects it on a V1 listing
|
// start-after and continuation-token belong to ListObjectsV2, so S3 rejects
|
||||||
// instead of ignoring it. The SDK ListObjects input has no StartAfter field,
|
// either one on a V1 listing, with or without a value. The SDK ListObjects
|
||||||
// so the request is signed and sent by hand.
|
// input has neither field, so the requests are signed and sent by hand.
|
||||||
func ListObjects_start_after(s *S3Conf) error {
|
func ListObjects_start_after(s *S3Conf) error {
|
||||||
testName := "ListObjects_start_after"
|
testName := "ListObjects_start_after"
|
||||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||||
@@ -206,8 +206,20 @@ func ListObjects_start_after(s *S3Conf) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startAfterErr := s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, "")
|
||||||
|
contTokenErr := s3err.GetInvalidArgumentErr(s3err.InvalidArgContinuationToken, "")
|
||||||
|
for _, test := range []struct {
|
||||||
|
query string
|
||||||
|
expected s3err.S3Error
|
||||||
|
}{
|
||||||
|
{"start-after=bar", startAfterErr},
|
||||||
|
{"start-after=", startAfterErr},
|
||||||
|
{"start-after", startAfterErr},
|
||||||
|
{"continuation-token=bar", contTokenErr},
|
||||||
|
{"continuation-token=", contTokenErr},
|
||||||
|
} {
|
||||||
req, err := createSignedReq(http.MethodGet, s.endpoint,
|
req, err := createSignedReq(http.MethodGet, s.endpoint,
|
||||||
fmt.Sprintf("%v?start-after=bar", bucket),
|
fmt.Sprintf("%v?%v", bucket, test.query),
|
||||||
s.awsID, s.awsSecret, "s3", s.awsRegion, "", nil, time.Now(), nil)
|
s.awsID, s.awsSecret, "s3", s.awsRegion, "", nil, time.Now(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -218,7 +230,12 @@ func ListObjects_start_after(s *S3Conf) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkHTTPResponseApiErr(resp, s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, ""))
|
if err := checkHTTPResponseApiErr(resp, test.expected); err != nil {
|
||||||
|
return fmt.Errorf("%v: %w", test.query, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user