From 453136bd5ad6e8be0b2d82a1c703aba280d0e6a2 Mon Sep 17 00:00:00 2001 From: Ben McClelland Date: Sat, 24 Aug 2024 13:42:49 -0700 Subject: [PATCH] fix: return KeyTooLongError when filenames exceed allowed length The posix limits wont exactly match up with the AWS key length limits because posix has component length limits as well as path length limits. This reponds with the aws compatible KeyTooLongError under these conditions now. Note that delete object returns success even in the error cases. Fixes #755 --- backend/posix/posix.go | 36 ++++++++++--- backend/scoutfs/scoutfs.go | 9 ++++ s3err/s3err.go | 86 +++++++++++++++++--------------- tests/integration/group-tests.go | 6 +++ tests/integration/tests.go | 48 ++++++++++++++++++ 5 files changed, 139 insertions(+), 46 deletions(-) diff --git a/backend/posix/posix.go b/backend/posix/posix.go index e3895935..eab959fa 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -1231,6 +1231,9 @@ func (p *Posix) UploadPartCopy(ctx context.Context, upi *s3.UploadPartCopyInput) if errors.Is(err, fs.ErrNotExist) { return s3response.CopyObjectResult{}, s3err.GetAPIError(s3err.ErrNoSuchUpload) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return s3response.CopyObjectResult{}, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return s3response.CopyObjectResult{}, fmt.Errorf("stat uploadid: %w", err) } @@ -1258,6 +1261,9 @@ func (p *Posix) UploadPartCopy(ctx context.Context, upi *s3.UploadPartCopyInput) if errors.Is(err, fs.ErrNotExist) { return s3response.CopyObjectResult{}, s3err.GetAPIError(s3err.ErrNoSuchKey) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return s3response.CopyObjectResult{}, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return s3response.CopyObjectResult{}, fmt.Errorf("stat object: %w", err) } @@ -1413,6 +1419,12 @@ func (p *Posix) PutObject(ctx context.Context, po *s3.PutObjectInput) (string, e if err == nil && d.IsDir() { return "", s3err.GetAPIError(s3err.ErrExistingObjectIsDirectory) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return "", s3err.GetAPIError(s3err.ErrKeyTooLong) + } + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return "", fmt.Errorf("stat object: %w", err) + } f, err := p.openTmpFile(filepath.Join(*po.Bucket, metaTmpDir), *po.Bucket, *po.Key, contentLength, acct, doFalloc) @@ -1516,12 +1528,12 @@ func (p *Posix) DeleteObject(_ context.Context, input *s3.DeleteObjectInput) err objpath := filepath.Join(bucket, object) fi, err := os.Stat(objpath) - if errors.Is(err, fs.ErrNotExist) { - // AWS returns success if the object does not exist - return nil - } if err != nil { - return fmt.Errorf("stat object: %w", err) + // AWS returns success if the object does not exist or + // is invalid somehow. + // TODO: log if !errors.Is(err, fs.ErrNotExist) somewhere? + + return nil } if strings.HasSuffix(object, "/") && !fi.IsDir() { // requested object is expecting a directory with a trailing @@ -1642,6 +1654,9 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO if errors.Is(err, fs.ErrNotExist) { return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return nil, fmt.Errorf("stat object: %w", err) } @@ -1785,6 +1800,9 @@ func (p *Posix) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3. if errors.Is(err, fs.ErrNotExist) { return nil, s3err.GetAPIError(s3err.ErrInvalidPart) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return nil, fmt.Errorf("stat part: %w", err) } @@ -1819,6 +1837,9 @@ func (p *Posix) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3. if errors.Is(err, fs.ErrNotExist) { return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return nil, fmt.Errorf("stat object: %w", err) } @@ -1989,8 +2010,11 @@ func (p *Posix) CopyObject(ctx context.Context, input *s3.CopyObjectInput) (*s3. if errors.Is(err, fs.ErrNotExist) { return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { - return nil, fmt.Errorf("stat object: %w", err) + return nil, fmt.Errorf("open object: %w", err) } defer f.Close() diff --git a/backend/scoutfs/scoutfs.go b/backend/scoutfs/scoutfs.go index 5465b26f..fb48b0cb 100644 --- a/backend/scoutfs/scoutfs.go +++ b/backend/scoutfs/scoutfs.go @@ -458,6 +458,9 @@ func (s *ScoutFS) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s if errors.Is(err, fs.ErrNotExist) { return nil, s3err.GetAPIError(s3err.ErrInvalidPart) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return nil, fmt.Errorf("stat part: %w", err) } @@ -492,6 +495,9 @@ func (s *ScoutFS) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s if errors.Is(err, fs.ErrNotExist) { return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return nil, fmt.Errorf("stat object: %w", err) } @@ -613,6 +619,9 @@ func (s *ScoutFS) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.Ge if errors.Is(err, fs.ErrNotExist) { return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } if err != nil { return nil, fmt.Errorf("stat object: %w", err) } diff --git a/s3err/s3err.go b/s3err/s3err.go index 8433ca94..2767d0ce 100644 --- a/s3err/s3err.go +++ b/s3err/s3err.go @@ -131,6 +131,7 @@ const ( ErrUnexpectedContent ErrMissingSecurityHeader ErrInvalidMetadataDirective + ErrKeyTooLong // Non-AWS errors ErrExistingObjectIsDirectory @@ -152,7 +153,7 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrBucketNotEmpty: { Code: "BucketNotEmpty", - Description: "The bucket you tried to delete is not empty", + Description: "The bucket you tried to delete is not empty.", HTTPStatusCode: http.StatusConflict, }, ErrBucketAlreadyExists: { @@ -177,17 +178,17 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrInvalidMaxUploads: { Code: "InvalidArgument", - Description: "Argument max-uploads must be an integer between 0 and 2147483647", + Description: "Argument max-uploads must be an integer between 0 and 2147483647.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidMaxKeys: { Code: "InvalidArgument", - Description: "Argument maxKeys must be an integer between 0 and 2147483647", + Description: "Argument maxKeys must be an integer between 0 and 2147483647.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidMaxParts: { Code: "InvalidArgument", - Description: "Argument max-parts must be an integer between 0 and 2147483647", + Description: "Argument max-parts must be an integer between 0 and 2147483647.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidPartNumberMarker: { @@ -197,7 +198,7 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrNoSuchBucket: { Code: "NoSuchBucket", - Description: "The specified bucket does not exist", + Description: "The specified bucket does not exist.", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchKey: { @@ -222,7 +223,7 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrInvalidPartNumber: { Code: "InvalidArgument", - Description: "Part number must be an integer between 1 and 10000, inclusive", + Description: "Part number must be an integer between 1 and 10000, inclusive.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidCopyDest: { @@ -267,7 +268,7 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrPostPolicyConditionInvalidFormat: { Code: "PostPolicyInvalidKeyName", - Description: "Invalid according to Policy: Policy Condition failed", + Description: "Invalid according to Policy: Policy Condition failed.", HTTPStatusCode: http.StatusForbidden, }, ErrEntityTooSmall: { @@ -302,7 +303,7 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrMalformedPresignedDate: { Code: "AuthorizationQueryParametersError", - Description: "X-Amz-Date must be in the ISO8601 Long Format \"yyyyMMdd'T'HHmmss'Z'\"", + Description: "X-Amz-Date must be in the ISO8601 Long Format \"yyyyMMdd'T'HHmmss'Z'\".", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingSignHeadersTag: { @@ -317,7 +318,7 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrUnsignedHeaders: { Code: "AccessDenied", - Description: "There were headers present in the request which were not signed", + Description: "There were headers present in the request which were not signed.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidQueryParams: { @@ -332,22 +333,22 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrExpiredPresignRequest: { Code: "AccessDenied", - Description: "Request has expired", + Description: "Request has expired.", HTTPStatusCode: http.StatusForbidden, }, ErrMalformedExpires: { Code: "AuthorizationQueryParametersError", - Description: "X-Amz-Expires should be a number", + Description: "X-Amz-Expires should be a number.", HTTPStatusCode: http.StatusBadRequest, }, ErrNegativeExpires: { Code: "AuthorizationQueryParametersError", - Description: "X-Amz-Expires must be non-negative", + Description: "X-Amz-Expires must be non-negative.", HTTPStatusCode: http.StatusBadRequest, }, ErrMaximumExpires: { Code: "AuthorizationQueryParametersError", - Description: "X-Amz-Expires must be less than a week (in seconds); that is, the given X-Amz-Expires must be less than 604800 seconds", + Description: "X-Amz-Expires must be less than a week (in seconds); that is, the given X-Amz-Expires must be less than 604800 seconds.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidAccessKeyID: { @@ -357,7 +358,7 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrRequestNotReadyYet: { Code: "AccessDenied", - Description: "Request is not valid yet", + Description: "Request is not valid yet.", HTTPStatusCode: http.StatusForbidden, }, ErrSignatureDoesNotMatch: { @@ -367,17 +368,17 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrSignatureDateDoesNotMatch: { Code: "SignatureDoesNotMatch", - Description: "Date in Credential scope does not match YYYYMMDD from ISO-8601 version of date from HTTP", + Description: "Date in Credential scope does not match YYYYMMDD from ISO-8601 version of date from HTTP.", HTTPStatusCode: http.StatusForbidden, }, ErrSignatureTerminationStr: { Code: "SignatureDoesNotMatch", - Description: "Credential should be scoped with a valid terminator: 'aws4_request'", + Description: "Credential should be scoped with a valid terminator: 'aws4_request'.", HTTPStatusCode: http.StatusForbidden, }, ErrSignatureIncorrService: { Code: "SignatureDoesNotMatch", - Description: "Credential should be scoped to correct service: s3", + Description: "Credential should be scoped to correct service: s3.", HTTPStatusCode: http.StatusForbidden, }, ErrContentSHA256Mismatch: { @@ -387,32 +388,32 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrMissingDateHeader: { Code: "AccessDenied", - Description: "AWS authentication requires a valid Date or x-amz-date header", + Description: "AWS authentication requires a valid Date or x-amz-date header.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidRequest: { Code: "InvalidRequest", - Description: "Invalid Request", + Description: "Invalid Request.", HTTPStatusCode: http.StatusBadRequest, }, ErrAuthNotSetup: { Code: "InvalidRequest", - Description: "Signed request requires setting up SeaweedFS S3 authentication", + Description: "Signed request requires setting up SeaweedFS S3 authentication.", HTTPStatusCode: http.StatusBadRequest, }, ErrNotImplemented: { Code: "NotImplemented", - Description: "A header you provided implies functionality that is not implemented", + Description: "A header you provided implies functionality that is not implemented.", HTTPStatusCode: http.StatusNotImplemented, }, ErrPreconditionFailed: { Code: "PreconditionFailed", - Description: "At least one of the pre-conditions you specified did not hold", + Description: "At least one of the pre-conditions you specified did not hold.", HTTPStatusCode: http.StatusPreconditionFailed, }, ErrInvalidObjectState: { Code: "InvalidObjectState", - Description: "The operation is not valid for the current state of the object", + Description: "The operation is not valid for the current state of the object.", HTTPStatusCode: http.StatusForbidden, }, ErrInvalidRange: { @@ -427,52 +428,52 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrObjectLockConfigurationNotFound: { Code: "ObjectLockConfigurationNotFoundError", - Description: "Object Lock configuration does not exist for this bucket", + Description: "Object Lock configuration does not exist for this bucket.", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchObjectLockConfiguration: { Code: "NoSuchObjectLockConfiguration", - Description: "The specified object does not have an ObjectLock configuration", + Description: "The specified object does not have an ObjectLock configuration.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidBucketObjectLockConfiguration: { Code: "InvalidRequest", - Description: "Bucket is missing ObjectLockConfiguration", + Description: "Bucket is missing ObjectLockConfiguration.", HTTPStatusCode: http.StatusBadRequest, }, ErrObjectLockConfigurationNotAllowed: { Code: "InvalidBucketState", - Description: "Object Lock configuration cannot be enabled on existing buckets", + Description: "Object Lock configuration cannot be enabled on existing buckets.", HTTPStatusCode: http.StatusConflict, }, ErrObjectLocked: { Code: "InvalidRequest", - Description: "Object is WORM protected and cannot be overwritten", + Description: "Object is WORM protected and cannot be overwritten.", HTTPStatusCode: http.StatusBadRequest, }, ErrPastObjectLockRetainDate: { Code: "InvalidRequest", - Description: "the retain until date must be in the future", + Description: "the retain until date must be in the future.", HTTPStatusCode: http.StatusBadRequest, }, ErrObjectLockInvalidRetentionPeriod: { Code: "InvalidRetentionPeriod", - Description: "the retention days/years must be positive integer", + Description: "the retention days/years must be positive integer.", HTTPStatusCode: http.StatusBadRequest, }, ErrNoSuchBucketPolicy: { Code: "NoSuchBucketPolicy", - Description: "The bucket policy does not exist", + Description: "The bucket policy does not exist.", HTTPStatusCode: http.StatusNotFound, }, ErrBucketTaggingNotFound: { Code: "NoSuchTagSet", - Description: "The TagSet does not exist", + Description: "The TagSet does not exist.", HTTPStatusCode: http.StatusNotFound, }, ErrObjectLockInvalidHeaders: { Code: "InvalidRequest", - Description: "x-amz-object-lock-retain-until-date and x-amz-object-lock-mode must both be supplied", + Description: "x-amz-object-lock-retain-until-date and x-amz-object-lock-mode must both be supplied.", HTTPStatusCode: http.StatusBadRequest, }, ErrRequestTimeTooSkewed: { @@ -482,37 +483,37 @@ var errorCodeResponse = map[ErrorCode]APIError{ }, ErrInvalidBucketAclWithObjectOwnership: { Code: "ErrInvalidBucketAclWithObjectOwnership", - Description: "Bucket cannot have ACLs set with ObjectOwnership's BucketOwnerEnforced setting", + Description: "Bucket cannot have ACLs set with ObjectOwnership's BucketOwnerEnforced setting.", HTTPStatusCode: http.StatusBadRequest, }, ErrBothCannedAndHeaderGrants: { Code: "InvalidRequest", - Description: "Specifying both Canned ACLs and Header Grants is not allowed", + Description: "Specifying both Canned ACLs and Header Grants is not allowed.", HTTPStatusCode: http.StatusBadRequest, }, ErrOwnershipControlsNotFound: { Code: "OwnershipControlsNotFoundError", - Description: "The bucket ownership controls were not found", + Description: "The bucket ownership controls were not found.", HTTPStatusCode: http.StatusNotFound, }, ErrAclNotSupported: { Code: "AccessControlListNotSupported", - Description: "The bucket does not allow ACLs", + Description: "The bucket does not allow ACLs.", HTTPStatusCode: http.StatusBadRequest, }, ErrMalformedACL: { Code: "MalformedACLError", - Description: "The XML you provided was not well-formed or did not validate against our published schema", + Description: "The XML you provided was not well-formed or did not validate against our published schema.", HTTPStatusCode: http.StatusBadRequest, }, ErrUnexpectedContent: { Code: "UnexpectedContent", - Description: "This request does not support content", + Description: "This request does not support content.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingSecurityHeader: { Code: "MissingSecurityHeader", - Description: "Your request was missing a required header", + Description: "Your request was missing a required header.", HTTPStatusCode: http.StatusNotFound, }, ErrInvalidMetadataDirective: { @@ -520,6 +521,11 @@ var errorCodeResponse = map[ErrorCode]APIError{ Description: "Unknown metadata directive.", HTTPStatusCode: http.StatusBadRequest, }, + ErrKeyTooLong: { + Code: "KeyTooLongError", + Description: "Your key is too long.", + HTTPStatusCode: http.StatusBadRequest, + }, // non aws errors ErrExistingObjectIsDirectory: { diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index 6772b3d3..06e0ecd1 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -132,6 +132,7 @@ func TestPutObject(s *S3Conf) { PutObject_special_chars(s) PutObject_invalid_long_tags(s) PutObject_missing_object_lock_retention_config(s) + PutObject_name_too_long(s) PutObject_with_object_lock(s) PutObject_success(s) PutObject_invalid_credentials(s) @@ -143,6 +144,7 @@ func TestHeadObject(s *S3Conf) { HeadObject_non_existing_mp(s) HeadObject_mp_success(s) HeadObject_non_existing_dir_object(s) + HeadObject_name_too_long(s) HeadObject_success(s) } @@ -186,6 +188,7 @@ func TestListObjectsV2(s *S3Conf) { func TestDeleteObject(s *S3Conf) { DeleteObject_non_existing_object(s) + DeleteObject_name_too_long(s) DeleteObject_non_existing_dir_object(s) DeleteObject_success(s) DeleteObject_success_status_code(s) @@ -539,6 +542,7 @@ func GetIntTests() IntTests { "PresignedAuth_incorrect_secret_key": PresignedAuth_incorrect_secret_key, "PresignedAuth_PutObject_success": PresignedAuth_PutObject_success, "PutObject_missing_object_lock_retention_config": PutObject_missing_object_lock_retention_config, + "PutObject_name_too_long": PutObject_name_too_long, "PutObject_with_object_lock": PutObject_with_object_lock, "PresignedAuth_Put_GetObject_with_data": PresignedAuth_Put_GetObject_with_data, "PresignedAuth_Put_GetObject_with_UTF8_chars": PresignedAuth_Put_GetObject_with_UTF8_chars, @@ -588,6 +592,7 @@ func GetIntTests() IntTests { "HeadObject_non_existing_mp": HeadObject_non_existing_mp, "HeadObject_mp_success": HeadObject_mp_success, "HeadObject_non_existing_dir_object": HeadObject_non_existing_dir_object, + "HeadObject_name_too_long": HeadObject_name_too_long, "HeadObject_success": HeadObject_success, "GetObjectAttributes_non_existing_bucket": GetObjectAttributes_non_existing_bucket, "GetObjectAttributes_non_existing_object": GetObjectAttributes_non_existing_object, @@ -616,6 +621,7 @@ func GetIntTests() IntTests { "ListObjectsV2_both_delimiter_and_prefix": ListObjectsV2_both_delimiter_and_prefix, "ListObjectsV2_single_dir_object_with_delim_and_prefix": ListObjectsV2_single_dir_object_with_delim_and_prefix, "DeleteObject_non_existing_object": DeleteObject_non_existing_object, + "DeleteObject_name_too_long": DeleteObject_name_too_long, "DeleteObject_non_existing_dir_object": DeleteObject_non_existing_dir_object, "DeleteObject_success": DeleteObject_success, "DeleteObject_success_status_code": DeleteObject_success_status_code, diff --git a/tests/integration/tests.go b/tests/integration/tests.go index 82818588..4dcc5053 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -2769,6 +2769,25 @@ func PutObject_missing_object_lock_retention_config(s *S3Conf) error { }) } +func PutObject_name_too_long(s *S3Conf) error { + testName := "PutObject_name_too_long" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + key := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.PutObject(ctx, &s3.PutObjectInput{ + Bucket: &bucket, + Key: &key, + }) + cancel() + if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrKeyTooLong)); err != nil { + return err + } + + return nil + }) +} + func PutObject_with_object_lock(s *S3Conf) error { testName := "PutObject_with_object_lock" runF(testName) @@ -2876,6 +2895,22 @@ func HeadObject_non_existing_object(s *S3Conf) error { }) } +func HeadObject_name_too_long(s *S3Conf) error { + testName := "HeadObject_name_too_long" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.HeadObject(ctx, &s3.HeadObjectInput{ + Bucket: &bucket, + Key: getPtr("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + }) + cancel() + if err := checkSdkApiErr(err, "BadRequest"); err != nil { + return err + } + return nil + }) +} + func HeadObject_invalid_part_number(s *S3Conf) error { testName := "HeadObject_invalid_part_number" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { @@ -4051,6 +4086,19 @@ func DeleteObject_non_existing_object(s *S3Conf) error { }) } +func DeleteObject_name_too_long(s *S3Conf) error { + testName := "DeleteObject_name_too_long" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.DeleteObject(ctx, &s3.DeleteObjectInput{ + Bucket: &bucket, + Key: getPtr("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + }) + cancel() + return err + }) +} + func DeleteObject_non_existing_dir_object(s *S3Conf) error { testName := "DeleteObject_non_existing_dir_object" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {