You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-library/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/multipart.go

445 lines
14 KiB

/*
* Copyright 2017 Baidu, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
// multipart.go - the multipart-related APIs definition supported by the BOS service
package api
import (
"bytes"
"fmt"
"strings"
"github.com/baidubce/bce-sdk-go/bce"
"github.com/baidubce/bce-sdk-go/http"
"github.com/baidubce/bce-sdk-go/util"
)
// InitiateMultipartUpload - initiate a multipart upload to get a upload ID
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name
// - object: the object name
// - contentType: the content type of the object to be uploaded which should be specified,
// otherwise use the default(application/octet-stream)
// - args: the optional arguments
// RETURNS:
// - *InitiateMultipartUploadResult: the result data structure
// - error: nil if ok otherwise the specific error
func InitiateMultipartUpload(cli bce.Client, bucket, object, contentType string,
args *InitiateMultipartUploadArgs) (*InitiateMultipartUploadResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.POST)
req.SetParam("uploads", "")
if len(contentType) == 0 {
contentType = RAW_CONTENT_TYPE
}
req.SetHeader(http.CONTENT_TYPE, contentType)
// Optional arguments settings
if args != nil {
setOptionalNullHeaders(req, map[string]string{
http.CACHE_CONTROL: args.CacheControl,
http.CONTENT_DISPOSITION: args.ContentDisposition,
http.EXPIRES: args.Expires,
})
if validStorageClass(args.StorageClass) {
req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass)
} else {
if len(args.StorageClass) != 0 {
return nil, bce.NewBceClientError("invalid storage class value: " +
args.StorageClass)
}
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &InitiateMultipartUploadResult{}
if err := resp.ParseJsonBody(result); err != nil {
return nil, err
}
defer func() { resp.Body().Close() }()
return result, nil
}
// UploadPart - upload the single part in the multipart upload process
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name
// - object: the object name
// - uploadId: the multipart upload id
// - partNumber: the current part number
// - content: the uploaded part content
// - args: the optional arguments
// RETURNS:
// - string: the etag of the uploaded part
// - error: nil if ok otherwise the specific error
func UploadPart(cli bce.Client, bucket, object, uploadId string, partNumber int,
content *bce.Body, args *UploadPartArgs) (string, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.PUT)
req.SetParam("uploadId", uploadId)
req.SetParam("partNumber", fmt.Sprintf("%d", partNumber))
if content == nil {
return "", bce.NewBceClientError("upload part content should not be empty")
}
if content.Size() >= THRESHOLD_100_CONTINUE {
req.SetHeader("Expect", "100-continue")
}
req.SetBody(content)
// Optional arguments settings
if args != nil {
setOptionalNullHeaders(req, map[string]string{
http.CONTENT_MD5: args.ContentMD5,
http.BCE_CONTENT_SHA256: args.ContentSha256,
http.BCE_CONTENT_CRC32: args.ContentCrc32,
})
//set traffic-limit
if args.TrafficLimit > 0 {
if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN {
return "", bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit))
}
req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit))
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return "", err
}
if resp.IsFail() {
return "", resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return strings.Trim(resp.Header(http.ETAG), "\""), nil
}
// UploadPartFromBytes - upload the single part in the multipart upload process
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name
// - object: the object name
// - uploadId: the multipart upload id
// - partNumber: the current part number
// - content: the uploaded part content
// - args: the optional arguments
// RETURNS:
// - string: the etag of the uploaded part
// - error: nil if ok otherwise the specific error
func UploadPartFromBytes(cli bce.Client, bucket, object, uploadId string, partNumber int,
content []byte, args *UploadPartArgs) (string, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.PUT)
req.SetParam("uploadId", uploadId)
req.SetParam("partNumber", fmt.Sprintf("%d", partNumber))
if content == nil {
return "", bce.NewBceClientError("upload part content should not be empty")
}
size := len(content)
if size >= THRESHOLD_100_CONTINUE {
req.SetHeader("Expect", "100-continue")
}
// set md5 and content-length
req.SetLength(int64(size))
if size > 0 {
// calc md5
if args == nil || args.ContentMD5 == "" {
buf := bytes.NewBuffer(content)
contentMD5, err := util.CalculateContentMD5(buf, int64(size))
if err != nil {
return "", err
}
req.SetHeader(http.CONTENT_MD5, contentMD5)
}
req.SetHeader(http.CONTENT_LENGTH, fmt.Sprintf("%d", size))
}
// Optional arguments settings
if args != nil {
setOptionalNullHeaders(req, map[string]string{
http.CONTENT_MD5: args.ContentMD5,
http.BCE_CONTENT_SHA256: args.ContentSha256,
http.BCE_CONTENT_CRC32: args.ContentCrc32,
})
//set traffic-limit
if args.TrafficLimit > 0 {
if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN {
return "", bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d",
TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit))
}
req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit))
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := cli.SendRequestFromBytes(req, resp, content); err != nil {
return "", err
}
if resp.IsFail() {
return "", resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return strings.Trim(resp.Header(http.ETAG), "\""), nil
}
// UploadPartCopy - copy the multipart data
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the destination bucket name
// - object: the destination object name
// - source: the copy source uri
// - uploadId: the multipart upload id
// - partNumber: the current part number
// - args: the optional arguments
// RETURNS:
// - *CopyObjectResult: the lastModified and eTag of the part
// - error: nil if ok otherwise the specific error
func UploadPartCopy(cli bce.Client, bucket, object, source, uploadId string, partNumber int,
args *UploadPartCopyArgs) (*CopyObjectResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.PUT)
req.SetParam("uploadId", uploadId)
req.SetParam("partNumber", fmt.Sprintf("%d", partNumber))
if len(source) == 0 {
return nil, bce.NewBceClientError("upload part copy source should not be empty")
}
req.SetHeader(http.BCE_COPY_SOURCE, util.UriEncode(source, false))
// Optional arguments settings
if args != nil {
setOptionalNullHeaders(req, map[string]string{
http.BCE_COPY_SOURCE_RANGE: args.SourceRange,
http.BCE_COPY_SOURCE_IF_MATCH: args.IfMatch,
http.BCE_COPY_SOURCE_IF_NONE_MATCH: args.IfNoneMatch,
http.BCE_COPY_SOURCE_IF_MODIFIED_SINCE: args.IfModifiedSince,
http.BCE_COPY_SOURCE_IF_UNMODIFIED_SINCE: args.IfUnmodifiedSince,
})
//set traffic-limit
if args.TrafficLimit > 0 {
if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN {
return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit))
}
req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit))
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &CopyObjectResult{}
if err := resp.ParseJsonBody(result); err != nil {
return nil, err
}
return result, nil
}
// CompleteMultipartUpload - finish a multipart upload operation
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the destination bucket name
// - object: the destination object name
// - uploadId: the multipart upload id
// - parts: all parts info stream
// - meta: user defined meta data
// RETURNS:
// - *CompleteMultipartUploadResult: the result data
// - error: nil if ok otherwise the specific error
func CompleteMultipartUpload(cli bce.Client, bucket, object, uploadId string,
body *bce.Body, args *CompleteMultipartUploadArgs) (*CompleteMultipartUploadResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.POST)
req.SetParam("uploadId", uploadId)
if body == nil {
return nil, bce.NewBceClientError("upload body info should not be emtpy")
}
if body.Size() >= THRESHOLD_100_CONTINUE {
req.SetHeader("Expect", "100-continue")
}
req.SetBody(body)
// Optional arguments settings
if args.UserMeta != nil {
if err := setUserMetadata(req, args.UserMeta); err != nil {
return nil, err
}
}
if len(args.Process) != 0 {
req.SetHeader(http.BCE_PROCESS, args.Process)
}
if len(args.ContentCrc32) != 0 {
req.SetHeader(http.BCE_CONTENT_CRC32, args.ContentCrc32)
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &CompleteMultipartUploadResult{}
if err := resp.ParseJsonBody(result); err != nil {
return nil, err
}
headers := resp.Headers()
if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok {
result.ContentCrc32 = val
}
return result, nil
}
// AbortMultipartUpload - abort a multipart upload operation
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the destination bucket name
// - object: the destination object name
// - uploadId: the multipart upload id
// RETURNS:
// - error: nil if ok otherwise the specific error
func AbortMultipartUpload(cli bce.Client, bucket, object, uploadId string) error {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.DELETE)
req.SetParam("uploadId", uploadId)
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return err
}
if resp.IsFail() {
return resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return nil
}
// ListParts - list the successfully uploaded parts info by upload id
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the destination bucket name
// - object: the destination object name
// - uploadId: the multipart upload id
// - args: the optional arguments
// partNumberMarker: return parts after this marker
// maxParts: the max number of return parts, default and maximum is 1000
// RETURNS:
// - *ListPartsResult: the uploaded parts info result
// - error: nil if ok otherwise the specific error
func ListParts(cli bce.Client, bucket, object, uploadId string,
args *ListPartsArgs) (*ListPartsResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.GET)
req.SetParam("uploadId", uploadId)
// Optional arguments settings
if args != nil {
if len(args.PartNumberMarker) > 0 {
req.SetParam("partNumberMarker", args.PartNumberMarker)
}
if args.MaxParts > 0 {
req.SetParam("maxParts", fmt.Sprintf("%d", args.MaxParts))
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &ListPartsResult{}
if err := resp.ParseJsonBody(result); err != nil {
return nil, err
}
return result, nil
}
// ListMultipartUploads - list the unfinished uploaded parts of the given bucket
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the destination bucket name
// - args: the optional arguments
// RETURNS:
// - *ListMultipartUploadsResult: the unfinished uploaded parts info result
// - error: nil if ok otherwise the specific error
func ListMultipartUploads(cli bce.Client, bucket string,
args *ListMultipartUploadsArgs) (*ListMultipartUploadsResult, error) {
req := &bce.BceRequest{}
req.SetUri(getBucketUri(bucket))
req.SetMethod(http.GET)
req.SetParam("uploads", "")
// Optional arguments settings
if args != nil {
if len(args.Delimiter) > 0 {
req.SetParam("delimiter", args.Delimiter)
}
if len(args.KeyMarker) > 0 {
req.SetParam("keyMarker", args.KeyMarker)
}
if args.MaxUploads > 0 {
req.SetParam("maxUploads", fmt.Sprintf("%d", args.MaxUploads))
}
if len(args.Prefix) > 0 {
req.SetParam("prefix", args.Prefix)
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &ListMultipartUploadsResult{}
if err := resp.ParseJsonBody(result); err != nil {
return nil, err
}
return result, nil
}