From 66b979ee8623c210ae322f85d012733cbcc0bcb6 Mon Sep 17 00:00:00 2001 From: niksis02 Date: Fri, 11 Apr 2025 21:07:08 +0400 Subject: [PATCH] fix: Sets limit to tag set count to 10 for PutObjectTagging and 50 for PutBucketTagging Fixes #1204 Fixes #1205 Tag count in `PutBucketTagging` and `PutObjectTagging` is limited. `PutBucketTagging`: 50 `PutObjectTagging`: 10 Adds the changes to return errors respectively --- s3api/controllers/base.go | 26 +++++++++++++++ s3err/s3err.go | 12 +++++++ tests/integration/group-tests.go | 4 +++ tests/integration/tests.go | 57 ++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/s3api/controllers/base.go b/s3api/controllers/base.go index 429086f..29e824c 100644 --- a/s3api/controllers/base.go +++ b/s3api/controllers/base.go @@ -1225,6 +1225,19 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error { }) } + if len(bucketTagging.TagSet.Tags) > 50 { + if c.debug { + log.Printf("bucket tagging length exceeds 50: %v\n", len(bucketTagging.TagSet.Tags)) + } + return SendResponse(ctx, s3err.GetAPIError(s3err.ErrBucketTaggingLimited), + &MetaOpts{ + Logger: c.logger, + MetricsMng: c.mm, + Action: metrics.ActionPutBucketTagging, + BucketOwner: parsedAcl.Owner, + }) + } + tags := make(map[string]string, len(bucketTagging.TagSet.Tags)) for _, tag := range bucketTagging.TagSet.Tags { @@ -1863,6 +1876,19 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error { }) } + if len(objTagging.TagSet.Tags) > 10 { + if c.debug { + log.Printf("bucket tagging length exceeds 10: %v\n", len(objTagging.TagSet.Tags)) + } + return SendResponse(ctx, s3err.GetAPIError(s3err.ErrObjectTaggingLimited), + &MetaOpts{ + Logger: c.logger, + MetricsMng: c.mm, + Action: metrics.ActionPutObjectTagging, + BucketOwner: parsedAcl.Owner, + }) + } + tags := make(map[string]string, len(objTagging.TagSet.Tags)) for _, tag := range objTagging.TagSet.Tags { diff --git a/s3err/s3err.go b/s3err/s3err.go index 1663644..2e195ca 100644 --- a/s3err/s3err.go +++ b/s3err/s3err.go @@ -85,6 +85,8 @@ const ( ErrInvalidCopySource ErrInvalidCopySourceRange ErrInvalidTag + ErrBucketTaggingLimited + ErrObjectTaggingLimited ErrAuthHeaderEmpty ErrSignatureVersionNotSupported ErrMalformedPOSTRequest @@ -311,6 +313,16 @@ var errorCodeResponse = map[ErrorCode]APIError{ Description: "The Tag value you have provided is invalid", HTTPStatusCode: http.StatusBadRequest, }, + ErrBucketTaggingLimited: { + Code: "BadRequest", + Description: "Bucket tag count cannot be greater than 50", + HTTPStatusCode: http.StatusBadRequest, + }, + ErrObjectTaggingLimited: { + Code: "BadRequest", + Description: "Object tags cannot be greater than 10", + HTTPStatusCode: http.StatusBadRequest, + }, ErrMalformedXML: { Code: "MalformedXML", Description: "The XML you provided was not well-formed or did not validate against our published schema.", diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index ea8ba9a..1f46b57 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -118,6 +118,7 @@ func TestDeleteBucketOwnershipControls(s *S3Conf) { func TestPutBucketTagging(s *S3Conf) { PutBucketTagging_non_existing_bucket(s) PutBucketTagging_long_tags(s) + PutBucketTagging_tag_count_limit(s) PutBucketTagging_success(s) PutBucketTagging_success_status(s) } @@ -297,6 +298,7 @@ func TestCopyObject(s *S3Conf) { func TestPutObjectTagging(s *S3Conf) { PutObjectTagging_non_existing_object(s) PutObjectTagging_long_tags(s) + PutObjectTagging_tag_count_limit(s) PutObjectTagging_success(s) } @@ -850,6 +852,7 @@ func GetIntTests() IntTests { "DeleteBucketOwnershipControls_success": DeleteBucketOwnershipControls_success, "PutBucketTagging_non_existing_bucket": PutBucketTagging_non_existing_bucket, "PutBucketTagging_long_tags": PutBucketTagging_long_tags, + "PutBucketTagging_tag_count_limit": PutBucketTagging_tag_count_limit, "PutBucketTagging_success": PutBucketTagging_success, "PutBucketTagging_success_status": PutBucketTagging_success_status, "GetBucketTagging_non_existing_bucket": GetBucketTagging_non_existing_bucket, @@ -956,6 +959,7 @@ func GetIntTests() IntTests { "CopyObject_success": CopyObject_success, "PutObjectTagging_non_existing_object": PutObjectTagging_non_existing_object, "PutObjectTagging_long_tags": PutObjectTagging_long_tags, + "PutObjectTagging_tag_count_limit": PutObjectTagging_tag_count_limit, "PutObjectTagging_success": PutObjectTagging_success, "GetObjectTagging_non_existing_object": GetObjectTagging_non_existing_object, "GetObjectTagging_unset_tags": GetObjectTagging_unset_tags, diff --git a/tests/integration/tests.go b/tests/integration/tests.go index 6bf3213..6f634eb 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -2519,6 +2519,30 @@ func PutBucketTagging_long_tags(s *S3Conf) error { }) } +func PutBucketTagging_tag_count_limit(s *S3Conf) error { + testName := "PutBucketTagging_tag_count_limit" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + tagSet := []types.Tag{} + + for i := 0; i < 51; i++ { + tagSet = append(tagSet, types.Tag{ + Key: getPtr(fmt.Sprintf("key-%v", i)), + Value: getPtr(genRandString(10)), + }) + } + + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.PutBucketTagging(ctx, &s3.PutBucketTaggingInput{ + Bucket: &bucket, + Tagging: &types.Tagging{ + TagSet: tagSet, + }, + }) + cancel() + return checkApiErr(err, s3err.GetAPIError(s3err.ErrBucketTaggingLimited)) + }) +} + func PutBucketTagging_success(s *S3Conf) error { testName := "PutBucketTagging_success" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { @@ -6987,6 +7011,39 @@ func PutObjectTagging_long_tags(s *S3Conf) error { }) } +func PutObjectTagging_tag_count_limit(s *S3Conf) error { + testName := "PutObjectTagging_tag_count_limit" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + obj := "my-obj" + _, err := putObjectWithData(10, &s3.PutObjectInput{ + Bucket: &bucket, + Key: &obj, + }, s3client) + if err != nil { + return err + } + + tagSet := []types.Tag{} + for i := 0; i < 11; i++ { + tagSet = append(tagSet, types.Tag{ + Key: getPtr(fmt.Sprintf("key-%v", i)), + Value: getPtr(genRandString(15)), + }) + } + + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err = s3client.PutObjectTagging(ctx, &s3.PutObjectTaggingInput{ + Bucket: &bucket, + Key: &obj, + Tagging: &types.Tagging{ + TagSet: tagSet, + }, + }) + cancel() + return checkApiErr(err, s3err.GetAPIError(s3err.ErrObjectTaggingLimited)) + }) +} + func PutObjectTagging_success(s *S3Conf) error { testName := "PutObjectTagging_success" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {