diff --git a/api-put-object-multipart.go b/api-put-object-multipart.go index 342a8dc2b..abcbd2981 100644 --- a/api-put-object-multipart.go +++ b/api-put-object-multipart.go @@ -104,7 +104,7 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj // Choose hash algorithms to be calculated by hashCopyN, // avoid sha256 with non-v4 signature request or // HTTPS connection. - hashAlgos, hashSums := c.hashMaterials(opts.SendContentMd5) + hashAlgos, hashSums := c.hashMaterials(opts.SendContentMd5, !opts.DisableContentSha256) length, rErr := readFull(reader, buf) if rErr == io.EOF && partNumber > 1 { @@ -140,7 +140,9 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj // Proceed to upload the part. objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, - md5Base64, sha256Hex, int64(length), opts.ServerSideEncryption) + md5Base64, sha256Hex, int64(length), + opts.ServerSideEncryption, + !opts.DisableContentSha256) if uerr != nil { return UploadInfo{}, uerr } @@ -241,7 +243,7 @@ func (c *Client) initiateMultipartUpload(ctx context.Context, bucketName, object // uploadPart - Uploads a part in a multipart upload. func (c *Client) uploadPart(ctx context.Context, bucketName, objectName, uploadID string, reader io.Reader, - partNumber int, md5Base64, sha256Hex string, size int64, sse encrypt.ServerSide, + partNumber int, md5Base64, sha256Hex string, size int64, sse encrypt.ServerSide, streamSha256 bool, ) (ObjectPart, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { @@ -289,6 +291,7 @@ func (c *Client) uploadPart(ctx context.Context, bucketName, objectName, uploadI contentLength: size, contentMD5Base64: md5Base64, contentSHA256Hex: sha256Hex, + streamSha256: streamSha256, } // Execute PUT on each part. diff --git a/api-put-object-streaming.go b/api-put-object-streaming.go index 2497aecf3..98354900a 100644 --- a/api-put-object-streaming.go +++ b/api-put-object-streaming.go @@ -186,7 +186,10 @@ func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketN // Proceed to upload the part. objPart, err := c.uploadPart(ctx, bucketName, objectName, uploadID, hookReader, uploadReq.PartNum, - "", "", partSize, opts.ServerSideEncryption) + "", "", partSize, + opts.ServerSideEncryption, + !opts.DisableContentSha256, + ) if err != nil { uploadedPartsCh <- uploadedPartRes{ Error: err, @@ -322,7 +325,10 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, io.LimitReader(hookReader, partSize), - partNumber, md5Base64, "", partSize, opts.ServerSideEncryption) + partNumber, md5Base64, "", partSize, + opts.ServerSideEncryption, + !opts.DisableContentSha256, + ) if uerr != nil { return UploadInfo{}, uerr } @@ -452,6 +458,7 @@ func (c *Client) putObjectDo(ctx context.Context, bucketName, objectName string, contentLength: size, contentMD5Base64: md5Base64, contentSHA256Hex: sha256Hex, + streamSha256: !opts.DisableContentSha256, } if opts.Internal.SourceVersionID != "" { if opts.Internal.SourceVersionID != nullVersionID { diff --git a/api-put-object.go b/api-put-object.go index 181f1a943..9328fb6c1 100644 --- a/api-put-object.go +++ b/api-put-object.go @@ -84,6 +84,7 @@ type PutObjectOptions struct { PartSize uint64 LegalHold LegalHoldStatus SendContentMd5 bool + DisableContentSha256 bool DisableMultipart bool Internal AdvancedPutOptions } @@ -344,7 +345,10 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam // Proceed to upload the part. objPart, uerr := c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, - md5Base64, "", int64(length), opts.ServerSideEncryption) + md5Base64, "", int64(length), + opts.ServerSideEncryption, + !opts.DisableContentSha256, + ) if uerr != nil { return UploadInfo{}, uerr } diff --git a/api.go b/api.go index a73d110cc..a6d622044 100644 --- a/api.go +++ b/api.go @@ -315,14 +315,16 @@ func (c *Client) SetS3TransferAccelerate(accelerateEndpoint string) { // - For signature v4 request if the connection is insecure compute only sha256. // - For signature v4 request if the connection is secure compute only md5. // - For anonymous request compute md5. -func (c *Client) hashMaterials(isMd5Requested bool) (hashAlgos map[string]md5simd.Hasher, hashSums map[string][]byte) { +func (c *Client) hashMaterials(isMd5Requested, isSha256Requested bool) (hashAlgos map[string]md5simd.Hasher, hashSums map[string][]byte) { hashSums = make(map[string][]byte) hashAlgos = make(map[string]md5simd.Hasher) if c.overrideSignerType.IsV4() { if c.secure { hashAlgos["md5"] = c.md5Hasher() } else { - hashAlgos["sha256"] = c.sha256Hasher() + if isSha256Requested { + hashAlgos["sha256"] = c.sha256Hasher() + } } } else { if c.overrideSignerType.IsAnonymous() { @@ -417,6 +419,7 @@ type requestMetadata struct { contentLength int64 contentMD5Base64 string // carries base64 encoded md5sum contentSHA256Hex string // carries hex encoded sha256sum + streamSha256 bool } // dumpHTTP - dump HTTP request and response. @@ -812,7 +815,7 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request case signerType.IsV2(): // Add signature version '2' authorization header. req = signer.SignV2(*req, accessKeyID, secretAccessKey, isVirtualHost) - case metadata.objectName != "" && metadata.queryValues == nil && method == http.MethodPut && metadata.customHeader.Get("X-Amz-Copy-Source") == "" && !c.secure: + case metadata.streamSha256 && !c.secure: // Streaming signature is used by default for a PUT object request. Additionally we also // look if the initialized client is secure, if yes then we don't need to perform // streaming signature. diff --git a/core.go b/core.go index c2a90239f..148671eec 100644 --- a/core.go +++ b/core.go @@ -88,7 +88,8 @@ func (c Core) ListMultipartUploads(ctx context.Context, bucket, prefix, keyMarke // PutObjectPart - Upload an object part. func (c Core) PutObjectPart(ctx context.Context, bucket, object, uploadID string, partID int, data io.Reader, size int64, md5Base64, sha256Hex string, sse encrypt.ServerSide) (ObjectPart, error) { - return c.uploadPart(ctx, bucket, object, uploadID, data, partID, md5Base64, sha256Hex, size, sse) + streamSha256 := true + return c.uploadPart(ctx, bucket, object, uploadID, data, partID, md5Base64, sha256Hex, size, sse, streamSha256) } // ListObjectParts - List uploaded parts of an incomplete upload.x