From ed44fe1969c7cc3b12551a7ce6dcdb51db02d87e Mon Sep 17 00:00:00 2001 From: niksis02 Date: Fri, 4 Apr 2025 23:17:22 +0400 Subject: [PATCH] fix: Handles the error cases for empty checksum headers for PutObject and UploadPart Fixes #1186 Fixes #1188 Fixes #1189 If multiple checksum headers are provided, no matter if they are empty or not, the gateway should return `(InvalidRequest): Expecting a single x-amz-checksum- header. Multiple checksum Types are not allowed.` An empty checksum header is considered as invalid, because it's not valid crc32, crc32c ... --- s3api/utils/utils.go | 18 ++++----- tests/integration/tests.go | 78 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/s3api/utils/utils.go b/s3api/utils/utils.go index 00f4a998..ddd8689a 100644 --- a/s3api/utils/utils.go +++ b/s3api/utils/utils.go @@ -488,24 +488,20 @@ func ParseChecksumHeaders(ctx *fiber.Ctx) (types.ChecksumAlgorithm, map[types.Ch return sdkAlgorithm, nil, hdrErr } - headerCtr := 0 + if len(checksums) > 1 { + return sdkAlgorithm, checksums, s3err.GetAPIError(s3err.ErrMultipleChecksumHeaders) + } + for al, val := range checksums { - if val != "" && !IsValidChecksum(val, al) { + if !IsValidChecksum(val, al) { return sdkAlgorithm, checksums, s3err.GetInvalidChecksumHeaderErr(fmt.Sprintf("x-amz-checksum-%v", strings.ToLower(string(al)))) } // If any other checksum value is provided, // rather than x-amz-sdk-checksum-algorithm - if sdkAlgorithm != "" && sdkAlgorithm != al && val != "" { - return sdkAlgorithm, checksums, s3err.GetAPIError(s3err.ErrMultipleChecksumHeaders) - } - if val != "" { - sdkAlgorithm = al - headerCtr++ - } - - if headerCtr > 1 { + if sdkAlgorithm != "" && sdkAlgorithm != al { return sdkAlgorithm, checksums, s3err.GetAPIError(s3err.ErrMultipleChecksumHeaders) } + sdkAlgorithm = al } return sdkAlgorithm, checksums, nil diff --git a/tests/integration/tests.go b/tests/integration/tests.go index ef79d28c..135f27da 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -2981,14 +2981,29 @@ func PutObject_multiple_checksum_headers(s *S3Conf) error { return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { obj := "my-obj" - ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) - _, err := s3client.PutObject(ctx, &s3.PutObjectInput{ + _, err := putObjectWithData(10, &s3.PutObjectInput{ Bucket: &bucket, Key: &obj, ChecksumSHA1: getPtr("Kq5sNclPz7QV2+lfQIuc6R7oRu0="), ChecksumCRC32C: getPtr("m0cB1Q=="), - }) - cancel() + }, s3client) + // FIXME: The error message for PutObject is not properly serialized by the sdk + // References to aws sdk issue https://github.com/aws/aws-sdk-go-v2/issues/2921 + + // if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrMultipleChecksumHeaders)); err != nil { + // return err + // } + if err := checkSdkApiErr(err, "InvalidRequest"); err != nil { + return err + } + + // Empty checksums case + _, err = putObjectWithData(10, &s3.PutObjectInput{ + Bucket: &bucket, + Key: &obj, + ChecksumSHA1: getPtr(""), + ChecksumCRC32C: getPtr(""), + }, s3client) // FIXME: The error message for PutObject is not properly serialized by the sdk // References to aws sdk issue https://github.com/aws/aws-sdk-go-v2/issues/2921 @@ -3017,6 +3032,10 @@ func PutObject_invalid_checksum_header(s *S3Conf) error { crc64nvme *string }{ // CRC32 tests + { + algo: "crc32", + crc32: getPtr(""), + }, { algo: "crc32", crc32: getPtr("invalid_base64!"), // invalid base64 @@ -3026,6 +3045,10 @@ func PutObject_invalid_checksum_header(s *S3Conf) error { crc32: getPtr("YXNrZGpoZ2tqYXNo"), // valid base64 but not crc32 }, // CRC32C tests + { + algo: "crc32c", + crc32c: getPtr(""), + }, { algo: "crc32c", crc32c: getPtr("invalid_base64!"), // invalid base64 @@ -3035,6 +3058,10 @@ func PutObject_invalid_checksum_header(s *S3Conf) error { crc32c: getPtr("c2RhZnNhZGZzZGFm"), // valid base64 but not crc32c }, // SHA1 tests + { + algo: "sha1", + sha1: getPtr(""), + }, { algo: "sha1", sha1: getPtr("invalid_base64!"), // invalid base64 @@ -3044,6 +3071,10 @@ func PutObject_invalid_checksum_header(s *S3Conf) error { sha1: getPtr("c2RhZmRhc2Zkc2Fmc2RhZnNhZGZzYWRm"), // valid base64 but not sha1 }, // SHA256 tests + { + algo: "sha256", + sha256: getPtr(""), + }, { algo: "sha256", sha256: getPtr("invalid_base64!"), // invalid base64 @@ -3053,6 +3084,10 @@ func PutObject_invalid_checksum_header(s *S3Conf) error { sha256: getPtr("ZGZnbmRmZ2hoZmRoZmdkaA=="), // valid base64 but not sha56 }, // CRC64Nvme tests + { + algo: "crc64nvme", + sha256: getPtr(""), + }, { algo: "crc64nvme", sha256: getPtr("invalid_base64!"), // invalid base64 @@ -7667,6 +7702,21 @@ func UploadPart_multiple_checksum_headers(s *S3Conf) error { return err } + // multiple empty checksums + ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) + _, err = s3client.UploadPart(ctx, &s3.UploadPartInput{ + Bucket: &bucket, + Key: &obj, + ChecksumSHA1: getPtr(""), + ChecksumCRC32C: getPtr(""), + UploadId: mp.UploadId, + PartNumber: &partNumber, + }) + cancel() + if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrMultipleChecksumHeaders)); err != nil { + return err + } + return nil }) } @@ -7692,6 +7742,10 @@ func UploadPart_invalid_checksum_header(s *S3Conf) error { crc64nvme *string }{ // CRC32 tests + { + algo: "crc32", + crc32: getPtr(""), + }, { algo: "crc32", crc32: getPtr("invalid_base64!"), // invalid base64 @@ -7701,6 +7755,10 @@ func UploadPart_invalid_checksum_header(s *S3Conf) error { crc32: getPtr("YXNrZGpoZ2tqYXNo"), // valid base64 but not crc32 }, // CRC32C tests + { + algo: "crc32c", + crc32c: getPtr(""), + }, { algo: "crc32c", crc32c: getPtr("invalid_base64!"), // invalid base64 @@ -7710,6 +7768,10 @@ func UploadPart_invalid_checksum_header(s *S3Conf) error { crc32c: getPtr("c2RhZnNhZGZzZGFm"), // valid base64 but not crc32c }, // SHA1 tests + { + algo: "sha1", + sha1: getPtr(""), + }, { algo: "sha1", sha1: getPtr("invalid_base64!"), // invalid base64 @@ -7719,6 +7781,10 @@ func UploadPart_invalid_checksum_header(s *S3Conf) error { sha1: getPtr("c2RhZmRhc2Zkc2Fmc2RhZnNhZGZzYWRm"), // valid base64 but not sha1 }, // SHA256 tests + { + algo: "sha256", + sha256: getPtr(""), + }, { algo: "sha256", sha256: getPtr("invalid_base64!"), // invalid base64 @@ -7728,6 +7794,10 @@ func UploadPart_invalid_checksum_header(s *S3Conf) error { sha256: getPtr("ZGZnbmRmZ2hoZmRoZmdkaA=="), // valid base64 but not sha56 }, // CRC64NVME tests + { + algo: "crc64nvme", + crc64nvme: getPtr(""), + }, { algo: "crc64nvme", crc64nvme: getPtr("invalid_base64!"), // invalid base64