Repository: minio/minio-go
Pull request #2017 (2024-11-12 03:55:37)

feat: CopyObject md demo update


Patch:
diff --git a/.github/workflows/go-windows.yml b/.github/workflows/go-windows.yml
index dec2dd1..ae6e899 100644
--- a/.github/workflows/go-windows.yml
+++ b/.github/workflows/go-windows.yml
@@ -38,6 +38,7 @@ jobs:
           ENABLE_HTTPS: 1
           MINIO_KMS_MASTER_KEY: my-minio-key:6368616e676520746869732070617373776f726420746f206120736563726574
           MINIO_CI_CD: true
+          MINT_NO_FULL_OBJECT: true
         run: |
           New-Item -ItemType Directory -Path "$env:temp/certs-dir"
           Copy-Item -Path testcerts\* -Destination "$env:temp/certs-dir"
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 22eaad4..eb73d14 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -39,6 +39,7 @@ jobs:
           MINIO_KMS_MASTER_KEY: my-minio-key:6368616e676520746869732070617373776f726420746f206120736563726574
           SSL_CERT_FILE: /tmp/certs-dir/public.crt
           MINIO_CI_CD: true
+          MINT_NO_FULL_OBJECT: true
         run: |
           sudo apt update -y
           sudo apt install devscripts -y
diff --git a/api-datatypes.go b/api-datatypes.go
index 97a6f80..8a8fd88 100644
--- a/api-datatypes.go
+++ b/api-datatypes.go
@@ -143,10 +143,11 @@ type UploadInfo struct {
 	// Verified checksum values, if any.
 	// Values are base64 (standard) encoded.
 	// For multipart objects this is a checksum of the checksum of each part.
-	ChecksumCRC32  string
-	ChecksumCRC32C string
-	ChecksumSHA1   string
-	ChecksumSHA256 string
+	ChecksumCRC32     string
+	ChecksumCRC32C    string
+	ChecksumSHA1      string
+	ChecksumSHA256    string
+	ChecksumCRC64NVME string
 }
 
 // RestoreInfo contains information of the restore operation of an archived object
@@ -215,10 +216,11 @@ type ObjectInfo struct {
 	Restore *RestoreInfo
 
 	// Checksum values
-	ChecksumCRC32  string
-	ChecksumCRC32C string
-	ChecksumSHA1   string
-	ChecksumSHA256 string
+	ChecksumCRC32     string
+	ChecksumCRC32C    string
+	ChecksumSHA1      string
+	ChecksumSHA256    string
+	ChecksumCRC64NVME string
 
 	Internal *struct {
 		K int // Data blocks
diff --git a/api-get-object.go b/api-get-object.go
index d7fd278..5cc85f6 100644
--- a/api-get-object.go
+++ b/api-get-object.go
@@ -318,7 +318,7 @@ func (o *Object) doGetRequest(request getRequest) (getResponse, error) {
 	response := <-o.resCh
 
 	// Return any error to the top level.
-	if response.Error != nil {
+	if response.Error != nil && response.Error != io.EOF {
 		return response, response.Error
 	}
 
@@ -340,7 +340,7 @@ func (o *Object) doGetRequest(request getRequest) (getResponse, error) {
 	// Data are ready on the wire, no need to reinitiate connection in lower level
 	o.seekData = false
 
-	return response, nil
+	return response, response.Error
 }
 
 // setOffset - handles the setting of offsets for
diff --git a/api-presigned.go b/api-presigned.go
index 9e85f81..2964220 100644
--- a/api-presigned.go
+++ b/api-presigned.go
@@ -140,7 +140,7 @@ func (c *Client) PresignedPostPolicy(ctx context.Context, p *PostPolicy) (u *url
 	}
 
 	// Get credentials from the configured credentials provider.
-	credValues, err := c.credsProvider.Get()
+	credValues, err := c.credsProvider.GetWithContext(c.CredContext())
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/api-put-object-multipart.go b/api-put-object-multipart.go
index a70cbea..03bd34f 100644
--- a/api-put-object-multipart.go
+++ b/api-put-object-multipart.go
@@ -83,10 +83,7 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj
 	// HTTPS connection.
 	hashAlgos, hashSums := c.hashMaterials(opts.SendContentMd5, !opts.DisableContentSha256)
 	if len(hashSums) == 0 {
-		if opts.UserMetadata == nil {
-			opts.UserMetadata = make(map[string]string, 1)
-		}
-		opts.UserMetadata["X-Amz-Checksum-Algorithm"] = opts.AutoChecksum.String()
+		addAutoChecksumHeaders(&opts)
 	}
 
 	// Initiate a new multipart upload.
@@ -113,7 +110,6 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj
 
 	// Create checksums
 	// CRC32C is ~50% faster on AMD64 @ 30GB/s
-	var crcBytes []byte
 	customHeader := make(http.Header)
 	crc := opts.AutoChecksum.Hasher()
 	for partNumber <= totalPartsCount {
@@ -154,7 +150,6 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj
 			crc.Write(buf[:length])
 			cSum := crc.Sum(nil)
 			customHeader.Set(opts.AutoChecksum.Key(), base64.StdEncoding.EncodeToString(cSum))
-			crcBytes = append(crcBytes, cSum...)
 		}
 
 		p := uploadPartParams{bucketName: bucketName, objectName: objectName, uploadID: uploadID, reader: rd, partNumber: partNumber, md5Base64: md5Base64, sha256Hex: sha256Hex, size: int64(length), sse: opts.ServerSideEncryption, streamSha256: !opts.DisableContentSha256, customHeader: customHeader}
@@ -182,18 +177,21 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj
 
 	// Loop over total uploaded parts to save them in
 	// Parts array before completing the multipart request.
+	allParts := make([]ObjectPart, 0, len(partsInfo))
 	for i := 1; i < partNumber; i++ {
 		part, ok := partsInfo[i]
 		if !ok {
 			return UploadInfo{}, errInvalidArgument(fmt.Sprintf("Missing part number %d", i))
 		}
+		allParts = append(allParts, part)
 		complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{
-			ETag:           part.ETag,
-			PartNumber:     part.PartNumber,
-			ChecksumCRC32:  part.ChecksumCRC32,
-			ChecksumCRC32C: part.ChecksumCRC32C,
-			ChecksumSHA1:   part.ChecksumSHA1,
-			ChecksumSHA256: part.ChecksumSHA256,
+			ETag:              part.ETag,
+			PartNumber:        part.PartNumber,
+			ChecksumCRC32:     part.ChecksumCRC32,
+			ChecksumCRC32C:    part.ChecksumCRC32C,
+			ChecksumSHA1:      part.ChecksumSHA1,
+			ChecksumSHA256:    part.ChecksumSHA256,
+			ChecksumCRC64NVME: part.ChecksumCRC64NVME,
 		})
 	}
 
@@ -203,12 +201,8 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj
 		ServerSideEncryption: opts.ServerSideEncryption,
 		AutoChecksum:         opts.AutoChecksum,
 	}
-	if len(crcBytes) > 0 {
-		// Add hash of hashes.
-		crc.Reset()
-		crc.Write(crcBytes)
-		opts.UserMetadata = map[string]string{opts.AutoChecksum.Key(): base64.StdEncoding.EncodeToString(crc.Sum(nil))}
-	}
+	applyAutoChecksum(&opts, allParts)
+
 	uploadInfo, err := c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload, opts)
 	if err != nil {
 		return UploadInfo{}, err
@@ -354,10 +348,11 @@ func (c *Client) uploadPart(ctx context.Context, p uploadPartParams) (ObjectPart
 	// Once successfully uploaded, return completed part.
 	h := resp.Header
 	objPart := ObjectPart{
-		ChecksumCRC32:  h.Get("x-amz-checksum-crc32"),
-		ChecksumCRC32C: h.Get("x-amz-checksum-crc32c"),
-		ChecksumSHA1:   h.Get("x-amz-checksum-sha1"),
-		ChecksumSHA256: h.Get("x-amz-checksum-sha256"),
+		ChecksumCRC32:     h.Get(ChecksumCRC32.Key()),
+		ChecksumCRC32C:    h.Get(ChecksumCRC32C.Key()),
+		ChecksumSHA1:      h.Get(ChecksumSHA1.Key()),
+		ChecksumSHA256:    h.Get(ChecksumSHA256.Key()),
+		ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
 	}
 	objPart.Size = p.size
 	objPart.PartNumber = p.partNumber
@@ -457,9 +452,10 @@ func (c *Client) completeMultipartUpload(ctx context.Context, bucketName, object
 		Expiration:       expTime,
 		ExpirationRuleID: ruleID,
 
-		ChecksumSHA256: completeMultipartUploadResult.ChecksumSHA256,
-		ChecksumSHA1:   completeMultipartUploadResult.ChecksumSHA1,
-		ChecksumCRC32:  completeMultipartUploadResult.ChecksumCRC32,
-		ChecksumCRC32C: completeMultipartUploadResult.ChecksumCRC32C,
+		ChecksumSHA256:    completeMultipartUploadResult.ChecksumSHA256,
+		ChecksumSHA1:      completeMultipartUploadResult.ChecksumSHA1,
+		ChecksumCRC32:     completeMultipartUploadResult.ChecksumCRC32,
+		ChecksumCRC32C:    completeMultipartUploadResult.ChecksumCRC32C,
+		ChecksumCRC64NVME: completeMultipartUploadResult.ChecksumCRC64NVME,
 	}, nil
 }
diff --git a/api-put-object-streaming.go b/api-put-object-streaming.go
index dac4c0e..3ff3b69 100644
--- a/api-put-object-streaming.go
+++ b/api-put-object-streaming.go
@@ -113,10 +113,7 @@ func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketN
 	}
 	withChecksum := c.trailingHeaderSupport
 	if withChecksum {
-		if opts.UserMetadata == nil {
-			opts.UserMetadata = make(map[string]string, 1)
-		}
-		opts.UserMetadata["X-Amz-Checksum-Algorithm"] = opts.AutoChecksum.String()
+		addAutoChecksumHeaders(&opts)
 	}
 	// Initiate a new multipart upload.
 	uploadID, err := c.newUploadID(ctx, bucketName, objectName, opts)
@@ -240,6 +237,7 @@ func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketN
 
 	// Gather the responses as they occur and update any
 	// progress bar.
+	allParts := make([]ObjectPart, 0, totalPartsCount)
 	for u := 1; u <= totalPartsCount; u++ {
 		select {
 		case <-ctx.Done():
@@ -248,16 +246,17 @@ func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketN
 			if uploadRes.Error != nil {
 				return UploadInfo{}, uploadRes.Error
 			}
-
+			allParts = append(allParts, uploadRes.Part)
 			// Update the totalUploadedSize.
 			totalUploadedSize += uploadRes.Size
 			complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{
-				ETag:           uploadRes.Part.ETag,
-				PartNumber:     uploadRes.Part.PartNumber,
-				ChecksumCRC32:  uploadRes.Part.ChecksumCRC32,
-				ChecksumCRC32C: uploadRes.Part.ChecksumCRC32C,
-				ChecksumSHA1:   uploadRes.Part.ChecksumSHA1,
-				ChecksumSHA256: uploadRes.Part.ChecksumSHA256,
+				ETag:              uploadRes.Part.ETag,
+				PartNumber:        uploadRes.Part.PartNumber,
+				ChecksumCRC32:     uploadRes.Part.ChecksumCRC32,
+				ChecksumCRC32C:    uploadRes.Part.ChecksumCRC32C,
+				ChecksumSHA1:      uploadRes.Part.ChecksumSHA1,
+				ChecksumSHA256:    uploadRes.Part.ChecksumSHA256,
+				ChecksumCRC64NVME: uploadRes.Part.ChecksumCRC64NVME,
 			})
 		}
 	}
@@ -275,15 +274,7 @@ func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketN
 		AutoChecksum:         opts.AutoChecksum,
 	}
 	if withChecksum {
-		// Add hash of hashes.
-		crc := opts.AutoChecksum.Hasher()
-		for _, part := range complMultipartUpload.Parts {
-			cs, err := base64.StdEncoding.DecodeString(part.Checksum(opts.AutoChecksum))
-			if err == nil {
-				crc.Write(cs)
-			}
-		}
-		opts.UserMetadata = map[string]string{opts.AutoChecksum.KeyCapitalized(): base64.StdEncoding.EncodeToString(crc.Sum(nil))}
+		applyAutoChecksum(&opts, allParts)
 	}
 
 	uploadInfo, err := c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload, opts)
@@ -312,10 +303,7 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b
 	}
 
 	if !opts.SendContentMd5 {
-		if opts.UserMetadata == nil {
-			opts.UserMetadata = make(map[string]string, 1)
-		}
-		opts.UserMetadata["X-Amz-Checksum-Algorithm"] = opts.AutoChecksum.String()
+		addAutoChecksumHeaders(&opts)
 	}
 
 	// Calculate the optimal parts info for a given size.
@@ -342,7 +330,6 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b
 
 	// Create checksums
 	// CRC32C is ~50% faster on AMD64 @ 30GB/s
-	var crcBytes []byte
 	customHeader := make(http.Header)
 	crc := opts.AutoChecksum.Hasher()
 	md5Hash := c.md5Hasher()
@@ -389,7 +376,6 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b
 			crc.Write(buf[:length])
 			cSum := crc.Sum(nil)
 			customHeader.Set(opts.AutoChecksum.KeyCapitalized(), base64.StdEncoding.EncodeToString(cSum))
-			crcBytes = append(crcBytes, cSum...)
 		}
 
 		// Update progress reader appropriately to the latest offset
@@ -420,18 +406,21 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b
 
 	// Loop over total uploaded parts to save them in
 	// Parts array before completing the multipart request.
+	allParts := make([]ObjectPart, 0, len(partsInfo))
 	for i := 1; i < partNumber; i++ {
 		part, ok := partsInfo[i]
 		if !ok {
 			return UploadInfo{}, errInvalidArgument(fmt.Sprintf("Missing part number %d", i))
 		}
+		allParts = append(allParts, part)
 		complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{
-			ETag:           part.ETag,
-			PartNumber:     part.PartNumber,
-			ChecksumCRC32:  part.ChecksumCRC32,
-			ChecksumCRC32C: part.ChecksumCRC32C,
-			ChecksumSHA1:   part.ChecksumSHA1,
-			ChecksumSHA256: part.ChecksumSHA256,
+			ETag:              part.ETag,
+			PartNumber:        part.PartNumber,
+			ChecksumCRC32:     part.ChecksumCRC32,
+			ChecksumCRC32C:    part.ChecksumCRC32C,
+			ChecksumSHA1:      part.ChecksumSHA1,
+			ChecksumSHA256:    part.ChecksumSHA256,
+			ChecksumCRC64NVME: part.ChecksumCRC64NVME,
 		})
 	}
 
@@ -442,12 +431,7 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b
 		ServerSideEncryption: opts.ServerSideEncryption,
 		AutoChecksum:         opts.AutoChecksum,
 	}
-	if len(crcBytes) > 0 {
-		// Add hash of hashes.
-		crc.Reset()
-		crc.Write(crcBytes)
-		opts.UserMetadata = map[string]string{opts.AutoChecksum.KeyCapitalized(): base64.StdEncoding.EncodeToString(crc.Sum(nil))}
-	}
+	applyAutoChecksum(&opts, allParts)
 	uploadInfo, err := c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload, opts)
 	if err != nil {
 		return UploadInfo{}, err
@@ -475,10 +459,7 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam
 		opts.AutoChecksum = opts.Checksum
 	}
 	if !opts.SendContentMd5 {
-		if opts.UserMetadata == nil {
-			opts.UserMetadata = make(map[string]string, 1)
-		}
-		opts.UserMetadata["X-Amz-Checksum-Algorithm"] = opts.AutoChecksum.String()
+		addAutoChecksumHeaders(&opts)
 	}
 
 	// Cancel all when an error occurs.
@@ -510,7 +491,6 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam
 
 	// Create checksums
 	// CRC32C is ~50% faster on AMD64 @ 30GB/s
-	var crcBytes []byte
 	crc := opts.AutoChecksum.Hasher()
 
 	// Total data read and written to server. should be equal to 'size' at the end of the call.
@@ -570,7 +550,6 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam
 			crc.Write(buf[:length])
 			cSum := crc.Sum(nil)
 			customHeader.Set(opts.AutoChecksum.Key(), base64.StdEncoding.EncodeToString(cSum))
