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

997 lines
31 KiB

/*
* Copyright 2017 Baidu, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
// object.go - the object APIs definition supported by the BOS service
package api
import (
"encoding/json"
"fmt"
"net"
"strconv"
"strings"
"github.com/baidubce/bce-sdk-go/auth"
"github.com/baidubce/bce-sdk-go/bce"
"github.com/baidubce/bce-sdk-go/http"
"github.com/baidubce/bce-sdk-go/util"
)
// PutObject - put the object from the string or the stream
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object
// - object: the name of the object
// - body: the input content of the object
// - args: the optional arguments of this api
// RETURNS:
// - string: the etag of the object
// - error: nil if ok otherwise the specific error
func PutObject(cli bce.Client, bucket, object string, body *bce.Body,
args *PutObjectArgs) (string, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.PUT)
if body == nil {
return "", bce.NewBceClientError("PutObject body should not be emtpy")
}
if body.Size() >= THRESHOLD_100_CONTINUE {
req.SetHeader("Expect", "100-continue")
}
req.SetBody(body)
// Optional arguments settings
if args != nil {
setOptionalNullHeaders(req, map[string]string{
http.CACHE_CONTROL: args.CacheControl,
http.CONTENT_DISPOSITION: args.ContentDisposition,
http.CONTENT_TYPE: args.ContentType,
http.EXPIRES: args.Expires,
http.BCE_CONTENT_SHA256: args.ContentSha256,
http.BCE_CONTENT_CRC32: args.ContentCrc32,
})
if args.ContentLength > 0 {
// User specified Content-Length can be smaller than the body size, so the body should
// be reset. The `net/http.Client' does not support the Content-Length bigger than the
// body size.
if args.ContentLength > body.Size() {
return "", bce.NewBceClientError(fmt.Sprintf("ContentLength %d is bigger than body size %d", args.ContentLength, body.Size()))
}
body, err := bce.NewBodyFromSizedReader(body.Stream(), args.ContentLength)
if err != nil {
return "", bce.NewBceClientError(err.Error())
}
req.SetHeader(http.CONTENT_LENGTH, fmt.Sprintf("%d", args.ContentLength))
req.SetBody(body) // re-assign body
}
//set traffic-limit
if args.TrafficLimit > 0 {
if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN {
return "", bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit))
}
req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit))
}
// Reset the contentMD5 if set by user
if len(args.ContentMD5) != 0 {
req.SetHeader(http.CONTENT_MD5, args.ContentMD5)
}
if validStorageClass(args.StorageClass) {
req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass)
} else {
if len(args.StorageClass) != 0 {
return "", bce.NewBceClientError("invalid storage class value: " +
args.StorageClass)
}
}
if err := setUserMetadata(req, args.UserMeta); err != nil {
return "", err
}
if len(args.Process) != 0 {
req.SetHeader(http.BCE_PROCESS, args.Process)
}
}
// add content-type if not assigned by user
if req.Header(http.CONTENT_TYPE) == "" {
req.SetHeader(http.CONTENT_TYPE, getDefaultContentType(object))
}
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return "", err
}
if resp.IsFail() {
return "", resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return strings.Trim(resp.Header(http.ETAG), "\""), nil
}
// CopyObject - copy one object to a new object with new bucket and/or name. It can alse set the
// metadata of the object with the same source and target.
//
// PARAMS:
// - cli: the client object which can perform sending request
// - bucket: the bucket name of the target object
// - object: the name of the target object
// - source: the source object uri
// - *CopyObjectArgs: the optional input args for copying object
// RETURNS:
// - *CopyObjectResult: the result object which contains etag and lastmodified
// - error: nil if ok otherwise the specific error
func CopyObject(cli bce.Client, bucket, object, source string,
args *CopyObjectArgs) (*CopyObjectResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.PUT)
if len(source) == 0 {
return nil, bce.NewBceClientError("copy source should not be null")
}
req.SetHeader(http.BCE_COPY_SOURCE, util.UriEncode(source, false))
// Optional arguments settings
if args != nil {
setOptionalNullHeaders(req, map[string]string{
http.CACHE_CONTROL: args.CacheControl,
http.CONTENT_DISPOSITION: args.ContentDisposition,
http.CONTENT_ENCODING: args.ContentEncoding,
http.CONTENT_RANGE: args.ContentRange,
http.CONTENT_TYPE: args.ContentType,
http.EXPIRES: args.Expires,
http.LAST_MODIFIED: args.LastModified,
http.ETAG: args.ETag,
http.CONTENT_MD5: args.ContentMD5,
http.BCE_CONTENT_SHA256: args.ContentSha256,
http.BCE_OBJECT_TYPE: args.ObjectType,
http.BCE_NEXT_APPEND_OFFSET: args.NextAppendOffset,
http.BCE_COPY_SOURCE_IF_MATCH: args.IfMatch,
http.BCE_COPY_SOURCE_IF_NONE_MATCH: args.IfNoneMatch,
http.BCE_COPY_SOURCE_IF_MODIFIED_SINCE: args.IfModifiedSince,
http.BCE_COPY_SOURCE_IF_UNMODIFIED_SINCE: args.IfUnmodifiedSince,
})
if args.ContentLength != 0 {
req.SetHeader(http.CONTENT_LENGTH, fmt.Sprintf("%d", args.ContentLength))
}
if validMetadataDirective(args.MetadataDirective) {
req.SetHeader(http.BCE_COPY_METADATA_DIRECTIVE, args.MetadataDirective)
} else {
if len(args.MetadataDirective) != 0 {
return nil, bce.NewBceClientError(
"invalid metadata directive value: " + args.MetadataDirective)
}
}
if validStorageClass(args.StorageClass) {
req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass)
} else {
if len(args.StorageClass) != 0 {
return nil, bce.NewBceClientError("invalid storage class value: " +
args.StorageClass)
}
}
//set traffic-limit
if args.TrafficLimit > 0 {
if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN {
return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit))
}
req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit))
}
if validCannedAcl(args.CannedAcl) {
req.SetHeader(http.BCE_ACL, args.CannedAcl)
}
if err := setUserMetadata(req, args.UserMeta); err != nil {
return nil, err
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
jsonBody := &CopyObjectResult{}
if err := resp.ParseJsonBody(jsonBody); err != nil {
return nil, err
}
return jsonBody, nil
}
// GetObject - get the object content with range and response-headers-specified support
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object
// - object: the name of the object
// - args: the optional args in querysring
// - ranges: the optional range start and end to get the given object
// RETURNS:
// - *GetObjectResult: the output content result of the object
// - error: nil if ok otherwise the specific error
func GetObject(cli bce.Client, bucket, object string, args map[string]string, // nolint:gocyclo
ranges ...int64) (*GetObjectResult, error) {
if object == "" {
err := fmt.Errorf("Get Object don't accept \"\" as a parameter")
return nil, err
}
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.GET)
// Optional arguments settings
if args != nil {
for k, v := range args {
if _, ok := GET_OBJECT_ALLOWED_RESPONSE_HEADERS[k]; ok {
req.SetParam("response"+k, v)
}
if strings.HasPrefix(k, http.BCE_PREFIX) {
req.SetParam(k, v)
}
}
}
if len(ranges) != 0 {
rangeStr := "bytes="
if len(ranges) == 1 {
rangeStr += fmt.Sprintf("%d", ranges[0]) + "-"
} else {
rangeStr += fmt.Sprintf("%d", ranges[0]) + "-" + fmt.Sprintf("%d", ranges[1])
}
req.SetHeader("Range", rangeStr)
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
headers := resp.Headers()
result := &GetObjectResult{}
if val, ok := headers[http.CACHE_CONTROL]; ok {
result.CacheControl = val
}
if val, ok := headers[http.CONTENT_DISPOSITION]; ok {
result.ContentDisposition = val
}
if val, ok := headers[http.CONTENT_LENGTH]; ok {
if length, err := strconv.ParseInt(val, 10, 64); err == nil {
result.ContentLength = length
}
}
if val, ok := headers[http.CONTENT_RANGE]; ok {
result.ContentRange = val
}
if val, ok := headers[http.CONTENT_TYPE]; ok {
result.ContentType = val
}
if val, ok := headers[http.CONTENT_MD5]; ok {
result.ContentMD5 = val
}
if val, ok := headers[http.EXPIRES]; ok {
result.Expires = val
}
if val, ok := headers[http.LAST_MODIFIED]; ok {
result.LastModified = val
}
if val, ok := headers[http.ETAG]; ok {
result.ETag = strings.Trim(val, "\"")
}
if val, ok := headers[http.CONTENT_LANGUAGE]; ok {
result.ContentLanguage = val
}
if val, ok := headers[http.CONTENT_ENCODING]; ok {
result.ContentEncoding = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_SHA256)]; ok {
result.ContentSha256 = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok {
result.ContentCrc32 = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_STORAGE_CLASS)]; ok {
result.StorageClass = val
}
bcePrefix := toHttpHeaderKey(http.BCE_USER_METADATA_PREFIX)
for k, v := range headers {
if strings.Index(k, bcePrefix) == 0 {
if result.UserMeta == nil {
result.UserMeta = make(map[string]string)
}
result.UserMeta[k[len(bcePrefix):]] = v
}
}
if val, ok := headers[toHttpHeaderKey(http.BCE_OBJECT_TYPE)]; ok {
result.ObjectType = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_NEXT_APPEND_OFFSET)]; ok {
result.NextAppendOffset = val
}
result.Body = resp.Body()
return result, nil
}
// GetObjectMeta - get the meta data of the given object
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object
// - object: the name of the object
// RETURNS:
// - *GetObjectMetaResult: the result of this api
// - error: nil if ok otherwise the specific error
func GetObjectMeta(cli bce.Client, bucket, object string) (*GetObjectMetaResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.HEAD)
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
headers := resp.Headers()
result := &GetObjectMetaResult{}
if val, ok := headers[http.CACHE_CONTROL]; ok {
result.CacheControl = val
}
if val, ok := headers[http.CONTENT_DISPOSITION]; ok {
result.ContentDisposition = val
}
if val, ok := headers[http.CONTENT_LENGTH]; ok {
if length, err := strconv.ParseInt(val, 10, 64); err == nil {
result.ContentLength = length
}
}
if val, ok := headers[http.CONTENT_RANGE]; ok {
result.ContentRange = val
}
if val, ok := headers[http.CONTENT_TYPE]; ok {
result.ContentType = val
}
if val, ok := headers[http.CONTENT_MD5]; ok {
result.ContentMD5 = val
}
if val, ok := headers[http.EXPIRES]; ok {
result.Expires = val
}
if val, ok := headers[http.LAST_MODIFIED]; ok {
result.LastModified = val
}
if val, ok := headers[http.ETAG]; ok {
result.ETag = strings.Trim(val, "\"")
}
if val, ok := headers[http.CONTENT_ENCODING]; ok {
result.ContentEncoding = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_SHA256)]; ok {
result.ContentSha256 = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok {
result.ContentCrc32 = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_STORAGE_CLASS)]; ok {
result.StorageClass = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_RESTORE)]; ok {
result.BceRestore = val
}
if val, ok := headers[http.BCE_OBJECT_TYPE]; ok {
result.BceObjectType = val
}
bcePrefix := toHttpHeaderKey(http.BCE_USER_METADATA_PREFIX)
for k, v := range headers {
if strings.Index(k, bcePrefix) == 0 {
if result.UserMeta == nil {
result.UserMeta = make(map[string]string)
}
result.UserMeta[k[len(bcePrefix):]] = v
}
}
if val, ok := headers[toHttpHeaderKey(http.BCE_OBJECT_TYPE)]; ok {
result.ObjectType = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_NEXT_APPEND_OFFSET)]; ok {
result.NextAppendOffset = val
}
defer func() { resp.Body().Close() }()
return result, nil
}
// SelectObject - select the object content
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object
// - object: the name of the object
// - args: the optional arguments to perform the select operation
// RETURNS:
// - *SelectObjectResult: the output select content result of the object
// - error: nil if ok otherwise the specific error
func SelectObject(cli bce.Client, bucket, object string, args *SelectObjectArgs) (*SelectObjectResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.POST)
req.SetParam("select", "")
req.SetParam("type", args.SelectType)
jsonBytes, jsonErr := json.Marshal(args)
if jsonErr != nil {
return nil, jsonErr
}
body, err := bce.NewBodyFromBytes(jsonBytes)
if err != nil {
return nil, err
}
req.SetBody(body)
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &SelectObjectResult{}
result.Body = resp.Body()
return result, nil
}
// FetchObject - fetch the object by the given url and store it to a bucket
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name to store the object
// - object: the name of the object to be stored
// - source: the source url to fetch
// - args: the optional arguments to perform the fetch operation
// RETURNS:
// - *FetchObjectArgs: the result of this api
// - error: nil if ok otherwise the specific error
func FetchObject(cli bce.Client, bucket, object, source string,
args *FetchObjectArgs) (*FetchObjectResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.POST)
req.SetParam("fetch", "")
if len(source) == 0 {
return nil, bce.NewBceClientError("invalid fetch source value: " + source)
}
req.SetHeader(http.BCE_PREFIX+"fetch-source", source)
// Optional arguments settings
if args != nil {
if validFetchMode(args.FetchMode) {
req.SetHeader(http.BCE_PREFIX+"fetch-mode", args.FetchMode)
} else {
if len(args.FetchMode) != 0 {
return nil, bce.NewBceClientError("invalid fetch mode value: " + args.FetchMode)
}
}
if validStorageClass(args.StorageClass) {
req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass)
} else {
if len(args.StorageClass) != 0 {
return nil, bce.NewBceClientError("invalid storage class value: " +
args.StorageClass)
}
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
jsonBody := &FetchObjectResult{}
if err := resp.ParseJsonBody(jsonBody); err != nil {
return nil, err
}
return jsonBody, nil
}
// AppendObject - append the given content to a new or existed object which is appendable
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object
// - object: the name of the object
// - content: the content to be appended
// - args: the optional arguments to perform the append operation
// RETURNS:
// - *AppendObjectResult: the result status for this api
// - error: nil if ok otherwise the specific error
func AppendObject(cli bce.Client, bucket, object string, content *bce.Body,
args *AppendObjectArgs) (*AppendObjectResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.POST)
req.SetParam("append", "")
if content == nil {
return nil, bce.NewBceClientError("AppendObject body should not be emtpy")
}
if content.Size() >= THRESHOLD_100_CONTINUE {
req.SetHeader("Expect", "100-continue")
}
req.SetBody(content)
// Optional arguments settings
if args != nil {
if args.Offset < 0 {
return nil, bce.NewBceClientError(
fmt.Sprintf("invalid append offset value: %d", args.Offset))
}
if args.Offset > 0 {
req.SetParam("offset", fmt.Sprintf("%d", args.Offset))
}
setOptionalNullHeaders(req, map[string]string{
http.CACHE_CONTROL: args.CacheControl,
http.CONTENT_DISPOSITION: args.ContentDisposition,
http.CONTENT_MD5: args.ContentMD5,
http.CONTENT_TYPE: args.ContentType,
http.EXPIRES: args.Expires,
http.BCE_CONTENT_SHA256: args.ContentSha256,
http.BCE_CONTENT_CRC32: args.ContentCrc32,
})
if validStorageClass(args.StorageClass) {
req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass)
} else {
if len(args.StorageClass) != 0 {
return nil, bce.NewBceClientError("invalid storage class value: " +
args.StorageClass)
}
}
if err := setUserMetadata(req, args.UserMeta); err != nil {
return nil, err
}
//set traffic-limit
if args.TrafficLimit > 0 {
if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN {
return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit))
}
req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit))
}
}
// Send request and get the result
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
headers := resp.Headers()
result := &AppendObjectResult{}
if val, ok := headers[http.CONTENT_MD5]; ok {
result.ContentMD5 = val
}
if val, ok := headers[toHttpHeaderKey(http.BCE_NEXT_APPEND_OFFSET)]; ok {
nextOffset, offsetErr := strconv.ParseInt(val, 10, 64)
if offsetErr != nil {
nextOffset = content.Size()
}
result.NextAppendOffset = nextOffset
} else {
result.NextAppendOffset = content.Size()
}
if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok {
result.ContentCrc32 = val
}
if val, ok := headers[http.ETAG]; ok {
result.ETag = strings.Trim(val, "\"")
}
defer func() { resp.Body().Close() }()
return result, nil
}
// DeleteObject - delete the given object
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object to be deleted
// - object: the name of the object
// RETURNS:
// - error: nil if ok otherwise the specific error
func DeleteObject(cli bce.Client, bucket, object string) error {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.DELETE)
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return err
}
if resp.IsFail() {
return resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return nil
}
// DeleteMultipleObjects - delete the given objects within a single http request
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the objects to be deleted
// - objectListStream: the objects list to be delete with json format
// RETURNS:
// - *DeleteMultipleObjectsResult: the objects failed to delete
// - error: nil if ok otherwise the specific error
func DeleteMultipleObjects(cli bce.Client, bucket string,
objectListStream *bce.Body) (*DeleteMultipleObjectsResult, error) {
req := &bce.BceRequest{}
req.SetUri(getBucketUri(bucket))
req.SetMethod(http.POST)
req.SetParam("delete", "")
req.SetHeader(http.CONTENT_TYPE, "application/json; charset=utf-8")
if objectListStream == nil {
return nil, bce.NewBceClientError("DeleteMultipleObjects body should not be emtpy")
}
if objectListStream.Size() >= THRESHOLD_100_CONTINUE {
req.SetHeader("Expect", "100-continue")
}
req.SetBody(objectListStream)
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
jsonBody := &DeleteMultipleObjectsResult{}
if err := resp.ParseJsonBody(jsonBody); err != nil {
return nil, err
}
return jsonBody, nil
}
// GeneratePresignedUrl - generate an authorization url with expire time and optional arguments
//
// PARAMS:
// - conf: the client configuration
// - signer: the client signer object to generate the authorization string
// - bucket: the target bucket name
// - object: the target object name
// - expire: expire time in seconds
// - method: optional sign method, default is GET
// - headers: optional sign headers, default just set the Host
// - params: optional sign params, default is empty
// RETURNS:
// - string: the presigned url with authorization string
func GeneratePresignedUrl(conf *bce.BceClientConfiguration, signer auth.Signer, bucket,
object string, expire int, method string, headers, params map[string]string) string {
return GeneratePresignedUrlInternal(conf, signer, bucket, object, expire, method, headers, params, false)
}
func GeneratePresignedUrlPathStyle(conf *bce.BceClientConfiguration, signer auth.Signer, bucket,
object string, expire int, method string, headers, params map[string]string) string {
return GeneratePresignedUrlInternal(conf, signer, bucket, object, expire, method, headers, params, true)
}
func GeneratePresignedUrlInternal(conf *bce.BceClientConfiguration, signer auth.Signer, bucket,
object string, expire int, method string, headers, params map[string]string, path_style bool) string {
req := &bce.BceRequest{}
// Set basic arguments
if len(method) == 0 {
method = http.GET
}
req.SetMethod(method)
req.SetEndpoint(conf.Endpoint)
if req.Protocol() == "" {
req.SetProtocol(bce.DEFAULT_PROTOCOL)
}
domain := req.Host()
if pos := strings.Index(domain, ":"); pos != -1 {
domain = domain[:pos]
}
if path_style {
req.SetUri(getObjectUri(bucket, object))
if conf.CnameEnabled || isCnameLikeHost(conf.Endpoint) {
req.SetUri(getCnameUri(req.Uri()))
}
} else {
if len(bucket) != 0 && net.ParseIP(domain) == nil { // not use an IP as the endpoint by client
req.SetUri(bce.URI_PREFIX + object)
if !conf.CnameEnabled && !isCnameLikeHost(conf.Endpoint) {
req.SetHost(bucket + "." + req.Host())
}
} else {
req.SetUri(getObjectUri(bucket, object))
if conf.CnameEnabled || isCnameLikeHost(conf.Endpoint) {
req.SetUri(getCnameUri(req.Uri()))
}
}
}
// Set headers and params if given.
req.SetHeader(http.HOST, req.Host())
if headers != nil {
for k, v := range headers {
req.SetHeader(k, v)
}
}
if params != nil {
for k, v := range params {
req.SetParam(k, v)
}
}
// Copy one SignOptions object to rewrite it.
option := *conf.SignOption
if expire != 0 {
option.ExpireSeconds = expire
}
if conf.Credentials.SessionToken != "" {
req.SetParam(http.BCE_SECURITY_TOKEN, conf.Credentials.SessionToken)
}
// Generate the authorization string and return the signed url.
signer.Sign(&req.Request, conf.Credentials, &option)
req.SetParam("authorization", req.Header(http.AUTHORIZATION))
return fmt.Sprintf("%s://%s%s?%s", req.Protocol(), req.Host(),
util.UriEncode(req.Uri(), false), req.QueryString())
}
// PutObjectAcl - set the ACL of the given object
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name
// - object: the object name
// - cannedAcl: support private and public-read
// - grantRead: user id list
// - grantFullControl: user id list
// - aclBody: the acl file body
// RETURNS:
// - error: nil if success otherwise the specific error
func PutObjectAcl(cli bce.Client, bucket, object, cannedAcl string,
grantRead, grantFullControl []string, aclBody *bce.Body) error {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.PUT)
req.SetParam("acl", "")
// Joiner for generate the user id list string for grant acl header
joiner := func(ids []string) string {
for i := range ids {
ids[i] = "id=\"" + ids[i] + "\""
}
return strings.Join(ids, ",")
}
// Choose a acl setting method
methods := 0
if len(cannedAcl) != 0 {
methods += 1
if validCannedAcl(cannedAcl) {
req.SetHeader(http.BCE_ACL, cannedAcl)
}
}
if len(grantRead) != 0 {
methods += 1
req.SetHeader(http.BCE_GRANT_READ, joiner(grantRead))
}
if len(grantFullControl) != 0 {
methods += 1
req.SetHeader(http.BCE_GRANT_FULL_CONTROL, joiner(grantFullControl))
}
if aclBody != nil {
methods += 1
req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE)
req.SetBody(aclBody)
}
if methods != 1 {
return bce.NewBceClientError("BOS only support one acl setting method at the same time")
}
// Do sending request
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return err
}
if resp.IsFail() {
return resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return nil
}
// GetObjectAcl - get the ACL of the given object
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name
// - object: the object name
// RETURNS:
// - result: the object acl result object
// - error: nil if success otherwise the specific error
func GetObjectAcl(cli bce.Client, bucket, object string) (*GetObjectAclResult, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.GET)
req.SetParam("acl", "")
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return nil, err
}
if resp.IsFail() {
return nil, resp.ServiceError()
}
result := &GetObjectAclResult{}
if err := resp.ParseJsonBody(result); err != nil {
return nil, err
}
return result, nil
}
// DeleteObjectAcl - delete the ACL of the given object
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name
// - object: the object name
// RETURNS:
// - error: nil if success otherwise the specific error
func DeleteObjectAcl(cli bce.Client, bucket, object string) error {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetMethod(http.DELETE)
req.SetParam("acl", "")
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return err
}
if resp.IsFail() {
return resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return nil
}
// RestoreObject - restore the archive object
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name
// - object: the object name
// - args: the restore args
// RETURNS:
// - error: nil if success otherwise the specific error
func RestoreObject(cli bce.Client, bucket string, object string, args ArchiveRestoreArgs) error {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, object))
req.SetParam("restore", "")
req.SetMethod(http.POST)
req.SetHeader(http.BCE_RESTORE_DAYS, strconv.Itoa(args.RestoreDays))
req.SetHeader(http.BCE_RESTORE_TIER, args.RestoreTier)
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return err
}
if resp.IsFail() {
return resp.ServiceError()
}
return nil
}
// PutObjectSymlink - put the object from the string or the stream
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object
// - object: the name of the object
// - symlinkKey: the name of the symlink
// - symlinkArgs: the optional arguments of this api
// RETURNS:
// - error: nil if ok otherwise the specific error
func PutObjectSymlink(cli bce.Client, bucket string, object string, symlinkKey string, symlinkArgs *PutSymlinkArgs) error {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, symlinkKey))
req.SetParam("symlink", "")
req.SetMethod(http.PUT)
if symlinkArgs != nil {
if len(symlinkArgs.ForbidOverwrite) != 0 {
if !validForbidOverwrite(symlinkArgs.ForbidOverwrite) {
return bce.NewBceClientError("invalid forbid overwrite val," + symlinkArgs.ForbidOverwrite)
}
req.SetHeader(http.BCE_FORBID_OVERWRITE, symlinkArgs.ForbidOverwrite)
}
if len(symlinkArgs.StorageClass) != 0 {
if !validStorageClass(symlinkArgs.StorageClass) {
return bce.NewBceClientError("invalid storage class val," + symlinkArgs.StorageClass)
}
if symlinkArgs.StorageClass == STORAGE_CLASS_ARCHIVE {
return bce.NewBceClientError("archive storage class not support")
}
req.SetHeader(http.BCE_STORAGE_CLASS, symlinkArgs.StorageClass)
}
if len(symlinkArgs.UserMeta) != 0 {
if err := setUserMetadata(req, symlinkArgs.UserMeta); err != nil {
return err
}
}
if len(symlinkArgs.SymlinkBucket) != 0 {
req.SetHeader(http.BCE_SYMLINK_BUCKET, symlinkArgs.SymlinkBucket)
}
}
req.SetHeader(http.BCE_SYMLINK_TARGET, object)
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return err
}
if resp.IsFail() {
return resp.ServiceError()
}
defer func() { resp.Body().Close() }()
return nil
}
// PutObjectSymlink - put the object from the string or the stream
//
// PARAMS:
// - cli: the client agent which can perform sending request
// - bucket: the bucket name of the object
// - symlinkKey: the name of the symlink
// RETURNS:
// - string: the name of the target object
// - error: nil if ok otherwise the specific error
func GetObjectSymlink(cli bce.Client, bucket string, symlinkKey string) (string, error) {
req := &bce.BceRequest{}
req.SetUri(getObjectUri(bucket, symlinkKey))
req.SetParam("symlink", "")
req.SetMethod(http.GET)
resp := &bce.BceResponse{}
if err := SendRequest(cli, req, resp); err != nil {
return "", err
}
if resp.IsFail() {
return "", resp.ServiceError()
}
defer func() { resp.Body().Close() }()
if resp.Header(http.BCE_SYMLINK_BUCKET) != "" {
result := BOS_CONFIG_PREFIX + resp.Header(http.BCE_SYMLINK_BUCKET) + "/" + resp.Header(http.BCE_SYMLINK_TARGET)
return result, nil
}
return resp.Header(http.BCE_SYMLINK_TARGET), nil
}