fix: makes checksum type and algorithm case insensitive in CreateMultipartUpload

Fixes #1339

`x-amz-checksum-type` and `x-amz-checksum-algorithm` request headers should be case insensitive in `CreateMultipartUpload`.

The changes include parsing the header values to upper case before validating and passing to back-end. `x-amz-checksum-type` response header was added in`CreateMultipartUpload`, which was missing before.
This commit is contained in:
niksis02
2025-07-25 20:35:26 +04:00
parent 35fc8c214a
commit 3363988206
6 changed files with 54 additions and 21 deletions
+2 -1
View File
@@ -217,6 +217,7 @@ func (c S3ApiController) CreateMultipartUpload(ctx *fiber.Ctx) (*Response, error
if err == nil {
headers = map[string]*string{
"x-amz-checksum-algorithm": utils.ConvertToStringPtr(checksumAlgorithm),
"x-amz-checksum-type": utils.ConvertToStringPtr(checksumType),
}
}
return &Response{
@@ -233,7 +234,7 @@ func (c S3ApiController) CompleteMultipartUpload(ctx *fiber.Ctx) (*Response, err
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
uploadId := ctx.Query("uploadId")
mpuObjSizeHdr := ctx.Get("X-Amz-Mp-Object-Size")
checksumType := types.ChecksumType(ctx.Get("x-amz-checksum-type"))
checksumType := types.ChecksumType(strings.ToUpper(ctx.Get("x-amz-checksum-type")))
// context locals
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
+2
View File
@@ -293,6 +293,7 @@ func TestS3ApiController_CreateMultipartUpload(t *testing.T) {
beRes: s3response.InitiateMultipartUploadResult{},
headers: map[string]string{
"x-amz-checksum-algorithm": string(types.ChecksumAlgorithmCrc32),
"x-amz-checksum-type": string(types.ChecksumTypeComposite),
},
},
output: testOutput{
@@ -300,6 +301,7 @@ func TestS3ApiController_CreateMultipartUpload(t *testing.T) {
Data: s3response.InitiateMultipartUploadResult{},
Headers: map[string]*string{
"x-amz-checksum-algorithm": utils.ConvertToStringPtr(types.ChecksumAlgorithmCrc32),
"x-amz-checksum-type": utils.ConvertToStringPtr(types.ChecksumTypeComposite),
},
MetaOpts: &MetaOptions{
BucketOwner: "root",
+2 -2
View File
@@ -569,12 +569,12 @@ func checkChecksumTypeAndAlgo(algo types.ChecksumAlgorithm, t types.ChecksumType
// Parses and validates the x-amz-checksum-algorithm and x-amz-checksum-type headers
func ParseCreateMpChecksumHeaders(ctx *fiber.Ctx) (types.ChecksumAlgorithm, types.ChecksumType, error) {
algo := types.ChecksumAlgorithm(ctx.Get("x-amz-checksum-algorithm"))
algo := types.ChecksumAlgorithm(strings.ToUpper(ctx.Get("x-amz-checksum-algorithm")))
if err := IsChecksumAlgorithmValid(algo); err != nil {
return "", "", err
}
chType := types.ChecksumType(ctx.Get("x-amz-checksum-type"))
chType := types.ChecksumType(strings.ToUpper(ctx.Get("x-amz-checksum-type")))
if err := IsChecksumTypeValid(chType); err != nil {
return "", "", err
}
+3 -3
View File
@@ -334,7 +334,7 @@ func TestCreateMultipartUpload(s *S3Conf) {
CreateMultipartUpload_invalid_checksum_algorithm(s)
CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type(s)
CreateMultipartUpload_invalid_checksum_type(s)
CreateMultipartUpload_valid_checksum_algorithm(s)
CreateMultipartUpload_valid_algo_type(s)
}
CreateMultipartUpload_success(s)
}
@@ -723,7 +723,7 @@ func TestScoutfs(s *S3Conf) {
CreateMultipartUpload_invalid_checksum_algorithm(s)
CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type(s)
CreateMultipartUpload_invalid_checksum_type(s)
CreateMultipartUpload_valid_checksum_algorithm(s)
CreateMultipartUpload_valid_algo_type(s)
CreateMultipartUpload_success(s)
CompletedMultipartUpload_non_existing_bucket(s)
@@ -1104,7 +1104,7 @@ func GetIntTests() IntTests {
"CreateMultipartUpload_invalid_checksum_algorithm": CreateMultipartUpload_invalid_checksum_algorithm,
"CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type": CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type,
"CreateMultipartUpload_invalid_checksum_type": CreateMultipartUpload_invalid_checksum_type,
"CreateMultipartUpload_valid_checksum_algorithm": CreateMultipartUpload_valid_checksum_algorithm,
"CreateMultipartUpload_valid_algo_type": CreateMultipartUpload_valid_algo_type,
"CreateMultipartUpload_success": CreateMultipartUpload_success,
"UploadPart_non_existing_bucket": UploadPart_non_existing_bucket,
"UploadPart_invalid_part_number": UploadPart_invalid_part_number,
+29 -15
View File
@@ -8043,23 +8043,37 @@ func CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type(s *S3Conf
})
}
func CreateMultipartUpload_valid_checksum_algorithm(s *S3Conf) error {
testName := "CreateMultipartUpload_valid_checksum_algorithm"
func CreateMultipartUpload_valid_algo_type(s *S3Conf) error {
testName := "CreateMultipartUpload_valid_algo_type"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.CreateMultipartUpload(ctx, &s3.CreateMultipartUploadInput{
Bucket: &bucket,
Key: getPtr("my-obj"),
ChecksumAlgorithm: types.ChecksumAlgorithmCrc32c,
})
cancel()
if err != nil {
return err
}
obj := "my-obj"
for _, test := range []struct {
chType types.ChecksumType
chAlgo types.ChecksumAlgorithm
}{
// composite type
{types.ChecksumTypeComposite, types.ChecksumAlgorithmCrc32},
{types.ChecksumTypeComposite, types.ChecksumAlgorithmCrc32c},
{types.ChecksumTypeComposite, types.ChecksumAlgorithmSha1},
{types.ChecksumTypeComposite, types.ChecksumAlgorithmSha256},
// full object type
{types.ChecksumTypeFullObject, types.ChecksumAlgorithmCrc64nvme},
{types.ChecksumTypeFullObject, types.ChecksumAlgorithmCrc32},
{types.ChecksumTypeFullObject, types.ChecksumAlgorithmCrc32c},
} {
randChType := types.ChecksumType(randomizeCase(string(test.chType)))
randChAlgo := types.ChecksumAlgorithm(randomizeCase(string(test.chAlgo)))
out, err := createMp(s3client, bucket, obj, withChecksum(randChAlgo), withChecksumType(randChType))
if err != nil {
return err
}
if res.ChecksumAlgorithm != types.ChecksumAlgorithmCrc32c {
return fmt.Errorf("expected the checksum algorithm to be %v, instead got %v",
types.ChecksumAlgorithmCrc32c, res.ChecksumAlgorithm)
if out.ChecksumAlgorithm != test.chAlgo {
return fmt.Errorf("expected the checksum algorithm to be %v, instead got %v", test.chAlgo, out.ChecksumAlgorithm)
}
if out.ChecksumType != test.chType {
return fmt.Errorf("expected the checksum type to be %v, instead got %v", test.chType, out.ChecksumType)
}
}
return nil
+16
View File
@@ -39,6 +39,7 @@ import (
"sort"
"strings"
"time"
"unicode"
"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
@@ -1436,3 +1437,18 @@ type PublicBucketTestCase struct {
Call func(ctx context.Context) error
ExpectedErr error
}
// randomizeCase randomizes the provided string latters case
func randomizeCase(s string) string {
var b strings.Builder
for _, ch := range s {
if rnd.Intn(2) == 0 {
b.WriteRune(unicode.ToLower(ch))
} else {
b.WriteRune(unicode.ToUpper(ch))
}
}
return b.String()
}