14 // InitiateMultipartUpload initializes multipart upload
16 // objectKey object name
17 // options the object constricts for upload. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires,
18 // ServerSideEncryption, Meta, check out the following link:
19 // https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/InitiateMultipartUpload.html
21 // InitiateMultipartUploadResult the return value of the InitiateMultipartUpload, which is used for calls later on such as UploadPartFromFile,UploadPartCopy.
22 // error it's nil if the operation succeeds, otherwise it's an error object.
24 func (bucket Bucket) InitiateMultipartUpload(objectKey string, options ...Option) (InitiateMultipartUploadResult, error) {
25 var imur InitiateMultipartUploadResult
26 opts := AddContentType(options, objectKey)
27 params, _ := GetRawParams(options)
28 _, ok := params["sequential"]
31 params["sequential"] = nil
33 params["uploads"] = nil
35 resp, err := bucket.do("POST", objectKey, params, opts, nil, nil)
39 defer resp.Body.Close()
41 err = xmlUnmarshal(resp.Body, &imur)
45 // UploadPart uploads parts
47 // After initializing a Multipart Upload, the upload Id and object key could be used for uploading the parts.
48 // Each part has its part number (ranges from 1 to 10,000). And for each upload Id, the part number identifies the position of the part in the whole file.
49 // And thus with the same part number and upload Id, another part upload will overwrite the data.
50 // Except the last one, minimal part size is 100KB. There's no limit on the last part size.
52 // imur the returned value of InitiateMultipartUpload.
53 // reader io.Reader the reader for the part's data.
54 // size the part size.
55 // partNumber the part number (ranges from 1 to 10,000). Invalid part number will lead to InvalidArgument error.
57 // UploadPart the return value of the upload part. It consists of PartNumber and ETag. It's valid when error is nil.
58 // error it's nil if the operation succeeds, otherwise it's an error object.
60 func (bucket Bucket) UploadPart(imur InitiateMultipartUploadResult, reader io.Reader,
61 partSize int64, partNumber int, options ...Option) (UploadPart, error) {
62 request := &UploadPartRequest{
66 PartNumber: partNumber,
69 result, err := bucket.DoUploadPart(request, options)
71 return result.Part, err
74 // UploadPartFromFile uploads part from the file.
76 // imur the return value of a successful InitiateMultipartUpload.
77 // filePath the local file path to upload.
78 // startPosition the start position in the local file.
79 // partSize the part size.
80 // partNumber the part number (from 1 to 10,000)
82 // UploadPart the return value consists of PartNumber and ETag.
83 // error it's nil if the operation succeeds, otherwise it's an error object.
85 func (bucket Bucket) UploadPartFromFile(imur InitiateMultipartUploadResult, filePath string,
86 startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) {
87 var part = UploadPart{}
88 fd, err := os.Open(filePath)
93 fd.Seek(startPosition, os.SEEK_SET)
95 request := &UploadPartRequest{
99 PartNumber: partNumber,
102 result, err := bucket.DoUploadPart(request, options)
104 return result.Part, err
107 // DoUploadPart does the actual part upload.
109 // request part upload request
111 // UploadPartResult the result of uploading part.
112 // error it's nil if the operation succeeds, otherwise it's an error object.
114 func (bucket Bucket) DoUploadPart(request *UploadPartRequest, options []Option) (*UploadPartResult, error) {
115 listener := GetProgressListener(options)
116 options = append(options, ContentLength(request.PartSize))
117 params := map[string]interface{}{}
118 params["partNumber"] = strconv.Itoa(request.PartNumber)
119 params["uploadId"] = request.InitResult.UploadID
120 resp, err := bucket.do("PUT", request.InitResult.Key, params, options,
121 &io.LimitedReader{R: request.Reader, N: request.PartSize}, listener)
123 return &UploadPartResult{}, err
125 defer resp.Body.Close()
128 ETag: resp.Headers.Get(HTTPHeaderEtag),
129 PartNumber: request.PartNumber,
132 if bucket.GetConfig().IsEnableCRC {
133 err = CheckCRC(resp, "DoUploadPart")
135 return &UploadPartResult{part}, err
139 return &UploadPartResult{part}, nil
142 // UploadPartCopy uploads part copy
144 // imur the return value of InitiateMultipartUpload
145 // copySrc source Object name
146 // startPosition the part's start index in the source file
147 // partSize the part size
148 // partNumber the part number, ranges from 1 to 10,000. If it exceeds the range OSS returns InvalidArgument error.
149 // options the constraints of source object for the copy. The copy happens only when these contraints are met. Otherwise it returns error.
150 // CopySourceIfNoneMatch, CopySourceIfModifiedSince CopySourceIfUnmodifiedSince, check out the following link for the detail
151 // https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/UploadPartCopy.html
153 // UploadPart the return value consists of PartNumber and ETag.
154 // error it's nil if the operation succeeds, otherwise it's an error object.
156 func (bucket Bucket) UploadPartCopy(imur InitiateMultipartUploadResult, srcBucketName, srcObjectKey string,
157 startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) {
158 var out UploadPartCopyResult
162 //first find version id
163 versionIdKey := "versionId"
164 versionId, _ := FindOption(options, versionIdKey, nil)
165 if versionId == nil {
166 opts = []Option{CopySource(srcBucketName, url.QueryEscape(srcObjectKey)),
167 CopySourceRange(startPosition, partSize)}
169 opts = []Option{CopySourceVersion(srcBucketName, url.QueryEscape(srcObjectKey), versionId.(string)),
170 CopySourceRange(startPosition, partSize)}
171 options = DeleteOption(options, versionIdKey)
174 opts = append(opts, options...)
176 params := map[string]interface{}{}
177 params["partNumber"] = strconv.Itoa(partNumber)
178 params["uploadId"] = imur.UploadID
179 resp, err := bucket.do("PUT", imur.Key, params, opts, nil, nil)
183 defer resp.Body.Close()
185 err = xmlUnmarshal(resp.Body, &out)
190 part.PartNumber = partNumber
195 // CompleteMultipartUpload completes the multipart upload.
197 // imur the return value of InitiateMultipartUpload.
198 // parts the array of return value of UploadPart/UploadPartFromFile/UploadPartCopy.
200 // CompleteMultipartUploadResponse the return value when the call succeeds. Only valid when the error is nil.
201 // error it's nil if the operation succeeds, otherwise it's an error object.
203 func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult,
204 parts []UploadPart, options ...Option) (CompleteMultipartUploadResult, error) {
205 var out CompleteMultipartUploadResult
207 sort.Sort(UploadParts(parts))
208 cxml := completeMultipartUploadXML{}
210 bs, err := xml.Marshal(cxml)
214 buffer := new(bytes.Buffer)
217 params := map[string]interface{}{}
218 params["uploadId"] = imur.UploadID
219 resp, err := bucket.do("POST", imur.Key, params, options, buffer, nil)
223 defer resp.Body.Close()
225 err = xmlUnmarshal(resp.Body, &out)
229 // AbortMultipartUpload aborts the multipart upload.
231 // imur the return value of InitiateMultipartUpload.
233 // error it's nil if the operation succeeds, otherwise it's an error object.
235 func (bucket Bucket) AbortMultipartUpload(imur InitiateMultipartUploadResult, options ...Option) error {
236 params := map[string]interface{}{}
237 params["uploadId"] = imur.UploadID
238 resp, err := bucket.do("DELETE", imur.Key, params, options, nil, nil)
242 defer resp.Body.Close()
243 return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent})
246 // ListUploadedParts lists the uploaded parts.
248 // imur the return value of InitiateMultipartUpload.
250 // ListUploadedPartsResponse the return value if it succeeds, only valid when error is nil.
251 // error it's nil if the operation succeeds, otherwise it's an error object.
253 func (bucket Bucket) ListUploadedParts(imur InitiateMultipartUploadResult, options ...Option) (ListUploadedPartsResult, error) {
254 var out ListUploadedPartsResult
255 options = append(options, EncodingType("url"))
257 params := map[string]interface{}{}
258 params, err := GetRawParams(options)
263 params["uploadId"] = imur.UploadID
264 resp, err := bucket.do("GET", imur.Key, params, options, nil, nil)
268 defer resp.Body.Close()
270 err = xmlUnmarshal(resp.Body, &out)
274 err = decodeListUploadedPartsResult(&out)
278 // ListMultipartUploads lists all ongoing multipart upload tasks
280 // options listObject's filter. Prefix specifies the returned object's prefix; KeyMarker specifies the returned object's start point in lexicographic order;
281 // MaxKeys specifies the max entries to return; Delimiter is the character for grouping object keys.
283 // ListMultipartUploadResponse the return value if it succeeds, only valid when error is nil.
284 // error it's nil if the operation succeeds, otherwise it's an error object.
286 func (bucket Bucket) ListMultipartUploads(options ...Option) (ListMultipartUploadResult, error) {
287 var out ListMultipartUploadResult
289 options = append(options, EncodingType("url"))
290 params, err := GetRawParams(options)
294 params["uploads"] = nil
296 resp, err := bucket.do("GET", "", params, options, nil, nil)
300 defer resp.Body.Close()
302 err = xmlUnmarshal(resp.Body, &out)
306 err = decodeListMultipartUploadResult(&out)