-			crcBytes = append(crcBytes, cSum...)
 		}
 
 		wg.Add(1)
@@ -630,18 +609,21 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam
 
 	// Loop over total uploaded parts to save them in
 	// Parts array before completing the multipart request.
+	allParts := make([]ObjectPart, 0, len(partsInfo))
 	for i := 1; i < partNumber; i++ {
 		part, ok := partsInfo[i]
 		if !ok {
 			return UploadInfo{}, errInvalidArgument(fmt.Sprintf("Missing part number %d", i))
 		}
+		allParts = append(allParts, part)
 		complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{
-			ETag:           part.ETag,
-			PartNumber:     part.PartNumber,
-			ChecksumCRC32:  part.ChecksumCRC32,
-			ChecksumCRC32C: part.ChecksumCRC32C,
-			ChecksumSHA1:   part.ChecksumSHA1,
-			ChecksumSHA256: part.ChecksumSHA256,
+			ETag:              part.ETag,
+			PartNumber:        part.PartNumber,
+			ChecksumCRC32:     part.ChecksumCRC32,
+			ChecksumCRC32C:    part.ChecksumCRC32C,
+			ChecksumSHA1:      part.ChecksumSHA1,
+			ChecksumSHA256:    part.ChecksumSHA256,
+			ChecksumCRC64NVME: part.ChecksumCRC64NVME,
 		})
 	}
 
@@ -652,12 +634,8 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam
 		ServerSideEncryption: opts.ServerSideEncryption,
 		AutoChecksum:         opts.AutoChecksum,
 	}
-	if len(crcBytes) > 0 {
-		// Add hash of hashes.
-		crc.Reset()
-		crc.Write(crcBytes)
-		opts.UserMetadata = map[string]string{opts.AutoChecksum.KeyCapitalized(): base64.StdEncoding.EncodeToString(crc.Sum(nil))}
-	}
+	applyAutoChecksum(&opts, allParts)
+
 	uploadInfo, err := c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload, opts)
 	if err != nil {
 		return UploadInfo{}, err
@@ -823,9 +801,10 @@ func (c *Client) putObjectDo(ctx context.Context, bucketName, objectName string,
 		ExpirationRuleID: ruleID,
 
 		// Checksum values
-		ChecksumCRC32:  h.Get("x-amz-checksum-crc32"),
-		ChecksumCRC32C: h.Get("x-amz-checksum-crc32c"),
-		ChecksumSHA1:   h.Get("x-amz-checksum-sha1"),
-		ChecksumSHA256: h.Get("x-amz-checksum-sha256"),
+		ChecksumCRC32:     h.Get(ChecksumCRC32.Key()),
+		ChecksumCRC32C:    h.Get(ChecksumCRC32C.Key()),
+		ChecksumSHA1:      h.Get(ChecksumSHA1.Key()),
+		ChecksumSHA256:    h.Get(ChecksumSHA256.Key()),
+		ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
 	}, nil
 }
diff --git a/api-put-object.go b/api-put-object.go
index 10131a5..0981757 100644
--- a/api-put-object.go
+++ b/api-put-object.go
@@ -387,10 +387,7 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam
 		opts.AutoChecksum = opts.Checksum
 	}
 	if !opts.SendContentMd5 {
-		if opts.UserMetadata == nil {
-			opts.UserMetadata = make(map[string]string, 1)
-		}
-		opts.UserMetadata["X-Amz-Checksum-Algorithm"] = opts.AutoChecksum.String()
+		addAutoChecksumHeaders(&opts)
 	}
 
 	// Initiate a new multipart upload.
@@ -417,7 +414,6 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam
 
 	// Create checksums
 	// CRC32C is ~50% faster on AMD64 @ 30GB/s
-	var crcBytes []byte
 	customHeader := make(http.Header)
 	crc := opts.AutoChecksum.Hasher()
 
@@ -443,7 +439,6 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam
 			crc.Write(buf[:length])
 			cSum := crc.Sum(nil)
 			customHeader.Set(opts.AutoChecksum.Key(), base64.StdEncoding.EncodeToString(cSum))
-			crcBytes = append(crcBytes, cSum...)
 		}
 
 		// Update progress reader appropriately to the latest offset
@@ -475,18 +470,21 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam
 
 	// Loop over total uploaded parts to save them in
 	// Parts array before completing the multipart request.
+	allParts := make([]ObjectPart, 0, len(partsInfo))
 	for i := 1; i < partNumber; i++ {
 		part, ok := partsInfo[i]
 		if !ok {
 			return UploadInfo{}, errInvalidArgument(fmt.Sprintf("Missing part number %d", i))
 		}
+		allParts = append(allParts, part)
 		complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{
-			ETag:           part.ETag,
-			PartNumber:     part.PartNumber,
-			ChecksumCRC32:  part.ChecksumCRC32,
-			ChecksumCRC32C: part.ChecksumCRC32C,
-			ChecksumSHA1:   part.ChecksumSHA1,
-			ChecksumSHA256: part.ChecksumSHA256,
+			ETag:              part.ETag,
+			PartNumber:        part.PartNumber,
+			ChecksumCRC32:     part.ChecksumCRC32,
+			ChecksumCRC32C:    part.ChecksumCRC32C,
+			ChecksumSHA1:      part.ChecksumSHA1,
+			ChecksumSHA256:    part.ChecksumSHA256,
+			ChecksumCRC64NVME: part.ChecksumCRC64NVME,
 		})
 	}
 
@@ -497,12 +495,8 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam
 		ServerSideEncryption: opts.ServerSideEncryption,
 		AutoChecksum:         opts.AutoChecksum,
 	}
-	if len(crcBytes) > 0 {
-		// Add hash of hashes.
-		crc.Reset()
-		crc.Write(crcBytes)
-		opts.UserMetadata = map[string]string{opts.AutoChecksum.KeyCapitalized(): base64.StdEncoding.EncodeToString(crc.Sum(nil))}
-	}
+	applyAutoChecksum(&opts, allParts)
+
 	uploadInfo, err := c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload, opts)
 	if err != nil {
 		return UploadInfo{}, err
diff --git a/api-s3-datatypes.go b/api-s3-datatypes.go
index 790606c..5e015fb 100644
--- a/api-s3-datatypes.go
+++ b/api-s3-datatypes.go
@@ -18,6 +18,7 @@
 package minio
 
 import (
+	"encoding/base64"
 	"encoding/xml"
 	"errors"
 	"io"
@@ -276,10 +277,45 @@ type ObjectPart struct {
 	Size int64
 
 	// Checksum values of each part.
-	ChecksumCRC32  string
-	ChecksumCRC32C string
-	ChecksumSHA1   string
-	ChecksumSHA256 string
+	ChecksumCRC32     string
+	ChecksumCRC32C    string
+	ChecksumSHA1      string
+	ChecksumSHA256    string
+	ChecksumCRC64NVME string
+}
+
+// Checksum will return the checksum for the given type.
+// Will return the empty string if not set.
+func (c ObjectPart) Checksum(t ChecksumType) string {
+	switch {
+	case t.Is(ChecksumCRC32C):
+		return c.ChecksumCRC32C
+	case t.Is(ChecksumCRC32):
+		return c.ChecksumCRC32
+	case t.Is(ChecksumSHA1):
+		return c.ChecksumSHA1
+	case t.Is(ChecksumSHA256):
+		return c.ChecksumSHA256
+	case t.Is(ChecksumCRC64NVME):
+		return c.ChecksumCRC64NVME
+	}
+	return ""
+}
+
+// ChecksumRaw returns the decoded checksum from the part.
+func (c ObjectPart) ChecksumRaw(t ChecksumType) ([]byte, error) {
+	b64 := c.Checksum(t)
+	if b64 == "" {
+		return nil, errors.New("no checksum set")
+	}
+	decoded, err := base64.StdEncoding.DecodeString(b64)
+	if err != nil {
+		return nil, err
+	}
+	if len(decoded) != t.RawByteLen() {
+		return nil, errors.New("checksum length mismatch")
+	}
+	return decoded, nil
 }
 
 // ListObjectPartsResult container for ListObjectParts response.
@@ -296,6 +332,12 @@ type ListObjectPartsResult struct {
 	NextPartNumberMarker int
 	MaxParts             int
 
+	// ChecksumAlgorithm will be CRC32, CRC32C, etc.
+	ChecksumAlgorithm string
+
+	// ChecksumType is FULL_OBJECT or COMPOSITE (assume COMPOSITE when unset)
+	ChecksumType string
+
 	// Indicates whether the returned list of parts is truncated.
 	IsTruncated bool
 	ObjectParts []ObjectPart `xml:"Part"`
@@ -320,10 +362,11 @@ type completeMultipartUploadResult struct {
 	ETag     string
 
 	// Checksum values, hash of hashes of parts.
-	ChecksumCRC32  string
-	ChecksumCRC32C string
-	ChecksumSHA1   string
-	ChecksumSHA256 string
+	ChecksumCRC32     string
+	ChecksumCRC32C    string
+	ChecksumSHA1      string
+	ChecksumSHA256    string
+	ChecksumCRC64NVME string
 }
 
 // CompletePart sub container lists individual part numbers and their
@@ -334,10 +377,11 @@ type CompletePart struct {
 	ETag       string
 
 	// Checksum values
-	ChecksumCRC32  string `xml:"ChecksumCRC32,omitempty"`
-	ChecksumCRC32C string `xml:"ChecksumCRC32C,omitempty"`
-	ChecksumSHA1   string `xml:"ChecksumSHA1,omitempty"`
-	ChecksumSHA256 string `xml:"ChecksumSHA256,omitempty"`
+	ChecksumCRC32     string `xml:"ChecksumCRC32,omitempty"`
+	ChecksumCRC32C    string `xml:"ChecksumCRC32C,omitempty"`
+	ChecksumSHA1      string `xml:"ChecksumSHA1,omitempty"`
+	ChecksumSHA256    string `xml:"ChecksumSHA256,omitempty"`
+	ChecksumCRC64NVME string `xml:",omitempty"`
 }
 
 // Checksum will return the checksum for the given type.
@@ -352,6 +396,8 @@ func (c CompletePart) Checksum(t ChecksumType) string {
 		return c.ChecksumSHA1
 	case t.Is(ChecksumSHA256):
 		return c.ChecksumSHA256
+	case t.Is(ChecksumCRC64NVME):
+		return c.ChecksumCRC64NVME
 	}
 	return ""
 }
diff --git a/api.go b/api.go
index 83c003e..cc0ded2 100644
--- a/api.go
+++ b/api.go
@@ -133,7 +133,7 @@ type Options struct {
 // Global constants.
 const (
 	libraryName    = "minio-go"
-	libraryVersion = "v7.0.82"
+	libraryVersion = "v7.0.84"
 )
 
 // User Agent should always following the below style.
@@ -600,9 +600,9 @@ func (c *Client) executeMethod(ctx context.Context, method string, metadata requ
 		return nil, errors.New(c.endpointURL.String() + " is offline.")
 	}
 
-	var retryable bool          // Indicates if request can be retried.
-	var bodySeeker io.Seeker    // Extracted seeker from io.Reader.
-	var reqRetry = c.maxRetries // Indicates how many times we can retry the request
+	var retryable bool       // Indicates if request can be retried.
+	var bodySeeker io.Seeker // Extracted seeker from io.Reader.
+	reqRetry := c.maxRetries // Indicates how many times we can retry the request
 
 	if metadata.contentBody != nil {
 		// Check if body is seekable then it is retryable.
@@ -808,7 +808,7 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
 	}
 
 	// Get credentials from the configured credentials provider.
-	value, err := c.credsProvider.Get()
+	value, err := c.credsProvider.GetWithContext(c.CredContext())
 	if err != nil {
 		return nil, err
 	}
@@ -1018,3 +1018,15 @@ func (c *Client) isVirtualHostStyleRequest(url url.URL, bucketName string) bool
 	// path style requests
 	return s3utils.IsVirtualHostSupported(url, bucketName)
 }
+
+// CredContext returns the context for fetching credentials
+func (c *Client) CredContext() *credentials.CredContext {
+	httpClient := c.httpClient
+	if httpClient == nil {
+		httpClient = http.DefaultClient
+	}
+	return &credentials.CredContext{
+		Client:   httpClient,
+		Endpoint: c.endpointURL.String(),
+	}
+}
diff --git a/bucket-cache.go b/bucket-cache.go
index b1d3b38..4e4305a 100644
--- a/bucket-cache.go
+++ b/bucket-cache.go
@@ -212,7 +212,7 @@ func (c *Client) getBucketLocationRequest(ctx context.Context, bucketName string
 	c.setUserAgent(req)
 
 	// Get credentials from the configured credentials provider.
-	value, err := c.credsProvider.Get()
+	value, err := c.credsProvider.GetWithContext(c.CredContext())
 	if err != nil {
 		return nil, err
 	}
diff --git a/checksum.go b/checksum.go
index 7eb1bf2..8e4c27c 100644
--- a/checksum.go
+++ b/checksum.go
@@ -21,11 +21,15 @@ import (
 	"crypto/sha1"
 	"crypto/sha256"
 	"encoding/base64"
+	"encoding/binary"
+	"errors"
 	"hash"
 	"hash/crc32"
+	"hash/crc64"
 	"io"
 	"math/bits"
 	"net/http"
+	"sort"
 )
 
 // ChecksumType contains information about the checksum type.
@@ -41,23 +45,41 @@ const (
 	ChecksumCRC32
 	// ChecksumCRC32C indicates a CRC32 checksum with Castagnoli table.
 	ChecksumCRC32C
+	// ChecksumCRC64NVME indicates CRC64 with 0xad93d23594c93659 polynomial.
+	ChecksumCRC64NVME
 
 	// Keep after all valid checksums
 	checksumLast
 
+	// ChecksumFullObject is a modifier that can be used on CRC32 and CRC32C
+	// to indicate full object checksums.
+	ChecksumFullObject
+
 	// checksumMask is a mask for valid checksum types.
 	checksumMask = checksumLast - 1
 
 	// ChecksumNone indicates no checksum.
 	ChecksumNone ChecksumType = 0
 
-	amzChecksumAlgo   = "x-amz-checksum-algorithm"
-	amzChecksumCRC32  = "x-amz-checksum-crc32"
-	amzChecksumCRC32C = "x-amz-checksum-crc32c"
-	amzChecksumSHA1   = "x-amz-checksum-sha1"
-	amzChecksumSHA256 = "x-amz-checksum-sha256"
+	// ChecksumFullObjectCRC32 indicates full object CRC32
+	ChecksumFullObjectCRC32 = ChecksumCRC32 | ChecksumFullObject
+
+	// ChecksumFullObjectCRC32C indicates full object CRC32C
+	ChecksumFullObjectCRC32C = ChecksumCRC32C | ChecksumFullObject
+
+	amzChecksumAlgo      = "x-amz-checksum-algorithm"
+	amzChecksumCRC32     = "x-amz-checksum-crc32"
+	amzChecksumCRC32C    = "x-amz-checksum-crc32c"
+	amzChecksumSHA1      = "x-amz-checksum-sha1"
+	amzChecksumSHA256    = "x-amz-checksum-sha256"
+	amzChecksumCRC64NVME = "x-amz-checksum-crc64nvme"
 )
 
+// Base returns the base type, without modifiers.
+func (c ChecksumType) Base() ChecksumType {
+	return c & checksumMask
+}
+
 // Is returns if c is all of t.
 func (c ChecksumType) Is(t ChecksumType) bool {
 	return c&t == t
@@ -75,10 +97,39 @@ func (c ChecksumType) Key() string {
 		return amzChecksumSHA1
 	case ChecksumSHA256:
 		return amzChecksumSHA256
+	case ChecksumCRC64NVME:
+		return amzChecksumCRC64NVME
 	}
 	return ""
 }
 
+// CanComposite will return if the checksum type can be used for composite multipart upload on AWS.
+func (c ChecksumType) CanComposite() bool {
+	switch c & checksumMask {
+	case ChecksumSHA256, ChecksumSHA1, ChecksumCRC32, ChecksumCRC32C:
+		return true
+	}
+	return false
+}
+
+// CanMergeCRC will return if the checksum type can be used for multipart upload on AWS.
+func (c ChecksumType) CanMergeCRC() bool {
+	switch c & checksumMask {
+	case ChecksumCRC32, ChecksumCRC32C, ChecksumCRC64NVME:
+		return true
+	}
+	return false
+}
+
+// FullObjectRequested will return if the checksum type indicates full object checksum was requested.
+func (c ChecksumType) FullObjectRequested() bool {
+	switch c & (ChecksumFullObject | checksumMask) {
+	case ChecksumFullObjectCRC32C, ChecksumFullObjectCRC32, ChecksumCRC64NVME:
+		return true
+	}
+	return false
+}
+
 // KeyCapitalized returns the capitalized key as used in HTTP headers.
 func (c ChecksumType) KeyCapitalized() string {
 	return http.CanonicalHeaderKey(c.Key())
@@ -93,10 +144,17 @@ func (c ChecksumType) RawByteLen() int {
 		return sha1.Size
 	case ChecksumSHA256:
 		return sha256.Size
+	case ChecksumCRC64NVME:
+		return crc64.Size
 	}
 	return 0
 }
 
+const crc64NVMEPolynomial = 0xad93d23594c93659
+
+// crc64 uses reversed polynomials.
+var crc64Table = crc64.MakeTable(bits.Reverse64(crc64NVMEPolynomial))
+
 // Hasher returns a hasher corresponding to the checksum type.
 // Returns nil if no checksum.
 func (c ChecksumType) Hasher() hash.Hash {
@@ -109,13 +167,15 @@ func (c ChecksumType) Hasher() hash.Hash {
 		return sha1.New()
 	case ChecksumSHA256:
 		return sha256.New()
+	case ChecksumCRC64NVME:
+		return crc64.New(crc64Table)
 	}
 	return nil
 }
 
 // IsSet returns whether the type is valid and known.
 func (c ChecksumType) IsSet() bool {
-	return bits.OnesCount32(uint32(c)) == 1
+	return bits.OnesCount32(uint32(c&checksumMask)) == 1
 }
 
 // SetDefault will set the checksum if not already set.
@@ -125,6 +185,16 @@ func (c *ChecksumType) SetDefault(t ChecksumType) {
 	}
 }
 
+// EncodeToString the encoded hash value of the content provided in b.
+func (c ChecksumType) EncodeToString(b []byte) string {
+	if !c.IsSet() {
+		return ""
+	}
+	h := c.Hasher()
+	h.Write(b)
+	return base64.StdEncoding.EncodeToString(h.Sum(nil))
+}
+
 // String returns the type as a string.
 // CRC32, CRC32C, SHA1, and SHA256 for valid values.
 // Empty string for unset and "<invalid>" if not valid.
@@ -140,6 +210,8 @@ func (c ChecksumType) String() string {
 		return "SHA256"
 	case ChecksumNone:
 		return ""
+	case ChecksumCRC64NVME:
+		return "CRC64NVME"
 	}
 	return "<invalid>"
 }
@@ -221,3 +293,129 @@ func (c Checksum) Raw() []byte {
 	}
 	return c.r
 }
