From 7025898c83a540c9c8b65bcf3afaa2c81b3d191f Mon Sep 17 00:00:00 2001 From: yangpeng Date: Mon, 29 Jan 2024 16:07:09 +0800 Subject: [PATCH] refine complete multipart upload --- oss/bucket_test.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++ oss/const.go | 1 + oss/multipart.go | 20 ++++++++--------- oss/option.go | 5 +++++ 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/oss/bucket_test.go b/oss/bucket_test.go index 4ae3e17..86be4cc 100644 --- a/oss/bucket_test.go +++ b/oss/bucket_test.go @@ -5318,6 +5318,60 @@ func (s *OssBucketSuite) TestVersioningCompleteMultipartUpload(c *C) { ForceDeleteBucket(client, bucketName, c) } +func (s *OssBucketSuite) TestCompleteMultipartUploadWithCompleteAll(c *C) { + // create a bucket with default proprety + client, err := New(endpoint, accessID, accessKey) + c.Assert(err, IsNil) + + bucketName := bucketNamePrefix + RandLowStr(6) + err = client.CreateBucket(bucketName) + c.Assert(err, IsNil) + + bucket, err := client.Bucket(bucketName) + + objectName := objectNamePrefix + RandStr(8) + var fileName = "test-file-" + RandStr(8) + content := RandStr(500 * 1024) + CreateFile(fileName, content, c) + + chunks, err := SplitFileByPartNum(fileName, 3) + c.Assert(err, IsNil) + + options := []Option{ + Expires(futureDate), Meta("my", "myprop"), + } + + fd, err := os.Open(fileName) + c.Assert(err, IsNil) + defer fd.Close() + + imur, err := bucket.InitiateMultipartUpload(objectName, options...) + c.Assert(err, IsNil) + var parts []UploadPart + for _, chunk := range chunks { + fd.Seek(chunk.Offset, os.SEEK_SET) + part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number) + c.Assert(err, IsNil) + parts = append(parts, part) + } + + var respHeader http.Header + _, err = bucket.CompleteMultipartUpload(imur, parts, GetResponseHeader(&respHeader), CompleteAll("yes")) + c.Assert(err, NotNil) + + _, err = bucket.CompleteMultipartUpload(imur, nil, GetResponseHeader(&respHeader), CompleteAll("yes")) + c.Assert(err, IsNil) + + meta, err := bucket.GetObjectDetailedMeta(objectName) + c.Assert(err, IsNil) + c.Assert(meta.Get("X-Oss-Meta-My"), Equals, "myprop") + c.Assert(meta.Get("Expires"), Equals, futureDate.Format(http.TimeFormat)) + c.Assert(meta.Get("X-Oss-Object-Type"), Equals, "Multipart") + os.Remove(fileName) + bucket.DeleteObject(objectName) + ForceDeleteBucket(client, bucketName, c) +} + func (s *OssBucketSuite) TestVersioningUploadPartCopy(c *C) { // create a bucket with default proprety client, err := New(endpoint, accessID, accessKey) diff --git a/oss/const.go b/oss/const.go index 400f7cf..70a13a0 100644 --- a/oss/const.go +++ b/oss/const.go @@ -212,6 +212,7 @@ const ( HttpHeaderOssNotification = "X-Oss-Notification" HTTPHeaderOssEc = "X-Oss-Ec" HTTPHeaderOssErr = "X-Oss-Err" + HTTPHeaderOssCompleteAll = "X-Oss-Complete-All" ) // HTTP Param diff --git a/oss/multipart.go b/oss/multipart.go index aea7faf..eacbac0 100644 --- a/oss/multipart.go +++ b/oss/multipart.go @@ -197,17 +197,17 @@ func (bucket Bucket) UploadPartCopy(imur InitiateMultipartUploadResult, srcBucke func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult, parts []UploadPart, options ...Option) (CompleteMultipartUploadResult, error) { var out CompleteMultipartUploadResult - - sort.Sort(UploadParts(parts)) - cxml := completeMultipartUploadXML{} - cxml.Part = parts - bs, err := xml.Marshal(cxml) - if err != nil { - return out, err - } buffer := new(bytes.Buffer) - buffer.Write(bs) - + if len(parts) > 0 { + sort.Sort(UploadParts(parts)) + cxml := completeMultipartUploadXML{} + cxml.Part = parts + bs, err := xml.Marshal(cxml) + if err != nil { + return out, err + } + buffer.Write(bs) + } params := map[string]interface{}{} params["uploadId"] = imur.UploadID resp, err := bucket.do("POST", imur.Key, params, options, buffer, nil) diff --git a/oss/option.go b/oss/option.go index 7e517dd..c781097 100644 --- a/oss/option.go +++ b/oss/option.go @@ -237,6 +237,11 @@ func RequestPayer(payerType PayerType) Option { return setHeader(HTTPHeaderOssRequester, strings.ToLower(string(payerType))) } +// CompleteAll is an option to set X-Oss-Complete-All header +func CompleteAll(value string) Option { + return setHeader(HTTPHeaderOssCompleteAll, value) +} + // RequestPayerParam is an option to set payer who pay for the request func RequestPayerParam(payerType PayerType) Option { return addParam(strings.ToLower(HTTPHeaderOssRequester), strings.ToLower(string(payerType)))