diff --git a/go.mod b/go.mod index 4c5e5384b..d479ca991 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( cloud.google.com/go/storage v1.30.1 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 - github.com/aliyun/aliyun-oss-go-sdk v2.1.8+incompatible + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/aws/aws-sdk-go v1.54.20 github.com/gophercloud/gophercloud v0.17.0 github.com/gophercloud/utils v0.0.0-20200204043447-9864b6f1f12f @@ -41,7 +41,6 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect - github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect @@ -97,7 +96,6 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/satori/go.uuid v1.2.0 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect diff --git a/go.sum b/go.sum index d911c18ff..e8345cf8d 100644 --- a/go.sum +++ b/go.sum @@ -28,15 +28,13 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/aliyun/aliyun-oss-go-sdk v2.1.8+incompatible h1:hLUNPbx10wawWW7DeNExvTrlb90db3UnnNTFKHZEFhE= -github.com/aliyun/aliyun-oss-go-sdk v2.1.8+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.54.20 h1:FZ2UcXya7bUkvkpf7TaPmiL7EubK0go1nlXGLRwEsoo= github.com/aws/aws-sdk-go v1.54.20/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -249,8 +247,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go index bc1e4fa3f..2eccf3163 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go @@ -6,6 +6,7 @@ import ( "crypto/sha1" "crypto/sha256" "encoding/base64" + "encoding/hex" "fmt" "hash" "io" @@ -13,6 +14,7 @@ import ( "sort" "strconv" "strings" + "time" ) // headerSorter defines the key-value structure for storing the sorted data in signHeader. @@ -44,11 +46,59 @@ func (conn Conn) getAdditionalHeaderKeys(req *http.Request) ([]string, map[strin return keysList, keysMap } +// getAdditionalHeaderKeysV4 get exist key in http header +func (conn Conn) getAdditionalHeaderKeysV4(req *http.Request) ([]string, map[string]string) { + var keysList []string + keysMap := make(map[string]string) + srcKeys := make(map[string]string) + + for k := range req.Header { + srcKeys[strings.ToLower(k)] = "" + } + + for _, v := range conn.config.AdditionalHeaders { + if _, ok := srcKeys[strings.ToLower(v)]; ok { + if !strings.EqualFold(v, HTTPHeaderContentMD5) && !strings.EqualFold(v, HTTPHeaderContentType) { + keysMap[strings.ToLower(v)] = "" + } + } + } + + for k := range keysMap { + keysList = append(keysList, k) + } + sort.Strings(keysList) + return keysList, keysMap +} + // signHeader signs the header and sets it as the authorization header. -func (conn Conn) signHeader(req *http.Request, canonicalizedResource string) { - akIf := conn.config.GetCredentials() +func (conn Conn) signHeader(req *http.Request, canonicalizedResource string, credentials Credentials) { + akIf := credentials authorizationStr := "" - if conn.config.AuthVersion == AuthV2 { + if conn.config.AuthVersion == AuthV4 { + strDay := "" + strDate := req.Header.Get(HttpHeaderOssDate) + if strDate == "" { + strDate = req.Header.Get(HTTPHeaderDate) + t, _ := time.Parse(http.TimeFormat, strDate) + strDay = t.Format("20060102") + } else { + t, _ := time.Parse(timeFormatV4, strDate) + strDay = t.Format("20060102") + } + signHeaderProduct := conn.config.GetSignProduct() + signHeaderRegion := conn.config.GetSignRegion() + + additionalList, _ := conn.getAdditionalHeaderKeysV4(req) + if len(additionalList) > 0 { + authorizationFmt := "OSS4-HMAC-SHA256 Credential=%v/%v/%v/" + signHeaderProduct + "/aliyun_v4_request,AdditionalHeaders=%v,Signature=%v" + additionnalHeadersStr := strings.Join(additionalList, ";") + authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), strDay, signHeaderRegion, additionnalHeadersStr, conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), nil)) + } else { + authorizationFmt := "OSS4-HMAC-SHA256 Credential=%v/%v/%v/" + signHeaderProduct + "/aliyun_v4_request,Signature=%v" + authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), strDay, signHeaderRegion, conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), nil)) + } + } else if conn.config.AuthVersion == AuthV2 { additionalList, _ := conn.getAdditionalHeaderKeys(req) if len(additionalList) > 0 { authorizationFmt := "OSS2 AccessKeyId:%v,AdditionalHeaders:%v,Signature:%v" @@ -107,17 +157,8 @@ func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string, k h = hmac.New(func() hash.Hash { return sha256.New() }, []byte(keySecret)) } - // convert sign to log for easy to view if conn.config.LogLevel >= Debug { - var signBuf bytes.Buffer - for i := 0; i < len(signStr); i++ { - if signStr[i] != '\n' { - signBuf.WriteByte(signStr[i]) - } else { - signBuf.WriteString("\\n") - } - } - conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, signBuf.String()) + conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, EscapeLFString(signStr)) } io.WriteString(h, signStr) @@ -126,6 +167,114 @@ func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string, k return signedStr } +func (conn Conn) getSignedStrV4(req *http.Request, canonicalizedResource string, keySecret string, signingTime *time.Time) string { + // Find out the "x-oss-"'s address in header of the request + ossHeadersMap := make(map[string]string) + additionalList, additionalMap := conn.getAdditionalHeaderKeysV4(req) + for k, v := range req.Header { + lowKey := strings.ToLower(k) + if strings.EqualFold(lowKey, HTTPHeaderContentMD5) || + strings.EqualFold(lowKey, HTTPHeaderContentType) || + strings.HasPrefix(lowKey, "x-oss-") { + ossHeadersMap[lowKey] = strings.Trim(v[0], " ") + } else { + if _, ok := additionalMap[lowKey]; ok { + ossHeadersMap[lowKey] = strings.Trim(v[0], " ") + } + } + } + + // get day,eg 20210914 + //signingTime + signDate := "" + strDay := "" + if signingTime != nil { + signDate = signingTime.Format(timeFormatV4) + strDay = signingTime.Format(shortTimeFormatV4) + } else { + var t time.Time + // Required parameters + if date := req.Header.Get(HTTPHeaderDate); date != "" { + signDate = date + t, _ = time.Parse(http.TimeFormat, date) + } + + if ossDate := req.Header.Get(HttpHeaderOssDate); ossDate != "" { + signDate = ossDate + t, _ = time.Parse(timeFormatV4, ossDate) + } + + strDay = t.Format("20060102") + } + + hs := newHeaderSorter(ossHeadersMap) + + // Sort the ossHeadersMap by the ascending order + hs.Sort() + + // Get the canonicalizedOSSHeaders + canonicalizedOSSHeaders := "" + for i := range hs.Keys { + canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" + } + + signStr := "" + + // v4 signature + hashedPayload := DefaultContentSha256 + if val := req.Header.Get(HttpHeaderOssContentSha256); val != "" { + hashedPayload = val + } + + // subResource + resource := canonicalizedResource + subResource := "" + subPos := strings.LastIndex(canonicalizedResource, "?") + if subPos != -1 { + subResource = canonicalizedResource[subPos+1:] + resource = canonicalizedResource[0:subPos] + } + + // get canonical request + canonicalReuqest := req.Method + "\n" + resource + "\n" + subResource + "\n" + canonicalizedOSSHeaders + "\n" + strings.Join(additionalList, ";") + "\n" + hashedPayload + rh := sha256.New() + io.WriteString(rh, canonicalReuqest) + hashedRequest := hex.EncodeToString(rh.Sum(nil)) + + if conn.config.LogLevel >= Debug { + conn.config.WriteLog(Debug, "[Req:%p]CanonicalRequest:%s\n", req, EscapeLFString(canonicalReuqest)) + } + + // Product & Region + signedStrV4Product := conn.config.GetSignProduct() + signedStrV4Region := conn.config.GetSignRegion() + + signStr = "OSS4-HMAC-SHA256" + "\n" + signDate + "\n" + strDay + "/" + signedStrV4Region + "/" + signedStrV4Product + "/aliyun_v4_request" + "\n" + hashedRequest + if conn.config.LogLevel >= Debug { + conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, EscapeLFString(signStr)) + } + + h1 := hmac.New(func() hash.Hash { return sha256.New() }, []byte("aliyun_v4"+keySecret)) + io.WriteString(h1, strDay) + h1Key := h1.Sum(nil) + + h2 := hmac.New(func() hash.Hash { return sha256.New() }, h1Key) + io.WriteString(h2, signedStrV4Region) + h2Key := h2.Sum(nil) + + h3 := hmac.New(func() hash.Hash { return sha256.New() }, h2Key) + io.WriteString(h3, signedStrV4Product) + h3Key := h3.Sum(nil) + + h4 := hmac.New(func() hash.Hash { return sha256.New() }, h3Key) + io.WriteString(h4, "aliyun_v4_request") + h4Key := h4.Sum(nil) + + h := hmac.New(func() hash.Hash { return sha256.New() }, h4Key) + io.WriteString(h, signStr) + return fmt.Sprintf("%x", h.Sum(nil)) +} + func (conn Conn) getRtmpSignedStr(bucketName, channelName, playlistName string, expiration int64, keySecret string, params map[string]interface{}) string { if params[HTTPParamAccessKeyID] == nil { return "" diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go index 430252c02..26dea3bb2 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go @@ -2,6 +2,7 @@ package oss import ( "bytes" + "context" "crypto/md5" "encoding/base64" "encoding/xml" @@ -9,6 +10,7 @@ import ( "hash" "hash/crc64" "io" + "io/ioutil" "net/http" "net/url" "os" @@ -28,11 +30,11 @@ type Bucket struct { // objectKey the object key in UTF-8 encoding. The length must be between 1 and 1023, and cannot start with "/" or "\". // reader io.Reader instance for reading the data for uploading // options the options for uploading the object. The valid options here are CacheControl, ContentDisposition, ContentEncoding -// Expires, ServerSideEncryption, ObjectACL and Meta. Refer to the link below for more details. -// https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html // -// error it's nil if no error, otherwise it's an error object. +// Expires, ServerSideEncryption, ObjectACL and Meta. Refer to the link below for more details. +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject // +// error it's nil if no error, otherwise it's an error object. func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Option) error { opts := AddContentType(options, objectKey) @@ -56,7 +58,6 @@ func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Op // options the options for uploading the object. Refer to the parameter options in PutObject for more details. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Option) error { fd, err := os.Open(filePath) if err != nil { @@ -86,7 +87,6 @@ func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Op // // Response the response from OSS. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) { isOptSet, _, _ := IsOptionSet(options, HTTPHeaderContentType) if !isOptSet { @@ -100,16 +100,26 @@ func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (* if err != nil { return nil, err } - if bucket.GetConfig().IsEnableCRC { err = CheckCRC(resp, "DoPutObject") if err != nil { return resp, err } } - err = CheckRespCode(resp.StatusCode, []int{http.StatusOK}) - + body, _ := ioutil.ReadAll(resp.Body) + if len(body) > 0 { + if err != nil { + err = tryConvertServiceError(body, resp, err) + } else { + rb, _ := FindOption(options, responseBody, nil) + if rb != nil { + if rbody, ok := rb.(*[]byte); ok { + *rbody = body + } + } + } + } return resp, err } @@ -117,12 +127,12 @@ func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (* // // objectKey the object key. // options the options for downloading the object. The valid values are: Range, IfModifiedSince, IfUnmodifiedSince, IfMatch, -// IfNoneMatch, AcceptEncoding. For more details, please check out: -// https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html +// +// IfNoneMatch, AcceptEncoding. For more details, please check out: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject // // io.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) { result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options) if err != nil { @@ -139,7 +149,6 @@ func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadClos // options the options for downloading the object. Refer to the parameter options in method GetObject for more details. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error { tempFilePath := filePath + TempFileSuffix @@ -189,7 +198,6 @@ func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Opti // // GetObjectResult the result instance of getting the object. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) { params, _ := GetRawParams(options) resp, err := bucket.do("GET", request.ObjectKey, params, options, nil, nil) @@ -224,13 +232,13 @@ func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (* // srcObjectKey the source object to copy. // destObjectKey the target object to copy. // options options for copying an object. You can specify the conditions of copy. The valid conditions are CopySourceIfMatch, -// CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective. -// Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires, -// ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details : -// https://help.aliyun.com/document_detail/oss/api-reference/object/CopyObject.html // -// error it's nil if no error, otherwise it's an error object. +// CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective. +// Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires, +// ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details : +// https://www.alibabacloud.com/help/en/object-storage-service/latest/copyobject // +// error it's nil if no error, otherwise it's an error object. func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) { var out CopyObjectResult @@ -263,12 +271,10 @@ func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...O // options copy options, check out parameter options in function CopyObject for more details. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey string, options ...Option) (CopyObjectResult, error) { return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...) } -// // CopyObjectFrom copies the object to another bucket. // // srcBucketName source bucket name. @@ -277,7 +283,6 @@ func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey st // options copy options. Check out parameter options in function CopyObject. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) CopyObjectFrom(srcBucketName, srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) { destBucketName := bucket.BucketName var out CopyObjectResult @@ -308,13 +313,19 @@ func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, op return out, err } params := map[string]interface{}{} - resp, err := bucket.Client.Conn.Do("PUT", destBucketName, destObjectKey, params, headers, nil, 0, nil) + + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoWithContext(ctx, "PUT", destBucketName, destObjectKey, params, headers, nil, 0, nil) // get response header respHeader, _ := FindOption(options, responseHeader, nil) if respHeader != nil { pRespHeader := respHeader.(*http.Header) - *pRespHeader = resp.Headers + if resp != nil { + *pRespHeader = resp.Headers + } } if err != nil { @@ -337,11 +348,11 @@ func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, op // reader io.Reader. The read instance for reading the data to append. // appendPosition the start position to append. // destObjectProperties the options for the first appending, such as CacheControl, ContentDisposition, ContentEncoding, -// Expires, ServerSideEncryption, ObjectACL. +// +// Expires, ServerSideEncryption, ObjectACL. // // int64 the next append position, it's valid when error is nil. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosition int64, options ...Option) (int64, error) { request := &AppendObjectRequest{ ObjectKey: objectKey, @@ -364,7 +375,6 @@ func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosi // // AppendObjectResult the result object for appending object. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) { params := map[string]interface{}{} params["append"] = nil @@ -383,14 +393,20 @@ func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Opti listener := GetProgressListener(options) handleOptions(headers, opts) - resp, err := bucket.Client.Conn.Do("POST", bucket.BucketName, request.ObjectKey, params, headers, + + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoWithContext(ctx, "POST", bucket.BucketName, request.ObjectKey, params, headers, request.Reader, initCRC, listener) // get response header respHeader, _ := FindOption(options, responseHeader, nil) if respHeader != nil { pRespHeader := respHeader.(*http.Header) - *pRespHeader = resp.Headers + if resp != nil { + *pRespHeader = resp.Headers + } } if err != nil { @@ -419,7 +435,6 @@ func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Opti // objectKey the object key to delete. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error { params, _ := GetRawParams(options) resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil) @@ -434,57 +449,35 @@ func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error { // // objectKeys the object keys to delete. // options the options for deleting objects. -// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. +// +// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. // // DeleteObjectsResult the result object. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) { out := DeleteObjectsResult{} dxml := deleteXML{} for _, key := range objectKeys { dxml.Objects = append(dxml.Objects, DeleteObject{Key: key}) } - isQuiet, _ := FindOption(options, deleteObjectsQuiet, false) dxml.Quiet = isQuiet.(bool) - - bs, err := xml.Marshal(dxml) + xmlData := marshalDeleteObjectToXml(dxml) + body, err := bucket.DeleteMultipleObjectsXml(xmlData, options...) if err != nil { return out, err } - buffer := new(bytes.Buffer) - buffer.Write(bs) - - contentType := http.DetectContentType(buffer.Bytes()) - options = append(options, ContentType(contentType)) - sum := md5.Sum(bs) - b64 := base64.StdEncoding.EncodeToString(sum[:]) - options = append(options, ContentMD5(b64)) - - params := map[string]interface{}{} - params["delete"] = nil - params["encoding-type"] = "url" - - resp, err := bucket.do("POST", "", params, options, buffer, nil) - if err != nil { - return out, err - } - defer resp.Body.Close() - deletedResult := DeleteObjectVersionsResult{} if !dxml.Quiet { - if err = xmlUnmarshal(resp.Body, &deletedResult); err == nil { + if err = xmlUnmarshal(strings.NewReader(body), &deletedResult); err == nil { err = decodeDeleteObjectsResult(&deletedResult) } } - // Keep compatibility:need convert to struct DeleteObjectsResult out.XMLName = deletedResult.XMLName for _, v := range deletedResult.DeletedObjectsDetail { out.DeletedObjects = append(out.DeletedObjects, v.Key) } - return out, err } @@ -492,47 +485,56 @@ func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (Dele // // objectVersions the object keys and versions to delete. // options the options for deleting objects. -// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. +// +// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. // // DeleteObjectVersionsResult the result object. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options ...Option) (DeleteObjectVersionsResult, error) { out := DeleteObjectVersionsResult{} dxml := deleteXML{} dxml.Objects = objectVersions - isQuiet, _ := FindOption(options, deleteObjectsQuiet, false) dxml.Quiet = isQuiet.(bool) - - bs, err := xml.Marshal(dxml) + xmlData := marshalDeleteObjectToXml(dxml) + body, err := bucket.DeleteMultipleObjectsXml(xmlData, options...) if err != nil { return out, err } + if !dxml.Quiet { + if err = xmlUnmarshal(strings.NewReader(body), &out); err == nil { + err = decodeDeleteObjectsResult(&out) + } + } + return out, err +} + +// DeleteMultipleObjectsXml deletes multiple object or deletes multiple object versions. +// +// xmlData the object keys and versions to delete as the xml format. +// options the options for deleting objects. +// +// string the result response body. +// error it's nil if no error, otherwise it's an error. +func (bucket Bucket) DeleteMultipleObjectsXml(xmlData string, options ...Option) (string, error) { buffer := new(bytes.Buffer) + bs := []byte(xmlData) buffer.Write(bs) - - contentType := http.DetectContentType(buffer.Bytes()) - options = append(options, ContentType(contentType)) + options = append(options, ContentType("application/xml")) sum := md5.Sum(bs) b64 := base64.StdEncoding.EncodeToString(sum[:]) options = append(options, ContentMD5(b64)) - params := map[string]interface{}{} params["delete"] = nil params["encoding-type"] = "url" - - resp, err := bucket.do("POST", "", params, options, buffer, nil) + resp, err := bucket.doInner("POST", "", params, options, buffer, nil) if err != nil { - return out, err + return "", err } defer resp.Body.Close() - if !dxml.Quiet { - if err = xmlUnmarshal(resp.Body, &out); err == nil { - err = decodeDeleteObjectsResult(&out) - } - } + body, err := ioutil.ReadAll(resp.Body) + out := string(body) return out, err } @@ -541,7 +543,6 @@ func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options // bool flag of object's existence (true:exists; false:non-exist) when error is nil. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, error) { _, err := bucket.GetObjectMeta(objectKey, options...) if err == nil { @@ -561,23 +562,23 @@ func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, e // ListObjects lists the objects under the current bucket. // // options it contains all the filters for listing objects. -// It could specify a prefix filter on object keys, the max keys count to return and the object key marker and the delimiter for grouping object names. -// The key marker means the returned objects' key must be greater than it in lexicographic order. // -// For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21, -// my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns -// my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns -// my-object-3, my-object-31, my-object-32 three objects. If the max keys is 5, then it returns 5 objects. -// The three filters could be used together to achieve filter and paging functionality. -// If the prefix is the folder name, then it could list all files under this folder (including the files under its subfolders). -// But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties. -// For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects. -// But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix. +// It could specify a prefix filter on object keys, the max keys count to return and the object key marker and the delimiter for grouping object names. +// The key marker means the returned objects' key must be greater than it in lexicographic order. // -// For common usage scenario, check out sample/list_object.go. +// For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21, +// my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns +// my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns +// my-object-3, my-object-31, my-object-32 three objects. If the max keys is 5, then it returns 5 objects. +// The three filters could be used together to achieve filter and paging functionality. +// If the prefix is the folder name, then it could list all files under this folder (including the files under its subfolders). +// But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties. +// For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects. +// But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix. // -// ListObjectsResult the return value after operation succeeds (only valid when error is nil). +// For common usage scenario, check out sample/list_object.go. // +// ListObjectsResult the return value after operation succeeds (only valid when error is nil). func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) { var out ListObjectsResult @@ -587,7 +588,7 @@ func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) { return out, err } - resp, err := bucket.do("GET", "", params, options, nil, nil) + resp, err := bucket.doInner("GET", "", params, options, nil, nil) if err != nil { return out, err } @@ -602,8 +603,8 @@ func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) { return out, err } +// ListObjectsV2 lists the objects under the current bucket. // Recommend to use ListObjectsV2 to replace ListObjects -// ListOListObjectsV2bjects lists the objects under the current bucket. // ListObjectsResultV2 the return value after operation succeeds (only valid when error is nil). func (bucket Bucket) ListObjectsV2(options ...Option) (ListObjectsResultV2, error) { var out ListObjectsResultV2 @@ -615,7 +616,7 @@ func (bucket Bucket) ListObjectsV2(options ...Option) (ListObjectsResultV2, erro return out, err } - resp, err := bucket.do("GET", "", params, options, nil, nil) + resp, err := bucket.doInner("GET", "", params, options, nil, nil) if err != nil { return out, err } @@ -641,7 +642,7 @@ func (bucket Bucket) ListObjectVersions(options ...Option) (ListObjectVersionsRe } params["versions"] = nil - resp, err := bucket.do("GET", "", params, options, nil, nil) + resp, err := bucket.doInner("GET", "", params, options, nil, nil) if err != nil { return out, err } @@ -660,10 +661,10 @@ func (bucket Bucket) ListObjectVersions(options ...Option) (ListObjectVersionsRe // // objectKey object // options options for setting the metadata. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires, -// ServerSideEncryption, and custom metadata. // -// error it's nil if no error, otherwise it's an error object. +// ServerSideEncryption, and custom metadata. // +// error it's nil if no error, otherwise it's an error object. func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error { options = append(options, MetadataDirective(MetaReplace)) _, err := bucket.CopyObject(objectKey, objectKey, options...) @@ -674,11 +675,11 @@ func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error { // // objectKey object key. // options the constraints of the object. Only when the object meets the requirements this method will return the metadata. Otherwise returns error. Valid options are IfModifiedSince, IfUnmodifiedSince, -// IfMatch, IfNoneMatch. For more details check out https://help.aliyun.com/document_detail/oss/api-reference/object/HeadObject.html +// +// IfMatch, IfNoneMatch. For more details check out https://www.alibabacloud.com/help/en/object-storage-service/latest/headobject // // http.Header object meta when error is nil. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) { params, _ := GetRawParams(options) resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil) @@ -699,7 +700,6 @@ func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) // // http.Header the object's metadata, valid when error is nil. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) { params, _ := GetRawParams(options) params["objectMeta"] = nil @@ -728,7 +728,6 @@ func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.He // objectAcl object ACL. Valid options are PrivateACL, PublicReadACL, PublicReadWriteACL. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options ...Option) error { options = append(options, ObjectACL(objectACL)) params, _ := GetRawParams(options) @@ -747,7 +746,6 @@ func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options . // // GetObjectACLResult the result object when error is nil. GetObjectACLResult.Acl is the object ACL. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjectACLResult, error) { var out GetObjectACLResult params, _ := GetRawParams(options) @@ -774,7 +772,6 @@ func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjec // targetObjectKey the target object key to point to. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error { options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey))) params, _ := GetRawParams(options) @@ -793,8 +790,8 @@ func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, opt // objectKey the symlink object's key. // // error it's nil if no error, otherwise it's an error object. -// When error is nil, the target file key is in the X-Oss-Symlink-Target header of the returned object. // +// When error is nil, the target file key is in the X-Oss-Symlink-Target header of the returned object. func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Header, error) { params, _ := GetRawParams(options) params["symlink"] = nil @@ -824,7 +821,6 @@ func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Heade // objectKey object key to restore. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) RestoreObject(objectKey string, options ...Option) error { params, _ := GetRawParams(options) params["restore"] = nil @@ -895,8 +891,12 @@ func (bucket Bucket) RestoreObjectXML(objectKey, configXML string, options ...Op // // string returns the signed URL, when error is nil. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec int64, options ...Option) (string, error) { + err := CheckObjectNameEx(objectKey, isVerifyObjectStrict(bucket.GetConfig())) + if err != nil { + return "", err + } + if expiredInSec < 0 { return "", fmt.Errorf("invalid expires: %d, expires must bigger than 0", expiredInSec) } @@ -913,7 +913,7 @@ func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec i return "", err } - return bucket.Client.Conn.signURL(method, bucket.BucketName, objectKey, expiration, params, headers), nil + return bucket.Client.Conn.signURL(method, bucket.BucketName, objectKey, expiration, params, headers) } // PutObjectWithURL uploads an object with the URL. If the object exists, it will be overwritten. @@ -922,11 +922,11 @@ func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec i // signedURL signed URL. // reader io.Reader the read instance for reading the data for the upload. // options the options for uploading the data. The valid options are CacheControl, ContentDisposition, ContentEncoding, -// Expires, ServerSideEncryption, ObjectACL and custom metadata. Check out the following link for details: -// https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html // -// error it's nil if no error, otherwise it's an error object. +// Expires, ServerSideEncryption, ObjectACL and custom metadata. Check out the following link for details: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject // +// error it's nil if no error, otherwise it's an error object. func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, options ...Option) error { resp, err := bucket.DoPutObjectWithURL(signedURL, reader, options) if err != nil { @@ -945,7 +945,6 @@ func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, option // options options for uploading, same as the options in PutObject function. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, options ...Option) error { fd, err := os.Open(filePath) if err != nil { @@ -970,7 +969,6 @@ func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, option // // Response the response object which contains the HTTP response. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, options []Option) (*Response, error) { listener := GetProgressListener(options) @@ -996,12 +994,12 @@ func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, opti // // signedURL the signed URL. // options options for downloading the object. Valid options are IfModifiedSince, IfUnmodifiedSince, IfMatch, -// IfNoneMatch, AcceptEncoding. For more information, check out the following link: -// https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html +// +// IfNoneMatch, AcceptEncoding. For more information, check out the following link: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject // // io.ReadCloser the reader object for getting the data from response. It needs be closed after the usage. It's only valid when error is nil. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.ReadCloser, error) { result, err := bucket.DoGetObjectWithURL(signedURL, options) if err != nil { @@ -1017,7 +1015,6 @@ func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.R // options the options for downloading object. Check out the parameter options in function GetObject for the reference. // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options ...Option) error { tempFilePath := filePath + TempFileSuffix @@ -1068,7 +1065,6 @@ func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options // // GetObjectResult the result object when the error is nil. // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) { params, _ := GetRawParams(options) resp, err := bucket.doURL("GET", signedURL, params, options, nil, nil) @@ -1098,18 +1094,15 @@ func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*Ge return result, nil } -// // ProcessObject apply process on the specified image file. // // The supported process includes resize, rotate, crop, watermark, format, // udf, customized style, etc. // -// // objectKey object key to process. // process process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA" // // error it's nil if no error, otherwise it's an error object. -// func (bucket Bucket) ProcessObject(objectKey string, process string, options ...Option) (ProcessObjectResult, error) { var out ProcessObjectResult params, _ := GetRawParams(options) @@ -1126,14 +1119,38 @@ func (bucket Bucket) ProcessObject(objectKey string, process string, options ... return out, err } +// AsyncProcessObject apply async process on the specified image file. +// +// The supported process includes resize, rotate, crop, watermark, format, +// udf, customized style, etc. // +// objectKey object key to process. +// asyncProcess process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA" +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) AsyncProcessObject(objectKey string, asyncProcess string, options ...Option) (AsyncProcessObjectResult, error) { + var out AsyncProcessObjectResult + params, _ := GetRawParams(options) + params["x-oss-async-process"] = nil + processData := fmt.Sprintf("%v=%v", "x-oss-async-process", asyncProcess) + data := strings.NewReader(processData) + + resp, err := bucket.do("POST", objectKey, params, nil, data, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = jsonUnmarshal(resp.Body, &out) + return out, err +} + // PutObjectTagging add tagging to object // // objectKey object key to add tagging // tagging tagging to be added // // error nil if success, otherwise error -// func (bucket Bucket) PutObjectTagging(objectKey string, tagging Tagging, options ...Option) error { bs, err := xml.Marshal(tagging) if err != nil { @@ -1177,21 +1194,14 @@ func (bucket Bucket) GetObjectTagging(objectKey string, options ...Option) (GetO return out, err } -// // DeleteObjectTagging delete object taggging // // objectKey object key to delete tagging // // error nil if success, otherwise error -// func (bucket Bucket) DeleteObjectTagging(objectKey string, options ...Option) error { params, _ := GetRawParams(options) params["tagging"] = nil - - if objectKey == "" { - return fmt.Errorf("invalid argument: object name is empty") - } - resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil) if err != nil { return err @@ -1203,7 +1213,7 @@ func (bucket Bucket) DeleteObjectTagging(objectKey string, options ...Option) er func (bucket Bucket) OptionsMethod(objectKey string, options ...Option) (http.Header, error) { var out http.Header - resp, err := bucket.do("OPTIONS", objectKey, nil, options, nil, nil) + resp, err := bucket.doInner("OPTIONS", objectKey, nil, options, nil, nil) if err != nil { return out, err } @@ -1215,11 +1225,11 @@ func (bucket Bucket) OptionsMethod(objectKey string, options ...Option) (http.He // public func (bucket Bucket) Do(method, objectName string, params map[string]interface{}, options []Option, data io.Reader, listener ProgressListener) (*Response, error) { - return bucket.do(method, objectName, params, options, data, listener) + return bucket.doInner(method, objectName, params, options, data, listener) } // Private -func (bucket Bucket) do(method, objectName string, params map[string]interface{}, options []Option, +func (bucket Bucket) doInner(method, objectName string, params map[string]interface{}, options []Option, data io.Reader, listener ProgressListener) (*Response, error) { headers := make(map[string]string) err := handleOptions(headers, options) @@ -1232,34 +1242,56 @@ func (bucket Bucket) do(method, objectName string, params map[string]interface{} return nil, err } - resp, err := bucket.Client.Conn.Do(method, bucket.BucketName, objectName, + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoWithContext(ctx, method, bucket.BucketName, objectName, params, headers, data, 0, listener) // get response header respHeader, _ := FindOption(options, responseHeader, nil) if respHeader != nil && resp != nil { pRespHeader := respHeader.(*http.Header) - *pRespHeader = resp.Headers + if resp != nil { + *pRespHeader = resp.Headers + } } return resp, err } +// Private check object name before bucket.do +func (bucket Bucket) do(method, objectName string, params map[string]interface{}, options []Option, + data io.Reader, listener ProgressListener) (*Response, error) { + err := CheckObjectName(objectName) + if err != nil { + return nil, err + } + resp, err := bucket.doInner(method, objectName, params, options, data, listener) + return resp, err +} + func (bucket Bucket) doURL(method HTTPMethod, signedURL string, params map[string]interface{}, options []Option, data io.Reader, listener ProgressListener) (*Response, error) { + headers := make(map[string]string) err := handleOptions(headers, options) if err != nil { return nil, err } - resp, err := bucket.Client.Conn.DoURL(method, signedURL, headers, data, 0, listener) + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoURLWithContext(ctx, method, signedURL, headers, data, 0, listener) // get response header respHeader, _ := FindOption(options, responseHeader, nil) if respHeader != nil { pRespHeader := respHeader.(*http.Header) - *pRespHeader = resp.Headers + if resp != nil { + *pRespHeader = resp.Headers + } } return resp, err diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go index aacf3e7f7..5910bb3bf 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go @@ -49,10 +49,6 @@ func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption) // URL parse url := &urlMaker{} - err := url.Init(config.Endpoint, config.IsCname, config.IsUseProxy) - if err != nil { - return nil, err - } // HTTP connect conn := &Conn{config: config, url: url} @@ -68,7 +64,12 @@ func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption) option(client) } - if config.AuthVersion != AuthV1 && config.AuthVersion != AuthV2 { + err := url.InitExt(config.Endpoint, config.IsCname, config.IsUseProxy, config.IsPathStyle) + if err != nil { + return nil, err + } + + if config.AuthVersion != AuthV1 && config.AuthVersion != AuthV2 && config.AuthVersion != AuthV4 { return nil, fmt.Errorf("Init client Error, invalid Auth version: %v", config.AuthVersion) } @@ -78,6 +79,27 @@ func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption) return client, err } +// SetRegion set region for client +// +// region the region, such as cn-hangzhou +func (client *Client) SetRegion(region string) { + client.Config.Region = region +} + +// SetCloudBoxId set CloudBoxId for client +// +// cloudBoxId the id of cloudBox +func (client *Client) SetCloudBoxId(cloudBoxId string) { + client.Config.CloudBoxId = cloudBoxId +} + +// SetProduct set Product type for client +// +// Product product type +func (client *Client) SetProduct(product string) { + client.Config.Product = product +} + // Bucket gets the bucket instance. // // bucketName the bucket name. @@ -148,6 +170,24 @@ func (client Client) CreateBucket(bucketName string, options ...Option) error { return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) } +// create bucket xml +func (client Client) CreateBucketXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + // ListBuckets lists buckets of the current account under the given endpoint, with optional filters. // // options specifies the filters such as Prefix, Marker and MaxKeys. Prefix is the bucket name's prefix filter. @@ -176,6 +216,36 @@ func (client Client) ListBuckets(options ...Option) (ListBucketsResult, error) { return out, err } +// ListCloudBoxes lists cloud boxes of the current account under the given endpoint, with optional filters. +// +// options specifies the filters such as Prefix, Marker and MaxKeys. Prefix is the bucket name's prefix filter. +// And marker makes sure the returned buckets' name are greater than it in lexicographic order. +// Maxkeys limits the max keys to return, and by default it's 100 and up to 1000. +// For the common usage scenario, please check out list_bucket.go in the sample. +// ListBucketsResponse the response object if error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) ListCloudBoxes(options ...Option) (ListCloudBoxResult, error) { + var out ListCloudBoxResult + + params, err := GetRawParams(options) + if err != nil { + return out, err + } + + params["cloudboxes"] = nil + + resp, err := client.do("GET", "", params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + // IsBucketExist checks if the bucket exists // // bucketName the bucket name. @@ -215,17 +285,17 @@ func (client Client) DeleteBucket(bucketName string, options ...Option) error { // GetBucketLocation gets the bucket location. // // Checks out the following link for more information : -// https://help.aliyun.com/document_detail/oss/user_guide/oss_concept/endpoint.html +// https://www.alibabacloud.com/help/en/object-storage-service/latest/getbucketlocation // // bucketName the bucket name // // string bucket's datacenter location // error it's nil if no error, otherwise it's an error object. // -func (client Client) GetBucketLocation(bucketName string) (string, error) { +func (client Client) GetBucketLocation(bucketName string, options ...Option) (string, error) { params := map[string]interface{}{} params["location"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return "", err } @@ -243,11 +313,11 @@ func (client Client) GetBucketLocation(bucketName string) (string, error) { // // error it's nil if no error, otherwise it's an error object. // -func (client Client) SetBucketACL(bucketName string, bucketACL ACLType) error { +func (client Client) SetBucketACL(bucketName string, bucketACL ACLType, options ...Option) error { headers := map[string]string{HTTPHeaderOssACL: string(bucketACL)} params := map[string]interface{}{} params["acl"] = nil - resp, err := client.do("PUT", bucketName, params, headers, nil) + resp, err := client.do("PUT", bucketName, params, headers, nil, options...) if err != nil { return err } @@ -262,11 +332,11 @@ func (client Client) SetBucketACL(bucketName string, bucketACL ACLType) error { // GetBucketAclResponse the result object, and it's only valid when error is nil. // error it's nil if no error, otherwise it's an error object. // -func (client Client) GetBucketACL(bucketName string) (GetBucketACLResult, error) { +func (client Client) GetBucketACL(bucketName string, options ...Option) (GetBucketACLResult, error) { var out GetBucketACLResult params := map[string]interface{}{} params["acl"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return out, err } @@ -279,7 +349,7 @@ func (client Client) GetBucketACL(bucketName string) (GetBucketACLResult, error) // SetBucketLifecycle sets the bucket's lifecycle. // // For more information, checks out following link: -// https://help.aliyun.com/document_detail/oss/user_guide/manage_object/object_lifecycle.html +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketlifecycle // // bucketName the bucket name. // rules the lifecycle rules. There're two kind of rules: absolute time expiration and relative time expiration in days and day/month/year respectively. @@ -287,7 +357,7 @@ func (client Client) GetBucketACL(bucketName string) (GetBucketACLResult, error) // // error it's nil if no error, otherwise it's an error object. // -func (client Client) SetBucketLifecycle(bucketName string, rules []LifecycleRule) error { +func (client Client) SetBucketLifecycle(bucketName string, rules []LifecycleRule, options ...Option) error { err := verifyLifecycleRules(rules) if err != nil { return err @@ -306,7 +376,26 @@ func (client Client) SetBucketLifecycle(bucketName string, rules []LifecycleRule params := map[string]interface{}{} params["lifecycle"] = nil - resp, err := client.do("PUT", bucketName, params, headers, buffer) + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// SetBucketLifecycleXml sets the bucket's lifecycle rule from xml config +func (client Client) SetBucketLifecycleXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["lifecycle"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) if err != nil { return err } @@ -321,10 +410,10 @@ func (client Client) SetBucketLifecycle(bucketName string, rules []LifecycleRule // // error it's nil if no error, otherwise it's an error object. // -func (client Client) DeleteBucketLifecycle(bucketName string) error { +func (client Client) DeleteBucketLifecycle(bucketName string, options ...Option) error { params := map[string]interface{}{} params["lifecycle"] = nil - resp, err := client.do("DELETE", bucketName, params, nil, nil) + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) if err != nil { return err } @@ -339,11 +428,11 @@ func (client Client) DeleteBucketLifecycle(bucketName string) error { // GetBucketLifecycleResponse the result object upon successful request. It's only valid when error is nil. // error it's nil if no error, otherwise it's an error object. // -func (client Client) GetBucketLifecycle(bucketName string) (GetBucketLifecycleResult, error) { +func (client Client) GetBucketLifecycle(bucketName string, options ...Option) (GetBucketLifecycleResult, error) { var out GetBucketLifecycleResult params := map[string]interface{}{} params["lifecycle"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return out, err } @@ -361,29 +450,43 @@ func (client Client) GetBucketLifecycle(bucketName string) (GetBucketLifecycleRe return out, err } +func (client Client) GetBucketLifecycleXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["lifecycle"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + // SetBucketReferer sets the bucket's referer whitelist and the flag if allowing empty referrer. // // To avoid stealing link on OSS data, OSS supports the HTTP referrer header. A whitelist referrer could be set either by API or web console, as well as -// the allowing empty referrer flag. Note that this applies to requests from webbrowser only. +// the allowing empty referrer flag. Note that this applies to requests from web browser only. // For example, for a bucket os-example and its referrer http://www.aliyun.com, all requests from this URL could access the bucket. // For more information, please check out this link : -// https://help.aliyun.com/document_detail/oss/user_guide/security_management/referer.html +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketreferer // // bucketName the bucket name. -// referers the referrer white list. A bucket could have a referrer list and each referrer supports one '*' and multiple '?' as wildcards. +// referrers the referrer white list. A bucket could have a referrer list and each referrer supports one '*' and multiple '?' as wildcards. // The sample could be found in sample/bucket_referer.go // allowEmptyReferer the flag of allowing empty referrer. By default it's true. // // error it's nil if no error, otherwise it's an error object. // -func (client Client) SetBucketReferer(bucketName string, referers []string, allowEmptyReferer bool) error { +func (client Client) SetBucketReferer(bucketName string, referrers []string, allowEmptyReferer bool, options ...Option) error { rxml := RefererXML{} rxml.AllowEmptyReferer = allowEmptyReferer - if referers == nil { + if referrers == nil { rxml.RefererList = append(rxml.RefererList, "") } else { - for _, referer := range referers { - rxml.RefererList = append(rxml.RefererList, referer) + for _, referrer := range referrers { + rxml.RefererList = append(rxml.RefererList, referrer) } } @@ -391,16 +494,39 @@ func (client Client) SetBucketReferer(bucketName string, referers []string, allo if err != nil { return err } - buffer := new(bytes.Buffer) - buffer.Write(bs) + return client.PutBucketRefererXml(bucketName, string(bs), options...) +} + +// SetBucketRefererV2 gets the bucket's referer white list. +// +// setBucketReferer SetBucketReferer bucket referer config in struct format. +// +// GetBucketRefererResponse the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketRefererV2(bucketName string, setBucketReferer RefererXML, options ...Option) error { + bs, err := xml.Marshal(setBucketReferer) + if err != nil { + return err + } + return client.PutBucketRefererXml(bucketName, string(bs), options...) +} + +// PutBucketRefererXml set bucket's style +// bucketName the bucket name. +// xmlData the style in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketRefererXml(bucketName, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) contentType := http.DetectContentType(buffer.Bytes()) headers := map[string]string{} headers[HTTPHeaderContentType] = contentType params := map[string]interface{}{} params["referer"] = nil - resp, err := client.do("PUT", bucketName, params, headers, buffer) + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) if err != nil { return err } @@ -409,31 +535,40 @@ func (client Client) SetBucketReferer(bucketName string, referers []string, allo } // GetBucketReferer gets the bucket's referrer white list. -// // bucketName the bucket name. -// -// GetBucketRefererResponse the result object upon successful request. It's only valid when error is nil. +// GetBucketRefererResult the result object upon successful request. It's only valid when error is nil. // error it's nil if no error, otherwise it's an error object. -// -func (client Client) GetBucketReferer(bucketName string) (GetBucketRefererResult, error) { +func (client Client) GetBucketReferer(bucketName string, options ...Option) (GetBucketRefererResult, error) { var out GetBucketRefererResult + body, err := client.GetBucketRefererXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketRefererXml gets the bucket's referrer white list. +// bucketName the bucket name. +// GetBucketRefererResponse the bucket referer config result in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketRefererXml(bucketName string, options ...Option) (string, error) { params := map[string]interface{}{} params["referer"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { - return out, err + return "", err } defer resp.Body.Close() - - err = xmlUnmarshal(resp.Body, &out) - return out, err + body, err := ioutil.ReadAll(resp.Body) + return string(body), err } // SetBucketLogging sets the bucket logging settings. // // OSS could automatically store the access log. Only the bucket owner could enable the logging. // Once enabled, OSS would save all the access log into hourly log files in a specified bucket. -// For more information, please check out https://help.aliyun.com/document_detail/oss/user_guide/security_management/logging.html +// For more information, please check out https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketlogging // // bucketName bucket name to enable the log. // targetBucket the target bucket name to store the log files. @@ -442,7 +577,7 @@ func (client Client) GetBucketReferer(bucketName string) (GetBucketRefererResult // error it's nil if no error, otherwise it's an error object. // func (client Client) SetBucketLogging(bucketName, targetBucket, targetPrefix string, - isEnable bool) error { + isEnable bool, options ...Option) error { var err error var bs []byte if isEnable { @@ -468,7 +603,7 @@ func (client Client) SetBucketLogging(bucketName, targetBucket, targetPrefix str params := map[string]interface{}{} params["logging"] = nil - resp, err := client.do("PUT", bucketName, params, headers, buffer) + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) if err != nil { return err } @@ -482,10 +617,10 @@ func (client Client) SetBucketLogging(bucketName, targetBucket, targetPrefix str // // error it's nil if no error, otherwise it's an error object. // -func (client Client) DeleteBucketLogging(bucketName string) error { +func (client Client) DeleteBucketLogging(bucketName string, options ...Option) error { params := map[string]interface{}{} params["logging"] = nil - resp, err := client.do("DELETE", bucketName, params, nil, nil) + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) if err != nil { return err } @@ -500,11 +635,11 @@ func (client Client) DeleteBucketLogging(bucketName string) error { // // error it's nil if no error, otherwise it's an error object. // -func (client Client) GetBucketLogging(bucketName string) (GetBucketLoggingResult, error) { +func (client Client) GetBucketLogging(bucketName string, options ...Option) (GetBucketLoggingResult, error) { var out GetBucketLoggingResult params := map[string]interface{}{} params["logging"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return out, err } @@ -517,7 +652,7 @@ func (client Client) GetBucketLogging(bucketName string) (GetBucketLoggingResult // SetBucketWebsite sets the bucket's static website's index and error page. // // OSS supports static web site hosting for the bucket data. When the bucket is enabled with that, you can access the file in the bucket like the way to access a static website. -// For more information, please check out: https://help.aliyun.com/document_detail/oss/user_guide/static_host_website.html +// For more information, please check out: https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketwebsite // // bucketName the bucket name to enable static web site. // indexDocument index page. @@ -525,7 +660,7 @@ func (client Client) GetBucketLogging(bucketName string) (GetBucketLoggingResult // // error it's nil if no error, otherwise it's an error object. // -func (client Client) SetBucketWebsite(bucketName, indexDocument, errorDocument string) error { +func (client Client) SetBucketWebsite(bucketName, indexDocument, errorDocument string, options ...Option) error { wxml := WebsiteXML{} wxml.IndexDocument.Suffix = indexDocument wxml.ErrorDocument.Key = errorDocument @@ -543,7 +678,7 @@ func (client Client) SetBucketWebsite(bucketName, indexDocument, errorDocument s params := map[string]interface{}{} params["website"] = nil - resp, err := client.do("PUT", bucketName, params, headers, buffer) + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) if err != nil { return err } @@ -554,7 +689,7 @@ func (client Client) SetBucketWebsite(bucketName, indexDocument, errorDocument s // SetBucketWebsiteDetail sets the bucket's static website's detail // // OSS supports static web site hosting for the bucket data. When the bucket is enabled with that, you can access the file in the bucket like the way to access a static website. -// For more information, please check out: https://help.aliyun.com/document_detail/oss/user_guide/static_host_website.html +// For more information, please check out: https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketwebsite // // bucketName the bucket name to enable static web site. // @@ -587,7 +722,7 @@ func (client Client) SetBucketWebsiteDetail(bucketName string, wxml WebsiteXML, // SetBucketWebsiteXml sets the bucket's static website's rule // // OSS supports static web site hosting for the bucket data. When the bucket is enabled with that, you can access the file in the bucket like the way to access a static website. -// For more information, please check out: https://help.aliyun.com/document_detail/oss/user_guide/static_host_website.html +// For more information, please check out: https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketwebsite // // bucketName the bucket name to enable static web site. // @@ -619,10 +754,10 @@ func (client Client) SetBucketWebsiteXml(bucketName string, webXml string, optio // // error it's nil if no error, otherwise it's an error object. // -func (client Client) DeleteBucketWebsite(bucketName string) error { +func (client Client) DeleteBucketWebsite(bucketName string, options ...Option) error { params := map[string]interface{}{} params["website"] = nil - resp, err := client.do("DELETE", bucketName, params, nil, nil) + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) if err != nil { return err } @@ -630,6 +765,110 @@ func (client Client) DeleteBucketWebsite(bucketName string) error { return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) } +// OpenMetaQuery Enables the metadata management feature for a bucket. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) OpenMetaQuery(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["metaQuery"] = nil + params["comp"] = "add" + resp, err := client.do("POST", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetMetaQueryStatus Queries the information about the metadata index library of a bucket. +// +// bucketName the bucket name +// +// GetMetaQueryStatusResult the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetMetaQueryStatus(bucketName string, options ...Option) (GetMetaQueryStatusResult, error) { + var out GetMetaQueryStatusResult + params := map[string]interface{}{} + params["metaQuery"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// DoMetaQuery Queries the objects that meet specified conditions and lists the information about objects based on specified fields and sorting methods. +// +// bucketName the bucket name +// +// metaQuery the option of query +// +// DoMetaQueryResult the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DoMetaQuery(bucketName string, metaQuery MetaQuery, options ...Option) (DoMetaQueryResult, error) { + var out DoMetaQueryResult + bs, err := xml.Marshal(metaQuery) + if err != nil { + return out, err + } + out, err = client.DoMetaQueryXml(bucketName, string(bs), options...) + return out, err +} + +// DoMetaQueryXml Queries the objects that meet specified conditions and lists the information about objects based on specified fields and sorting methods. +// +// bucketName the bucket name +// +// metaQuery the option of query +// +// DoMetaQueryResult the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DoMetaQueryXml(bucketName string, metaQueryXml string, options ...Option) (DoMetaQueryResult, error) { + var out DoMetaQueryResult + buffer := new(bytes.Buffer) + buffer.Write([]byte(metaQueryXml)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["metaQuery"] = nil + params["comp"] = "query" + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// CloseMetaQuery Disables the metadata management feature for a bucket. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) CloseMetaQuery(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["metaQuery"] = nil + params["comp"] = "delete" + resp, err := client.do("POST", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + // GetBucketWebsite gets the bucket's default page (index page) and the error page. // // bucketName the bucket name @@ -637,11 +876,11 @@ func (client Client) DeleteBucketWebsite(bucketName string) error { // GetBucketWebsiteResponse the result object upon successful request. It's only valid when error is nil. // error it's nil if no error, otherwise it's an error object. // -func (client Client) GetBucketWebsite(bucketName string) (GetBucketWebsiteResult, error) { +func (client Client) GetBucketWebsite(bucketName string, options ...Option) (GetBucketWebsiteResult, error) { var out GetBucketWebsiteResult params := map[string]interface{}{} params["website"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return out, err } @@ -658,10 +897,10 @@ func (client Client) GetBucketWebsite(bucketName string) (GetBucketWebsiteResult // string the bucket's xml config, It's only valid when error is nil. // error it's nil if no error, otherwise it's an error object. // -func (client Client) GetBucketWebsiteXml(bucketName string) (string, error) { +func (client Client) GetBucketWebsiteXml(bucketName string, options ...Option) (string, error) { params := map[string]interface{}{} params["website"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return "", err } @@ -682,7 +921,7 @@ func (client Client) GetBucketWebsiteXml(bucketName string) (string, error) { // // error it's nil if no error, otherwise it's an error object. // -func (client Client) SetBucketCORS(bucketName string, corsRules []CORSRule) error { +func (client Client) SetBucketCORS(bucketName string, corsRules []CORSRule, options ...Option) error { corsxml := CORSXML{} for _, v := range corsRules { cr := CORSRule{} @@ -707,7 +946,40 @@ func (client Client) SetBucketCORS(bucketName string, corsRules []CORSRule) erro params := map[string]interface{}{} params["cors"] = nil - resp, err := client.do("PUT", bucketName, params, headers, buffer) + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// SetBucketCORSV2 sets the bucket's CORS rules +// +// bucketName the bucket name +// putBucketCORS the CORS rules to set. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketCORSV2(bucketName string, putBucketCORS PutBucketCORS, options ...Option) error { + bs, err := xml.Marshal(putBucketCORS) + if err != nil { + return err + } + err = client.SetBucketCORSXml(bucketName, string(bs), options...) + return err +} + +func (client Client) SetBucketCORSXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["cors"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) if err != nil { return err } @@ -721,10 +993,10 @@ func (client Client) SetBucketCORS(bucketName string, corsRules []CORSRule) erro // // error it's nil if no error, otherwise it's an error object. // -func (client Client) DeleteBucketCORS(bucketName string) error { +func (client Client) DeleteBucketCORS(bucketName string, options ...Option) error { params := map[string]interface{}{} params["cors"] = nil - resp, err := client.do("DELETE", bucketName, params, nil, nil) + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) if err != nil { return err } @@ -739,11 +1011,11 @@ func (client Client) DeleteBucketCORS(bucketName string) error { // // error it's nil if no error, otherwise it's an error object. // -func (client Client) GetBucketCORS(bucketName string) (GetBucketCORSResult, error) { +func (client Client) GetBucketCORS(bucketName string, options ...Option) (GetBucketCORSResult, error) { var out GetBucketCORSResult params := map[string]interface{}{} params["cors"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return out, err } @@ -753,6 +1025,20 @@ func (client Client) GetBucketCORS(bucketName string) (GetBucketCORSResult, erro return out, err } +func (client Client) GetBucketCORSXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["cors"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + // GetBucketInfo gets the bucket information. // // bucketName the bucket name. @@ -954,8 +1240,14 @@ func (client Client) GetBucketTagging(bucketName string, options ...Option) (Get // error nil if success, otherwise error // func (client Client) DeleteBucketTagging(bucketName string, options ...Option) error { + key, _ := FindOption(options, "tagging", nil) params := map[string]interface{}{} - params["tagging"] = nil + if key == nil { + params["tagging"] = nil + } else { + params["tagging"] = key.(string) + } + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) if err != nil { return err @@ -967,11 +1259,11 @@ func (client Client) DeleteBucketTagging(bucketName string, options ...Option) e // GetBucketStat get bucket stat // bucketName the bucket name. // error it's nil if no error, otherwise it's an error object. -func (client Client) GetBucketStat(bucketName string) (GetBucketStatResult, error) { +func (client Client) GetBucketStat(bucketName string, options ...Option) (GetBucketStatResult, error) { var out GetBucketStatResult params := map[string]interface{}{} params["stat"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return out, err } @@ -1221,7 +1513,7 @@ func (client Client) DeleteBucketQosInfo(bucketName string, options ...Option) e // // Set the Bucket inventory. // -// bucketName tht bucket name. +// bucketName the bucket name. // // inventoryConfig the inventory configuration. // @@ -1257,6 +1549,47 @@ func (client Client) SetBucketInventory(bucketName string, inventoryConfig Inven return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) } +// SetBucketInventoryXml API operation for Object Storage Service +// +// Set the Bucket inventory +// +// bucketName the bucket name. +// +// xmlBody the inventory configuration. +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) SetBucketInventoryXml(bucketName string, xmlBody string, options ...Option) error { + var inventoryConfig InventoryConfiguration + err := xml.Unmarshal([]byte(xmlBody), &inventoryConfig) + if err != nil { + return err + } + + if inventoryConfig.Id == "" { + return fmt.Errorf("inventory id is empty in xml") + } + + params := map[string]interface{}{} + params["inventoryId"] = inventoryConfig.Id + params["inventory"] = nil + + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + // GetBucketInventory API operation for Object Storage Service // // Get the Bucket inventory. @@ -1285,6 +1618,33 @@ func (client Client) GetBucketInventory(bucketName string, strInventoryId string return out, err } +// GetBucketInventoryXml API operation for Object Storage Service +// +// Get the Bucket inventory. +// +// bucketName tht bucket name. +// +// strInventoryId the inventory id. +// +// InventoryConfiguration the inventory configuration. +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) GetBucketInventoryXml(bucketName string, strInventoryId string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["inventory"] = nil + params["inventoryId"] = strInventoryId + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + // ListBucketInventory API operation for Object Storage Service // // List the Bucket inventory. @@ -1317,6 +1677,37 @@ func (client Client) ListBucketInventory(bucketName, continuationToken string, o return out, err } +// ListBucketInventoryXml API operation for Object Storage Service +// +// List the Bucket inventory. +// +// bucketName tht bucket name. +// +// continuationToken the users token. +// +// ListInventoryConfigurationsResult list all inventory configuration by . +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) ListBucketInventoryXml(bucketName, continuationToken string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["inventory"] = nil + if continuationToken == "" { + params["continuation-token"] = nil + } else { + params["continuation-token"] = continuationToken + } + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + // DeleteBucketInventory API operation for Object Storage Service. // // Delete Bucket inventory information. @@ -1563,7 +1954,7 @@ func (client Client) GetBucketTransferAcc(bucketName string, options ...Option) var out TransferAccConfiguration params := map[string]interface{}{} params["transferAcceleration"] = nil - resp, err := client.do("GET", bucketName, params, nil, nil) + resp, err := client.do("GET", bucketName, params, nil, nil, options...) if err != nil { return out, err } @@ -1580,7 +1971,7 @@ func (client Client) GetBucketTransferAcc(bucketName string, options ...Option) func (client Client) DeleteBucketTransferAcc(bucketName string, options ...Option) error { params := map[string]interface{}{} params["transferAcceleration"] = nil - resp, err := client.do("DELETE", bucketName, params, nil, nil) + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) if err != nil { return err } @@ -1588,135 +1979,853 @@ func (client Client) DeleteBucketTransferAcc(bucketName string, options ...Optio return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) } -// LimitUploadSpeed set upload bandwidth limit speed,default is 0,unlimited -// upSpeed KB/s, 0 is unlimited,default is 0 -// error it's nil if success, otherwise failure -func (client Client) LimitUploadSpeed(upSpeed int) error { - if client.Config == nil { - return fmt.Errorf("client config is nil") - } - return client.Config.LimitUploadSpeed(upSpeed) -} - -// UseCname sets the flag of using CName. By default it's false. -// -// isUseCname true: the endpoint has the CName, false: the endpoint does not have cname. Default is false. +// PutBucketReplication put bucket replication configuration +// bucketName the bucket name. +// xmlBody the replication configuration. +// error it's nil if no error, otherwise it's an error object. // -func UseCname(isUseCname bool) ClientOption { - return func(client *Client) { - client.Config.IsCname = isUseCname - client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy) +func (client Client) PutBucketReplication(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["replication"] = nil + params["comp"] = "add" + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) } -// Timeout sets the HTTP timeout in seconds. -// -// connectTimeoutSec HTTP timeout in seconds. Default is 10 seconds. 0 means infinite (not recommended) -// readWriteTimeout HTTP read or write's timeout in seconds. Default is 20 seconds. 0 means infinite. +// PutBucketRTC put bucket replication rtc +// bucketName the bucket name. +// rtc the bucket rtc config. +// error it's nil if no error, otherwise it's an error object. // -func Timeout(connectTimeoutSec, readWriteTimeout int64) ClientOption { - return func(client *Client) { - client.Config.HTTPTimeout.ConnectTimeout = - time.Second * time.Duration(connectTimeoutSec) - client.Config.HTTPTimeout.ReadWriteTimeout = - time.Second * time.Duration(readWriteTimeout) - client.Config.HTTPTimeout.HeaderTimeout = - time.Second * time.Duration(readWriteTimeout) - client.Config.HTTPTimeout.IdleConnTimeout = - time.Second * time.Duration(readWriteTimeout) - client.Config.HTTPTimeout.LongTimeout = - time.Second * time.Duration(readWriteTimeout*10) +func (client Client) PutBucketRTC(bucketName string, rtc PutBucketRTC, options ...Option) error { + bs, err := xml.Marshal(rtc) + if err != nil { + return err } + err = client.PutBucketRTCXml(bucketName, string(bs), options...) + return err } -// SecurityToken sets the temporary user's SecurityToken. -// -// token STS token +// PutBucketRTCXml put bucket rtc configuration +// bucketName the bucket name. +// xmlBody the rtc configuration in xml format. +// error it's nil if no error, otherwise it's an error object. // -func SecurityToken(token string) ClientOption { - return func(client *Client) { - client.Config.SecurityToken = strings.TrimSpace(token) +func (client Client) PutBucketRTCXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["rtc"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) } -// EnableMD5 enables MD5 validation. -// -// isEnableMD5 true: enable MD5 validation; false: disable MD5 validation. +// GetBucketReplication get bucket replication configuration +// bucketName the bucket name. +// string the replication configuration. +// error it's nil if no error, otherwise it's an error object. // -func EnableMD5(isEnableMD5 bool) ClientOption { - return func(client *Client) { - client.Config.IsEnableMD5 = isEnableMD5 +func (client Client) GetBucketReplication(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["replication"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err } -} + defer resp.Body.Close() -// MD5ThresholdCalcInMemory sets the memory usage threshold for computing the MD5, default is 16MB. -// -// threshold the memory threshold in bytes. When the uploaded content is more than 16MB, the temp file is used for computing the MD5. -// -func MD5ThresholdCalcInMemory(threshold int64) ClientOption { - return func(client *Client) { - client.Config.MD5Threshold = threshold + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err } + return string(data), err } -// EnableCRC enables the CRC checksum. Default is true. -// -// isEnableCRC true: enable CRC checksum; false: disable the CRC checksum. +// DeleteBucketReplication delete bucket replication configuration +// bucketName the bucket name. +// ruleId the ID of the replication configuration. +// error it's nil if no error, otherwise it's an error object. // -func EnableCRC(isEnableCRC bool) ClientOption { - return func(client *Client) { - client.Config.IsEnableCRC = isEnableCRC +func (client Client) DeleteBucketReplication(bucketName string, ruleId string, options ...Option) error { + replicationxml := ReplicationXML{} + replicationxml.ID = ruleId + + bs, err := xml.Marshal(replicationxml) + if err != nil { + return err } -} -// UserAgent specifies UserAgent. The default is aliyun-sdk-go/1.2.0 (windows/-/amd64;go1.5.2). -// -// userAgent the user agent string. -// -func UserAgent(userAgent string) ClientOption { - return func(client *Client) { - client.Config.UserAgent = userAgent - client.Config.UserSetUa = true + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["replication"] = nil + params["comp"] = "delete" + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) } -// Proxy sets the proxy (optional). The default is not using proxy. -// -// proxyHost the proxy host in the format "host:port". For example, proxy.com:80 . +// GetBucketReplicationLocation get the locations of the target bucket that can be copied to +// bucketName the bucket name. +// string the locations of the target bucket that can be copied to. +// error it's nil if no error, otherwise it's an error object. // -func Proxy(proxyHost string) ClientOption { - return func(client *Client) { - client.Config.IsUseProxy = true - client.Config.ProxyHost = proxyHost - client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy) +func (client Client) GetBucketReplicationLocation(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["replicationLocation"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err } -} + defer resp.Body.Close() -// AuthProxy sets the proxy information with user name and password. -// -// proxyHost the proxy host in the format "host:port". For example, proxy.com:80 . -// proxyUser the proxy user name. -// proxyPassword the proxy password. -// -func AuthProxy(proxyHost, proxyUser, proxyPassword string) ClientOption { - return func(client *Client) { - client.Config.IsUseProxy = true - client.Config.ProxyHost = proxyHost - client.Config.IsAuthProxy = true - client.Config.ProxyUser = proxyUser - client.Config.ProxyPassword = proxyPassword - client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy) + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err } + return string(data), err } +// GetBucketReplicationProgress get the replication progress of bucket +// bucketName the bucket name. +// ruleId the ID of the replication configuration. +// string the replication progress of bucket. +// error it's nil if no error, otherwise it's an error object. // -// HTTPClient sets the http.Client in use to the one passed in -// -func HTTPClient(HTTPClient *http.Client) ClientOption { - return func(client *Client) { - client.HTTPClient = HTTPClient +func (client Client) GetBucketReplicationProgress(bucketName string, ruleId string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["replicationProgress"] = nil + if ruleId != "" { + params["rule-id"] = ruleId } -} + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(data), err +} + +// GetBucketAccessMonitor get bucket's access monitor config +// bucketName the bucket name. +// GetBucketAccessMonitorResult the access monitor configuration result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketAccessMonitor(bucketName string, options ...Option) (GetBucketAccessMonitorResult, error) { + var out GetBucketAccessMonitorResult + body, err := client.GetBucketAccessMonitorXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketAccessMonitorXml get bucket's access monitor config +// bucketName the bucket name. +// string the access monitor configuration result of bucket xml foramt. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketAccessMonitorXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["accessmonitor"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// PutBucketAccessMonitor get bucket's access monitor config +// bucketName the bucket name. +// accessMonitor the access monitor configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketAccessMonitor(bucketName string, accessMonitor PutBucketAccessMonitor, options ...Option) error { + bs, err := xml.Marshal(accessMonitor) + if err != nil { + return err + } + err = client.PutBucketAccessMonitorXml(bucketName, string(bs), options...) + return err +} + +// PutBucketAccessMonitorXml get bucket's access monitor config +// bucketName the bucket name. +// xmlData the access monitor configuration in xml foramt +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketAccessMonitorXml(bucketName string, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["accessmonitor"] = nil + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// ListBucketCname list bucket's binding cname +// bucketName the bucket name. +// string the xml configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) ListBucketCname(bucketName string, options ...Option) (ListBucketCnameResult, error) { + var out ListBucketCnameResult + body, err := client.GetBucketCname(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketCname get bucket's binding cname +// bucketName the bucket name. +// string the xml configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketCname(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["cname"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(data), err +} + +// CreateBucketCnameToken create a token for the cname. +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) CreateBucketCnameToken(bucketName string, cname string, options ...Option) (CreateBucketCnameTokenResult, error) { + var out CreateBucketCnameTokenResult + params := map[string]interface{}{} + params["cname"] = nil + params["comp"] = "token" + + rxml := CnameConfigurationXML{} + rxml.Domain = cname + + bs, err := xml.Marshal(rxml) + if err != nil { + return out, err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// GetBucketCnameToken get a token for the cname +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketCnameToken(bucketName string, cname string, options ...Option) (GetBucketCnameTokenResult, error) { + var out GetBucketCnameTokenResult + params := map[string]interface{}{} + params["cname"] = cname + params["comp"] = "token" + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// PutBucketCnameXml map a custom domain name to a bucket +// bucketName the bucket name. +// xmlBody the cname configuration in xml foramt +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketCnameXml(bucketName string, xmlBody string, options ...Option) error { + params := map[string]interface{}{} + params["cname"] = nil + params["comp"] = "add" + + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// PutBucketCname map a custom domain name to a bucket +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketCname(bucketName string, cname string, options ...Option) error { + rxml := CnameConfigurationXML{} + rxml.Domain = cname + bs, err := xml.Marshal(rxml) + if err != nil { + return err + } + return client.PutBucketCnameXml(bucketName, string(bs), options...) +} + +// PutBucketCnameWithCertificate map a custom domain name to a bucket +// bucketName the bucket name. +// PutBucketCname the bucket cname config in struct format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketCnameWithCertificate(bucketName string, putBucketCname PutBucketCname, options ...Option) error { + bs, err := xml.Marshal(putBucketCname) + if err != nil { + return err + } + return client.PutBucketCnameXml(bucketName, string(bs), options...) +} + +// DeleteBucketCname remove the mapping of the custom domain name from a bucket. +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DeleteBucketCname(bucketName string, cname string, options ...Option) error { + params := map[string]interface{}{} + params["cname"] = nil + params["comp"] = "delete" + + rxml := CnameConfigurationXML{} + rxml.Domain = cname + + bs, err := xml.Marshal(rxml) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// PutBucketResourceGroup set bucket's resource group +// bucketName the bucket name. +// resourceGroup the resource group configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResourceGroup(bucketName string, resourceGroup PutBucketResourceGroup, options ...Option) error { + bs, err := xml.Marshal(resourceGroup) + if err != nil { + return err + } + err = client.PutBucketResourceGroupXml(bucketName, string(bs), options...) + return err +} + +// PutBucketResourceGroupXml set bucket's resource group +// bucketName the bucket name. +// xmlData the resource group in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResourceGroupXml(bucketName string, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["resourceGroup"] = nil + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketResourceGroup get bucket's resource group +// bucketName the bucket name. +// GetBucketResourceGroupResult the resource group configuration result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResourceGroup(bucketName string, options ...Option) (GetBucketResourceGroupResult, error) { + var out GetBucketResourceGroupResult + body, err := client.GetBucketResourceGroupXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketResourceGroupXml get bucket's resource group +// bucketName the bucket name. +// string the resource group result of bucket xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResourceGroupXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["resourceGroup"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// PutBucketStyle set bucket's style +// bucketName the bucket name. +// styleContent the style content. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketStyle(bucketName, styleName string, styleContent string, options ...Option) error { + bs := fmt.Sprintf("", styleContent) + err := client.PutBucketStyleXml(bucketName, styleName, bs, options...) + return err +} + +// PutBucketStyleXml set bucket's style +// bucketName the bucket name. +// styleName the style name. +// xmlData the style in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketStyleXml(bucketName, styleName, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["style"] = nil + params["styleName"] = styleName + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketStyle get bucket's style +// bucketName the bucket name. +// styleName the bucket style name. +// GetBucketStyleResult the style result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketStyle(bucketName, styleName string, options ...Option) (GetBucketStyleResult, error) { + var out GetBucketStyleResult + body, err := client.GetBucketStyleXml(bucketName, styleName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketStyleXml get bucket's style +// bucketName the bucket name. +// styleName the bucket style name. +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketStyleXml(bucketName, styleName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["style"] = nil + params["styleName"] = styleName + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// ListBucketStyle get bucket's styles +// bucketName the bucket name. +// GetBucketListStyleResult the list style result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) ListBucketStyle(bucketName string, options ...Option) (GetBucketListStyleResult, error) { + var out GetBucketListStyleResult + body, err := client.ListBucketStyleXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// ListBucketStyleXml get bucket's list style +// bucketName the bucket name. +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) ListBucketStyleXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["style"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// DeleteBucketStyle delete bucket's style +// bucketName the bucket name. +// styleName the bucket style name. +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DeleteBucketStyle(bucketName, styleName string, options ...Option) error { + params := map[string]interface{}{} + params["style"] = bucketName + params["styleName"] = styleName + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// PutBucketResponseHeader set bucket response header +// bucketName the bucket name. +// xmlData the resource group in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResponseHeader(bucketName string, responseHeader PutBucketResponseHeader, options ...Option) error { + bs, err := xml.Marshal(responseHeader) + if err != nil { + return err + } + err = client.PutBucketResponseHeaderXml(bucketName, string(bs), options...) + return err +} + +// PutBucketResponseHeaderXml set bucket response header +// bucketName the bucket name. +// xmlData the bucket response header in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResponseHeaderXml(bucketName, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["responseHeader"] = nil + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketResponseHeader get bucket's response header. +// bucketName the bucket name. +// GetBucketResponseHeaderResult the response header result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResponseHeader(bucketName string, options ...Option) (GetBucketResponseHeaderResult, error) { + var out GetBucketResponseHeaderResult + body, err := client.GetBucketResponseHeaderXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketResponseHeaderXml get bucket's resource group +// bucketName the bucket name. +// string the response header result of bucket xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResponseHeaderXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["responseHeader"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// DeleteBucketResponseHeader delete response header from a bucket. +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DeleteBucketResponseHeader(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["responseHeader"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// DescribeRegions get describe regions +// GetDescribeRegionsResult the result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DescribeRegions(options ...Option) (DescribeRegionsResult, error) { + var out DescribeRegionsResult + body, err := client.DescribeRegionsXml(options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// DescribeRegionsXml get describe regions +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DescribeRegionsXml(options ...Option) (string, error) { + params, err := GetRawParams(options) + if err != nil { + return "", err + } + if params["regions"] == nil { + params["regions"] = nil + } + resp, err := client.do("GET", "", params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// LimitUploadSpeed set upload bandwidth limit speed,default is 0,unlimited +// upSpeed KB/s, 0 is unlimited,default is 0 +// error it's nil if success, otherwise failure +func (client Client) LimitUploadSpeed(upSpeed int) error { + if client.Config == nil { + return fmt.Errorf("client config is nil") + } + return client.Config.LimitUploadSpeed(upSpeed) +} + +// LimitDownloadSpeed set download bandwidth limit speed,default is 0,unlimited +// downSpeed KB/s, 0 is unlimited,default is 0 +// error it's nil if success, otherwise failure +func (client Client) LimitDownloadSpeed(downSpeed int) error { + if client.Config == nil { + return fmt.Errorf("client config is nil") + } + return client.Config.LimitDownloadSpeed(downSpeed) +} + +// UseCname sets the flag of using CName. By default it's false. +// +// isUseCname true: the endpoint has the CName, false: the endpoint does not have cname. Default is false. +// +func UseCname(isUseCname bool) ClientOption { + return func(client *Client) { + client.Config.IsCname = isUseCname + } +} + +// ForcePathStyle sets the flag of using Path Style. By default it's false. +// +// isPathStyle true: the endpoint has the Path Style, false: the endpoint does not have Path Style. Default is false. +// +func ForcePathStyle(isPathStyle bool) ClientOption { + return func(client *Client) { + client.Config.IsPathStyle = isPathStyle + } +} + +// Timeout sets the HTTP timeout in seconds. +// +// connectTimeoutSec HTTP timeout in seconds. Default is 10 seconds. 0 means infinite (not recommended) +// readWriteTimeout HTTP read or write's timeout in seconds. Default is 20 seconds. 0 means infinite. +// +func Timeout(connectTimeoutSec, readWriteTimeout int64) ClientOption { + return func(client *Client) { + client.Config.HTTPTimeout.ConnectTimeout = + time.Second * time.Duration(connectTimeoutSec) + client.Config.HTTPTimeout.ReadWriteTimeout = + time.Second * time.Duration(readWriteTimeout) + client.Config.HTTPTimeout.HeaderTimeout = + time.Second * time.Duration(readWriteTimeout) + client.Config.HTTPTimeout.IdleConnTimeout = + time.Second * time.Duration(readWriteTimeout) + client.Config.HTTPTimeout.LongTimeout = + time.Second * time.Duration(readWriteTimeout*10) + } +} + +// MaxConns sets the HTTP max connections for a client. +// +// maxIdleConns controls the maximum number of idle (keep-alive) connections across all hosts. Default is 100. +// maxIdleConnsPerHost controls the maximum idle (keep-alive) connections to keep per-host. Default is 100. +// maxConnsPerHost limits the total number of connections per host. Default is no limit. +// +func MaxConns(maxIdleConns, maxIdleConnsPerHost, maxConnsPerHost int) ClientOption { + return func(client *Client) { + client.Config.HTTPMaxConns.MaxIdleConns = maxIdleConns + client.Config.HTTPMaxConns.MaxIdleConnsPerHost = maxIdleConnsPerHost + client.Config.HTTPMaxConns.MaxConnsPerHost = maxConnsPerHost + } +} + +// SecurityToken sets the temporary user's SecurityToken. +// +// token STS token +// +func SecurityToken(token string) ClientOption { + return func(client *Client) { + client.Config.SecurityToken = strings.TrimSpace(token) + } +} + +// EnableMD5 enables MD5 validation. +// +// isEnableMD5 true: enable MD5 validation; false: disable MD5 validation. +// +func EnableMD5(isEnableMD5 bool) ClientOption { + return func(client *Client) { + client.Config.IsEnableMD5 = isEnableMD5 + } +} + +// MD5ThresholdCalcInMemory sets the memory usage threshold for computing the MD5, default is 16MB. +// +// threshold the memory threshold in bytes. When the uploaded content is more than 16MB, the temp file is used for computing the MD5. +// +func MD5ThresholdCalcInMemory(threshold int64) ClientOption { + return func(client *Client) { + client.Config.MD5Threshold = threshold + } +} + +// EnableCRC enables the CRC checksum. Default is true. +// +// isEnableCRC true: enable CRC checksum; false: disable the CRC checksum. +// +func EnableCRC(isEnableCRC bool) ClientOption { + return func(client *Client) { + client.Config.IsEnableCRC = isEnableCRC + } +} + +// UserAgent specifies UserAgent. The default is aliyun-sdk-go/1.2.0 (windows/-/amd64;go1.5.2). +// +// userAgent the user agent string. +// +func UserAgent(userAgent string) ClientOption { + return func(client *Client) { + client.Config.UserAgent = userAgent + client.Config.UserSetUa = true + } +} + +// Proxy sets the proxy (optional). The default is not using proxy. +// +// proxyHost the proxy host in the format "host:port". For example, proxy.com:80 . +// +func Proxy(proxyHost string) ClientOption { + return func(client *Client) { + client.Config.IsUseProxy = true + client.Config.ProxyHost = proxyHost + } +} + +// AuthProxy sets the proxy information with user name and password. +// +// proxyHost the proxy host in the format "host:port". For example, proxy.com:80 . +// proxyUser the proxy user name. +// proxyPassword the proxy password. +// +func AuthProxy(proxyHost, proxyUser, proxyPassword string) ClientOption { + return func(client *Client) { + client.Config.IsUseProxy = true + client.Config.ProxyHost = proxyHost + client.Config.IsAuthProxy = true + client.Config.ProxyUser = proxyUser + client.Config.ProxyPassword = proxyPassword + } +} + +// +// HTTPClient sets the http.Client in use to the one passed in +// +func HTTPClient(HTTPClient *http.Client) ClientOption { + return func(client *Client) { + client.HTTPClient = HTTPClient + } +} // // SetLogLevel sets the oss sdk log level @@ -1736,14 +2845,14 @@ func SetLogger(Logger *log.Logger) ClientOption { } } -// SetCredentialsProvider sets funciton for get the user's ak +// SetCredentialsProvider sets function for get the user's ak func SetCredentialsProvider(provider CredentialsProvider) ClientOption { return func(client *Client) { client.Config.CredentialsProvider = provider } } -// SetLocalAddr sets funciton for local addr +// SetLocalAddr sets function for local addr func SetLocalAddr(localAddr net.Addr) ClientOption { return func(client *Client) { client.Config.LocalAddr = localAddr @@ -1764,13 +2873,48 @@ func AdditionalHeaders(headers []string) ClientOption { } } -// only effective from go1.7 onward,RedirectEnabled set http redirect enabled or not +// RedirectEnabled only effective from go1.7 onward,RedirectEnabled set http redirect enabled or not func RedirectEnabled(enabled bool) ClientOption { return func(client *Client) { client.Config.RedirectEnabled = enabled } } +// InsecureSkipVerify skip verifying tls certificate file +func InsecureSkipVerify(enabled bool) ClientOption { + return func(client *Client) { + client.Config.InsecureSkipVerify = enabled + } +} + +// Region set region +func Region(region string) ClientOption { + return func(client *Client) { + client.Config.Region = region + } +} + +// CloudBoxId set cloudBox id +func CloudBoxId(cloudBoxId string) ClientOption { + return func(client *Client) { + client.Config.CloudBoxId = cloudBoxId + } +} + +// Product set product type +func Product(product string) ClientOption { + return func(client *Client) { + client.Config.Product = product + } +} + +// VerifyObjectStrict sets the flag of verifying object name strictly. +func VerifyObjectStrict(enable bool) ClientOption { + return func(client *Client) { + client.Config.VerifyObjectStrict = enable + } +} + // Private func (client Client) do(method, bucketName string, params map[string]interface{}, headers map[string]string, data io.Reader, options ...Option) (*Response, error) { @@ -1803,7 +2947,9 @@ func (client Client) do(method, bucketName string, params map[string]interface{} respHeader, _ := FindOption(options, responseHeader, nil) if respHeader != nil { pRespHeader := respHeader.(*http.Header) - *pRespHeader = resp.Headers + if resp != nil { + *pRespHeader = resp.Headers + } } return resp, err diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go index 55e5e370a..305fbcf12 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go @@ -34,20 +34,26 @@ type HTTPTimeout struct { type HTTPMaxConns struct { MaxIdleConns int MaxIdleConnsPerHost int + MaxConnsPerHost int } -// CredentialInf is interface for get AccessKeyID,AccessKeySecret,SecurityToken +// Credentials is interface for get AccessKeyID,AccessKeySecret,SecurityToken type Credentials interface { GetAccessKeyID() string GetAccessKeySecret() string GetSecurityToken() string } -// CredentialInfBuild is interface for get CredentialInf +// CredentialsProvider is interface for get Credential Info type CredentialsProvider interface { GetCredentials() Credentials } +type CredentialsProviderE interface { + CredentialsProvider + GetCredentialsE() (Credentials, error) +} + type defaultCredentials struct { config *Config } @@ -72,6 +78,68 @@ func (defBuild *defaultCredentialsProvider) GetCredentials() Credentials { return &defaultCredentials{config: defBuild.config} } +type envCredentials struct { + AccessKeyId string + AccessKeySecret string + SecurityToken string +} + +type EnvironmentVariableCredentialsProvider struct { + cred Credentials +} + +func (credentials *envCredentials) GetAccessKeyID() string { + return credentials.AccessKeyId +} + +func (credentials *envCredentials) GetAccessKeySecret() string { + return credentials.AccessKeySecret +} + +func (credentials *envCredentials) GetSecurityToken() string { + return credentials.SecurityToken +} + +func (defBuild *EnvironmentVariableCredentialsProvider) GetCredentials() Credentials { + var accessID, accessKey, token string + if defBuild.cred == nil { + accessID = os.Getenv("OSS_ACCESS_KEY_ID") + accessKey = os.Getenv("OSS_ACCESS_KEY_SECRET") + token = os.Getenv("OSS_SESSION_TOKEN") + } else { + accessID = defBuild.cred.GetAccessKeyID() + accessKey = defBuild.cred.GetAccessKeySecret() + token = defBuild.cred.GetSecurityToken() + } + + return &envCredentials{ + AccessKeyId: accessID, + AccessKeySecret: accessKey, + SecurityToken: token, + } +} + +func NewEnvironmentVariableCredentialsProvider() (EnvironmentVariableCredentialsProvider, error) { + var provider EnvironmentVariableCredentialsProvider + accessID := os.Getenv("OSS_ACCESS_KEY_ID") + if accessID == "" { + return provider, fmt.Errorf("access key id is empty!") + } + accessKey := os.Getenv("OSS_ACCESS_KEY_SECRET") + if accessKey == "" { + return provider, fmt.Errorf("access key secret is empty!") + } + token := os.Getenv("OSS_SESSION_TOKEN") + envCredential := &envCredentials{ + AccessKeyId: accessID, + AccessKeySecret: accessKey, + SecurityToken: token, + } + return EnvironmentVariableCredentialsProvider{ + cred: envCredential, + }, nil +} + // Config defines oss configuration type Config struct { Endpoint string // OSS endpoint @@ -83,6 +151,7 @@ type Config struct { Timeout uint // Timeout in seconds. By default it's 60. SecurityToken string // STS Token IsCname bool // If cname is in the endpoint. + IsPathStyle bool // If Path Style is in the endpoint. HTTPTimeout HTTPTimeout // HTTP timeout HTTPMaxConns HTTPMaxConns // Http max connections IsUseProxy bool // Flag of using proxy. @@ -97,12 +166,19 @@ type Config struct { Logger *log.Logger // For write log UploadLimitSpeed int // Upload limit speed:KB/s, 0 is unlimited UploadLimiter *OssLimiter // Bandwidth limit reader for upload + DownloadLimitSpeed int // Download limit speed:KB/s, 0 is unlimited + DownloadLimiter *OssLimiter // Bandwidth limit reader for download CredentialsProvider CredentialsProvider // User provides interface to get AccessKeyID, AccessKeySecret, SecurityToken LocalAddr net.Addr // local client host info UserSetUa bool // UserAgent is set by user or not - AuthVersion AuthVersionType // v1 or v2 signature,default is v1 + AuthVersion AuthVersionType // v1 or v2, v4 signature,default is v1 AdditionalHeaders []string // special http headers needed to be sign RedirectEnabled bool // only effective from go1.7 onward, enable http redirect or not + InsecureSkipVerify bool // for https, Whether to skip verifying the server certificate file + Region string // such as cn-hangzhou + CloudBoxId string // + Product string // oss or oss-cloudbox, default is oss + VerifyObjectStrict bool // a flag of verifying object name strictly. Default is enable. } // LimitUploadSpeed uploadSpeed:KB/s, 0 is unlimited,default is 0 @@ -123,6 +199,24 @@ func (config *Config) LimitUploadSpeed(uploadSpeed int) error { return err } +// LimitDownLoadSpeed downloadSpeed:KB/s, 0 is unlimited,default is 0 +func (config *Config) LimitDownloadSpeed(downloadSpeed int) error { + if downloadSpeed < 0 { + return fmt.Errorf("invalid argument, the value of downloadSpeed is less than 0") + } else if downloadSpeed == 0 { + config.DownloadLimitSpeed = 0 + config.DownloadLimiter = nil + return nil + } + + var err error + config.DownloadLimiter, err = GetOssLimiter(downloadSpeed) + if err == nil { + config.DownloadLimitSpeed = downloadSpeed + } + return err +} + // WriteLog output log function func (config *Config) WriteLog(LogLevel int, format string, a ...interface{}) { if config.LogLevel < LogLevel || config.Logger == nil { @@ -140,6 +234,22 @@ func (config *Config) GetCredentials() Credentials { return config.CredentialsProvider.GetCredentials() } +// for get Sign Product +func (config *Config) GetSignProduct() string { + if config.CloudBoxId != "" { + return "oss-cloudbox" + } + return "oss" +} + +// for get Sign Region +func (config *Config) GetSignRegion() string { + if config.CloudBoxId != "" { + return config.CloudBoxId + } + return config.Region +} + // getDefaultOssConfig gets the default configuration. func getDefaultOssConfig() *Config { config := Config{} @@ -153,6 +263,7 @@ func getDefaultOssConfig() *Config { config.Timeout = 60 // Seconds config.SecurityToken = "" config.IsCname = false + config.IsPathStyle = false config.HTTPTimeout.ConnectTimeout = time.Second * 30 // 30s config.HTTPTimeout.ReadWriteTimeout = time.Second * 60 // 60s @@ -180,6 +291,11 @@ func getDefaultOssConfig() *Config { config.AuthVersion = AuthV1 config.RedirectEnabled = true + config.InsecureSkipVerify = false + + config.Product = "oss" + + config.VerifyObjectStrict = true return &config } diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go index fbbb1bb7e..86e2b6f2f 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go @@ -2,6 +2,7 @@ package oss import ( "bytes" + "context" "crypto/md5" "encoding/base64" "encoding/json" @@ -48,8 +49,16 @@ var signKeyList = []string{"acl", "uploads", "location", "cors", "worm", "wormId", "wormExtend", "withHashContext", "x-oss-enable-md5", "x-oss-enable-sha1", "x-oss-enable-sha256", "x-oss-hash-ctx", "x-oss-md5-ctx", "transferAcceleration", + "regionList", "cloudboxes", "x-oss-ac-source-ip", "x-oss-ac-subnet-mask", "x-oss-ac-vpc-id", "x-oss-ac-forward-allow", + "metaQuery", "resourceGroup", "rtc", "x-oss-async-process", "responseHeader", } +const ( + timeFormatV4 = "20060102T150405Z" + shortTimeFormatV4 = "20060102" + signingAlgorithmV4 = "OSS4-HMAC-SHA256" +) + // init initializes Conn func (conn *Conn) init(config *Config, urlMaker *urlMaker, client *http.Client) error { if client == nil { @@ -86,16 +95,35 @@ func (conn *Conn) init(config *Config, urlMaker *urlMaker, client *http.Client) // Do sends request and returns the response func (conn Conn) Do(method, bucketName, objectName string, params map[string]interface{}, headers map[string]string, + data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { + return conn.DoWithContext(nil, method, bucketName, objectName, params, headers, data, initCRC, listener) +} + +// DoWithContext sends request and returns the response with context +func (conn Conn) DoWithContext(ctx context.Context, method, bucketName, objectName string, params map[string]interface{}, headers map[string]string, data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { urlParams := conn.getURLParams(params) subResource := conn.getSubResource(params) uri := conn.url.getURL(bucketName, objectName, urlParams) - resource := conn.getResource(bucketName, objectName, subResource) - return conn.doRequest(method, uri, resource, headers, data, initCRC, listener) + + resource := "" + if conn.config.AuthVersion != AuthV4 { + resource = conn.getResource(bucketName, objectName, subResource) + } else { + resource = conn.getResourceV4(bucketName, objectName, subResource) + } + + return conn.doRequest(ctx, method, uri, resource, headers, data, initCRC, listener) } // DoURL sends the request with signed URL and returns the response result. func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]string, + data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { + return conn.DoURLWithContext(nil, method, signedURL, headers, data, initCRC, listener) +} + +// DoURLWithContext sends the request with signed URL and context and returns the response result. +func (conn Conn) DoURLWithContext(ctx context.Context, method HTTPMethod, signedURL string, headers map[string]string, data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { // Get URI from signedURL uri, err := url.ParseRequestURI(signedURL) @@ -114,6 +142,9 @@ func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]s Host: uri.Host, } + if ctx != nil { + req = req.WithContext(ctx) + } tracker := &readerTracker{completedBytes: 0} fd, crc := conn.handleBody(req, data, initCRC, listener, tracker) if fd != nil { @@ -149,9 +180,10 @@ func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]s resp, err := conn.client.Do(req) if err != nil { // Transfer failed + conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error()) event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0) publishProgress(listener, event) - conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error()) + return nil, err } @@ -182,7 +214,7 @@ func (conn Conn) getURLParams(params map[string]interface{}) string { buf.WriteByte('&') } buf.WriteString(url.QueryEscape(k)) - if params[k] != nil { + if params[k] != nil && params[k].(string) != "" { buf.WriteString("=" + strings.Replace(url.QueryEscape(params[k].(string)), "+", "%20", -1)) } } @@ -195,7 +227,7 @@ func (conn Conn) getSubResource(params map[string]interface{}) string { keys := make([]string, 0, len(params)) signParams := make(map[string]string) for k := range params { - if conn.config.AuthVersion == AuthV2 { + if conn.config.AuthVersion == AuthV2 || conn.config.AuthVersion == AuthV4 { encodedKey := url.QueryEscape(k) keys = append(keys, encodedKey) if params[k] != nil && params[k] != "" { @@ -218,7 +250,9 @@ func (conn Conn) getSubResource(params map[string]interface{}) string { } buf.WriteString(k) if _, ok := signParams[k]; ok { - buf.WriteString("=" + signParams[k]) + if signParams[k] != "" { + buf.WriteString("=" + signParams[k]) + } } } return buf.String() @@ -250,10 +284,31 @@ func (conn Conn) getResource(bucketName, objectName, subResource string) string return fmt.Sprintf("/%s/%s%s", bucketName, objectName, subResource) } -func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource string, headers map[string]string, +// getResource gets canonicalized resource +func (conn Conn) getResourceV4(bucketName, objectName, subResource string) string { + if subResource != "" { + subResource = "?" + subResource + } + + if bucketName == "" { + return fmt.Sprintf("/%s", subResource) + } + + if objectName != "" { + objectName = url.QueryEscape(objectName) + objectName = strings.Replace(objectName, "+", "%20", -1) + objectName = strings.Replace(objectName, "%2F", "/", -1) + return fmt.Sprintf("/%s/%s%s", bucketName, objectName, subResource) + } + return fmt.Sprintf("/%s/%s", bucketName, subResource) +} + +func (conn Conn) doRequest(ctx context.Context, method string, uri *url.URL, canonicalizedResource string, headers map[string]string, data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { method = strings.ToUpper(method) - req := &http.Request{ + var req *http.Request + var err error + req = &http.Request{ Method: method, URL: uri, Proto: "HTTP/1.1", @@ -262,7 +317,9 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st Header: make(http.Header), Host: uri.Host, } - + if ctx != nil { + req = req.WithContext(ctx) + } tracker := &readerTracker{completedBytes: 0} fd, crc := conn.handleBody(req, data, initCRC, listener, tracker) if fd != nil { @@ -278,12 +335,24 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st req.Header.Set("Proxy-Authorization", basic) } - date := time.Now().UTC().Format(http.TimeFormat) - req.Header.Set(HTTPHeaderDate, date) + stNow := time.Now().UTC() + req.Header.Set(HTTPHeaderDate, stNow.Format(http.TimeFormat)) req.Header.Set(HTTPHeaderHost, req.Host) req.Header.Set(HTTPHeaderUserAgent, conn.config.UserAgent) - akIf := conn.config.GetCredentials() + if conn.config.AuthVersion == AuthV4 { + req.Header.Set(HttpHeaderOssContentSha256, DefaultContentSha256) + } + + var akIf Credentials + if providerE, ok := conn.config.CredentialsProvider.(CredentialsProviderE); ok { + if akIf, err = providerE.GetCredentialsE(); err != nil { + return nil, err + } + } else { + akIf = conn.config.GetCredentials() + } + if akIf.GetSecurityToken() != "" { req.Header.Set(HTTPHeaderOssSecurityToken, akIf.GetSecurityToken()) } @@ -294,7 +363,7 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st } } - conn.signHeader(req, canonicalizedResource) + conn.signHeader(req, canonicalizedResource, akIf) // Transfer started event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength, 0) @@ -307,10 +376,10 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st resp, err := conn.client.Do(req) if err != nil { + conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error()) // Transfer failed event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0) publishProgress(listener, event) - conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error()) return nil, err } @@ -326,10 +395,15 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st return conn.handleResponse(resp, crc) } -func (conn Conn) signURL(method HTTPMethod, bucketName, objectName string, expiration int64, params map[string]interface{}, headers map[string]string) string { - akIf := conn.config.GetCredentials() - if akIf.GetSecurityToken() != "" { - params[HTTPParamSecurityToken] = akIf.GetSecurityToken() +func (conn Conn) signURL(method HTTPMethod, bucketName, objectName string, expiration int64, params map[string]interface{}, headers map[string]string) (string, error) { + var akIf Credentials + var err error + if providerE, ok := conn.config.CredentialsProvider.(CredentialsProviderE); ok { + if akIf, err = providerE.GetCredentialsE(); err != nil { + return "", err + } + } else { + akIf = conn.config.GetCredentials() } m := strings.ToUpper(string(method)) @@ -344,38 +418,74 @@ func (conn Conn) signURL(method HTTPMethod, bucketName, objectName string, expir req.Header.Set("Proxy-Authorization", basic) } - req.Header.Set(HTTPHeaderDate, strconv.FormatInt(expiration, 10)) - req.Header.Set(HTTPHeaderUserAgent, conn.config.UserAgent) + if conn.config.AuthVersion == AuthV4 { + if akIf.GetSecurityToken() != "" { + params[HTTPParamOssSecurityToken] = akIf.GetSecurityToken() + } - if headers != nil { - for k, v := range headers { - req.Header.Set(k, v) + if headers != nil { + for k, v := range headers { + req.Header.Set(k, v) + } } - } - if conn.config.AuthVersion == AuthV2 { - params[HTTPParamSignatureVersion] = "OSS2" - params[HTTPParamExpiresV2] = strconv.FormatInt(expiration, 10) - params[HTTPParamAccessKeyIDV2] = conn.config.AccessKeyID + now := time.Now().UTC() + expires := expiration - now.Unix() + product := conn.config.GetSignProduct() + region := conn.config.GetSignRegion() + strDay := now.Format(shortTimeFormatV4) additionalList, _ := conn.getAdditionalHeaderKeys(req) + + params[HTTPParamSignatureVersion] = signingAlgorithmV4 + params[HTTPParamCredential] = fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request", akIf.GetAccessKeyID(), strDay, region, product) + params[HTTPParamDate] = now.Format(timeFormatV4) + params[HTTPParamExpiresV2] = strconv.FormatInt(expires, 10) if len(additionalList) > 0 { params[HTTPParamAdditionalHeadersV2] = strings.Join(additionalList, ";") } - } - subResource := conn.getSubResource(params) - canonicalizedResource := conn.getResource(bucketName, objectName, subResource) - signedStr := conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()) + subResource := conn.getSubResource(params) + canonicalizedResource := conn.getResourceV4(bucketName, objectName, subResource) + authorizationStr := conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), &now) + params[HTTPParamSignatureV2] = authorizationStr + } else { + if akIf.GetSecurityToken() != "" { + params[HTTPParamSecurityToken] = akIf.GetSecurityToken() + } - if conn.config.AuthVersion == AuthV1 { - params[HTTPParamExpires] = strconv.FormatInt(expiration, 10) - params[HTTPParamAccessKeyID] = akIf.GetAccessKeyID() - params[HTTPParamSignature] = signedStr - } else if conn.config.AuthVersion == AuthV2 { - params[HTTPParamSignatureV2] = signedStr + req.Header.Set(HTTPHeaderDate, strconv.FormatInt(expiration, 10)) + + if headers != nil { + for k, v := range headers { + req.Header.Set(k, v) + } + } + + if conn.config.AuthVersion == AuthV2 { + params[HTTPParamSignatureVersion] = "OSS2" + params[HTTPParamExpiresV2] = strconv.FormatInt(expiration, 10) + params[HTTPParamAccessKeyIDV2] = conn.config.AccessKeyID + additionalList, _ := conn.getAdditionalHeaderKeys(req) + if len(additionalList) > 0 { + params[HTTPParamAdditionalHeadersV2] = strings.Join(additionalList, ";") + } + } + + subResource := conn.getSubResource(params) + canonicalizedResource := conn.getResource(bucketName, objectName, subResource) + signedStr := conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()) + + if conn.config.AuthVersion == AuthV1 { + params[HTTPParamExpires] = strconv.FormatInt(expiration, 10) + params[HTTPParamAccessKeyID] = akIf.GetAccessKeyID() + params[HTTPParamSignature] = signedStr + } else if conn.config.AuthVersion == AuthV2 { + params[HTTPParamSignatureV2] = signedStr + } } + urlParams := conn.getURLParams(params) - return conn.url.getSignURL(bucketName, objectName, urlParams) + return conn.url.getSignURL(bucketName, objectName, urlParams), nil } func (conn Conn) signRtmpURL(bucketName, channelName, playlistName string, expiration int64) string { @@ -468,58 +578,131 @@ func (conn Conn) handleResponse(resp *http.Response, crc hash.Hash64) (*Response var srvCRC uint64 statusCode := resp.StatusCode - if statusCode >= 400 && statusCode <= 505 { - // 4xx and 5xx indicate that the operation has error occurred - var respBody []byte - respBody, err := readResponseBody(resp) - if err != nil { - return nil, err - } - - if len(respBody) == 0 { - err = ServiceError{ - StatusCode: statusCode, - RequestID: resp.Header.Get(HTTPHeaderOssRequestID), + if statusCode/100 != 2 { + if statusCode >= 400 && statusCode <= 505 { + // 4xx and 5xx indicate that the operation has error occurred + var respBody []byte + var errorXml []byte + respBody, err := readResponseBody(resp) + if err != nil { + return nil, err + } + errorXml = respBody + if len(respBody) == 0 && len(resp.Header.Get(HTTPHeaderOssErr)) > 0 { + errorXml, err = base64.StdEncoding.DecodeString(resp.Header.Get(HTTPHeaderOssErr)) + if err != nil { + errorXml = respBody + } } + if len(errorXml) == 0 { + err = ServiceError{ + StatusCode: statusCode, + RequestID: resp.Header.Get(HTTPHeaderOssRequestID), + Ec: resp.Header.Get(HTTPHeaderOssEc), + } + } else { + srvErr, errIn := serviceErrFromXML(errorXml, resp.StatusCode, + resp.Header.Get(HTTPHeaderOssRequestID)) + if errIn != nil { // error unmarshal the error response + if len(resp.Header.Get(HTTPHeaderOssEc)) > 0 { + err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s, ec = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID), resp.Header.Get(HTTPHeaderOssEc)) + } else { + err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID)) + } + } else { + err = srvErr + } + } + return &Response{ + StatusCode: resp.StatusCode, + Headers: resp.Header, + Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body + }, err + } else if statusCode >= 300 && statusCode <= 307 { + // OSS use 3xx, but response has no body + err := fmt.Errorf("oss: service returned %d,%s", resp.StatusCode, resp.Status) + return &Response{ + StatusCode: resp.StatusCode, + Headers: resp.Header, + Body: resp.Body, + }, err } else { - // Response contains storage service error object, unmarshal - srvErr, errIn := serviceErrFromXML(respBody, resp.StatusCode, - resp.Header.Get(HTTPHeaderOssRequestID)) - if errIn != nil { // error unmarshaling the error response - err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID)) + // (0,300) [308,400) [506,) + // Other extended http StatusCode + var respBody []byte + var errorXml []byte + respBody, err := readResponseBody(resp) + if err != nil { + return &Response{StatusCode: resp.StatusCode, Headers: resp.Header, Body: ioutil.NopCloser(bytes.NewReader(respBody))}, err + } + errorXml = respBody + if len(respBody) == 0 && len(resp.Header.Get(HTTPHeaderOssErr)) > 0 { + errorXml, err = base64.StdEncoding.DecodeString(resp.Header.Get(HTTPHeaderOssErr)) + if err != nil { + errorXml = respBody + } + } + if len(errorXml) == 0 { + err = ServiceError{ + StatusCode: statusCode, + RequestID: resp.Header.Get(HTTPHeaderOssRequestID), + Ec: resp.Header.Get(HTTPHeaderOssEc), + } } else { - err = srvErr + srvErr, errIn := serviceErrFromXML(errorXml, resp.StatusCode, + resp.Header.Get(HTTPHeaderOssRequestID)) + if errIn != nil { // error unmarshal the error response + if len(resp.Header.Get(HTTPHeaderOssEc)) > 0 { + err = fmt.Errorf("unknown response body, status = %s, RequestId = %s, ec = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID), resp.Header.Get(HTTPHeaderOssEc)) + } else { + err = fmt.Errorf("unknown response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID)) + } + } else { + err = srvErr + } } + return &Response{ + StatusCode: resp.StatusCode, + Headers: resp.Header, + Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body + }, err + } + } else { + if conn.config.IsEnableCRC && crc != nil { + cliCRC = crc.Sum64() } + srvCRC, _ = strconv.ParseUint(resp.Header.Get(HTTPHeaderOssCRC64), 10, 64) + realBody := resp.Body + if conn.isDownloadLimitResponse(resp) { + limitReader := &LimitSpeedReader{ + reader: realBody, + ossLimiter: conn.config.DownloadLimiter, + } + realBody = limitReader + } + + // 2xx, successful return &Response{ StatusCode: resp.StatusCode, Headers: resp.Header, - Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body - }, err - } else if statusCode >= 300 && statusCode <= 307 { - // OSS use 3xx, but response has no body - err := fmt.Errorf("oss: service returned %d,%s", resp.StatusCode, resp.Status) - return &Response{ - StatusCode: resp.StatusCode, - Headers: resp.Header, - Body: resp.Body, - }, err + Body: realBody, + ClientCRC: cliCRC, + ServerCRC: srvCRC, + }, nil } +} - if conn.config.IsEnableCRC && crc != nil { - cliCRC = crc.Sum64() +// isUploadLimitReq: judge limit upload speed or not +func (conn Conn) isDownloadLimitResponse(resp *http.Response) bool { + if resp == nil || conn.config.DownloadLimitSpeed == 0 || conn.config.DownloadLimiter == nil { + return false } - srvCRC, _ = strconv.ParseUint(resp.Header.Get(HTTPHeaderOssCRC64), 10, 64) - // 2xx, successful - return &Response{ - StatusCode: resp.StatusCode, - Headers: resp.Header, - Body: resp.Body, - ClientCRC: cliCRC, - ServerCRC: srvCRC, - }, nil + if strings.EqualFold(resp.Request.Method, "GET") { + return true + } + return false } // LoggerHTTPReq Print the header information of the http request @@ -680,9 +863,10 @@ func (c *timeoutConn) SetWriteDeadline(t time.Time) error { // UrlMaker builds URL and resource const ( - urlTypeCname = 1 - urlTypeIP = 2 - urlTypeAliyun = 3 + urlTypeCname = 1 + urlTypeIP = 2 + urlTypeAliyun = 3 + urlTypePathStyle = 4 ) type urlMaker struct { @@ -694,6 +878,11 @@ type urlMaker struct { // Init parses endpoint func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) error { + return um.InitExt(endpoint, isCname, isProxy, false) +} + +// InitExt parses endpoint +func (um *urlMaker) InitExt(endpoint string, isCname bool, isProxy bool, isPathStyle bool) error { if strings.HasPrefix(endpoint, "http://") { um.Scheme = "http" um.NetLoc = endpoint[len("http://"):] @@ -716,7 +905,7 @@ func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) error { host, _, err := net.SplitHostPort(um.NetLoc) if err != nil { host = um.NetLoc - if host[0] == '[' && host[len(host)-1] == ']' { + if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' { host = host[1 : len(host)-1] } } @@ -726,6 +915,8 @@ func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) error { um.Type = urlTypeIP } else if isCname { um.Type = urlTypeCname + } else if isPathStyle { + um.Type = urlTypePathStyle } else { um.Type = urlTypeAliyun } @@ -774,7 +965,7 @@ func (um urlMaker) buildURL(bucket, object string) (string, string) { if um.Type == urlTypeCname { host = um.NetLoc path = "/" + object - } else if um.Type == urlTypeIP { + } else if um.Type == urlTypeIP || um.Type == urlTypePathStyle { if bucket == "" { host = um.NetLoc path = "/" @@ -794,3 +985,37 @@ func (um urlMaker) buildURL(bucket, object string) (string, string) { return host, path } + +// buildURL builds URL +func (um urlMaker) buildURLV4(bucket, object string) (string, string) { + var host = "" + var path = "" + + object = url.QueryEscape(object) + object = strings.Replace(object, "+", "%20", -1) + + // no escape / + object = strings.Replace(object, "%2F", "/", -1) + + if um.Type == urlTypeCname { + host = um.NetLoc + path = "/" + object + } else if um.Type == urlTypeIP || um.Type == urlTypePathStyle { + if bucket == "" { + host = um.NetLoc + path = "/" + } else { + host = um.NetLoc + path = fmt.Sprintf("/%s/%s", bucket, object) + } + } else { + if bucket == "" { + host = um.NetLoc + path = "/" + } else { + host = bucket + "." + um.NetLoc + path = fmt.Sprintf("/%s/%s", bucket, object) + } + } + return host, path +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go index 6e02ef529..400f7cf95 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go @@ -76,6 +76,9 @@ const ( // StorageColdArchive cold archive StorageColdArchive StorageClassType = "ColdArchive" + + // StorageDeepColdArchive deep cold archive + StorageDeepColdArchive StorageClassType = "DeepColdArchive" ) //RedundancyType bucket data Redundancy type @@ -203,6 +206,12 @@ const ( HTTPHeaderOssTaskID = "X-Oss-Task-Id" HTTPHeaderOssHashCtx = "X-Oss-Hash-Ctx" HTTPHeaderOssMd5Ctx = "X-Oss-Md5-Ctx" + HTTPHeaderAllowSameActionOverLap = "X-Oss-Allow-Same-Action-Overlap" + HttpHeaderOssDate = "X-Oss-Date" + HttpHeaderOssContentSha256 = "X-Oss-Content-Sha256" + HttpHeaderOssNotification = "X-Oss-Notification" + HTTPHeaderOssEc = "X-Oss-Ec" + HTTPHeaderOssErr = "X-Oss-Err" ) // HTTP Param @@ -218,6 +227,9 @@ const ( HTTPParamAccessKeyIDV2 = "x-oss-access-key-id" HTTPParamSignatureV2 = "x-oss-signature" HTTPParamAdditionalHeadersV2 = "x-oss-additional-headers" + HTTPParamCredential = "x-oss-credential" + HTTPParamDate = "x-oss-date" + HTTPParamOssSecurityToken = "x-oss-security-token" ) // Other constants @@ -234,7 +246,9 @@ const ( NullVersion = "null" - Version = "v2.1.8" // Go SDK version + DefaultContentSha256 = "UNSIGNED-PAYLOAD" // for v4 signature + + Version = "v3.0.2" // Go SDK version ) // FrameType @@ -254,4 +268,6 @@ const ( AuthV1 AuthVersionType = "v1" // AuthV2 v2 AuthV2 AuthVersionType = "v2" + // AuthV4 v4 + AuthV4 AuthVersionType = "v4" ) diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go index a877211fa..aaa24f28a 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go @@ -3,7 +3,9 @@ package oss import ( "encoding/xml" "fmt" + "io/ioutil" "net/http" + "strconv" "strings" ) @@ -15,18 +17,22 @@ type ServiceError struct { RequestID string `xml:"RequestId"` // The UUID used to uniquely identify the request HostID string `xml:"HostId"` // The OSS server cluster's Id Endpoint string `xml:"Endpoint"` + Ec string `xml:"EC"` RawMessage string // The raw messages from OSS StatusCode int // HTTP status code + } // Error implements interface error func (e ServiceError) Error() string { - if e.Endpoint == "" { - return fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=\"%s\", RequestId=%s", - e.StatusCode, e.Code, e.Message, e.RequestID) + errorStr := fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=\"%s\", RequestId=%s", e.StatusCode, e.Code, e.Message, e.RequestID) + if len(e.Endpoint) > 0 { + errorStr = fmt.Sprintf("%s, Endpoint=%s", errorStr, e.Endpoint) + } + if len(e.Ec) > 0 { + errorStr = fmt.Sprintf("%s, Ec=%s", errorStr, e.Ec) } - return fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=\"%s\", RequestId=%s, Endpoint=%s", - e.StatusCode, e.Code, e.Message, e.RequestID, e.Endpoint) + return errorStr } // UnexpectedStatusCodeError is returned when a storage service responds with neither an error @@ -65,6 +71,42 @@ func CheckRespCode(respCode int, allowed []int) error { return UnexpectedStatusCodeError{allowed, respCode} } +// CheckCallbackResp return error if the given response code is not 200 +func CheckCallbackResp(resp *Response) error { + var err error + contentLengthStr := resp.Headers.Get("Content-Length") + contentLength, _ := strconv.Atoi(contentLengthStr) + var bodyBytes []byte + if contentLength > 0 { + bodyBytes, _ = ioutil.ReadAll(resp.Body) + } + if len(bodyBytes) > 0 { + srvErr, errIn := serviceErrFromXML(bodyBytes, resp.StatusCode, + resp.Headers.Get(HTTPHeaderOssRequestID)) + if errIn != nil { + if len(resp.Headers.Get(HTTPHeaderOssEc)) > 0 { + err = fmt.Errorf("unknown response body, status code = %d, RequestId = %s, ec = %s", resp.StatusCode, resp.Headers.Get(HTTPHeaderOssRequestID), resp.Headers.Get(HTTPHeaderOssEc)) + } else { + err = fmt.Errorf("unknown response body, status code= %d, RequestId = %s", resp.StatusCode, resp.Headers.Get(HTTPHeaderOssRequestID)) + } + } else { + err = srvErr + } + } + return err +} + +func tryConvertServiceError(data []byte, resp *Response, def error) (err error) { + err = def + if len(data) > 0 { + srvErr, errIn := serviceErrFromXML(data, resp.StatusCode, resp.Headers.Get(HTTPHeaderOssRequestID)) + if errIn == nil { + err = srvErr + } + } + return err +} + // CRCCheckError is returned when crc check is inconsistent between client and server type CRCCheckError struct { clientCRC uint64 // Calculated CRC64 in client diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go index 943dc8fd0..2293f9904 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go @@ -1,3 +1,4 @@ +//go:build !go1.7 // +build !go1.7 // "golang.org/x/time/rate" is depended on golang context package go1.7 onward diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go index f6baf2987..ea0826cec 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go @@ -1,3 +1,4 @@ +//go:build go1.7 // +build go1.7 package oss diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go index bf5ba070b..1fd30fdfd 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go @@ -203,7 +203,7 @@ func (bucket Bucket) ListLiveChannel(options ...Option) (ListLiveChannelResult, params["live"] = nil - resp, err := bucket.do("GET", "", params, nil, nil, nil) + resp, err := bucket.doInner("GET", "", params, nil, nil, nil) if err != nil { return out, err } diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go index 64f4dcc63..96a9ee7aa 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go @@ -567,6 +567,28 @@ func TypeByExtension(filePath string) string { typ := mime.TypeByExtension(path.Ext(filePath)) if typ == "" { typ = extToMimeType[strings.ToLower(path.Ext(filePath))] + } else { + if strings.HasPrefix(typ, "text/") && strings.Contains(typ, "charset=") { + typ = removeCharsetInMimeType(typ) + } } return typ } + +// Remove charset from mime type +func removeCharsetInMimeType(typ string) (str string) { + temArr := strings.Split(typ, ";") + var builder strings.Builder + for i, s := range temArr { + tmpStr := strings.Trim(s, " ") + if strings.Contains(tmpStr, "charset=") { + continue + } + if i == 0 { + builder.WriteString(s) + } else { + builder.WriteString("; " + s) + } + } + return builder.String() +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go index 9e7141971..aea7fafb6 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/xml" "io" + "io/ioutil" "net/http" "net/url" "os" @@ -15,12 +16,12 @@ import ( // // objectKey object name // options the object constricts for upload. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires, -// ServerSideEncryption, Meta, check out the following link: -// https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/InitiateMultipartUpload.html +// +// ServerSideEncryption, Meta, check out the following link: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/initiatemultipartupload // // InitiateMultipartUploadResult the return value of the InitiateMultipartUpload, which is used for calls later on such as UploadPartFromFile,UploadPartCopy. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) InitiateMultipartUpload(objectKey string, options ...Option) (InitiateMultipartUploadResult, error) { var imur InitiateMultipartUploadResult opts := AddContentType(options, objectKey) @@ -53,7 +54,6 @@ func (bucket Bucket) InitiateMultipartUpload(objectKey string, options ...Option // // UploadPart the return value of the upload part. It consists of PartNumber and ETag. It's valid when error is nil. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) UploadPart(imur InitiateMultipartUploadResult, reader io.Reader, partSize int64, partNumber int, options ...Option) (UploadPart, error) { request := &UploadPartRequest{ @@ -78,7 +78,6 @@ func (bucket Bucket) UploadPart(imur InitiateMultipartUploadResult, reader io.Re // // UploadPart the return value consists of PartNumber and ETag. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) UploadPartFromFile(imur InitiateMultipartUploadResult, filePath string, startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) { var part = UploadPart{} @@ -107,7 +106,6 @@ func (bucket Bucket) UploadPartFromFile(imur InitiateMultipartUploadResult, file // // UploadPartResult the result of uploading part. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) DoUploadPart(request *UploadPartRequest, options []Option) (*UploadPartResult, error) { listener := GetProgressListener(options) options = append(options, ContentLength(request.PartSize)) @@ -144,12 +142,12 @@ func (bucket Bucket) DoUploadPart(request *UploadPartRequest, options []Option) // partSize the part size // partNumber the part number, ranges from 1 to 10,000. If it exceeds the range OSS returns InvalidArgument error. // options the constraints of source object for the copy. The copy happens only when these contraints are met. Otherwise it returns error. -// CopySourceIfNoneMatch, CopySourceIfModifiedSince CopySourceIfUnmodifiedSince, check out the following link for the detail -// https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/UploadPartCopy.html +// +// CopySourceIfNoneMatch, CopySourceIfModifiedSince CopySourceIfUnmodifiedSince, check out the following link for the detail +// https://www.alibabacloud.com/help/en/object-storage-service/latest/uploadpartcopy // // UploadPart the return value consists of PartNumber and ETag. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) UploadPartCopy(imur InitiateMultipartUploadResult, srcBucketName, srcObjectKey string, startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) { var out UploadPartCopyResult @@ -196,7 +194,6 @@ func (bucket Bucket) UploadPartCopy(imur InitiateMultipartUploadResult, srcBucke // // CompleteMultipartUploadResponse the return value when the call succeeds. Only valid when the error is nil. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult, parts []UploadPart, options ...Option) (CompleteMultipartUploadResult, error) { var out CompleteMultipartUploadResult @@ -218,8 +215,28 @@ func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult, return out, err } defer resp.Body.Close() - - err = xmlUnmarshal(resp.Body, &out) + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return out, err + } + err = CheckRespCode(resp.StatusCode, []int{http.StatusOK}) + if len(body) > 0 { + if err != nil { + err = tryConvertServiceError(body, resp, err) + } else { + callback, _ := FindOption(options, HTTPHeaderOssCallback, nil) + if callback == nil { + err = xml.Unmarshal(body, &out) + } else { + rb, _ := FindOption(options, responseBody, nil) + if rb != nil { + if rbody, ok := rb.(*[]byte); ok { + *rbody = body + } + } + } + } + } return out, err } @@ -228,7 +245,6 @@ func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult, // imur the return value of InitiateMultipartUpload. // // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) AbortMultipartUpload(imur InitiateMultipartUploadResult, options ...Option) error { params := map[string]interface{}{} params["uploadId"] = imur.UploadID @@ -246,7 +262,6 @@ func (bucket Bucket) AbortMultipartUpload(imur InitiateMultipartUploadResult, op // // ListUploadedPartsResponse the return value if it succeeds, only valid when error is nil. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) ListUploadedParts(imur InitiateMultipartUploadResult, options ...Option) (ListUploadedPartsResult, error) { var out ListUploadedPartsResult options = append(options, EncodingType("url")) @@ -275,11 +290,11 @@ func (bucket Bucket) ListUploadedParts(imur InitiateMultipartUploadResult, optio // ListMultipartUploads lists all ongoing multipart upload tasks // // options listObject's filter. Prefix specifies the returned object's prefix; KeyMarker specifies the returned object's start point in lexicographic order; -// MaxKeys specifies the max entries to return; Delimiter is the character for grouping object keys. +// +// MaxKeys specifies the max entries to return; Delimiter is the character for grouping object keys. // // ListMultipartUploadResponse the return value if it succeeds, only valid when error is nil. // error it's nil if the operation succeeds, otherwise it's an error object. -// func (bucket Bucket) ListMultipartUploads(options ...Option) (ListMultipartUploadResult, error) { var out ListMultipartUploadResult @@ -290,7 +305,7 @@ func (bucket Bucket) ListMultipartUploads(options ...Option) (ListMultipartUploa } params["uploads"] = nil - resp, err := bucket.do("GET", "", params, options, nil, nil) + resp, err := bucket.doInner("GET", "", params, options, nil, nil) if err != nil { return out, err } diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go index a8d5dc39d..7e517ddbe 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go @@ -1,7 +1,9 @@ package oss import ( + "context" "fmt" + "io/ioutil" "net/http" "net/url" "strconv" @@ -12,9 +14,11 @@ import ( type optionType string const ( - optionParam optionType = "HTTPParameter" // URL parameter - optionHTTP optionType = "HTTPHeader" // HTTP header - optionArg optionType = "FuncArgument" // Function argument + optionParam optionType = "HTTPParameter" // URL parameter + optionHTTP optionType = "HTTPHeader" // HTTP header + optionContext optionType = "HTTPContext" // context + optionArg optionType = "FuncArgument" // Function argument + ) const ( @@ -27,6 +31,8 @@ const ( responseHeader = "x-response-header" redundancyType = "redundancy-type" objectHashFunc = "object-hash-func" + responseBody = "x-response-body" + contextArg = "x-context-arg" ) type ( @@ -448,6 +454,11 @@ func ObjectHashFunc(value ObjecthashFuncType) Option { return addArg(objectHashFunc, value) } +// WithContext returns an option that sets the context for requests. +func WithContext(ctx context.Context) Option { + return addArg(contextArg, ctx) +} + // Checkpoint configuration type cpConfig struct { IsEnable bool @@ -485,6 +496,11 @@ func GetResponseHeader(respHeader *http.Header) Option { return addArg(responseHeader, respHeader) } +// CallbackResult for get response of call back +func CallbackResult(body *[]byte) Option { + return addArg(responseBody, body) +} + // ResponseContentType is an option to set response-content-type param func ResponseContentType(value string) Option { return addParam("response-content-type", value) @@ -678,3 +694,42 @@ func GetDeleteMark(header http.Header) bool { func GetQosDelayTime(header http.Header) string { return header.Get("x-oss-qos-delay-time") } + +// ForbidOverWrite is an option to set X-Oss-Forbid-Overwrite +func AllowSameActionOverLap(enabled bool) Option { + if enabled { + return setHeader(HTTPHeaderAllowSameActionOverLap, "true") + } else { + return setHeader(HTTPHeaderAllowSameActionOverLap, "false") + } +} + +func GetCallbackBody(options []Option, resp *Response, callbackSet bool) error { + var err error + + // get response body + if callbackSet { + err = setBody(options, resp) + } else { + callback, _ := FindOption(options, HTTPHeaderOssCallback, nil) + if callback != nil { + err = setBody(options, resp) + } + } + return err +} + +func setBody(options []Option, resp *Response) error { + respBody, _ := FindOption(options, responseBody, nil) + if respBody != nil && resp != nil { + pRespBody := respBody.(*[]byte) + pBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + if pBody != nil { + *pRespBody = pBody + } + } + return nil +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go index 9f3aa9f61..1b6535ba5 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go @@ -10,7 +10,7 @@ type ProgressEventType int const ( // TransferStartedEvent transfer started, set TotalBytes TransferStartedEvent ProgressEventType = 1 + iota - // TransferDataEvent transfer data, set ConsumedBytes anmd TotalBytes + // TransferDataEvent transfer data, set ConsumedBytes and TotalBytes TransferDataEvent // TransferCompletedEvent transfer completed TransferCompletedEvent diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go index d09bc5ebd..ea17d5bd5 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go @@ -1,3 +1,4 @@ +//go:build !go1.7 // +build !go1.7 package oss diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go index 5b0bb8674..5d1442dd1 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go @@ -1,3 +1,4 @@ +//go:build go1.7 // +build go1.7 package oss diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go index 8b75782f3..75a454555 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go @@ -107,6 +107,7 @@ func (sr *SelectObjectResponse) readFrames(p []byte) (int, error) { if err != nil || !checkValid { return nn, fmt.Errorf("%s", err.Error()) } + sr.Frame.OpenLine = false } else if sr.Frame.FrameType == EndFrameType { err = sr.analysisEndFrame() if err != nil { diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go index 795ca8bb3..08a83a001 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go @@ -1,8 +1,10 @@ +//go:build !go1.7 // +build !go1.7 package oss import ( + "crypto/tls" "net" "net/http" "time" @@ -30,5 +32,11 @@ func newTransport(conn *Conn, config *Config) *http.Transport { MaxIdleConnsPerHost: httpMaxConns.MaxIdleConnsPerHost, ResponseHeaderTimeout: httpTimeOut.HeaderTimeout, } + + if config.InsecureSkipVerify { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, + } + } return transport } diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go index 757543bc4..1acb84154 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go @@ -1,8 +1,10 @@ +//go:build go1.7 // +build go1.7 package oss import ( + "crypto/tls" "net" "net/http" "time" @@ -29,8 +31,15 @@ func newTransport(conn *Conn, config *Config) *http.Transport { }, MaxIdleConns: httpMaxConns.MaxIdleConns, MaxIdleConnsPerHost: httpMaxConns.MaxIdleConnsPerHost, + MaxConnsPerHost: httpMaxConns.MaxConnsPerHost, IdleConnTimeout: httpTimeOut.IdleConnTimeout, ResponseHeaderTimeout: httpTimeOut.HeaderTimeout, } + + if config.InsecureSkipVerify { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, + } + } return transport } diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go index e80d2db5d..a704e3cef 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go @@ -5,6 +5,8 @@ import ( "encoding/xml" "fmt" "net/url" + "strconv" + "strings" "time" ) @@ -27,6 +29,29 @@ type BucketProperties struct { Location string `xml:"Location"` // Bucket datacenter CreationDate time.Time `xml:"CreationDate"` // Bucket create time StorageClass string `xml:"StorageClass"` // Bucket storage class + Region string `xml:"Region"` // Bucket region +} + +// ListCloudBoxResult defines the result object from ListBuckets request +type ListCloudBoxResult struct { + XMLName xml.Name `xml:"ListCloudBoxResult"` + Prefix string `xml:"Prefix"` // The prefix in this query + Marker string `xml:"Marker"` // The marker filter + MaxKeys int `xml:"MaxKeys"` // The max entry count to return. This information is returned when IsTruncated is true. + IsTruncated bool `xml:"IsTruncated"` // Flag true means there's remaining cloudboxes to return. + NextMarker string `xml:"NextMarker"` // The marker filter for the next list call + Owner string `xml:"Owner>DisplayName"` // The owner information + CloudBoxes []CloudBoxProperties `xml:"CloudBoxes>CloudBox"` // The cloudbox list +} + +// CloudBoxProperties defines cloudbox properties +type CloudBoxProperties struct { + XMLName xml.Name `xml:"CloudBox"` + ID string `xml:"ID"` + Name string `xml:"Name"` + Region string `xml:"Region"` + ControlEndpoint string `xml:"ControlEndpoint"` + DataEndpoint string `xml:"DataEndpoint"` } // GetBucketACLResult defines GetBucketACL request's result @@ -56,6 +81,7 @@ type LifecycleRule struct { // Deprecated: Use NonVersionTransitions instead. NonVersionTransition *LifecycleVersionTransition `xml:"-"` // NonVersionTransition is not suggested to use NonVersionTransitions []LifecycleVersionTransition `xml:"NoncurrentVersionTransition,omitempty"` + Filter *LifecycleFilter `xml:Filter,omitempty` //condition parameter container of this exclusion rule } // LifecycleExpiration defines the rule's expiration property @@ -69,10 +95,13 @@ type LifecycleExpiration struct { // LifecycleTransition defines the rule's transition propery type LifecycleTransition struct { - XMLName xml.Name `xml:"Transition"` - Days int `xml:"Days,omitempty"` // Relative transition time: The transition time in days after the last modified time - CreatedBeforeDate string `xml:"CreatedBeforeDate,omitempty"` // objects created before the date will be expired - StorageClass StorageClassType `xml:"StorageClass,omitempty"` // Specifies the target storage type + XMLName xml.Name `xml:"Transition"` + Days int `xml:"Days,omitempty"` // Relative transition time: The transition time in days after the last modified time + CreatedBeforeDate string `xml:"CreatedBeforeDate,omitempty"` // objects created before the date will be expired + StorageClass StorageClassType `xml:"StorageClass,omitempty"` // Specifies the target storage type + IsAccessTime *bool `xml:"IsAccessTime,omitempty"` // access time + ReturnToStdWhenVisit *bool `xml:"ReturnToStdWhenVisit,omitempty"` // Return To Std When Visit + AllowSmallFile *bool `xml:AllowSmallFile,omitempty` } // LifecycleAbortMultipartUpload defines the rule's abort multipart upload propery @@ -90,12 +119,31 @@ type LifecycleVersionExpiration struct { // LifecycleVersionTransition defines the rule's NoncurrentVersionTransition propery type LifecycleVersionTransition struct { - XMLName xml.Name `xml:"NoncurrentVersionTransition"` - NoncurrentDays int `xml:"NoncurrentDays,omitempty"` // How many days after the Object becomes a non-current version - StorageClass StorageClassType `xml:"StorageClass,omitempty"` + XMLName xml.Name `xml:"NoncurrentVersionTransition"` + NoncurrentDays int `xml:"NoncurrentDays,omitempty"` // How many days after the Object becomes a non-current version + StorageClass StorageClassType `xml:"StorageClass,omitempty"` + IsAccessTime *bool `xml:"IsAccessTime,omitempty"` // access time + ReturnToStdWhenVisit *bool `xml:"ReturnToStdWhenVisit,omitempty"` // Return To Std When Visit + AllowSmallFile *bool `xml:AllowSmallFile,omitempty` +} + +// LifecycleFilter defines the rule's Filter propery +type LifecycleFilter struct { + XMLName xml.Name `xml:"Filter"` + Not []LifecycleFilterNot `xml:"Not,omitempty"` + ObjectSizeGreaterThan *int64 `xml:"ObjectSizeGreaterThan,omitempty"` + ObjectSizeLessThan *int64 `xml:"ObjectSizeLessThan,omitempty"` +} + +// LifecycleFilterNot defines the rule's Filter Not propery +type LifecycleFilterNot struct { + XMLName xml.Name `xml:"Not"` + Prefix string `xml:"Prefix"` //Object prefix applicable to this exclusion rule + Tag *Tag `xml:"Tag,omitempty"` //the tags applicable to this exclusion rule } const iso8601DateFormat = "2006-01-02T15:04:05.000Z" +const iso8601DateFormatSecond = "2006-01-02T15:04:05Z" // BuildLifecycleRuleByDays builds a lifecycle rule objects will expiration in days after the last modified time func BuildLifecycleRuleByDays(id, prefix string, status bool, days int) LifecycleRule { @@ -161,14 +209,20 @@ type GetBucketLifecycleResult LifecycleConfiguration // RefererXML defines Referer configuration type RefererXML struct { - XMLName xml.Name `xml:"RefererConfiguration"` - AllowEmptyReferer bool `xml:"AllowEmptyReferer"` // Allow empty referrer - RefererList []string `xml:"RefererList>Referer"` // Referer whitelist + XMLName xml.Name `xml:"RefererConfiguration"` + AllowEmptyReferer bool `xml:"AllowEmptyReferer"` // Allow empty referrer + AllowTruncateQueryString *bool `xml:"AllowTruncateQueryString,omitempty"` + RefererList []string `xml:"RefererList>Referer"` // Referer whitelist + RefererBlacklist *RefererBlacklist `xml:"RefererBlacklist,omitempty"` // Referer blacklist } // GetBucketRefererResult defines result object for GetBucketReferer request type GetBucketRefererResult RefererXML +type RefererBlacklist struct { + Referer []string `xml:"Referer,omitempty"` +} + // LoggingXML defines logging configuration type LoggingXML struct { XMLName xml.Name `xml:"BucketLoggingStatus"` @@ -271,8 +325,9 @@ type GetBucketWebsiteResult WebsiteXML // CORSXML defines CORS configuration type CORSXML struct { - XMLName xml.Name `xml:"CORSConfiguration"` - CORSRules []CORSRule `xml:"CORSRule"` // CORS rules + XMLName xml.Name `xml:"CORSConfiguration"` + CORSRules []CORSRule `xml:"CORSRule"` // CORS rules + ResponseVary *bool `xml:"ResponseVary,omitempty"` // return Vary or not } // CORSRule defines CORS rules @@ -288,6 +343,9 @@ type CORSRule struct { // GetBucketCORSResult defines the result from GetBucketCORS request. type GetBucketCORSResult CORSXML +// PutBucketCORS defines the PutBucketCORS config xml. +type PutBucketCORS CORSXML + // GetBucketInfoResult defines the result from GetBucketInfo request. type GetBucketInfoResult struct { XMLName xml.Name `xml:"BucketInfo"` @@ -296,18 +354,21 @@ type GetBucketInfoResult struct { // BucketInfo defines Bucket information type BucketInfo struct { - XMLName xml.Name `xml:"Bucket"` - Name string `xml:"Name"` // Bucket name - Location string `xml:"Location"` // Bucket datacenter - CreationDate time.Time `xml:"CreationDate"` // Bucket creation time - ExtranetEndpoint string `xml:"ExtranetEndpoint"` // Bucket external endpoint - IntranetEndpoint string `xml:"IntranetEndpoint"` // Bucket internal endpoint - ACL string `xml:"AccessControlList>Grant"` // Bucket ACL - RedundancyType string `xml:"DataRedundancyType"` // Bucket DataRedundancyType - Owner Owner `xml:"Owner"` // Bucket owner - StorageClass string `xml:"StorageClass"` // Bucket storage class - SseRule SSERule `xml:"ServerSideEncryptionRule"` // Bucket ServerSideEncryptionRule - Versioning string `xml:"Versioning"` // Bucket Versioning + XMLName xml.Name `xml:"Bucket"` + Name string `xml:"Name"` // Bucket name + AccessMonitor string `xml:"AccessMonitor"` // Bucket Access Monitor + Location string `xml:"Location"` // Bucket datacenter + CreationDate time.Time `xml:"CreationDate"` // Bucket creation time + ExtranetEndpoint string `xml:"ExtranetEndpoint"` // Bucket external endpoint + IntranetEndpoint string `xml:"IntranetEndpoint"` // Bucket internal endpoint + ACL string `xml:"AccessControlList>Grant"` // Bucket ACL + RedundancyType string `xml:"DataRedundancyType"` // Bucket DataRedundancyType + Owner Owner `xml:"Owner"` // Bucket owner + StorageClass string `xml:"StorageClass"` // Bucket storage class + SseRule SSERule `xml:"ServerSideEncryptionRule"` // Bucket ServerSideEncryptionRule + Versioning string `xml:"Versioning"` // Bucket Versioning + TransferAcceleration string `xml:"TransferAcceleration"` // bucket TransferAcceleration + CrossRegionReplication string `xml:"CrossRegionReplication"` // bucket CrossRegionReplication } type SSERule struct { @@ -333,13 +394,14 @@ type ListObjectsResult struct { // ObjectProperties defines Objecct properties type ObjectProperties struct { XMLName xml.Name `xml:"Contents"` - Key string `xml:"Key"` // Object key - Type string `xml:"Type"` // Object type - Size int64 `xml:"Size"` // Object size - ETag string `xml:"ETag"` // Object ETag - Owner Owner `xml:"Owner"` // Object owner information - LastModified time.Time `xml:"LastModified"` // Object last modified time - StorageClass string `xml:"StorageClass"` // Object storage class (Standard, IA, Archive) + Key string `xml:"Key"` // Object key + Type string `xml:"Type"` // Object type + Size int64 `xml:"Size"` // Object size + ETag string `xml:"ETag"` // Object ETag + Owner Owner `xml:"Owner"` // Object owner information + LastModified time.Time `xml:"LastModified"` // Object last modified time + StorageClass string `xml:"StorageClass"` // Object storage class (Standard, IA, Archive) + RestoreInfo string `xml:"RestoreInfo,omitempty"` // Object restoreInfo } // ListObjectsResultV2 defines the result from ListObjectsV2 request @@ -385,15 +447,16 @@ type ObjectDeleteMarkerProperties struct { type ObjectVersionProperties struct { XMLName xml.Name `xml:"Version"` - Key string `xml:"Key"` // The Object Key - VersionId string `xml:"VersionId"` // The Object VersionId - IsLatest bool `xml:"IsLatest"` // is latest version or not - LastModified time.Time `xml:"LastModified"` // Object last modified time - Type string `xml:"Type"` // Object type - Size int64 `xml:"Size"` // Object size - ETag string `xml:"ETag"` // Object ETag - StorageClass string `xml:"StorageClass"` // Object storage class (Standard, IA, Archive) - Owner Owner `xml:"Owner"` // bucket owner element + Key string `xml:"Key"` // The Object Key + VersionId string `xml:"VersionId"` // The Object VersionId + IsLatest bool `xml:"IsLatest"` // is latest version or not + LastModified time.Time `xml:"LastModified"` // Object last modified time + Type string `xml:"Type"` // Object type + Size int64 `xml:"Size"` // Object size + ETag string `xml:"ETag"` // Object ETag + StorageClass string `xml:"StorageClass"` // Object storage class (Standard, IA, Archive) + Owner Owner `xml:"Owner"` // bucket owner element + RestoreInfo string `xml:"RestoreInfo,omitempty"` // Object restoreInfo } // Owner defines Bucket/Object's owner @@ -432,13 +495,13 @@ type DeleteObjectsResult struct { DeletedObjects []string // Deleted object key list } -// DeleteObjectsResult_inner defines result of DeleteObjects request +// DeleteObjectVersionsResult defines result of DeleteObjects request type DeleteObjectVersionsResult struct { XMLName xml.Name `xml:"DeleteResult"` DeletedObjectsDetail []DeletedKeyInfo `xml:"Deleted"` // Deleted object detail info } -// DeleteKeyInfo defines object delete info +// DeletedKeyInfo defines object delete info type DeletedKeyInfo struct { XMLName xml.Name `xml:"Deleted"` Key string `xml:"Key"` // Object key @@ -550,6 +613,13 @@ type ProcessObjectResult struct { Status string `json:"status"` } +// AsyncProcessObjectResult defines result object of AsyncProcessObject +type AsyncProcessObjectResult struct { + EventId string `json:"EventId"` + RequestId string `json:"RequestId"` + TaskId string `json:"TaskId"` +} + // decodeDeleteObjectsResult decodes deleting objects result in URL encoding func decodeDeleteObjectsResult(result *DeleteObjectVersionsResult) error { var err error @@ -741,6 +811,33 @@ func decodeListMultipartUploadResult(result *ListMultipartUploadResult) error { return nil } +// marshalDeleteObjectToXml deleteXML struct to xml +func marshalDeleteObjectToXml(dxml deleteXML) string { + var builder strings.Builder + builder.WriteString("") + builder.WriteString("") + builder.WriteString(strconv.FormatBool(dxml.Quiet)) + builder.WriteString("") + if len(dxml.Objects) > 0 { + for _, object := range dxml.Objects { + builder.WriteString("") + if object.Key != "" { + builder.WriteString("") + builder.WriteString(EscapeXml(object.Key)) + builder.WriteString("") + } + if object.VersionId != "" { + builder.WriteString("") + builder.WriteString(object.VersionId) + builder.WriteString("") + } + builder.WriteString("") + } + } + builder.WriteString("") + return builder.String() +} + // createBucketConfiguration defines the configuration for creating a bucket. type createBucketConfiguration struct { XMLName xml.Name `xml:"CreateBucketConfiguration"` @@ -854,13 +951,13 @@ type Tag struct { Value string `xml:"Value"` } -// Tagging tagset for the object +// Tagging tag set for the object type Tagging struct { XMLName xml.Name `xml:"Tagging"` Tags []Tag `xml:"TagSet>Tag,omitempty"` } -// for GetObjectTagging return value +// GetObjectTaggingResult for GetObjectTagging return value type GetObjectTaggingResult Tagging // VersioningConfig for the bucket @@ -871,13 +968,13 @@ type VersioningConfig struct { type GetBucketVersioningResult VersioningConfig -// Server Encryption rule for the bucket +// ServerEncryptionRule Server Encryption rule for the bucket type ServerEncryptionRule struct { XMLName xml.Name `xml:"ServerSideEncryptionRule"` SSEDefault SSEDefaultRule `xml:"ApplyServerSideEncryptionByDefault"` } -// Server Encryption deafult rule for the bucket +// SSEDefaultRule Server Encryption deafult rule for the bucket type SSEDefaultRule struct { XMLName xml.Name `xml:"ApplyServerSideEncryptionByDefault"` SSEAlgorithm string `xml:"SSEAlgorithm,omitempty"` @@ -889,10 +986,23 @@ type GetBucketEncryptionResult ServerEncryptionRule type GetBucketTaggingResult Tagging type BucketStat struct { - XMLName xml.Name `xml:"BucketStat"` - Storage int64 `xml:"Storage"` - ObjectCount int64 `xml:"ObjectCount"` - MultipartUploadCount int64 `xml:"MultipartUploadCount"` + XMLName xml.Name `xml:"BucketStat"` + Storage int64 `xml:"Storage"` + ObjectCount int64 `xml:"ObjectCount"` + MultipartUploadCount int64 `xml:"MultipartUploadCount"` + LiveChannelCount int64 `xml:"LiveChannelCount"` + LastModifiedTime int64 `xml:"LastModifiedTime"` + StandardStorage int64 `xml:"StandardStorage"` + StandardObjectCount int64 `xml:"StandardObjectCount"` + InfrequentAccessStorage int64 `xml:"InfrequentAccessStorage"` + InfrequentAccessRealStorage int64 `xml:"InfrequentAccessRealStorage"` + InfrequentAccessObjectCount int64 `xml:"InfrequentAccessObjectCount"` + ArchiveStorage int64 `xml:"ArchiveStorage"` + ArchiveRealStorage int64 `xml:"ArchiveRealStorage"` + ArchiveObjectCount int64 `xml:"ArchiveObjectCount"` + ColdArchiveStorage int64 `xml:"ColdArchiveStorage"` + ColdArchiveRealStorage int64 `xml:"ColdArchiveRealStorage"` + ColdArchiveObjectCount int64 `xml:"ColdArchiveObjectCount"` } type GetBucketStatResult BucketStat @@ -1075,7 +1185,7 @@ func (selectReq *SelectRequest) jsonEncodeBase64() { } } -// CsvOptions is a element in the SelectObject api request's params +// SelectOptions is a element in the SelectObject api request's params type SelectOptions struct { XMLName xml.Name `xml:"Options"` SkipPartialDataRecord *bool `xml:"SkipPartialDataRecord,omitempty"` @@ -1252,3 +1362,334 @@ type TransferAccConfiguration struct { XMLName xml.Name `xml:"TransferAccelerationConfiguration"` Enabled bool `xml:"Enabled"` } + +// ReplicationXML defines simple replication xml, and ReplicationXML is used for "DeleteBucketReplication" in client.go +type ReplicationXML struct { + XMLName xml.Name `xml:"ReplicationRules"` + ID string `xml:"ID,omitempty"` +} + +// PutBucketReplication define the bucket replication config +type PutBucketReplication BucketReplicationXml + +// GetBucketReplicationResult define get bucket's replication config +type GetBucketReplicationResult BucketReplicationXml + +// GetBucketReplicationLocationResult define get bucket's replication location +type GetBucketReplicationLocationResult BucketReplicationLocationXml + +// GetBucketReplicationProgressResult define get bucket's replication progress +type GetBucketReplicationProgressResult BucketReplicationProgressXml + +// PutBucketRTC define the bucket rtc config +type PutBucketRTC BucketRTCXml + +// BucketReplicationXml define the xml of bucket replication config +type BucketReplicationXml struct { + XMLName xml.Name `xml:"ReplicationConfiguration"` + Rule []ReplicationRule `xml:"Rule,omitempty"` +} + +// BucketReplicationProgressXml define the xml of bucket replication config +type BucketReplicationProgressXml struct { + XMLName xml.Name `xml:"ReplicationProgress"` + Rule []ReplicationRule `xml:"Rule,omitempty"` +} + +// BucketRTCXml define the xml of bucket rtc config +type BucketRTCXml struct { + XMLName xml.Name `xml:"ReplicationRule"` + RTC *string `xml:"RTC>Status,omitempty"` + ID string `xml:"ID,omitempty"` +} + +// ReplicationRule define the xml of bucket replication config rule +type ReplicationRule struct { + ID string `xml:"ID,omitempty"` + RTC *string `xml:"RTC>Status,omitempty"` + PrefixSet *ReplicationRulePrefix `xml:"PrefixSet,omitempty"` + Action string `xml:"Action,omitempty"` + Destination *ReplicationRuleDestination `xml:"Destination,omitempty"` + HistoricalObjectReplication string `xml:"HistoricalObjectReplication,omitempty"` + Status string `xml:"Status,omitempty"` + SyncRole string `xml:"SyncRole,omitempty"` + SourceSelectionCriteria *string `xml:"SourceSelectionCriteria>SseKmsEncryptedObjects>Status,omitempty"` + EncryptionConfiguration *string `xml:"EncryptionConfiguration>ReplicaKmsKeyID,omitempty"` + Progress *ReplicationRuleProgress `xml:"Progress,omitempty"` + HistoricalObject string `xml:"HistoricalObject,omitempty"` +} + +type ReplicationRulePrefix struct { + Prefix []*string `xml:"Prefix,omitempty"` +} + +type ReplicationRuleDestination struct { + Bucket string `xml:"Bucket,omitempty"` + Location string `xml:"Location,omitempty"` + TransferType string `xml:"TransferType,omitempty"` +} + +// BucketReplicationLocationXml define the xml of bucket replication location info +type BucketReplicationLocationXml struct { + XMLName xml.Name `xml:"ReplicationLocation"` + Location []string `xml:"Location,omitempty"` + LocationTransferType []ReplicationLocationTransferType `xml:"LocationTransferTypeConstraint>LocationTransferType,omitempty"` + RTCLocation []string `xml:"LocationRTCConstraint>Location,omitempty"` +} + +type ReplicationLocation struct { + Location string `xml:"Location,omitempty"` +} + +type ReplicationLocationTransferType struct { + Location string `xml:"Location,omitempty"` + TransferTypes string `xml:"TransferTypes>Type,omitempty"` +} + +type ReplicationRuleProgress struct { + HistoricalObject string `xml:"HistoricalObject,omitempty"` + NewObject string `xml:"NewObject,omitempty"` +} + +// CnameConfigurationXML define cname configuration +type CnameConfigurationXML struct { + XMLName xml.Name `xml:"BucketCnameConfiguration"` + Domain string `xml:"Cname>Domain"` +} + +type PutBucketCname PutBucketCnameXml + +// PutBucketCnameXml define cname configuration +type PutBucketCnameXml struct { + XMLName xml.Name `xml:"BucketCnameConfiguration"` + Cname string `xml:"Cname>Domain"` + CertificateConfiguration *CertificateConfiguration `xml:"Cname>CertificateConfiguration"` +} + +type CertificateConfiguration struct { + CertId string `xml:"CertId,omitempty"` + Certificate string `xml:"Certificate,omitempty"` + PrivateKey string `xml:"PrivateKey,omitempty"` + PreviousCertId string `xml:"PreviousCertId,omitempty"` + Force bool `xml:"Force,omitempty"` + DeleteCertificate bool `xml:"DeleteCertificate,omitempty"` +} + +// CnameTokenXML define cname token information +type CnameTokenXML struct { + XMLName xml.Name `xml:"CnameToken"` + Bucket string `xml:"Bucket,omitempty"` + Cname string `xml:"Cname,omitempty"` + Token string `xml:"Token,omitempty"` + ExpireTime string `xml:"ExpireTime,omitempty"` +} + +// CreateBucketCnameTokenResult defines result object for CreateBucketCnameToken request +type CreateBucketCnameTokenResult CnameTokenXML + +// GetBucketCnameTokenResult defines result object for GetBucketCnameToken request +type GetBucketCnameTokenResult CnameTokenXML + +// GetMetaQueryStatusResult defines result for GetMetaQueryStatus result +type GetMetaQueryStatusResult GetMetaQueryStatusResultXml + +// GetMetaQueryStatusResultXml define get meta query status information +type GetMetaQueryStatusResultXml struct { + XMLName xml.Name `xml:"MetaQueryStatus"` + State string `xml:"State"` + Phase string `xml:"Phase"` + CreateTime string `xml:"CreateTime"` + UpdateTime string `xml:"UpdateTime"` +} + +// MetaQuery defines meta query struct +type MetaQuery struct { + XMLName xml.Name `xml:"MetaQuery"` + NextToken string `xml:"NextToken,omitempty"` + MaxResults int64 `xml:"MaxResults,omitempty"` + Query string `xml:"Query"` + Sort string `xml:"Sort,omitempty"` + Order string `xml:"Order,omitempty"` + Aggregations []MetaQueryAggregationRequest `xml:"Aggregations>Aggregation,omitempty"` +} + +// MetaQueryAggregationRequest defines meta query aggregation request +type MetaQueryAggregationRequest struct { + XMLName xml.Name `xml:"Aggregation"` + Field string `xml:"Field,omitempty"` + Operation string `xml:"Operation,omitempty"` +} + +// MetaQueryAggregationResponse defines meta query aggregation response +type MetaQueryAggregationResponse struct { + XMLName xml.Name `xml:"Aggregation"` + Field string `xml:"Field,omitempty"` + Operation string `xml:"Operation,omitempty"` + Value float64 `xml:"Value,omitempty"` + Groups []MetaQueryGroup `xml:"Groups>Group,omitempty"` +} + +// DoMetaQueryResult defines result for DoMetaQuery result +type DoMetaQueryResult DoMetaQueryResultXml + +// DoMetaQueryResultXml defines do meta query information +type DoMetaQueryResultXml struct { + XMLName xml.Name `xml:"MetaQuery"` + NextToken string `xml:"NextToken,omitempty"` // next token + Files []MetaQueryFile `xml:"Files>File,omitempty"` // file + Aggregations []MetaQueryAggregationResponse `xml:"Aggregations>Aggregation,omitempty"'` // Aggregation +} + +// MetaQueryFile defines do meta query result file information +type MetaQueryFile struct { + XMLName xml.Name `xml:"File"` + Filename string `xml:"Filename"` //file name + Size int64 `xml:"Size"` // file size + FileModifiedTime string `xml:"FileModifiedTime"` // file Modified Time + OssObjectType string `xml:"OSSObjectType"` // Oss Object Type + OssStorageClass string `xml:"OSSStorageClass"` // Oss Storage Class + ObjectACL string `xml:"ObjectACL"` // Object Acl + ETag string `xml:"ETag"` // ETag + OssCRC64 string `xml:"OSSCRC64"` // Oss CRC64 + OssTaggingCount int64 `xml:"OSSTaggingCount,omitempty"` // Oss Tagging Count + OssTagging []MetaQueryTagging `xml:"OSSTagging>Tagging,omitempty"` // Tagging + OssUserMeta []MetaQueryUserMeta `xml:"OSSUserMeta>UserMeta,omitempty"` // UserMeta + ServerSideEncryption string `xml:"ServerSideEncryption,omitempty"` //Server Side Encryption + ServerSideEncryptionCustomerAlgorithm string `xml:"ServerSideEncryptionCustomerAlgorithm,omitempty"` // Server Side Encryption Customer Algorithm +} + +// MetaQueryTagging defines do meta query result tagging information +type MetaQueryTagging struct { + XMLName xml.Name `xml:"Tagging"` + Key string `xml:"Key"` + Value string `xml:"Value"` +} + +// MetaQueryUserMeta defines do meta query result user meta information +type MetaQueryUserMeta struct { + XMLName xml.Name `xml:"UserMeta"` + Key string `xml:"Key"` + Value string `xml:"Value"` +} + +// MetaQueryGroup defines do meta query result group information +type MetaQueryGroup struct { + XMLName xml.Name `xml:"Group"` + Value string `xml:"Value"` + Count int64 `xml:"Count"` +} + +// GetBucketAccessMonitorResult define config for get bucket access monitor +type GetBucketAccessMonitorResult BucketAccessMonitorXml + +// PutBucketAccessMonitor define the xml of bucket access monitor config +type PutBucketAccessMonitor BucketAccessMonitorXml + +// BucketAccessMonitorXml define get bucket access monitor information +type BucketAccessMonitorXml struct { + XMLName xml.Name `xml:"AccessMonitorConfiguration"` + Status string `xml:"Status"` // access monitor status +} + +// ListBucketCnameResult define the cname list of the bucket +type ListBucketCnameResult BucketCnameXml + +// BucketCnameXml define get the bucket cname information +type BucketCnameXml struct { + XMLName xml.Name `xml:"ListCnameResult"` + Bucket string `xml:"Bucket"` + Owner string `xml:"Owner"` + Cname []Cname `xml:"Cname"` +} + +// Cname define the cname information +type Cname struct { + Domain string `xml:"Domain"` + LastModified string `xml:"LastModified"` + Status string `xml:"Status"` + Certificate Certificate `xml:"Certificate"` +} + +// Certificate define Details of domain name certificate +type Certificate struct { + Type string `xml:"Type"` + CertId string `xml:"CertId"` + Status string `xml:"Status"` + CreationDate string `xml:"CreationDate"` + Fingerprint string `xml:"Fingerprint"` + ValidStartDate string `xml:"ValidStartDate"` + ValidEndDate string `xml:"ValidEndDate"` +} + +// GetBucketResourceGroupResult define resource group for the bucket +type GetBucketResourceGroupResult BucketResourceGroupXml + +// PutBucketResourceGroup define the xml of bucket's resource group config +type PutBucketResourceGroup BucketResourceGroupXml + +// BucketResourceGroupXml define the information of the bucket's resource group +type BucketResourceGroupXml struct { + XMLName xml.Name `xml:"BucketResourceGroupConfiguration"` + ResourceGroupId string `xml:"ResourceGroupId"` // resource groupId +} + +// GetBucketStyleResult define style for the bucket +type GetBucketStyleResult BucketStyleXml + +// GetBucketListStyleResult define the list style for the bucket +type GetBucketListStyleResult BucketListStyleXml + +// BucketListStyleXml define the list style of the bucket +type BucketListStyleXml struct { + XMLName xml.Name `xml:"StyleList"` + Style []BucketStyleXml `xml:"Style,omitempty"` // style +} + +// BucketStyleXml define the information of the bucket's style +type BucketStyleXml struct { + XMLName xml.Name `xml:"Style"` + Name string `xml:"Name,omitempty"` // style name + Content string `xml:"Content"` // style content + CreateTime string `xml:"CreateTime,omitempty"` // style create time + LastModifyTime string `xml:"LastModifyTime,omitempty"` // style last modify time +} + +// DescribeRegionsResult define get the describe regions result +type DescribeRegionsResult RegionInfoList + +type RegionInfo struct { + Region string `xml:"Region"` + InternetEndpoint string `xml:"InternetEndpoint"` + InternalEndpoint string `xml:"InternalEndpoint"` + AccelerateEndpoint string `xml:"AccelerateEndpoint"` +} + +type RegionInfoList struct { + XMLName xml.Name `xml:"RegionInfoList"` + Regions []RegionInfo `xml:"RegionInfo"` +} + +//PutBucketResponseHeader define the xml of bucket's response header config +type PutBucketResponseHeader ResponseHeaderXml + +//GetBucketResponseHeaderResult define the xml of bucket's response header result +type GetBucketResponseHeaderResult ResponseHeaderXml + +type ResponseHeaderXml struct { + XMLName xml.Name `xml:"ResponseHeaderConfiguration"` + Rule []ResponseHeaderRule `xml:Rule,omitempty"` // rule +} + +type ResponseHeaderRule struct { + Name string `xml:"Name"` // rule name + Filters ResponseHeaderRuleFilters `xml:"Filters,omitempty"` // rule filters Operation + HideHeaders ResponseHeaderRuleHeaders `xml:"HideHeaders,omitempty"` // rule hide header +} + +type ResponseHeaderRuleFilters struct { + Operation []string `xml:"Operation,omitempty"` +} + +type ResponseHeaderRuleHeaders struct { + Header []string `xml:"Header,omitempty"` +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go index 8b3ea09d2..becc6433d 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go @@ -1,6 +1,7 @@ package oss import ( + "bytes" "crypto/md5" "encoding/base64" "encoding/hex" @@ -256,7 +257,7 @@ func (bucket Bucket) uploadFile(objectKey, filePath string, partSize int64, opti } } - event = newProgressEvent(TransferStartedEvent, completedBytes, totalBytes, 0) + event = newProgressEvent(TransferCompletedEvent, completedBytes, totalBytes, 0) publishProgress(listener, event) // Complete the multpart upload @@ -279,6 +280,8 @@ type uploadCheckpoint struct { ObjectKey string // Key UploadID string // Upload ID Parts []cpPart // All parts of the local file + CallbackVal string + CallbackBody *[]byte } type cpStat struct { @@ -294,7 +297,19 @@ type cpPart struct { } // isValid checks if the uploaded data is valid---it's valid when the file is not updated and the checkpoint data is valid. -func (cp uploadCheckpoint) isValid(filePath string) (bool, error) { +func (cp uploadCheckpoint) isValid(filePath string,options []Option) (bool, error) { + + callbackVal, _ := FindOption(options, HTTPHeaderOssCallback, "") + if callbackVal != "" && cp.CallbackVal != callbackVal { + return false, nil + } + callbackBody, _ := FindOption(options, responseBody, nil) + if callbackBody != nil{ + body, _ := json.Marshal(callbackBody) + if bytes.Equal(*cp.CallbackBody, body) { + return false, nil + } + } // Compare the CP's magic number and MD5. cpb := cp cpb.MD5 = "" @@ -430,6 +445,13 @@ func prepare(cp *uploadCheckpoint, objectKey, filePath string, partSize int64, b } cp.FileStat.Size = st.Size() cp.FileStat.LastModified = st.ModTime() + callbackVal, _ := FindOption(options, HTTPHeaderOssCallback, "") + cp.CallbackVal = callbackVal.(string) + callbackBody, _ := FindOption(options, responseBody, nil) + if callbackBody != nil { + body, _ := json.Marshal(callbackBody) + cp.CallbackBody = &body + } md, err := calcFileMD5(filePath) if err != nil { return err @@ -462,8 +484,12 @@ func prepare(cp *uploadCheckpoint, objectKey, filePath string, partSize int64, b func complete(cp *uploadCheckpoint, bucket *Bucket, parts []UploadPart, cpFilePath string, options []Option) error { imur := InitiateMultipartUploadResult{Bucket: bucket.BucketName, Key: cp.ObjectKey, UploadID: cp.UploadID} + _, err := bucket.CompleteMultipartUpload(imur, parts, options...) if err != nil { + if e, ok := err.(ServiceError);ok && (e.StatusCode == 203 || e.StatusCode == 404) { + os.Remove(cpFilePath) + } return err } os.Remove(cpFilePath) @@ -485,7 +511,7 @@ func (bucket Bucket) uploadFileWithCp(objectKey, filePath string, partSize int64 } // Load error or the CP data is invalid. - valid, err := ucp.isValid(filePath) + valid, err := ucp.isValid(filePath,options) if err != nil || !valid { if err = prepare(&ucp, objectKey, filePath, partSize, &bucket, options); err != nil { return err diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go index 78b791300..8f3f03500 100644 --- a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go @@ -9,31 +9,33 @@ import ( "io" "net/http" "os" - "os/exec" "runtime" "strconv" "strings" "time" + "unicode/utf8" ) var sys_name string var sys_release string var sys_machine string +var ( + escQuot = []byte(""") // shorter than """ + escApos = []byte("'") // shorter than "'" + escAmp = []byte("&") + escLT = []byte("<") + escGT = []byte(">") + escTab = []byte(" ") + escNL = []byte(" ") + escCR = []byte(" ") + escFFFD = []byte("\uFFFD") // Unicode replacement character +) + func init() { sys_name = runtime.GOOS sys_release = "-" sys_machine = runtime.GOARCH - - if out, err := exec.Command("uname", "-s").CombinedOutput(); err == nil { - sys_name = string(bytes.TrimSpace(out)) - } - if out, err := exec.Command("uname", "-r").CombinedOutput(); err == nil { - sys_release = string(bytes.TrimSpace(out)) - } - if out, err := exec.Command("uname", "-m").CombinedOutput(); err == nil { - sys_machine = string(bytes.TrimSpace(out)) - } } // userAgent gets user agent @@ -376,6 +378,11 @@ func ChoiceCompletePartOption(options []Option) []Option { } } + notification, _ := FindOption(options, HttpHeaderOssNotification, nil) + if notification != nil { + outOption = append(outOption, SetHeader(HttpHeaderOssNotification, notification)) + } + return outOption } @@ -435,28 +442,90 @@ func CheckBucketName(bucketName string) error { return nil } +func CheckObjectName(objectName string) error { + if len(objectName) == 0 { + return fmt.Errorf("object name is empty") + } + return nil +} + +func CheckObjectNameEx(objectName string, strict bool) error { + if err := CheckObjectName(objectName); err != nil { + return err + } + + if strict && strings.HasPrefix(objectName, "?") { + return fmt.Errorf("object name is invalid, can't start with '?'") + } + + return nil +} + +/* + func GetReaderLen(reader io.Reader) (int64, error) { + var contentLength int64 + var err error + switch v := reader.(type) { + case *bytes.Buffer: + contentLength = int64(v.Len()) + case *bytes.Reader: + contentLength = int64(v.Len()) + case *strings.Reader: + contentLength = int64(v.Len()) + case *os.File: + fInfo, fError := v.Stat() + if fError != nil { + err = fmt.Errorf("can't get reader content length,%s", fError.Error()) + } else { + contentLength = fInfo.Size() + } + case *io.LimitedReader: + contentLength = int64(v.N) + case *LimitedReadCloser: + contentLength = int64(v.N) + default: + err = fmt.Errorf("can't get reader content length,unkown reader type") + } + return contentLength, err + } +*/ + func GetReaderLen(reader io.Reader) (int64, error) { var contentLength int64 var err error switch v := reader.(type) { - case *bytes.Buffer: - contentLength = int64(v.Len()) - case *bytes.Reader: - contentLength = int64(v.Len()) - case *strings.Reader: - contentLength = int64(v.Len()) - case *os.File: - fInfo, fError := v.Stat() - if fError != nil { - err = fmt.Errorf("can't get reader content length,%s", fError.Error()) - } else { - contentLength = fInfo.Size() - } case *io.LimitedReader: contentLength = int64(v.N) case *LimitedReadCloser: contentLength = int64(v.N) default: + // Len + type lenner interface { + Len() int + } + if lr, ok := reader.(lenner); ok { + return int64(lr.Len()), nil + } + // seeker len + if s, ok := reader.(io.Seeker); ok { + curOffset, err := s.Seek(0, io.SeekCurrent) + if err != nil { + return 0, err + } + endOffset, err := s.Seek(0, io.SeekEnd) + if err != nil { + return 0, err + } + _, err = s.Seek(curOffset, io.SeekStart) + if err != nil { + return 0, err + } + n := endOffset - curOffset + if n >= 0 { + return n, nil + } + } + // err = fmt.Errorf("can't get reader content length,unkown reader type") } return contentLength, err @@ -520,3 +589,86 @@ func ConvertEmptyValueToNil(params map[string]interface{}, keys []string) { } } } + +func EscapeLFString(str string) string { + var log bytes.Buffer + for i := 0; i < len(str); i++ { + if str[i] != '\n' { + log.WriteByte(str[i]) + } else { + log.WriteString("\\n") + } + } + return log.String() +} + +// EscapeString writes to p the properly escaped XML equivalent +// of the plain text data s. +func EscapeXml(s string) string { + var p strings.Builder + var esc []byte + hextable := "0123456789ABCDEF" + escPattern := []byte("�") + last := 0 + for i := 0; i < len(s); { + r, width := utf8.DecodeRuneInString(s[i:]) + i += width + switch r { + case '"': + esc = escQuot + case '\'': + esc = escApos + case '&': + esc = escAmp + case '<': + esc = escLT + case '>': + esc = escGT + case '\t': + esc = escTab + case '\n': + esc = escNL + case '\r': + esc = escCR + default: + if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) { + if r >= 0x00 && r < 0x20 { + escPattern[3] = hextable[r>>4] + escPattern[4] = hextable[r&0x0f] + esc = escPattern + } else { + esc = escFFFD + } + break + } + continue + } + p.WriteString(s[last : i-width]) + p.Write(esc) + last = i + } + p.WriteString(s[last:]) + return p.String() +} + +// Decide whether the given rune is in the XML Character Range, per +// the Char production of https://www.xml.com/axml/testaxml.htm, +// Section 2.2 Characters. +func isInCharacterRange(r rune) (inrange bool) { + return r == 0x09 || + r == 0x0A || + r == 0x0D || + r >= 0x20 && r <= 0xD7FF || + r >= 0xE000 && r <= 0xFFFD || + r >= 0x10000 && r <= 0x10FFFF +} + +func isVerifyObjectStrict(config *Config) bool { + if config != nil { + if config.AuthVersion == AuthV2 || config.AuthVersion == AuthV4 { + return false + } + return config.VerifyObjectStrict + } + return true +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 25ac1c984..4bb964261 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -70,7 +70,7 @@ github.com/Masterminds/semver # github.com/Masterminds/sprig v2.22.0+incompatible ## explicit github.com/Masterminds/sprig -# github.com/aliyun/aliyun-oss-go-sdk v2.1.8+incompatible +# github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible ## explicit github.com/aliyun/aliyun-oss-go-sdk/oss # github.com/aws/aws-sdk-go v1.54.20 @@ -127,8 +127,6 @@ github.com/aws/aws-sdk-go/service/sso/ssoiface github.com/aws/aws-sdk-go/service/ssooidc github.com/aws/aws-sdk-go/service/sts github.com/aws/aws-sdk-go/service/sts/stsiface -# github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f -## explicit # github.com/beorn7/perks v1.0.1 ## explicit; go 1.11 github.com/beorn7/perks/quantile @@ -429,8 +427,6 @@ github.com/prometheus/procfs/internal/util # github.com/robfig/cron/v3 v3.0.1 ## explicit; go 1.12 github.com/robfig/cron/v3 -# github.com/satori/go.uuid v1.2.0 -## explicit # github.com/sirupsen/logrus v1.9.3 ## explicit; go 1.13 github.com/sirupsen/logrus