+
+// CompositeChecksum returns the composite checksum of all provided parts.
+func (c ChecksumType) CompositeChecksum(p []ObjectPart) (*Checksum, error) {
+	if !c.CanComposite() {
+		return nil, errors.New("cannot do composite checksum")
+	}
+	sort.Slice(p, func(i, j int) bool {
+		return p[i].PartNumber < p[j].PartNumber
+	})
+	c = c.Base()
+	crcBytes := make([]byte, 0, len(p)*c.RawByteLen())
+	for _, part := range p {
+		pCrc, err := part.ChecksumRaw(c)
+		if err != nil {
+			return nil, err
+		}
+		crcBytes = append(crcBytes, pCrc...)
+	}
+	h := c.Hasher()
+	h.Write(crcBytes)
+	return &Checksum{Type: c, r: h.Sum(nil)}, nil
+}
+
+// FullObjectChecksum will return the full object checksum from provided parts.
+func (c ChecksumType) FullObjectChecksum(p []ObjectPart) (*Checksum, error) {
+	if !c.CanMergeCRC() {
+		return nil, errors.New("cannot merge this checksum type")
+	}
+	c = c.Base()
+	sort.Slice(p, func(i, j int) bool {
+		return p[i].PartNumber < p[j].PartNumber
+	})
+
+	switch len(p) {
+	case 0:
+		return nil, errors.New("no parts given")
+	case 1:
+		check, err := p[0].ChecksumRaw(c)
+		if err != nil {
+			return nil, err
+		}
+		return &Checksum{
+			Type: c,
+			r:    check,
+		}, nil
+	}
+	var merged uint32
+	var merged64 uint64
+	first, err := p[0].ChecksumRaw(c)
+	if err != nil {
+		return nil, err
+	}
+	sz := p[0].Size
+	switch c {
+	case ChecksumCRC32, ChecksumCRC32C:
+		merged = binary.BigEndian.Uint32(first)
+	case ChecksumCRC64NVME:
+		merged64 = binary.BigEndian.Uint64(first)
+	}
+
+	poly32 := uint32(crc32.IEEE)
+	if c.Is(ChecksumCRC32C) {
+		poly32 = crc32.Castagnoli
+	}
+	for _, part := range p[1:] {
+		if part.Size == 0 {
+			continue
+		}
+		sz += part.Size
+		pCrc, err := part.ChecksumRaw(c)
+		if err != nil {
+			return nil, err
+		}
+		switch c {
+		case ChecksumCRC32, ChecksumCRC32C:
+			merged = crc32Combine(poly32, merged, binary.BigEndian.Uint32(pCrc), part.Size)
+		case ChecksumCRC64NVME:
+			merged64 = crc64Combine(bits.Reverse64(crc64NVMEPolynomial), merged64, binary.BigEndian.Uint64(pCrc), part.Size)
+		}
+	}
+	var tmp [8]byte
+	switch c {
+	case ChecksumCRC32, ChecksumCRC32C:
+		binary.BigEndian.PutUint32(tmp[:], merged)
+		return &Checksum{
+			Type: c,
+			r:    tmp[:4],
+		}, nil
+	case ChecksumCRC64NVME:
+		binary.BigEndian.PutUint64(tmp[:], merged64)
+		return &Checksum{
+			Type: c,
+			r:    tmp[:8],
+		}, nil
+	default:
+		return nil, errors.New("unknown checksum type")
+	}
+}
+
+func addAutoChecksumHeaders(opts *PutObjectOptions) {
+	if opts.UserMetadata == nil {
+		opts.UserMetadata = make(map[string]string, 1)
+	}
+	opts.UserMetadata["X-Amz-Checksum-Algorithm"] = opts.AutoChecksum.String()
+	if opts.AutoChecksum.FullObjectRequested() {
+		opts.UserMetadata["X-Amz-Checksum-Type"] = "FULL_OBJECT"
+	}
+}
+
+func applyAutoChecksum(opts *PutObjectOptions, allParts []ObjectPart) {
+	if !opts.AutoChecksum.IsSet() {
+		return
+	}
+	if opts.AutoChecksum.CanComposite() && !opts.AutoChecksum.Is(ChecksumFullObject) {
+		// Add composite hash of hashes.
+		crc, err := opts.AutoChecksum.CompositeChecksum(allParts)
+		if err == nil {
+			opts.UserMetadata = map[string]string{opts.AutoChecksum.Key(): crc.Encoded()}
+		}
+	} else if opts.AutoChecksum.CanMergeCRC() {
+		crc, err := opts.AutoChecksum.FullObjectChecksum(allParts)
+		if err == nil {
+			opts.UserMetadata = map[string]string{opts.AutoChecksum.KeyCapitalized(): crc.Encoded(), "X-Amz-Checksum-Type": "FULL_OBJECT"}
+		}
+	}
+}
diff --git a/docs/API.md b/docs/API.md
index 0e6fac7..b40fbd7 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -667,7 +667,7 @@ dstOpts := minio.CopyDestOptions{
 }
 
 // Copy object call
-uploadInfo, err := minioClient.CopyObject(context.Background(), dst, src)
+uploadInfo, err := minioClient.CopyObject(context.Background(), dstOpts, srcOpts)
 if err != nil {
     fmt.Println(err)
     return
@@ -703,7 +703,7 @@ dstOpts := minio.CopyDestOptions{
 }
 
 // Copy object call
-_, err = minioClient.CopyObject(context.Background(), dst, src)
+_, err = minioClient.CopyObject(context.Background(), dstOpts, srcOpts)
 if err != nil {
     fmt.Println(err)
     return
diff --git a/examples/minio/go.mod b/examples/minio/go.mod
index e73ba6d..7c41f56 100644
--- a/examples/minio/go.mod
+++ b/examples/minio/go.mod
@@ -11,17 +11,17 @@ require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/go-ini/ini v1.67.0 // indirect
-	github.com/goccy/go-json v0.10.3 // indirect
+	github.com/goccy/go-json v0.10.4 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/klauspost/compress v1.17.11 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.9 // indirect
 	github.com/minio/md5-simd v1.1.2 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/rs/xid v1.6.0 // indirect
-	golang.org/x/crypto v0.28.0 // indirect
-	golang.org/x/net v0.30.0 // indirect
-	golang.org/x/sys v0.26.0 // indirect
-	golang.org/x/text v0.19.0 // indirect
+	golang.org/x/crypto v0.31.0 // indirect
+	golang.org/x/net v0.33.0 // indirect
+	golang.org/x/sys v0.28.0 // indirect
+	golang.org/x/text v0.21.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
 
diff --git a/examples/minio/go.sum b/examples/minio/go.sum
index a15de3d..6a1b063 100644
--- a/examples/minio/go.sum
+++ b/examples/minio/go.sum
@@ -6,50 +6,36 @@ github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
 github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
 github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
+github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
-github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
 github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
 github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
 github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
+github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
 github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
 github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
 github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
 github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
-golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
-golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
-golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
-golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
-golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
-golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
 golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
 golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
-golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
-golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
-golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
-golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/examples/s3/go.mod b/examples/s3/go.mod
index e607735..52bc904 100644
--- a/examples/s3/go.mod
+++ b/examples/s3/go.mod
@@ -10,25 +10,25 @@ require github.com/minio/minio-go/v7 v7.0.73
 require (
 	github.com/cheggaaa/pb v1.0.29
 	github.com/minio/sio v0.3.0
-	golang.org/x/crypto v0.28.0
+	golang.org/x/crypto v0.31.0
 )
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/go-ini/ini v1.67.0 // indirect
-	github.com/goccy/go-json v0.10.3 // indirect
+	github.com/goccy/go-json v0.10.4 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/klauspost/compress v1.17.11 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.9 // indirect
 	github.com/mattn/go-runewidth v0.0.14 // indirect
 	github.com/minio/md5-simd v1.1.2 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/rivo/uniseg v0.4.4 // indirect
 	github.com/rs/xid v1.6.0 // indirect
-	golang.org/x/net v0.30.0 // indirect
-	golang.org/x/sys v0.26.0 // indirect
-	golang.org/x/text v0.19.0 // indirect
+	golang.org/x/net v0.33.0 // indirect
+	golang.org/x/sys v0.28.0 // indirect
+	golang.org/x/text v0.21.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
 
diff --git a/examples/s3/go.sum b/examples/s3/go.sum
index 9844b0c..762c893 100644
--- a/examples/s3/go.sum
+++ b/examples/s3/go.sum
@@ -10,15 +10,17 @@ github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
 github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
 github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
+github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
-github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
 github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
 github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
 github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
+github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
 github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -36,45 +38,29 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
 github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
 github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
 github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
-golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
-golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
-golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
-golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
-golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
-golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
 golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
 golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
-golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
-golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
-golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
-golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
-golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/go.mod b/go.mod
index 3737229..399fedb 100644
--- a/go.mod
+++ b/go.mod
@@ -5,18 +5,18 @@ go 1.22
 require (
 	github.com/dustin/go-humanize v1.0.1
 	github.com/go-ini/ini v1.67.0
-	github.com/goccy/go-json v0.10.3
+	github.com/goccy/go-json v0.10.4
 	github.com/google/uuid v1.6.0
 	github.com/klauspost/compress v1.17.11
 	github.com/minio/md5-simd v1.1.2
 	github.com/rs/xid v1.6.0
-	golang.org/x/crypto v0.28.0
-	golang.org/x/net v0.30.0
+	golang.org/x/crypto v0.31.0
+	golang.org/x/net v0.33.0
 )
 
 require (
-	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.9 // indirect
 	github.com/stretchr/testify v1.9.0 // indirect
-	golang.org/x/sys v0.26.0 // indirect
-	golang.org/x/text v0.19.0 // indirect
+	golang.org/x/sys v0.28.0 // indirect
+	golang.org/x/text v0.21.0 // indirect
 )
diff --git a/go.sum b/go.sum
index bb38e5f..cbbefe8 100644
--- a/go.sum
+++ b/go.sum
@@ -4,15 +4,15 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
 github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
-github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
+github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
 github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
-github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
+github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
 github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
 github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -21,14 +21,13 @@ github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
 github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
 github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
-golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
-golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
-golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
-golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pkg/credentials/assume_role.go b/pkg/credentials/assume_role.go
index d245bc0..cd0a641 100644
--- a/pkg/credentials/assume_role.go
+++ b/pkg/credentials/assume_role.go
@@ -76,7 +76,8 @@ type AssumeRoleResult struct {
 type STSAssumeRole struct {
 	Expiry
 
-	// Required http Client to use when connecting to MinIO STS service.
+	// Optional http Client to use when connecting to MinIO STS service
+	// (overrides default client in CredContext)
 	Client *http.Client
 
 	// STS endpoint to fetch STS credentials.
@@ -108,16 +109,10 @@ type STSAssumeRoleOptions struct {
 // NewSTSAssumeRole returns a pointer to a new
 // Credentials object wrapping the STSAssumeRole.
 func NewSTSAssumeRole(stsEndpoint string, opts STSAssumeRoleOptions) (*Credentials, error) {
-	if stsEndpoint == "" {
-		return nil, errors.New("STS endpoint cannot be empty")
-	}
 	if opts.AccessKey == "" || opts.SecretKey == "" {
 		return nil, errors.New("AssumeRole credentials access/secretkey is mandatory")
 	}
 	return New(&STSAssumeRole{
-		Client: &http.Client{
-			Transport: http.DefaultTransport,
-		},
 		STSEndpoint: stsEndpoint,
 		Options:     opts,
 	}), nil
@@ -222,10 +217,30 @@ func getAssumeRoleCredentials(clnt *http.Client, endpoint string, opts STSAssume
 	return a, nil
 }
 
-// Retrieve retrieves credentials from the MinIO service.
-// Error will be returned if the request fails.
-func (m *STSAssumeRole) Retrieve() (Value, error) {
-	a, err := getAssumeRoleCredentials(m.Client, m.STSEndpoint, m.Options)
+// RetrieveWithCredContext retrieves credentials from the MinIO service.
+// Error will be returned if the request fails, optional cred context.
+func (m *STSAssumeRole) RetrieveWithCredContext(cc *CredContext) (Value, error) {
+	if cc == nil {
+		cc = defaultCredContext
+	}
+
+	client := m.Client
+	if client == nil {
+		client = cc.Client
+	}
+	if client == nil {
+		client = defaultCredContext.Client
+	}
+
+	stsEndpoint := m.STSEndpoint
+	if stsEndpoint == "" {
+		stsEndpoint = cc.Endpoint
+	}
+	if stsEndpoint == "" {
+		return Value{}, errors.New("STS endpoint unknown")
+	}
+
+	a, err := getAssumeRoleCredentials(client, stsEndpoint, m.Options)
 	if err != nil {
 		return Value{}, err
 	}
@@ -241,3 +256,9 @@ func (m *STSAssumeRole) Retrieve() (Value, error) {
 		SignerType:      SignatureV4,
 	}, nil
 }
+
+// Retrieve retrieves credentials from the MinIO service.
+// Error will be returned if the request fails.
+func (m *STSAssumeRole) Retrieve() (Value, error) {
+	return m.RetrieveWithCredContext(nil)
+}
diff --git a/pkg/credentials/chain.go b/pkg/credentials/chain.go
index ddccfb1..5ef3597 100644
--- a/pkg/credentials/chain.go
+++ b/pkg/credentials/chain.go
@@ -55,6 +55,24 @@ func NewChainCredentials(providers []Provider) *Credentials {
 	})
 }
 
+// RetrieveWithCredContext is like Retrieve with CredContext
+func (c *Chain) RetrieveWithCredContext(cc *CredContext) (Value, error) {
+	for _, p := range c.Providers {
+		creds, _ := p.RetrieveWithCredContext(cc)
+		// Always prioritize non-anonymous providers, if any.
+		if creds.AccessKeyID == "" && creds.SecretAccessKey == "" {
+			continue
+		}
+		c.curr = p
+		return creds, nil
+	}
+	// At this point we have exhausted all the providers and
+	// are left without any credentials return anonymous.
+	return Value{
+		SignerType: SignatureAnonymous,
+	}, nil
+}
+
 // Retrieve returns the credentials value, returns no credentials(anonymous)
 // if no credentials provider returned any value.
 //
diff --git a/pkg/credentials/credentials.go b/pkg/credentials/credentials.go
index 68f9b38..52aff9a 100644
--- a/pkg/credentials/credentials.go
+++ b/pkg/credentials/credentials.go
@@ -18,6 +18,7 @@
 package credentials
 
 import (
+	"net/http"
 	"sync"
 	"time"
 )
@@ -30,6 +31,10 @@ const (
 	defaultExpiryWindow = 0.8
 )
 
+// defaultCredContext is used when the credential context doesn't
+// actually matter or the default context is suitable.
+var defaultCredContext = &CredContext{Client: http.DefaultClient}
+
 // A Value is the S3 credentials value for individual credential fields.
 type Value struct {
 	// S3 Access key ID
@@ -52,8 +57,17 @@ type Value struct {
 // Value. A provider is required to manage its own Expired state, and what to
 // be expired means.
 type Provider interface {
+	// RetrieveWithCredContext returns nil if it successfully retrieved the
+	// value. Error is returned if the value were not obtainable, or empty.
+	// optionally takes CredContext for additional context to retrieve credentials.
+	RetrieveWithCredContext(cc *CredContext) (Value, error)
+
 	// Retrieve returns nil if it successfully retrieved the value.
 	// Error is returned if the value were not obtainable, or empty.
+	//
+	// Deprecated: Retrieve() exists for historical compatibility and should not
+	// be used. To get new credentials use the RetrieveWithCredContext function
+	// to ensure the proper context (i.e. HTTP client) will be used.
 	Retrieve() (Value, error)
 
 	// IsExpired returns if the credentials are no longer valid, and need
@@ -61,6 +75,18 @@ type Provider interface {
 	IsExpired() bool
 }
 
+// CredContext is passed to the Retrieve function of a provider to provide
+// some additional context to retrieve credentials.
+type CredContext struct {
+	// Client specifies the HTTP client that should be used if an HTTP
+	// request is to be made to fetch the credentials.
+	Client *http.Client
+
+	// Endpoint specifies the MinIO endpoint that will be used if no
+	// explicit endpoint is provided.
+	Endpoint string
+}
+
 // A Expiry provides shared expiration logic to be used by credentials
 // providers to implement expiry functionality.
 //
@@ -146,16 +172,36 @@ func New(provider Provider) *Credentials {
 //
 // If Credentials.Expire() was called the credentials Value will be force
 // expired, and the next call to Get() will cause them to be refreshed.
+//
+// Deprecated: Get() exists for historical compatibility and should not be
+// used. To get new credentials use the Credentials.GetWithContext function
+// to ensure the proper context (i.e. HTTP client) will be used.
 func (c *Credentials) Get() (Value, error) {
+	return c.GetWithContext(nil)
+}
+
+// GetWithContext returns the credentials value, or error if the
+// credentials Value failed to be retrieved.
+//
+// Will return the cached credentials Value if it has not expired. If the
+// credentials Value has expired the Provider's Retrieve() will be called
+// to refresh the credentials.
+//
+// If Credentials.Expire() was called the credentials Value will be force
+// expired, and the next call to Get() will cause them to be refreshed.
+func (c *Credentials) GetWithContext(cc *CredContext) (Value, error) {
 	if c == nil {
 		return Value{}, nil
 	}
+	if cc == nil {
+		cc = defaultCredContext
+	}
 
 	c.Lock()
 	defer c.Unlock()
 
 	if c.isExpired() {
-		creds, err := c.provider.Retrieve()
+		creds, err := c.provider.RetrieveWithCredContext(cc)
 		if err != nil {
 			return Value{}, err
 		}
diff --git a/pkg/credentials/env_aws.go b/pkg/credentials/env_aws.go
index b6e60d0..21ab0a3 100644
--- a/pkg/credentials/env_aws.go
+++ b/pkg/credentials/env_aws.go
@@ -37,8 +37,7 @@ func NewEnvAWS() *Credentials {
 	return New(&EnvAWS{})
 }
 
-// Retrieve retrieves the keys from the environment.
-func (e *EnvAWS) Retrieve() (Value, error) {
+func (e *EnvAWS) retrieve() (Value, error) {
 	e.retrieved = false
 
 	id := os.Getenv("AWS_ACCESS_KEY_ID")
@@ -65,6 +64,16 @@ func (e *EnvAWS) Retrieve() (Value, error) {
 	}, nil
 }
 
+// Retrieve retrieves the keys from the environment.
+func (e *EnvAWS) Retrieve() (Value, error) {
+	return e.retrieve()
+}
+
+// RetrieveWithCredContext is like Retrieve (no-op input of Cred Context)
+func (e *EnvAWS) RetrieveWithCredContext(_ *CredContext) (Value, error) {
+	return e.retrieve()
+}
+
 // IsExpired returns if the credentials have been retrieved.
 func (e *EnvAWS) IsExpired() bool {
 	return !e.retrieved
diff --git a/pkg/credentials/env_minio.go b/pkg/credentials/env_minio.go
index 5bfeab1..dbfbdfc 100644
--- a/pkg/credentials/env_minio.go
+++ b/pkg/credentials/env_minio.go
@@ -38,8 +38,7 @@ func NewEnvMinio() *Credentials {
 	return New(&EnvMinio{})
 }
 
-// Retrieve retrieves the keys from the environment.
-func (e *EnvMinio) Retrieve() (Value, error) {
+func (e *EnvMinio) retrieve() (Value, error) {
 	e.retrieved = false
 
 	id := os.Getenv("MINIO_ROOT_USER")
@@ -62,6 +61,16 @@ func (e *EnvMinio) Retrieve() (Value, error) {
 	}, nil
 }
 
+// Retrieve retrieves the keys from the environment.
+func (e *EnvMinio) Retrieve() (Value, error) {
+	return e.retrieve()
+}
+
+// RetrieveWithCredContext is like Retrieve() (no-op input cred context)
+func (e *EnvMinio) RetrieveWithCredContext(_ *CredContext) (Value, error) {
+	return e.retrieve()
+}
+
 // IsExpired returns if the credentials have been retrieved.
 func (e *EnvMinio) IsExpired() bool {
 	return !e.retrieved
diff --git a/pkg/credentials/file_aws_credentials.go b/pkg/credentials/file_aws_credentials.go
index 541e1a7..0c83fc7 100644
--- a/pkg/credentials/file_aws_credentials.go
+++ b/pkg/credentials/file_aws_credentials.go
@@ -71,9 +71,7 @@ func NewFileAWSCredentials(filename, profile string) *Credentials {
 	})
 }
 
-// Retrieve reads and extracts the shared credentials from the current
-// users home directory.
-func (p *FileAWSCredentials) Retrieve() (Value, error) {
+func (p *FileAWSCredentials) retrieve() (Value, error) {
 	if p.Filename == "" {
 		p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE")
 		if p.Filename == "" {
@@ -142,6 +140,17 @@ func (p *FileAWSCredentials) Retrieve() (Value, error) {
 	}, nil
 }
 
+// Retrieve reads and extracts the shared credentials from the current
+// users home directory.
+func (p *FileAWSCredentials) Retrieve() (Value, error) {
+	return p.retrieve()
+}
+
+// RetrieveWithCredContext is like Retrieve(), cred context is no-op for File credentials
+func (p *FileAWSCredentials) RetrieveWithCredContext(_ *CredContext) (Value, error) {
+	return p.retrieve()
+}
+
 // loadProfiles loads from the file pointed to by shared credentials filename for profile.
 // The credentials retrieved from the profile will be returned or error. Error will be
 // returned if it fails to read from the file, or the data is invalid.
diff --git a/pkg/credentials/file_minio_client.go b/pkg/credentials/file_minio_client.go
index 750e26f..5805281 100644
--- a/pkg/credentials/file_minio_client.go
+++ b/pkg/credentials/file_minio_client.go
@@ -56,9 +56,7 @@ func NewFileMinioClient(filename, alias string) *Credentials {
 	})
 }
 
-// Retrieve reads and extracts the shared credentials from the current
-// users home directory.
-func (p *FileMinioClient) Retrieve() (Value, error) {
+func (p *FileMinioClient) retrieve() (Value, error) {
 	if p.Filename == "" {
 		if value, ok := os.LookupEnv("MINIO_SHARED_CREDENTIALS_FILE"); ok {
 			p.Filename = value
@@ -96,6 +94,17 @@ func (p *FileMinioClient) Retrieve() (Value, error) {
 	}, nil
 }
 
+// Retrieve reads and extracts the shared credentials from the current
+// users home directory.
+func (p *FileMinioClient) Retrieve() (Value, error) {
+	return p.retrieve()
+}
+
+// RetrieveWithCredContext - is like Retrieve()
+func (p *FileMinioClient) RetrieveWithCredContext(_ *CredContext) (Value, error) {
+	return p.retrieve()
+}
+
 // IsExpired returns if the shared credentials have expired.
 func (p *FileMinioClient) IsExpired() bool {
 	return !p.retrieved
diff --git a/pkg/credentials/iam_aws.go b/pkg/credentials/iam_aws.go
index ea4b3ef..0ba06e7 100644
--- a/pkg/credentials/iam_aws.go
+++ b/pkg/credentials/iam_aws.go
@@ -49,7 +49,8 @@ const DefaultExpiryWindow = -1
 type IAM struct {
 	Expiry
 
-	// Required http Client to use when connecting to IAM metadata service.
+	// Optional http Client to use when connecting to IAM metadata service
+	// (overrides default client in CredContext)
 	Client *http.Client
 
 	// Custom endpoint to fetch IAM role credentials.
@@ -90,17 +91,16 @@ const (
 // NewIAM returns a pointer to a new Credentials object wrapping the IAM.
 func NewIAM(endpoint string) *Credentials {
 	return New(&IAM{
-		Client: &http.Client{
-			Transport: http.DefaultTransport,
-		},
 		Endpoint: endpoint,
 	})
 }
 
-// Retrieve retrieves credentials from the EC2 service.
-// Error will be returned if the request fails, or unable to extract
-// the desired
-func (m *IAM) Retrieve() (Value, error) {
+// RetrieveWithCredContext is like Retrieve with Cred Context
+func (m *IAM) RetrieveWithCredContext(cc *CredContext) (Value, error) {
+	if cc == nil {
+		cc = defaultCredContext
+	}
+
 	token := os.Getenv("AWS_CONTAINER_AUTHORIZATION_TOKEN")
 	if token == "" {
 		token = m.Container.AuthorizationToken
@@ -144,7 +144,19 @@ func (m *IAM) Retrieve() (Value, error) {
 	var roleCreds ec2RoleCredRespBody
 	var err error
 
+	client := m.Client
+	if client == nil {
+		client = cc.Client
+	}
+	if client == nil {
+		client = defaultCredContext.Client
+	}
+
 	endpoint := m.Endpoint
+	if endpoint == "" {
+		endpoint = cc.Endpoint
+	}
+
 	switch {
 	case identityFile != "":
 		if len(endpoint) == 0 {
@@ -160,7 +172,7 @@ func (m *IAM) Retrieve() (Value, error) {
 		}
 
 		creds := &STSWebIdentity{
-			Client:      m.Client,
+			Client:      client,
 			STSEndpoint: endpoint,
 			GetWebIDTokenExpiry: func() (*WebIdentityToken, error) {
 				token, err := os.ReadFile(identityFile)
@@ -174,7 +186,7 @@ func (m *IAM) Retrieve() (Value, error) {
 			roleSessionName: roleSessionName,
 		}
 
-		stsWebIdentityCreds, err := creds.Retrieve()
+		stsWebIdentityCreds, err := creds.RetrieveWithCredContext(cc)
 		if err == nil {
 			m.SetExpiration(creds.Expiration(), DefaultExpiryWindow)
 		}
@@ -185,11 +197,11 @@ func (m *IAM) Retrieve() (Value, error) {
 			endpoint = fmt.Sprintf("%s%s", DefaultECSRoleEndpoint, relativeURI)
 		}
 
-		roleCreds, err = getEcsTaskCredentials(m.Client, endpoint, token)
+		roleCreds, err = getEcsTaskCredentials(client, endpoint, token)
 
 	case tokenFile != "" && fullURI != "":
 		endpoint = fullURI
-		roleCreds, err = getEKSPodIdentityCredentials(m.Client, endpoint, tokenFile)
+		roleCreds, err = getEKSPodIdentityCredentials(client, endpoint, tokenFile)
 
 	case fullURI != "":
 		if len(endpoint) == 0 {
@@ -203,10 +215,10 @@ func (m *IAM) Retrieve() (Value, error) {
 			}
 		}
 
-		roleCreds, err = getEcsTaskCredentials(m.Client, endpoint, token)
+		roleCreds, err = getEcsTaskCredentials(client, endpoint, token)
 
 	default:
-		roleCreds, err = getCredentials(m.Client, endpoint)
+		roleCreds, err = getCredentials(client, endpoint)
 	}
 
 	if err != nil {
@@ -224,6 +236,13 @@ func (m *IAM) Retrieve() (Value, error) {
 	}, nil
 }
 
+// Retrieve retrieves credentials from the EC2 service.
+// Error will be returned if the request fails, or unable to extract
+// the desired
+func (m *IAM) Retrieve() (Value, error) {
+	return m.RetrieveWithCredContext(nil)
+}
+
 // A ec2RoleCredRespBody provides the shape for unmarshaling credential
 // request responses.
 type ec2RoleCredRespBody struct {
diff --git a/pkg/credentials/static.go b/pkg/credentials/static.go
index 7dde00b..d90c98c 100644
--- a/pkg/credentials/static.go
+++ b/pkg/credentials/static.go
@@ -59,6 +59,11 @@ func (s *Static) Retrieve() (Value, error) {
 	return s.Value, nil
 }
 
+// RetrieveWithCredContext returns the static credentials.
+func (s *Static) RetrieveWithCredContext(_ *CredContext) (Value, error) {
+	return s.Retrieve()
+}
+
 // IsExpired returns if the credentials are expired.
 //
 // For Static, the credentials never expired.
diff --git a/pkg/credentials/sts_client_grants.go b/pkg/credentials/sts_client_grants.go
index 62bfbb6..ef6f436 100644
--- a/pkg/credentials/sts_client_grants.go
+++ b/pkg/credentials/sts_client_grants.go
@@ -72,7 +72,8 @@ type ClientGrantsToken struct {
 type STSClientGrants struct {
 	Expiry
 
-	// Required http Client to use when connecting to MinIO STS service.
+	// Optional http Client to use when connecting to MinIO STS service.
+	// (overrides default client in CredContext)
 	Client *http.Client
 
 	// MinIO endpoint to fetch STS credentials.
@@ -90,16 +91,10 @@ type STSClientGrants struct {
 // NewSTSClientGrants returns a pointer to a new
 // Credentials object wrapping the STSClientGrants.
 func NewSTSClientGrants(stsEndpoint string, getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)) (*Credentials, error) {
-	if stsEndpoint == "" {
-		return nil, errors.New("STS endpoint cannot be empty")
-	}
 	if getClientGrantsTokenExpiry == nil {
 		return nil, errors.New("Client grants access token and expiry retrieval function should be defined")
 	}
 	return New(&STSClientGrants{
-		Client: &http.Client{
-			Transport: http.DefaultTransport,
-		},
 		STSEndpoint:                stsEndpoint,
 		GetClientGrantsTokenExpiry: getClientGrantsTokenExpiry,
 	}), nil
@@ -162,10 +157,29 @@ func getClientGrantsCredentials(clnt *http.Client, endpoint string,
 	return a, nil
 }
 
-// Retrieve retrieves credentials from the MinIO service.
-// Error will be returned if the request fails.
-func (m *STSClientGrants) Retrieve() (Value, error) {
-	a, err := getClientGrantsCredentials(m.Client, m.STSEndpoint, m.GetClientGrantsTokenExpiry)
+// RetrieveWithCredContext is like Retrieve() with cred context
+func (m *STSClientGrants) RetrieveWithCredContext(cc *CredContext) (Value, error) {
+	if cc == nil {
+		cc = defaultCredContext
+	}
+
+	client := m.Client
+	if client == nil {
+		client = cc.Client
+	}
+	if client == nil {
+		client = defaultCredContext.Client
+	}
+
+	stsEndpoint := m.STSEndpoint
+	if stsEndpoint == "" {
+		stsEndpoint = cc.Endpoint
+	}
+	if stsEndpoint == "" {
+		return Value{}, errors.New("STS endpoint unknown")
+	}
+
+	a, err := getClientGrantsCredentials(client, stsEndpoint, m.GetClientGrantsTokenExpiry)
 	if err != nil {
 		return Value{}, err
 	}
@@ -181,3 +195,9 @@ func (m *STSClientGrants) Retrieve() (Value, error) {
 		SignerType:      SignatureV4,
 	}, nil
 }
+
+// Retrieve retrieves credentials from the MinIO service.
+// Error will be returned if the request fails.
+func (m *STSClientGrants) Retrieve() (Value, error) {
+	return m.RetrieveWithCredContext(nil)
+}
diff --git a/pkg/credentials/sts_custom_identity.go b/pkg/credentials/sts_custom_identity.go
index 75e1a77..0021f93 100644
--- a/pkg/credentials/sts_custom_identity.go
+++ b/pkg/credentials/sts_custom_identity.go
@@ -53,6 +53,8 @@ type AssumeRoleWithCustomTokenResponse struct {
 type CustomTokenIdentity struct {
 	Expiry
 
+	// Optional http Client to use when connecting to MinIO STS service.
+	// (overrides default client in CredContext)
 	Client *http.Client
 
 	// MinIO server STS endpoint to fetch STS credentials.
@@ -69,9 +71,21 @@ type CustomTokenIdentity struct {
 	RequestedExpiry time.Duration
 }
 
-// Retrieve - to satisfy Provider interface; fetches credentials from MinIO.
-func (c *CustomTokenIdentity) Retrieve() (value Value, err error) {
-	u, err := url.Parse(c.STSEndpoint)
+// RetrieveWithCredContext with Retrieve optionally cred context
+func (c *CustomTokenIdentity) RetrieveWithCredContext(cc *CredContext) (value Value, err error) {
+	if cc == nil {
+		cc = defaultCredContext
+	}
+
+	stsEndpoint := c.STSEndpoint
+	if stsEndpoint == "" {
+		stsEndpoint = cc.Endpoint
+	}
+	if stsEndpoint == "" {
+		return Value{}, errors.New("STS endpoint unknown")
+	}
+
+	u, err := url.Parse(stsEndpoint)
 	if err != nil {
 		return value, err
 	}
@@ -92,7 +106,15 @@ func (c *CustomTokenIdentity) Retrieve() (value Value, err error) {
 		return value, err
 	}
 
-	resp, err := c.Client.Do(req)
+	client := c.Client
+	if client == nil {
+		client = cc.Client
+	}
+	if client == nil {
+		client = defaultCredContext.Client
+	}
+
+	resp, err := client.Do(req)
 	if err != nil {
 		return value, err
 	}
@@ -118,11 +140,15 @@ func (c *CustomTokenIdentity) Retrieve() (value Value, err error) {
 	}, nil
 }
 
+// Retrieve - to satisfy Provider interface; fetches credentials from MinIO.
+func (c *CustomTokenIdentity) Retrieve() (value Value, err error) {
+	return c.RetrieveWithCredContext(nil)
+}
+
 // NewCustomTokenCredentials - returns credentials using the
 // AssumeRoleWithCustomToken STS API.
 func NewCustomTokenCredentials(stsEndpoint, token, roleArn string, optFuncs ...CustomTokenOpt) (*Credentials, error) {
 	c := CustomTokenIdentity{
-		Client:      &http.Client{Transport: http.DefaultTransport},
 		STSEndpoint: stsEndpoint,
 		Token:       token,
 		RoleArn:     roleArn,
diff --git a/pkg/credentials/sts_ldap_identity.go b/pkg/credentials/sts_ldap_identity.go
index b8df289..e63997e 100644
--- a/pkg/credentials/sts_ldap_identity.go
+++ b/pkg/credentials/sts_ldap_identity.go
@@ -20,6 +20,7 @@ package credentials
 import (
 	"bytes"
 	"encoding/xml"
+	"errors"
 	"fmt"
 	"io"
 	"net/http"
@@ -55,7 +56,8 @@ type LDAPIdentityResult struct {
 type LDAPIdentity struct {
 	Expiry
 
-	// Required http Client to use when connecting to MinIO STS service.
+	// Optional http Client to use when connecting to MinIO STS service.
+	// (overrides default client in CredContext)
 	Client *http.Client
 
 	// Exported STS endpoint to fetch STS credentials.
@@ -77,7 +79,6 @@ type LDAPIdentity struct {
 // Identity.
 func NewLDAPIdentity(stsEndpoint, ldapUsername, ldapPassword string, optFuncs ...LDAPIdentityOpt) (*Credentials, error) {
 	l := LDAPIdentity{
-		Client:       &http.Client{Transport: http.DefaultTransport},
 		STSEndpoint:  stsEndpoint,
 		LDAPUsername: ldapUsername,
 		LDAPPassword: ldapPassword,
@@ -113,7 +114,6 @@ func LDAPIdentityExpiryOpt(d time.Duration) LDAPIdentityOpt {
 // Deprecated: Use the `LDAPIdentityPolicyOpt` with `NewLDAPIdentity` instead.
 func NewLDAPIdentityWithSessionPolicy(stsEndpoint, ldapUsername, ldapPassword, policy string) (*Credentials, error) {
 	return New(&LDAPIdentity{
-		Client:       &http.Client{Transport: http.DefaultTransport},
 		STSEndpoint:  stsEndpoint,
 		LDAPUsername: ldapUsername,
 		LDAPPassword: ldapPassword,
@@ -121,10 +121,22 @@ func NewLDAPIdentityWithSessionPolicy(stsEndpoint, ldapUsername, ldapPassword, p
 	}), nil
 }
 
-// Retrieve gets the credential by calling the MinIO STS API for
+// RetrieveWithCredContext gets the credential by calling the MinIO STS API for
 // LDAP on the configured stsEndpoint.
-func (k *LDAPIdentity) Retrieve() (value Value, err error) {
-	u, err := url.Parse(k.STSEndpoint)
+func (k *LDAPIdentity) RetrieveWithCredContext(cc *CredContext) (value Value, err error) {
+	if cc == nil {
+		cc = defaultCredContext
+	}
+
+	stsEndpoint := k.STSEndpoint
+	if stsEndpoint == "" {
+		stsEndpoint = cc.Endpoint
+	}
+	if stsEndpoint == "" {
+		return Value{}, errors.New("STS endpoint unknown")
+	}
+
+	u, err := url.Parse(stsEndpoint)
 	if err != nil {
 		return value, err
 	}
@@ -148,7 +160,15 @@ func (k *LDAPIdentity) Retrieve() (value Value, err error) {
 
 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
-	resp, err := k.Client.Do(req)
+	client := k.Client
+	if client == nil {
+		client = cc.Client
+	}
+	if client == nil {
+		client = defaultCredContext.Client
+	}
+
+	resp, err := client.Do(req)
 	if err != nil {
 		return value, err
 	}
@@ -188,3 +208,9 @@ func (k *LDAPIdentity) Retrieve() (value Value, err error) {
 		SignerType:      SignatureV4,
 	}, nil
 }
+
+// Retrieve gets the credential by calling the MinIO STS API for
+// LDAP on the configured stsEndpoint.
+func (k *LDAPIdentity) Retrieve() (value Value, err error) {
+	return k.RetrieveWithCredContext(defaultCredContext)
+}
diff --git a/pkg/credentials/sts_tls_identity.go b/pkg/credentials/sts_tls_identity.go
index 1008350..c904bbe 100644
--- a/pkg/credentials/sts_tls_identity.go
+++ b/pkg/credentials/sts_tls_identity.go
@@ -20,8 +20,8 @@ import (
 	"crypto/tls"
 	"encoding/xml"
 	"errors"
+	"fmt"
 	"io"
-	"net"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -36,7 +36,12 @@ type CertificateIdentityOption func(*STSCertificateIdentity)
 // CertificateIdentityWithTransport returns a CertificateIdentityOption that
 // customizes the STSCertificateIdentity with the given http.RoundTripper.
 func CertificateIdentityWithTransport(t http.RoundTripper) CertificateIdentityOption {
-	return CertificateIdentityOption(func(i *STSCertificateIdentity) { i.Client.Transport = t })
+	return CertificateIdentityOption(func(i *STSCertificateIdentity) {
+		if i.Client == nil {
+			i.Client = &http.Client{}
+		}
+		i.Client.Transport = t
+	})
 }
 
 // CertificateIdentityWithExpiry returns a CertificateIdentityOption that
@@ -53,6 +58,10 @@ func CertificateIdentityWithExpiry(livetime time.Duration) CertificateIdentityOp
 type STSCertificateIdentity struct {
 	Expiry
 
+	// Optional http Client to use when connecting to MinIO STS service.
+	// (overrides default client in CredContext)
+	Client *http.Client
+
 	// STSEndpoint is the base URL endpoint of the STS API.
 	// For example, https://minio.local:9000
 	STSEndpoint string
@@ -68,50 +77,18 @@ type STSCertificateIdentity struct {
 	// The default livetime is one hour.
 	S3CredentialLivetime time.Duration
 
-	// Client is the HTTP client used to authenticate and fetch
-	// S3 credentials.
-	//
-	// A custom TLS client configuration can be specified by
-	// using a custom http.Transport:
-	//   Client: http.Client {
-	//       Transport: &http.Transport{
-	//           TLSClientConfig: &tls.Config{},
-	//       },
-	//   }
-	Client http.Client
+	// Certificate is the client certificate that is used for
+	// STS authentication.
+	Certificate tls.Certificate
 }
 
-var _ Provider = (*STSWebIdentity)(nil) // compiler check
-
 // NewSTSCertificateIdentity returns a STSCertificateIdentity that authenticates
 // to the given STS endpoint with the given TLS certificate and retrieves and
 // rotates S3 credentials.
 func NewSTSCertificateIdentity(endpoint string, certificate tls.Certificate, options ...CertificateIdentityOption) (*Credentials, error) {
-	if endpoint == "" {
-		return nil, errors.New("STS endpoint cannot be empty")
-	}
-	if _, err := url.Parse(endpoint); err != nil {
-		return nil, err
-	}
 	identity := &STSCertificateIdentity{
 		STSEndpoint: endpoint,
-		Client: http.Client{
-			Transport: &http.Transport{
-				Proxy: http.ProxyFromEnvironment,
-				DialContext: (&net.Dialer{
-					Timeout:   30 * time.Second,
-					KeepAlive: 30 * time.Second,
-				}).DialContext,
-				ForceAttemptHTTP2:     true,
-				MaxIdleConns:          100,
-				IdleConnTimeout:       90 * time.Second,
-				TLSHandshakeTimeout:   10 * time.Second,
-				ExpectContinueTimeout: 5 * time.Second,
-				TLSClientConfig: &tls.Config{
-					Certificates: []tls.Certificate{certificate},
-				},
-			},
-		},
+		Certificate: certificate,
 	}
 	for _, option := range options {
 		option(identity)
@@ -119,10 +96,21 @@ func NewSTSCertificateIdentity(endpoint string, certificate tls.Certificate, opt
 	return New(identity), nil
 }
 
-// Retrieve fetches a new set of S3 credentials from the configured
-// STS API endpoint.
-func (i *STSCertificateIdentity) Retrieve() (Value, error) {
-	endpointURL, err := url.Parse(i.STSEndpoint)
+// RetrieveWithCredContext is Retrieve with cred context
+func (i *STSCertificateIdentity) RetrieveWithCredContext(cc *CredContext) (Value, error) {
+	if cc == nil {
+		cc = defaultCredContext
+	}
+
+	stsEndpoint := i.STSEndpoint
+	if stsEndpoint == "" {
+		stsEndpoint = cc.Endpoint
+	}
+	if stsEndpoint == "" {
+		return Value{}, errors.New("STS endpoint unknown")
+	}
+
+	endpointURL, err := url.Parse(stsEndpoint)
 	if err != nil {
 		return Value{}, err
 	}
@@ -145,7 +133,28 @@ func (i *STSCertificateIdentity) Retrieve() (Value, error) {
 	}
 	req.Form.Add("DurationSeconds", strconv.FormatUint(uint64(livetime.Seconds()), 10))
 
-	resp, err := i.Client.Do(req)
+	client := i.Client
+	if client == nil {
+		client = cc.Client
+	}
+	if client == nil {
+		client = defaultCredContext.Client
+	}
+
+	tr, ok := client.Transport.(*http.Transport)
+	if !ok {
+		return Value{}, fmt.Errorf("CredContext should contain an http.Transport value")
+	}
+
+	// Clone the HTTP transport (patch the TLS client certificate)
+	trCopy := tr.Clone()
+	trCopy.TLSClientConfig.Certificates = []tls.Certificate{i.Certificate}
+
+	// Clone the HTTP client (patch the HTTP transport)
+	clientCopy := *client
+	clientCopy.Transport = trCopy
+
+	resp, err := clientCopy.Do(req)
 	if err != nil {
 		return Value{}, err
 	}
@@ -193,6 +202,11 @@ func (i *STSCertificateIdentity) Retrieve() (Value, error) {
 	}, nil
 }
 
+// Retrieve fetches a new set of S3 credentials from the configured STS API endpoint.
+func (i *STSCertificateIdentity) Retrieve() (Value, error) {
+	return i.RetrieveWithCredContext(defaultCredContext)
+}
+
 // Expiration returns the expiration time of the current S3 credentials.
 func (i *STSCertificateIdentity) Expiration() time.Time { return i.expiration }
 
diff --git a/pkg/credentials/sts_web_identity.go b/pkg/credentials/sts_web_identity.go
index 787f0a3..2352588 100644
--- a/pkg/credentials/sts_web_identity.go
+++ b/pkg/credentials/sts_web_identity.go
@@ -69,7 +69,8 @@ type WebIdentityToken struct {
 type STSWebIdentity struct {
 	Expiry
 
-	// Required http Client to use when connecting to MinIO STS service.
+	// Optional http Client to use when connecting to MinIO STS service.
+	// (overrides default client in CredContext)
 	Client *http.Client
 
 	// Exported STS endpoint to fetch STS credentials.
@@ -97,16 +98,10 @@ type STSWebIdentity struct {
 // NewSTSWebIdentity returns a pointer to a new
 // Credentials object wrapping the STSWebIdentity.
 func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error), opts ...func(*STSWebIdentity)) (*Credentials, error) {
-	if stsEndpoint == "" {
-		return nil, errors.New("STS endpoint cannot be empty")
-	}
 	if getWebIDTokenExpiry == nil {
 		return nil, errors.New("Web ID token and expiry retrieval function should be defined")
 	}
 	i := &STSWebIdentity{
-		Client: &http.Client{
-			Transport: http.DefaultTransport,
-		},
 		STSEndpoint:         stsEndpoint,
 		GetWebIDTokenExpiry: getWebIDTokenExpiry,
 	}
@@ -162,6 +157,10 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSession
 		// Usually set when server is using extended userInfo endpoint.
 		v.Set("WebIdentityAccessToken", idToken.AccessToken)
 	}
+	if idToken.RefreshToken != "" {
+		// Usually set when server is using extended userInfo endpoint.
+		v.Set("WebIdentityRefreshToken", idToken.RefreshToken)
+	}
 	if idToken.Expiry > 0 {
 		v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry))
 	}
@@ -215,10 +214,29 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSession
 	return a, nil
 }
 
-// Retrieve retrieves credentials from the MinIO service.
-// Error will be returned if the request fails.
-func (m *STSWebIdentity) Retrieve() (Value, error) {
-	a, err := getWebIdentityCredentials(m.Client, m.STSEndpoint, m.RoleARN, m.roleSessionName, m.Policy, m.GetWebIDTokenExpiry)
+// RetrieveWithCredContext is like Retrieve with optional cred context.
+func (m *STSWebIdentity) RetrieveWithCredContext(cc *CredContext) (Value, error) {
+	if cc == nil {
+		cc = defaultCredContext
+	}
+
+	client := m.Client
+	if client == nil {
+		client = cc.Client
+	}
+	if client == nil {
+		client = defaultCredContext.Client
+	}
+
+	stsEndpoint := m.STSEndpoint
+	if stsEndpoint == "" {
+		stsEndpoint = cc.Endpoint
+	}
+	if stsEndpoint == "" {
+		return Value{}, errors.New("STS endpoint unknown")
+	}
+
+	a, err := getWebIdentityCredentials(client, stsEndpoint, m.RoleARN, m.roleSessionName, m.Policy, m.GetWebIDTokenExpiry)
 	if err != nil {
 		return Value{}, err
 	}
@@ -235,6 +253,12 @@ func (m *STSWebIdentity) Retrieve() (Value, error) {
 	}, nil
 }
 
+// Retrieve retrieves credentials from the MinIO service.
+// Error will be returned if the request fails.
+func (m *STSWebIdentity) Retrieve() (Value, error) {
+	return m.RetrieveWithCredContext(nil)
+}
+
 // Expiration returns the expiration time of the credentials
 func (m *STSWebIdentity) Expiration() time.Time {
 	return m.expiration
diff --git a/pkg/s3utils/utils.go b/pkg/s3utils/utils.go
index 0e63ce2..80fd029 100644
--- a/pkg/s3utils/utils.go
+++ b/pkg/s3utils/utils.go
@@ -118,53 +118,53 @@ func GetRegionFromURL(endpointURL url.URL) string {
 	if endpointURL == sentinelURL {
 		return ""
 	}
-	if endpointURL.Host == "s3-external-1.amazonaws.com" {
+	if endpointURL.Hostname() == "s3-external-1.amazonaws.com" {
 		return ""
 	}
 
 	// if elb's are used we cannot calculate which region it may be, just return empty.
-	if elbAmazonRegex.MatchString(endpointURL.Host) || elbAmazonCnRegex.MatchString(endpointURL.Host) {
+	if elbAmazonRegex.MatchString(endpointURL.Hostname()) || elbAmazonCnRegex.MatchString(endpointURL.Hostname()) {
 		return ""
 	}
 
 	// We check for FIPS dualstack matching first to avoid the non-greedy
 	// regex for FIPS non-dualstack matching a dualstack URL
-	parts := amazonS3HostFIPSDualStack.FindStringSubmatch(endpointURL.Host)
+	parts := amazonS3HostFIPSDualStack.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
 
-	parts = amazonS3HostFIPS.FindStringSubmatch(endpointURL.Host)
+	parts = amazonS3HostFIPS.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
 
-	parts = amazonS3HostDualStack.FindStringSubmatch(endpointURL.Host)
+	parts = amazonS3HostDualStack.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
 
-	parts = amazonS3HostHyphen.FindStringSubmatch(endpointURL.Host)
+	parts = amazonS3HostHyphen.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
 
-	parts = amazonS3ChinaHost.FindStringSubmatch(endpointURL.Host)
+	parts = amazonS3ChinaHost.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
 
-	parts = amazonS3ChinaHostDualStack.FindStringSubmatch(endpointURL.Host)
+	parts = amazonS3ChinaHostDualStack.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
 
-	parts = amazonS3HostDot.FindStringSubmatch(endpointURL.Host)
+	parts = amazonS3HostDot.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
 
-	parts = amazonS3HostPrivateLink.FindStringSubmatch(endpointURL.Host)
+	parts = amazonS3HostPrivateLink.FindStringSubmatch(endpointURL.Hostname())
 	if len(parts) > 1 {
 		return parts[1]
 	}
diff --git a/retry.go b/retry.go
index 4cc4592..ed95401 100644
--- a/retry.go
+++ b/retry.go
@@ -112,6 +112,7 @@ func isS3CodeRetryable(s3Code string) (ok bool) {
 
 // List of HTTP status codes which are retryable.
 var retryableHTTPStatusCodes = map[int]struct{}{
+	http.StatusRequestTimeout:      {},
 	429:                            {}, // http.StatusTooManyRequests is not part of the Go 1.5 library, yet
 	499:                            {}, // client closed request, retry. A non-standard status code introduced by nginx.
 	http.StatusInternalServerError: {},
diff --git a/utils.go b/utils.go
index a5beb37..cd7d2c2 100644
--- a/utils.go
+++ b/utils.go
@@ -378,10 +378,11 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
 		Restore:      restore,
 
 		// Checksum values
-		ChecksumCRC32:  h.Get("x-amz-checksum-crc32"),
-		ChecksumCRC32C: h.Get("x-amz-checksum-crc32c"),
-		ChecksumSHA1:   h.Get("x-amz-checksum-sha1"),
-		ChecksumSHA256: h.Get("x-amz-checksum-sha256"),
+		ChecksumCRC32:     h.Get(ChecksumCRC32.Key()),
+		ChecksumCRC32C:    h.Get(ChecksumCRC32C.Key()),
+		ChecksumSHA1:      h.Get(ChecksumSHA1.Key()),
+		ChecksumSHA256:    h.Get(ChecksumSHA256.Key()),
+		ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
 	}, nil
 }
 
@@ -698,3 +699,146 @@ func (h *hashReaderWrapper) Read(p []byte) (n int, err error) {
 	}
 	return n, err
 }
+
+// Following is ported from C to Go in 2016 by Justin Ruggles, with minimal alteration.
+// Used uint for unsigned long. Used uint32 for input arguments in order to match
+// the Go hash/crc32 package. zlib CRC32 combine (https://github.com/madler/zlib)
+// Modified for hash/crc64 by Klaus Post, 2024.
+func gf2MatrixTimes(mat []uint64, vec uint64) uint64 {
+	var sum uint64
+
+	for vec != 0 {
+		if vec&1 != 0 {
+			sum ^= mat[0]
+		}
+		vec >>= 1
+		mat = mat[1:]
+	}
+	return sum
+}
+
+func gf2MatrixSquare(square, mat []uint64) {
+	if len(square) != len(mat) {
+		panic("square matrix size mismatch")
+	}
+	for n := range mat {
+		square[n] = gf2MatrixTimes(mat, mat[n])
+	}
+}
+
+// crc32Combine returns the combined CRC-32 hash value of the two passed CRC-32
+// hash values crc1 and crc2. poly represents the generator polynomial
+// and len2 specifies the byte length that the crc2 hash covers.
+func crc32Combine(poly uint32, crc1, crc2 uint32, len2 int64) uint32 {
+	// degenerate case (also disallow negative lengths)
+	if len2 <= 0 {
+		return crc1
+	}
+
+	even := make([]uint64, 32) // even-power-of-two zeros operator
+	odd := make([]uint64, 32)  // odd-power-of-two zeros operator
+
+	// put operator for one zero bit in odd
+	odd[0] = uint64(poly) // CRC-32 polynomial
+	row := uint64(1)
+	for n := 1; n < 32; n++ {
+		odd[n] = row
+		row <<= 1
+	}
+
+	// put operator for two zero bits in even
+	gf2MatrixSquare(even, odd)
+
+	// put operator for four zero bits in odd
+	gf2MatrixSquare(odd, even)
+
+	// apply len2 zeros to crc1 (first square will put the operator for one
+	// zero byte, eight zero bits, in even)
+	crc1n := uint64(crc1)
+	for {
+		// apply zeros operator for this bit of len2
+		gf2MatrixSquare(even, odd)
+		if len2&1 != 0 {
+			crc1n = gf2MatrixTimes(even, crc1n)
+		}
+		len2 >>= 1
+
+		// if no more bits set, then done
+		if len2 == 0 {
+			break
+		}
+
+		// another iteration of the loop with odd and even swapped
+		gf2MatrixSquare(odd, even)
+		if len2&1 != 0 {
+			crc1n = gf2MatrixTimes(odd, crc1n)
+		}
+		len2 >>= 1
+
+		// if no more bits set, then done
+		if len2 == 0 {
+			break
+		}
+	}
+
+	// return combined crc
+	crc1n ^= uint64(crc2)
+	return uint32(crc1n)
+}
+
+func crc64Combine(poly uint64, crc1, crc2 uint64, len2 int64) uint64 {
+	// degenerate case (also disallow negative lengths)
+	if len2 <= 0 {
+		return crc1
+	}
+
+	even := make([]uint64, 64) // even-power-of-two zeros operator
+	odd := make([]uint64, 64)  // odd-power-of-two zeros operator
+
+	// put operator for one zero bit in odd
+	odd[0] = poly // CRC-64 polynomial
+	row := uint64(1)
+	for n := 1; n < 64; n++ {
+		odd[n] = row
+		row <<= 1
+	}
+
+	// put operator for two zero bits in even
+	gf2MatrixSquare(even, odd)
+
+	// put operator for four zero bits in odd
+	gf2MatrixSquare(odd, even)
+
+	// apply len2 zeros to crc1 (first square will put the operator for one
+	// zero byte, eight zero bits, in even)
+	crc1n := crc1
+	for {
+		// apply zeros operator for this bit of len2
+		gf2MatrixSquare(even, odd)
+		if len2&1 != 0 {
+			crc1n = gf2MatrixTimes(even, crc1n)
+		}
+		len2 >>= 1
+
+		// if no more bits set, then done
+		if len2 == 0 {
+			break
+		}
+
+		// another iteration of the loop with odd and even swapped
+		gf2MatrixSquare(odd, even)
+		if len2&1 != 0 {
+			crc1n = gf2MatrixTimes(odd, crc1n)
+		}
+		len2 >>= 1
+
+		// if no more bits set, then done
+		if len2 == 0 {
+			break
+		}
+	}
+
+	// return combined crc
+	crc1n ^= crc2
+	return crc1n
+}


Test patch:
diff --git a/bucket-cache_test.go b/bucket-cache_test.go
index 61ac9bd..40f76ca 100644
--- a/bucket-cache_test.go
+++ b/bucket-cache_test.go
@@ -97,7 +97,7 @@ func TestGetBucketLocationRequest(t *testing.T) {
 		c.setUserAgent(req)
 
 		// Get credentials from the configured credentials provider.
-		value, err := c.credsProvider.Get()
+		value, err := c.credsProvider.GetWithContext(c.CredContext())
 		if err != nil {
 			return nil, err
 		}
diff --git a/functional_tests.go b/functional_tests.go
index 43383d1..33e87e6 100644
--- a/functional_tests.go
+++ b/functional_tests.go
@@ -2006,9 +2006,13 @@ func testPutObjectWithChecksums() {
 		{cs: minio.ChecksumCRC32},
 		{cs: minio.ChecksumSHA1},
 		{cs: minio.ChecksumSHA256},
+		{cs: minio.ChecksumCRC64NVME},
 	}
 
 	for _, test := range tests {
+		if os.Getenv("MINT_NO_FULL_OBJECT") != "" && test.cs.FullObjectRequested() {
+			continue
+		}
 		bufSize := dataFileMap["datafile-10-kB"]
 
 		// Save the data
@@ -2065,6 +2069,7 @@ func testPutObjectWithChecksums() {
 		cmpChecksum(resp.ChecksumSHA1, meta["x-amz-checksum-sha1"])
 		cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
 		cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
+		cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
 
 		// Read the data back
 		gopts := minio.GetObjectOptions{Checksum: true}
@@ -2084,6 +2089,7 @@ func testPutObjectWithChecksums() {
 		cmpChecksum(st.ChecksumSHA1, meta["x-amz-checksum-sha1"])
 		cmpChecksum(st.ChecksumCRC32, meta["x-amz-checksum-crc32"])
 		cmpChecksum(st.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
+		cmpChecksum(st.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
 
 		if st.Size != int64(bufSize) {
 			logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
@@ -2127,12 +2133,12 @@ func testPutObjectWithChecksums() {
 		cmpChecksum(st.ChecksumSHA1, "")
 		cmpChecksum(st.ChecksumCRC32, "")
 		cmpChecksum(st.ChecksumCRC32C, "")
+		cmpChecksum(st.ChecksumCRC64NVME, "")
 
 		delete(args, "range")
 		delete(args, "metadata")
+		logSuccess(testName, function, args, startTime)
 	}
-
-	logSuccess(testName, function, args, startTime)
 }
 
 // Test PutObject with custom checksums.
@@ -2173,13 +2179,16 @@ func testPutObjectWithTrailingChecksums() {
 	tests := []struct {
 		cs minio.ChecksumType
 	}{
+		{cs: minio.ChecksumCRC64NVME},
 		{cs: minio.ChecksumCRC32C},
 		{cs: minio.ChecksumCRC32},
 		{cs: minio.ChecksumSHA1},
 		{cs: minio.ChecksumSHA256},
 	}
-
 	for _, test := range tests {
+		if os.Getenv("MINT_NO_FULL_OBJECT") != "" && test.cs.FullObjectRequested() {
+			continue
+		}
 		function := "PutObject(bucketName, objectName, reader,size, opts)"
 		bufSize := dataFileMap["datafile-10-kB"]
 
@@ -2227,6 +2236,7 @@ func testPutObjectWithTrailingChecksums() {
 		cmpChecksum(resp.ChecksumSHA1, meta["x-amz-checksum-sha1"])
 		cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
 		cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
+		cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
 
 		// Read the data back
 		gopts := minio.GetObjectOptions{Checksum: true}
@@ -2247,6 +2257,7 @@ func testPutObjectWithTrailingChecksums() {
 		cmpChecksum(st.ChecksumSHA1, meta["x-amz-checksum-sha1"])
 		cmpChecksum(st.ChecksumCRC32, meta["x-amz-checksum-crc32"])
 		cmpChecksum(st.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
+		cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
 
 		if st.Size != int64(bufSize) {
 			logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
@@ -2291,6 +2302,7 @@ func testPutObjectWithTrailingChecksums() {
 		cmpChecksum(st.ChecksumSHA1, "")
 		cmpChecksum(st.ChecksumCRC32, "")
 		cmpChecksum(st.ChecksumCRC32C, "")
+		cmpChecksum(st.ChecksumCRC64NVME, "")
 
 		function = "GetObjectAttributes(...)"
 		s, err := c.GetObjectAttributes(context.Background(), bucketName, objectName, minio.ObjectAttributesOptions{})
@@ -2305,9 +2317,8 @@ func testPutObjectWithTrailingChecksums() {
 
 		delete(args, "range")
 		delete(args, "metadata")
+		logSuccess(testName, function, args, startTime)
 	}
-
-	logSuccess(testName, function, args, startTime)
 }
 
 // Test PutObject with custom checksums.
@@ -2319,7 +2330,7 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 	args := map[string]interface{}{
 		"bucketName": "",
 		"objectName": "",
-		"opts":       fmt.Sprintf("minio.PutObjectOptions{UserMetadata: metadata, Progress: progress Checksum: %v}", trailing),
+		"opts":       fmt.Sprintf("minio.PutObjectOptions{UserMetadata: metadata, Trailing: %v}", trailing),
 	}
 
 	if !isFullMode() {
@@ -2344,14 +2355,18 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 		return
 	}
 
-	hashMultiPart := func(b []byte, partSize int, hasher hash.Hash) string {
+	hashMultiPart := func(b []byte, partSize int, cs minio.ChecksumType) string {
 		r := bytes.NewReader(b)
+		hasher := cs.Hasher()
+		if cs.FullObjectRequested() {
+			partSize = len(b)
+		}
 		tmp := make([]byte, partSize)
 		parts := 0
 		var all []byte
 		for {
 			n, err := io.ReadFull(r, tmp)
-			if err != nil && err != io.ErrUnexpectedEOF {
+			if err != nil && err != io.ErrUnexpectedEOF && err != io.EOF {
 				logError(testName, function, args, startTime, "", "Calc crc failed", err)
 			}
 			if n == 0 {
@@ -2365,6 +2380,9 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 				break
 			}
 		}
+		if parts == 1 {
+			return base64.StdEncoding.EncodeToString(hasher.Sum(nil))
+		}
 		hasher.Reset()
 		hasher.Write(all)
 		return fmt.Sprintf("%s-%d", base64.StdEncoding.EncodeToString(hasher.Sum(nil)), parts)
@@ -2373,6 +2391,9 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 	tests := []struct {
 		cs minio.ChecksumType
 	}{
+		{cs: minio.ChecksumFullObjectCRC32},
+		{cs: minio.ChecksumFullObjectCRC32C},
+		{cs: minio.ChecksumCRC64NVME},
 		{cs: minio.ChecksumCRC32C},
 		{cs: minio.ChecksumCRC32},
 		{cs: minio.ChecksumSHA1},
@@ -2380,8 +2401,12 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 	}
 
 	for _, test := range tests {
-		bufSize := dataFileMap["datafile-129-MB"]
+		if os.Getenv("MINT_NO_FULL_OBJECT") != "" && test.cs.FullObjectRequested() {
+			continue
+		}
 
+		args["section"] = "prep"
+		bufSize := dataFileMap["datafile-129-MB"]
 		// Save the data
 		objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
 		args["objectName"] = objectName
@@ -2405,7 +2430,7 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 		reader.Close()
 		h := test.cs.Hasher()
 		h.Reset()
-		want := hashMultiPart(b, partSize, test.cs.Hasher())
+		want := hashMultiPart(b, partSize, test.cs)
 
 		var cs minio.ChecksumType
 		rd := io.Reader(io.NopCloser(bytes.NewReader(b)))
@@ -2413,7 +2438,9 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 			cs = test.cs
 			rd = bytes.NewReader(b)
 		}
+
 		// Set correct CRC.
+		args["section"] = "PutObject"
 		resp, err := c.PutObject(context.Background(), bucketName, objectName, rd, int64(bufSize), minio.PutObjectOptions{
 			DisableContentSha256: true,
 			DisableMultipart:     false,
@@ -2427,7 +2454,7 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 			return
 		}
 
-		switch test.cs {
+		switch test.cs.Base() {
 		case minio.ChecksumCRC32C:
 			cmpChecksum(resp.ChecksumCRC32C, want)
 		case minio.ChecksumCRC32:
@@ -2436,15 +2463,41 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 			cmpChecksum(resp.ChecksumSHA1, want)
 		case minio.ChecksumSHA256:
 			cmpChecksum(resp.ChecksumSHA256, want)
+		case minio.ChecksumCRC64NVME:
+			cmpChecksum(resp.ChecksumCRC64NVME, want)
 		}
 
+		args["section"] = "HeadObject"
+		st, err := c.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{Checksum: true})
+		if err != nil {
+			logError(testName, function, args, startTime, "", "StatObject failed", err)
+			return
+		}
+		switch test.cs.Base() {
+		case minio.ChecksumCRC32C:
+			cmpChecksum(st.ChecksumCRC32C, want)
+		case minio.ChecksumCRC32:
+			cmpChecksum(st.ChecksumCRC32, want)
+		case minio.ChecksumSHA1:
+			cmpChecksum(st.ChecksumSHA1, want)
+		case minio.ChecksumSHA256:
+			cmpChecksum(st.ChecksumSHA256, want)
+		case minio.ChecksumCRC64NVME:
+			cmpChecksum(st.ChecksumCRC64NVME, want)
+		}
+
+		args["section"] = "GetObjectAttributes"
 		s, err := c.GetObjectAttributes(context.Background(), bucketName, objectName, minio.ObjectAttributesOptions{})
 		if err != nil {
 			logError(testName, function, args, startTime, "", "GetObjectAttributes failed", err)
 			return
 		}
-		want = want[:strings.IndexByte(want, '-')]
+
+		if strings.ContainsRune(want, '-') {
+			want = want[:strings.IndexByte(want, '-')]
+		}
 		switch test.cs {
+		// Full Object CRC does not return anything with GetObjectAttributes
 		case minio.ChecksumCRC32C:
 			cmpChecksum(s.Checksum.ChecksumCRC32C, want)
 		case minio.ChecksumCRC32:
@@ -2460,13 +2513,14 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 		gopts.PartNumber = 2
 
 		// We cannot use StatObject, since it ignores partnumber.
+		args["section"] = "GetObject-Part"
 		r, err := c.GetObject(context.Background(), bucketName, objectName, gopts)
 		if err != nil {
 			logError(testName, function, args, startTime, "", "GetObject failed", err)
 			return
 		}
 		io.Copy(io.Discard, r)
-		st, err := r.Stat()
+		st, err = r.Stat()
 		if err != nil {
 			logError(testName, function, args, startTime, "", "Stat failed", err)
 			return
@@ -2478,6 +2532,7 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 		want = base64.StdEncoding.EncodeToString(h.Sum(nil))
 
 		switch test.cs {
+		// Full Object CRC does not return any part CRC for whatever reason.
 		case minio.ChecksumCRC32C:
 			cmpChecksum(st.ChecksumCRC32C, want)
 		case minio.ChecksumCRC32:
@@ -2486,12 +2541,17 @@ func testPutMultipartObjectWithChecksums(trailing bool) {
 			cmpChecksum(st.ChecksumSHA1, want)
 		case minio.ChecksumSHA256:
 			cmpChecksum(st.ChecksumSHA256, want)
+		case minio.ChecksumCRC64NVME:
+			// AWS doesn't return part checksum, but may in the future.
+			if st.ChecksumCRC64NVME != "" {
+				cmpChecksum(st.ChecksumCRC64NVME, want)
+			}
 		}
 
 		delete(args, "metadata")
+		delete(args, "section")
+		logSuccess(testName, function, args, startTime)
 	}
-
-	logSuccess(testName, function, args, startTime)
 }
 
 // Test PutObject with trailing checksums.
@@ -2688,9 +2748,8 @@ func testTrailingChecksums() {
 		}
 
 		delete(args, "metadata")
+		logSuccess(testName, function, args, startTime)
 	}
-
-	logSuccess(testName, function, args, startTime)
 }
 
 // Test PutObject with custom checksums.
@@ -5324,21 +5383,11 @@ func testPresignedPostPolicyWrongFile() {
 
 	defer cleanupBucket(bucketName, c)
 
-	// Generate 33K of data.
-	reader := getDataReader("datafile-33-kB")
-	defer reader.Close()
-
 	objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
 	// Azure requires the key to not start with a number
 	metadataKey := randString(60, rand.NewSource(time.Now().UnixNano()), "user")
 	metadataValue := randString(60, rand.NewSource(time.Now().UnixNano()), "")
 
-	buf, err := io.ReadAll(reader)
-	if err != nil {
-		logError(testName, function, args, startTime, "", "ReadAll failed", err)
-		return
-	}
-
 	policy := minio.NewPostPolicy()
 	policy.SetBucket(bucketName)
 	policy.SetKey(objectName)
@@ -5347,8 +5396,8 @@ func testPresignedPostPolicyWrongFile() {
 	policy.SetContentLengthRange(10, 1024*1024)
 	policy.SetUserMetadata(metadataKey, metadataValue)
 
-	// Add CRC32C of the 33kB file that the policy will explicitly allow.
-	checksum := minio.ChecksumCRC32C.ChecksumBytes(buf)
+	// Add CRC32C of some data that the policy will explicitly allow.
+	checksum := minio.ChecksumCRC32C.ChecksumBytes([]byte{0x01, 0x02, 0x03})
 	err = policy.SetChecksum(checksum)
 	if err != nil {
 		logError(testName, function, args, startTime, "", "SetChecksum failed", err)
@@ -5363,7 +5412,7 @@ func testPresignedPostPolicyWrongFile() {
 		return
 	}
 
-	// At this stage, we have a policy that allows us to upload datafile-33-kB.
+	// At this stage, we have a policy that allows us to upload for a specific checksum.
 	// Test that uploading datafile-10-kB, with a different checksum, fails as expected
 	filePath := getMintDataDirFilePath("datafile-10-kB")
 	if filePath == "" {
@@ -5456,7 +5505,7 @@ func testPresignedPostPolicyWrongFile() {
 	// Normalize the response body, because S3 uses quotes around the policy condition components
 	// in the error message, MinIO does not.
 	resBodyStr := strings.ReplaceAll(string(resBody), `"`, "")
-	if !strings.Contains(resBodyStr, "Policy Condition failed: [eq, $x-amz-checksum-crc32c, aHnJMw==]") {
+	if !strings.Contains(resBodyStr, "Policy Condition failed: [eq, $x-amz-checksum-crc32c, 8TDyHg=") {
 		logError(testName, function, args, startTime, "", "Unexpected response body", errors.New(resBodyStr))
 		return
 	}
diff --git a/pkg/credentials/chain_test.go b/pkg/credentials/chain_test.go
index 280b37c..58a8981 100644
--- a/pkg/credentials/chain_test.go
+++ b/pkg/credentials/chain_test.go
@@ -33,6 +33,11 @@ func (s *testCredProvider) Retrieve() (Value, error) {
 	return s.creds, s.err
 }
 
+func (s *testCredProvider) RetrieveWithCredContext(_ *CredContext) (Value, error) {
+	s.expired = false
+	return s.creds, s.err
+}
+
 func (s *testCredProvider) IsExpired() bool {
 	return s.expired
 }
@@ -59,7 +64,7 @@ func TestChainGet(t *testing.T) {
 		},
 	}
 
-	creds, err := p.Retrieve()
+	creds, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -95,7 +100,7 @@ func TestChainIsExpired(t *testing.T) {
 		t.Fatal("Expected expired to be true before any Retrieve")
 	}
 
-	_, err := p.Retrieve()
+	_, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -112,7 +117,7 @@ func TestChainWithNoProvider(t *testing.T) {
 	if !p.IsExpired() {
 		t.Fatal("Expected to be expired with no providers")
 	}
-	_, err := p.Retrieve()
+	_, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		if err.Error() != "No valid providers found []" {
 			t.Error(err)
@@ -136,7 +141,7 @@ func TestChainProviderWithNoValidProvider(t *testing.T) {
 		t.Fatal("Expected to be expired with no providers")
 	}
 
-	_, err := p.Retrieve()
+	_, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		if err.Error() != "No valid providers found [FirstError SecondError]" {
 			t.Error(err)
diff --git a/pkg/credentials/credentials_test.go b/pkg/credentials/credentials_test.go
index 8283450..b387041 100644
--- a/pkg/credentials/credentials_test.go
+++ b/pkg/credentials/credentials_test.go
@@ -33,6 +33,11 @@ func (s *credProvider) Retrieve() (Value, error) {
 	return s.creds, s.err
 }
 
+func (s *credProvider) RetrieveWithCredContext(_ *CredContext) (Value, error) {
+	s.expired = false
+	return s.creds, s.err
+}
+
 func (s *credProvider) IsExpired() bool {
 	return s.expired
 }
@@ -47,7 +52,7 @@ func TestCredentialsGet(t *testing.T) {
 		expired: true,
 	})
 
-	creds, err := c.Get()
+	creds, err := c.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -65,7 +70,7 @@ func TestCredentialsGet(t *testing.T) {
 func TestCredentialsGetWithError(t *testing.T) {
 	c := New(&credProvider{err: errors.New("Custom error")})
 
-	_, err := c.Get()
+	_, err := c.GetWithContext(defaultCredContext)
 	if err != nil {
 		if err.Error() != "Custom error" {
 			t.Errorf("Expected \"Custom error\", got %s", err.Error())
diff --git a/pkg/credentials/env_test.go b/pkg/credentials/env_test.go
index 5e9240e..5b504c5 100644
--- a/pkg/credentials/env_test.go
+++ b/pkg/credentials/env_test.go
@@ -34,7 +34,7 @@ func TestEnvAWSRetrieve(t *testing.T) {
 		t.Error("Expect creds to be expired before retrieve.")
 	}
 
-	creds, err := e.Retrieve()
+	creds, err := e.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -63,7 +63,7 @@ func TestEnvAWSRetrieve(t *testing.T) {
 		SignerType:      SignatureV4,
 	}
 
-	creds, err = e.Retrieve()
+	creds, err = e.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -84,7 +84,7 @@ func TestEnvMinioRetrieve(t *testing.T) {
 		t.Error("Expect creds to be expired before retrieve.")
 	}
 
-	creds, err := e.Retrieve()
+	creds, err := e.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/pkg/credentials/file_test.go b/pkg/credentials/file_test.go
index fab48dc..3136a45 100644
--- a/pkg/credentials/file_test.go
+++ b/pkg/credentials/file_test.go
@@ -31,7 +31,7 @@ func TestFileAWS(t *testing.T) {
 	os.Clearenv()
 
 	creds := NewFileAWSCredentials("credentials.sample", "")
-	credValues, err := creds.Get()
+	credValues, err := creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -48,7 +48,7 @@ func TestFileAWS(t *testing.T) {
 
 	os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "credentials.sample")
 	creds = NewFileAWSCredentials("", "")
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -70,7 +70,7 @@ func TestFileAWS(t *testing.T) {
 
 	os.Setenv("AWS_SHARED_CREDENTIALS_FILE", filepath.Join(wd, "credentials.sample"))
 	creds = NewFileAWSCredentials("", "")
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -89,7 +89,7 @@ func TestFileAWS(t *testing.T) {
 	os.Setenv("AWS_PROFILE", "no_token")
 
 	creds = NewFileAWSCredentials("credentials.sample", "")
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -104,7 +104,7 @@ func TestFileAWS(t *testing.T) {
 	os.Clearenv()
 
 	creds = NewFileAWSCredentials("credentials.sample", "no_token")
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -117,7 +117,7 @@ func TestFileAWS(t *testing.T) {
 	}
 
 	creds = NewFileAWSCredentials("credentials-non-existent.sample", "no_token")
-	_, err = creds.Get()
+	_, err = creds.GetWithContext(defaultCredContext)
 	if !os.IsNotExist(err) {
 		t.Errorf("Expected open non-existent.json: no such file or directory, got %s", err)
 	}
@@ -128,7 +128,7 @@ func TestFileAWS(t *testing.T) {
 	os.Clearenv()
 
 	creds = NewFileAWSCredentials("credentials.sample", "with_process")
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -151,7 +151,7 @@ func TestFileMinioClient(t *testing.T) {
 	os.Clearenv()
 
 	creds := NewFileMinioClient("config.json.sample", "")
-	credValues, err := creds.Get()
+	credValues, err := creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -170,7 +170,7 @@ func TestFileMinioClient(t *testing.T) {
 	os.Setenv("MINIO_ALIAS", "play")
 
 	creds = NewFileMinioClient("config.json.sample", "")
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -188,7 +188,7 @@ func TestFileMinioClient(t *testing.T) {
 	os.Clearenv()
 
 	creds = NewFileMinioClient("config.json.sample", "play")
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -204,7 +204,7 @@ func TestFileMinioClient(t *testing.T) {
 	}
 
 	creds = NewFileMinioClient("non-existent.json", "play")
-	_, err = creds.Get()
+	_, err = creds.GetWithContext(defaultCredContext)
 	if !os.IsNotExist(err) {
 		t.Errorf("Expected open non-existent.json: no such file or directory, got %s", err)
 	}
diff --git a/pkg/credentials/iam_aws_test.go b/pkg/credentials/iam_aws_test.go
index 4089c13..69c794a 100644
--- a/pkg/credentials/iam_aws_test.go
+++ b/pkg/credentials/iam_aws_test.go
@@ -156,7 +156,7 @@ func initStsTestServer(expireOn string) *httptest.Server {
 
 func TestIAMMalformedEndpoint(t *testing.T) {
 	creds := NewIAM("%%%%")
-	_, err := creds.Get()
+	_, err := creds.GetWithContext(defaultCredContext)
 	if err == nil {
 		t.Fatal("Unexpected should fail here")
 	}
@@ -168,7 +168,7 @@ func TestIAMFailServer(t *testing.T) {
 
 	creds := NewIAM(server.URL)
 
-	_, err := creds.Get()
+	_, err := creds.GetWithContext(defaultCredContext)
 	if err == nil {
 		t.Fatal("Unexpected should fail here")
 	}
@@ -182,7 +182,7 @@ func TestIAMNoRoles(t *testing.T) {
 	defer server.Close()
 
 	creds := NewIAM(server.URL)
-	_, err := creds.Get()
+	_, err := creds.GetWithContext(defaultCredContext)
 	if err == nil {
 		t.Fatal("Unexpected should fail here")
 	}
@@ -196,11 +196,10 @@ func TestIAM(t *testing.T) {
 	defer server.Close()
 
 	p := &IAM{
-		Client:   http.DefaultClient,
 		Endpoint: server.URL,
 	}
 
-	creds, err := p.Retrieve()
+	creds, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -227,11 +226,10 @@ func TestIAMFailAssume(t *testing.T) {
 	defer server.Close()
 
 	p := &IAM{
-		Client:   http.DefaultClient,
 		Endpoint: server.URL,
 	}
 
-	_, err := p.Retrieve()
+	_, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err == nil {
 		t.Fatal("Unexpected success, should fail")
 	}
@@ -245,7 +243,6 @@ func TestIAMIsExpired(t *testing.T) {
 	defer server.Close()
 
 	p := &IAM{
-		Client:   http.DefaultClient,
 		Endpoint: server.URL,
 	}
 	p.CurrentTime = func() time.Time {
@@ -256,7 +253,7 @@ func TestIAMIsExpired(t *testing.T) {
 		t.Error("Expected creds to be expired before retrieve.")
 	}
 
-	_, err := p.Retrieve()
+	_, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -278,11 +275,10 @@ func TestEcsTask(t *testing.T) {
 	server := initEcsTaskTestServer("2014-12-16T01:51:37Z")
 	defer server.Close()
 	p := &IAM{
-		Client:   http.DefaultClient,
 		Endpoint: server.URL,
 	}
 	os.Setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/v2/credentials?id=task_credential_id")
-	creds, err := p.Retrieve()
+	creds, err := p.RetrieveWithCredContext(defaultCredContext)
 	os.Unsetenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
 	if err != nil {
 		t.Errorf("Unexpected failure %s", err)
@@ -307,12 +303,10 @@ func TestEcsTask(t *testing.T) {
 func TestEcsTaskFullURI(t *testing.T) {
 	server := initEcsTaskTestServer("2014-12-16T01:51:37Z")
 	defer server.Close()
-	p := &IAM{
-		Client: http.DefaultClient,
-	}
+	p := &IAM{}
 	os.Setenv("AWS_CONTAINER_CREDENTIALS_FULL_URI",
 		fmt.Sprintf("%s%s", server.URL, "/v2/credentials?id=task_credential_id"))
-	creds, err := p.Retrieve()
+	creds, err := p.RetrieveWithCredContext(defaultCredContext)
 	os.Unsetenv("AWS_CONTAINER_CREDENTIALS_FULL_URI")
 	if err != nil {
 		t.Errorf("Unexpected failure %s", err)
@@ -338,7 +332,6 @@ func TestSts(t *testing.T) {
 	server := initStsTestServer("2014-12-16T01:51:37Z")
 	defer server.Close()
 	p := &IAM{
-		Client:   http.DefaultClient,
 		Endpoint: server.URL,
 	}
 
@@ -352,7 +345,7 @@ func TestSts(t *testing.T) {
 
 	os.Setenv("AWS_WEB_IDENTITY_TOKEN_FILE", f.Name())
 	os.Setenv("AWS_ROLE_ARN", "arn:aws:sts::123456789012:assumed-role/FederatedWebIdentityRole/app1")
-	creds, err := p.Retrieve()
+	creds, err := p.RetrieveWithCredContext(defaultCredContext)
 	os.Unsetenv("AWS_WEB_IDENTITY_TOKEN_FILE")
 	os.Unsetenv("AWS_ROLE_ARN")
 	if err != nil {
@@ -379,7 +372,6 @@ func TestStsCn(t *testing.T) {
 	server := initStsTestServer("2014-12-16T01:51:37Z")
 	defer server.Close()
 	p := &IAM{
-		Client:   http.DefaultClient,
 		Endpoint: server.URL,
 	}
 
@@ -394,7 +386,7 @@ func TestStsCn(t *testing.T) {
 	os.Setenv("AWS_REGION", "cn-northwest-1")
 	os.Setenv("AWS_WEB_IDENTITY_TOKEN_FILE", f.Name())
 	os.Setenv("AWS_ROLE_ARN", "arn:aws:sts::123456789012:assumed-role/FederatedWebIdentityRole/app1")
-	creds, err := p.Retrieve()
+	creds, err := p.RetrieveWithCredContext(defaultCredContext)
 	os.Unsetenv("AWS_WEB_IDENTITY_TOKEN_FILE")
 	os.Unsetenv("AWS_ROLE_ARN")
 	if err != nil {
@@ -420,10 +412,9 @@ func TestStsCn(t *testing.T) {
 func TestIMDSv1Blocked(t *testing.T) {
 	server := initIMDSv2Server("2014-12-16T01:51:37Z", false)
 	p := &IAM{
-		Client:   http.DefaultClient,
 		Endpoint: server.URL,
 	}
-	_, err := p.Retrieve()
+	_, err := p.RetrieveWithCredContext(defaultCredContext)
 	if err != nil {
 		t.Errorf("Unexpected IMDSv2 failure %s", err)
 	}
diff --git a/pkg/credentials/static_test.go b/pkg/credentials/static_test.go
index 65bec05..a70cf36 100644
--- a/pkg/credentials/static_test.go
+++ b/pkg/credentials/static_test.go
@@ -21,7 +21,7 @@ import "testing"
 
 func TestStaticGet(t *testing.T) {
 	creds := NewStatic("UXHW", "SECRET", "", SignatureV4)
-	credValues, err := creds.Get()
+	credValues, err := creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -46,7 +46,7 @@ func TestStaticGet(t *testing.T) {
 	}
 
 	creds = NewStatic("", "", "", SignatureDefault)
-	credValues, err = creds.Get()
+	credValues, err = creds.GetWithContext(defaultCredContext)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/pkg/s3utils/utils_test.go b/pkg/s3utils/utils_test.go
index 9d545f4..3bcb7a6 100644
--- a/pkg/s3utils/utils_test.go
+++ b/pkg/s3utils/utils_test.go
@@ -27,114 +27,59 @@ import (
 // Tests get region from host URL.
 func TestGetRegionFromURL(t *testing.T) {
 	testCases := []struct {
-		u              url.URL
+		u              string
 		expectedRegion string
 	}{
-		{
-			u:              url.URL{Host: "storage.googleapis.com"},
-			expectedRegion: "",
-		},
-		{
-			u:              url.URL{Host: "s3.cn-north-1.amazonaws.com.cn"},
-			expectedRegion: "cn-north-1",
-		},
-		{
-			u:              url.URL{Host: "s3.dualstack.cn-north-1.amazonaws.com.cn"},
-			expectedRegion: "cn-north-1",
-		},
-		{
-			u:              url.URL{Host: "s3.cn-northwest-1.amazonaws.com.cn"},
-			expectedRegion: "cn-northwest-1",
-		},
-		{
-			u:              url.URL{Host: "s3.dualstack.cn-northwest-1.amazonaws.com.cn"},
-			expectedRegion: "cn-northwest-1",
-		},
-		{
-			u:              url.URL{Host: "s3-fips-us-gov-west-1.amazonaws.com"},
-			expectedRegion: "us-gov-west-1",
-		},
-		{
-			u:              url.URL{Host: "s3-fips.us-gov-west-1.amazonaws.com"},
-			expectedRegion: "us-gov-west-1",
-		},
-		{
-			u:              url.URL{Host: "s3-fips.us-gov-east-1.amazonaws.com"},
-			expectedRegion: "us-gov-east-1",
-		},
-		{
-			u:              url.URL{Host: "s3-us-gov-west-1.amazonaws.com"},
-			expectedRegion: "us-gov-west-1",
-		},
-		{
-			u:              url.URL{Host: "192.168.1.1"},
-			expectedRegion: "",
-		},
-		{
-			u:              url.URL{Host: "s3-eu-west-1.amazonaws.com"},
-			expectedRegion: "eu-west-1",
-		},
-		{
-			u:              url.URL{Host: "s3.eu-west-1.amazonaws.com"},
-			expectedRegion: "eu-west-1",
-		},
-		{
-			u:              url.URL{Host: "s3.dualstack.eu-west-1.amazonaws.com"},
-			expectedRegion: "eu-west-1",
-		},
-		{
-			u:              url.URL{Host: "s3.amazonaws.com"},
-			expectedRegion: "",
-		},
-		{
-			u:              url.URL{Host: "s3-external-1.amazonaws.com"},
-			expectedRegion: "",
-		},
-		{
-			u: url.URL{
-				Host: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.us-west-2.amazonaws.com",
-			},
-			expectedRegion: "",
-		},
-		{
-			u: url.URL{
-				Host: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.amazonaws.com",
-			},
-			expectedRegion: "",
-		},
-		{
-			u: url.URL{
-				Host: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.amazonaws.com.cn",
-			},
-		},
-		{
-			u: url.URL{
-				Host: "bucket.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com",
-			},
-			expectedRegion: "us-east-1",
-		},
-		{
-			u: url.URL{
-				Host: "accesspoint.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com",
-			},
-			expectedRegion: "us-east-1",
-		},
-		{
-			u: url.URL{
-				Host: "s3-fips.us-east-1.amazonaws.com",
-			},
-			expectedRegion: "us-east-1",
-		},
-		{
-			u: url.URL{
-				Host: "s3-fips.dualstack.us-west-1.amazonaws.com",
-			},
-			expectedRegion: "us-west-1",
-		},
+		{u: "storage.googleapis.com", expectedRegion: ""},
+		{u: "s3.cn-north-1.amazonaws.com.cn", expectedRegion: "cn-north-1"},
+		{u: "s3.dualstack.cn-north-1.amazonaws.com.cn", expectedRegion: "cn-north-1"},
+		{u: "s3.cn-northwest-1.amazonaws.com.cn", expectedRegion: "cn-northwest-1"},
+		{u: "s3.dualstack.cn-northwest-1.amazonaws.com.cn", expectedRegion: "cn-northwest-1"},
+		{u: "s3-fips-us-gov-west-1.amazonaws.com", expectedRegion: "us-gov-west-1"},
+		{u: "s3-fips.us-gov-west-1.amazonaws.com", expectedRegion: "us-gov-west-1"},
+		{u: "s3-fips.us-gov-east-1.amazonaws.com", expectedRegion: "us-gov-east-1"},
+		{u: "s3-us-gov-west-1.amazonaws.com", expectedRegion: "us-gov-west-1"},
+		{u: "192.168.1.1", expectedRegion: ""},
+		{u: "s3-eu-west-1.amazonaws.com", expectedRegion: "eu-west-1"},
+		{u: "s3.eu-west-1.amazonaws.com", expectedRegion: "eu-west-1"},
+		{u: "s3.dualstack.eu-west-1.amazonaws.com", expectedRegion: "eu-west-1"},
+		{u: "s3.amazonaws.com", expectedRegion: ""},
+		{u: "s3-external-1.amazonaws.com", expectedRegion: ""},
+		{u: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.us-west-2.amazonaws.com", expectedRegion: ""},
+		{u: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.amazonaws.com", expectedRegion: ""},
+		{u: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.amazonaws.com.cn", expectedRegion: ""},
+		{u: "bucket.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com", expectedRegion: "us-east-1"},
+		{u: "accesspoint.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com", expectedRegion: "us-east-1"},
+		{u: "s3-fips.us-east-1.amazonaws.com", expectedRegion: "us-east-1"},
+		{u: "s3-fips.dualstack.us-west-1.amazonaws.com", expectedRegion: "us-west-1"},
+
+		// Test cases with port numbers.
+		{u: "storage.googleapis.com:80", expectedRegion: ""},
+		{u: "s3.cn-north-1.amazonaws.com.cn:80", expectedRegion: "cn-north-1"},
+		{u: "s3.dualstack.cn-north-1.amazonaws.com.cn:80", expectedRegion: "cn-north-1"},
+		{u: "s3.cn-northwest-1.amazonaws.com.cn:80", expectedRegion: "cn-northwest-1"},
+		{u: "s3.dualstack.cn-northwest-1.amazonaws.com.cn:80", expectedRegion: "cn-northwest-1"},
+		{u: "s3-fips-us-gov-west-1.amazonaws.com:80", expectedRegion: "us-gov-west-1"},
+		{u: "s3-fips.us-gov-west-1.amazonaws.com:80", expectedRegion: "us-gov-west-1"},
+		{u: "s3-fips.us-gov-east-1.amazonaws.com:80", expectedRegion: "us-gov-east-1"},
+		{u: "s3-us-gov-west-1.amazonaws.com:80", expectedRegion: "us-gov-west-1"},
+		{u: "192.168.1.1:80", expectedRegion: ""},
+		{u: "s3-eu-west-1.amazonaws.com:80", expectedRegion: "eu-west-1"},
+		{u: "s3.eu-west-1.amazonaws.com:80", expectedRegion: "eu-west-1"},
+		{u: "s3.dualstack.eu-west-1.amazonaws.com:80", expectedRegion: "eu-west-1"},
+		{u: "s3.amazonaws.com:80", expectedRegion: ""},
+		{u: "s3-external-1.amazonaws.com:80", expectedRegion: ""},
+		{u: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.us-west-2.amazonaws.com:80", expectedRegion: ""},
+		{u: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.amazonaws.com:80", expectedRegion: ""},
+		{u: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.amazonaws.com.cn:80", expectedRegion: ""},
+		{u: "bucket.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com:80", expectedRegion: "us-east-1"},
+		{u: "accesspoint.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com:80", expectedRegion: "us-east-1"},
+		{u: "s3-fips.us-east-1.amazonaws.com:80", expectedRegion: "us-east-1"},
+		{u: "s3-fips.dualstack.us-west-1.amazonaws.com:80", expectedRegion: "us-west-1"},
 	}
 
 	for i, testCase := range testCases {
-		region := GetRegionFromURL(testCase.u)
+		region := GetRegionFromURL(url.URL{Host: testCase.u})
 		if testCase.expectedRegion != region {
 			t.Errorf("Test %d: Expected region %s, got %s", i+1, testCase.expectedRegion, region)
 		}
diff --git a/utils_test.go b/utils_test.go
index 0e2ed08..9c111de 100644
--- a/utils_test.go
+++ b/utils_test.go
@@ -20,6 +20,7 @@ package minio
 import (
 	"errors"
 	"fmt"
+	"math/rand"
 	"net/url"
 	"testing"
 	"time"
@@ -429,3 +430,43 @@ func TestIsCustomQueryValue(t *testing.T) {
 		}
 	}
 }
+
+func TestFullObjectChecksum64(t *testing.T) {
+	tests := []ChecksumType{
+		ChecksumCRC32,
+		ChecksumCRC32C,
+		ChecksumCRC64NVME,
+	}
+	for _, cs := range tests {
+		t.Run(cs.String(), func(t *testing.T) {
+			b := make([]byte, 1024000)
+			rng := rand.New(rand.NewSource(time.Now().UnixNano()))
+			rng.Read(b)
+			sum := cs.EncodeToString
+			want := sum(b)
+			var parts []ObjectPart
+			for len(b) > 0 {
+				sz := rng.Intn(len(b) / 2)
+				if len(b)-sz < 1024 {
+					sz = len(b)
+				}
+				switch cs {
+				case ChecksumCRC32:
+					parts = append(parts, ObjectPart{PartNumber: len(parts) + 1, ChecksumCRC32: cs.EncodeToString(b[:sz]), Size: int64(sz)})
+				case ChecksumCRC32C:
+					parts = append(parts, ObjectPart{PartNumber: len(parts) + 1, ChecksumCRC32C: cs.EncodeToString(b[:sz]), Size: int64(sz)})
+				case ChecksumCRC64NVME:
+					parts = append(parts, ObjectPart{PartNumber: len(parts) + 1, ChecksumCRC64NVME: cs.EncodeToString(b[:sz]), Size: int64(sz)})
+				}
+				b = b[sz:]
+			}
+			gotCRC, err := cs.FullObjectChecksum(parts)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if gotCRC.Encoded() != want {
+				t.Errorf("Checksum %v does not match the expected CRC got:%s want:%s", cs.String(), gotCRC.Encoded(), want)
+			}
+		})
+	}
+}