github.com/aliyun/aliyun-oss-go-sdk@v3.0.2+incompatible/oss/option.go (about)

     1  package oss
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/url"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  type optionType string
    15  
    16  const (
    17  	optionParam   optionType = "HTTPParameter" // URL parameter
    18  	optionHTTP    optionType = "HTTPHeader"    // HTTP header
    19  	optionContext optionType = "HTTPContext"   // context
    20  	optionArg     optionType = "FuncArgument"  // Function argument
    21  
    22  )
    23  
    24  const (
    25  	deleteObjectsQuiet = "delete-objects-quiet"
    26  	routineNum         = "x-routine-num"
    27  	checkpointConfig   = "x-cp-config"
    28  	initCRC64          = "init-crc64"
    29  	progressListener   = "x-progress-listener"
    30  	storageClass       = "storage-class"
    31  	responseHeader     = "x-response-header"
    32  	redundancyType     = "redundancy-type"
    33  	objectHashFunc     = "object-hash-func"
    34  	responseBody       = "x-response-body"
    35  	contextArg         = "x-context-arg"
    36  )
    37  
    38  type (
    39  	optionValue struct {
    40  		Value interface{}
    41  		Type  optionType
    42  	}
    43  
    44  	// Option HTTP option
    45  	Option func(map[string]optionValue) error
    46  )
    47  
    48  // ACL is an option to set X-Oss-Acl header
    49  func ACL(acl ACLType) Option {
    50  	return setHeader(HTTPHeaderOssACL, string(acl))
    51  }
    52  
    53  // ContentType is an option to set Content-Type header
    54  func ContentType(value string) Option {
    55  	return setHeader(HTTPHeaderContentType, value)
    56  }
    57  
    58  // ContentLength is an option to set Content-Length header
    59  func ContentLength(length int64) Option {
    60  	return setHeader(HTTPHeaderContentLength, strconv.FormatInt(length, 10))
    61  }
    62  
    63  // CacheControl is an option to set Cache-Control header
    64  func CacheControl(value string) Option {
    65  	return setHeader(HTTPHeaderCacheControl, value)
    66  }
    67  
    68  // ContentDisposition is an option to set Content-Disposition header
    69  func ContentDisposition(value string) Option {
    70  	return setHeader(HTTPHeaderContentDisposition, value)
    71  }
    72  
    73  // ContentEncoding is an option to set Content-Encoding header
    74  func ContentEncoding(value string) Option {
    75  	return setHeader(HTTPHeaderContentEncoding, value)
    76  }
    77  
    78  // ContentLanguage is an option to set Content-Language header
    79  func ContentLanguage(value string) Option {
    80  	return setHeader(HTTPHeaderContentLanguage, value)
    81  }
    82  
    83  // ContentMD5 is an option to set Content-MD5 header
    84  func ContentMD5(value string) Option {
    85  	return setHeader(HTTPHeaderContentMD5, value)
    86  }
    87  
    88  // Expires is an option to set Expires header
    89  func Expires(t time.Time) Option {
    90  	return setHeader(HTTPHeaderExpires, t.Format(http.TimeFormat))
    91  }
    92  
    93  // Meta is an option to set Meta header
    94  func Meta(key, value string) Option {
    95  	return setHeader(HTTPHeaderOssMetaPrefix+key, value)
    96  }
    97  
    98  // Range is an option to set Range header, [start, end]
    99  func Range(start, end int64) Option {
   100  	return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%d-%d", start, end))
   101  }
   102  
   103  // NormalizedRange is an option to set Range header, such as 1024-2048 or 1024- or -2048
   104  func NormalizedRange(nr string) Option {
   105  	return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%s", strings.TrimSpace(nr)))
   106  }
   107  
   108  // AcceptEncoding is an option to set Accept-Encoding header
   109  func AcceptEncoding(value string) Option {
   110  	return setHeader(HTTPHeaderAcceptEncoding, value)
   111  }
   112  
   113  // IfModifiedSince is an option to set If-Modified-Since header
   114  func IfModifiedSince(t time.Time) Option {
   115  	return setHeader(HTTPHeaderIfModifiedSince, t.Format(http.TimeFormat))
   116  }
   117  
   118  // IfUnmodifiedSince is an option to set If-Unmodified-Since header
   119  func IfUnmodifiedSince(t time.Time) Option {
   120  	return setHeader(HTTPHeaderIfUnmodifiedSince, t.Format(http.TimeFormat))
   121  }
   122  
   123  // IfMatch is an option to set If-Match header
   124  func IfMatch(value string) Option {
   125  	return setHeader(HTTPHeaderIfMatch, value)
   126  }
   127  
   128  // IfNoneMatch is an option to set IfNoneMatch header
   129  func IfNoneMatch(value string) Option {
   130  	return setHeader(HTTPHeaderIfNoneMatch, value)
   131  }
   132  
   133  // CopySource is an option to set X-Oss-Copy-Source header
   134  func CopySource(sourceBucket, sourceObject string) Option {
   135  	return setHeader(HTTPHeaderOssCopySource, "/"+sourceBucket+"/"+sourceObject)
   136  }
   137  
   138  // CopySourceVersion is an option to set X-Oss-Copy-Source header,include versionId
   139  func CopySourceVersion(sourceBucket, sourceObject string, versionId string) Option {
   140  	return setHeader(HTTPHeaderOssCopySource, "/"+sourceBucket+"/"+sourceObject+"?"+"versionId="+versionId)
   141  }
   142  
   143  // CopySourceRange is an option to set X-Oss-Copy-Source header
   144  func CopySourceRange(startPosition, partSize int64) Option {
   145  	val := "bytes=" + strconv.FormatInt(startPosition, 10) + "-" +
   146  		strconv.FormatInt((startPosition+partSize-1), 10)
   147  	return setHeader(HTTPHeaderOssCopySourceRange, val)
   148  }
   149  
   150  // CopySourceIfMatch is an option to set X-Oss-Copy-Source-If-Match header
   151  func CopySourceIfMatch(value string) Option {
   152  	return setHeader(HTTPHeaderOssCopySourceIfMatch, value)
   153  }
   154  
   155  // CopySourceIfNoneMatch is an option to set X-Oss-Copy-Source-If-None-Match header
   156  func CopySourceIfNoneMatch(value string) Option {
   157  	return setHeader(HTTPHeaderOssCopySourceIfNoneMatch, value)
   158  }
   159  
   160  // CopySourceIfModifiedSince is an option to set X-Oss-CopySource-If-Modified-Since header
   161  func CopySourceIfModifiedSince(t time.Time) Option {
   162  	return setHeader(HTTPHeaderOssCopySourceIfModifiedSince, t.Format(http.TimeFormat))
   163  }
   164  
   165  // CopySourceIfUnmodifiedSince is an option to set X-Oss-Copy-Source-If-Unmodified-Since header
   166  func CopySourceIfUnmodifiedSince(t time.Time) Option {
   167  	return setHeader(HTTPHeaderOssCopySourceIfUnmodifiedSince, t.Format(http.TimeFormat))
   168  }
   169  
   170  // MetadataDirective is an option to set X-Oss-Metadata-Directive header
   171  func MetadataDirective(directive MetadataDirectiveType) Option {
   172  	return setHeader(HTTPHeaderOssMetadataDirective, string(directive))
   173  }
   174  
   175  // ServerSideEncryption is an option to set X-Oss-Server-Side-Encryption header
   176  func ServerSideEncryption(value string) Option {
   177  	return setHeader(HTTPHeaderOssServerSideEncryption, value)
   178  }
   179  
   180  // ServerSideEncryptionKeyID is an option to set X-Oss-Server-Side-Encryption-Key-Id header
   181  func ServerSideEncryptionKeyID(value string) Option {
   182  	return setHeader(HTTPHeaderOssServerSideEncryptionKeyID, value)
   183  }
   184  
   185  // ServerSideDataEncryption is an option to set X-Oss-Server-Side-Data-Encryption header
   186  func ServerSideDataEncryption(value string) Option {
   187  	return setHeader(HTTPHeaderOssServerSideDataEncryption, value)
   188  }
   189  
   190  // SSECAlgorithm is an option to set X-Oss-Server-Side-Encryption-Customer-Algorithm header
   191  func SSECAlgorithm(value string) Option {
   192  	return setHeader(HTTPHeaderSSECAlgorithm, value)
   193  }
   194  
   195  // SSECKey is an option to set X-Oss-Server-Side-Encryption-Customer-Key header
   196  func SSECKey(value string) Option {
   197  	return setHeader(HTTPHeaderSSECKey, value)
   198  }
   199  
   200  // SSECKeyMd5 is an option to set X-Oss-Server-Side-Encryption-Customer-Key-Md5 header
   201  func SSECKeyMd5(value string) Option {
   202  	return setHeader(HTTPHeaderSSECKeyMd5, value)
   203  }
   204  
   205  // ObjectACL is an option to set X-Oss-Object-Acl header
   206  func ObjectACL(acl ACLType) Option {
   207  	return setHeader(HTTPHeaderOssObjectACL, string(acl))
   208  }
   209  
   210  // symlinkTarget is an option to set X-Oss-Symlink-Target
   211  func symlinkTarget(targetObjectKey string) Option {
   212  	return setHeader(HTTPHeaderOssSymlinkTarget, targetObjectKey)
   213  }
   214  
   215  // Origin is an option to set Origin header
   216  func Origin(value string) Option {
   217  	return setHeader(HTTPHeaderOrigin, value)
   218  }
   219  
   220  // ObjectStorageClass is an option to set the storage class of object
   221  func ObjectStorageClass(storageClass StorageClassType) Option {
   222  	return setHeader(HTTPHeaderOssStorageClass, string(storageClass))
   223  }
   224  
   225  // Callback is an option to set callback values
   226  func Callback(callback string) Option {
   227  	return setHeader(HTTPHeaderOssCallback, callback)
   228  }
   229  
   230  // CallbackVar is an option to set callback user defined values
   231  func CallbackVar(callbackVar string) Option {
   232  	return setHeader(HTTPHeaderOssCallbackVar, callbackVar)
   233  }
   234  
   235  // RequestPayer is an option to set payer who pay for the request
   236  func RequestPayer(payerType PayerType) Option {
   237  	return setHeader(HTTPHeaderOssRequester, strings.ToLower(string(payerType)))
   238  }
   239  
   240  // RequestPayerParam is an option to set payer who pay for the request
   241  func RequestPayerParam(payerType PayerType) Option {
   242  	return addParam(strings.ToLower(HTTPHeaderOssRequester), strings.ToLower(string(payerType)))
   243  }
   244  
   245  // SetTagging is an option to set object tagging
   246  func SetTagging(tagging Tagging) Option {
   247  	if len(tagging.Tags) == 0 {
   248  		return nil
   249  	}
   250  
   251  	taggingValue := ""
   252  	for index, tag := range tagging.Tags {
   253  		if index != 0 {
   254  			taggingValue += "&"
   255  		}
   256  		taggingValue += url.QueryEscape(tag.Key) + "=" + url.QueryEscape(tag.Value)
   257  	}
   258  	return setHeader(HTTPHeaderOssTagging, taggingValue)
   259  }
   260  
   261  // TaggingDirective is an option to set X-Oss-Metadata-Directive header
   262  func TaggingDirective(directive TaggingDirectiveType) Option {
   263  	return setHeader(HTTPHeaderOssTaggingDirective, string(directive))
   264  }
   265  
   266  // ACReqMethod is an option to set Access-Control-Request-Method header
   267  func ACReqMethod(value string) Option {
   268  	return setHeader(HTTPHeaderACReqMethod, value)
   269  }
   270  
   271  // ACReqHeaders is an option to set Access-Control-Request-Headers header
   272  func ACReqHeaders(value string) Option {
   273  	return setHeader(HTTPHeaderACReqHeaders, value)
   274  }
   275  
   276  // TrafficLimitHeader is an option to set X-Oss-Traffic-Limit
   277  func TrafficLimitHeader(value int64) Option {
   278  	return setHeader(HTTPHeaderOssTrafficLimit, strconv.FormatInt(value, 10))
   279  }
   280  
   281  // UserAgentHeader is an option to set HTTPHeaderUserAgent
   282  func UserAgentHeader(ua string) Option {
   283  	return setHeader(HTTPHeaderUserAgent, ua)
   284  }
   285  
   286  // ForbidOverWrite  is an option to set X-Oss-Forbid-Overwrite
   287  func ForbidOverWrite(forbidWrite bool) Option {
   288  	if forbidWrite {
   289  		return setHeader(HTTPHeaderOssForbidOverWrite, "true")
   290  	} else {
   291  		return setHeader(HTTPHeaderOssForbidOverWrite, "false")
   292  	}
   293  }
   294  
   295  // RangeBehavior  is an option to set Range value, such as "standard"
   296  func RangeBehavior(value string) Option {
   297  	return setHeader(HTTPHeaderOssRangeBehavior, value)
   298  }
   299  
   300  func PartHashCtxHeader(value string) Option {
   301  	return setHeader(HTTPHeaderOssHashCtx, value)
   302  }
   303  
   304  func PartMd5CtxHeader(value string) Option {
   305  	return setHeader(HTTPHeaderOssMd5Ctx, value)
   306  }
   307  
   308  func PartHashCtxParam(value string) Option {
   309  	return addParam("x-oss-hash-ctx", value)
   310  }
   311  
   312  func PartMd5CtxParam(value string) Option {
   313  	return addParam("x-oss-md5-ctx", value)
   314  }
   315  
   316  // Delimiter is an option to set delimiler parameter
   317  func Delimiter(value string) Option {
   318  	return addParam("delimiter", value)
   319  }
   320  
   321  // Marker is an option to set marker parameter
   322  func Marker(value string) Option {
   323  	return addParam("marker", value)
   324  }
   325  
   326  // MaxKeys is an option to set maxkeys parameter
   327  func MaxKeys(value int) Option {
   328  	return addParam("max-keys", strconv.Itoa(value))
   329  }
   330  
   331  // Prefix is an option to set prefix parameter
   332  func Prefix(value string) Option {
   333  	return addParam("prefix", value)
   334  }
   335  
   336  // EncodingType is an option to set encoding-type parameter
   337  func EncodingType(value string) Option {
   338  	return addParam("encoding-type", value)
   339  }
   340  
   341  // MaxUploads is an option to set max-uploads parameter
   342  func MaxUploads(value int) Option {
   343  	return addParam("max-uploads", strconv.Itoa(value))
   344  }
   345  
   346  // KeyMarker is an option to set key-marker parameter
   347  func KeyMarker(value string) Option {
   348  	return addParam("key-marker", value)
   349  }
   350  
   351  // VersionIdMarker is an option to set version-id-marker parameter
   352  func VersionIdMarker(value string) Option {
   353  	return addParam("version-id-marker", value)
   354  }
   355  
   356  // VersionId is an option to set versionId parameter
   357  func VersionId(value string) Option {
   358  	return addParam("versionId", value)
   359  }
   360  
   361  // TagKey is an option to set tag key parameter
   362  func TagKey(value string) Option {
   363  	return addParam("tag-key", value)
   364  }
   365  
   366  // TagValue is an option to set tag value parameter
   367  func TagValue(value string) Option {
   368  	return addParam("tag-value", value)
   369  }
   370  
   371  // UploadIDMarker is an option to set upload-id-marker parameter
   372  func UploadIDMarker(value string) Option {
   373  	return addParam("upload-id-marker", value)
   374  }
   375  
   376  // MaxParts is an option to set max-parts parameter
   377  func MaxParts(value int) Option {
   378  	return addParam("max-parts", strconv.Itoa(value))
   379  }
   380  
   381  // PartNumberMarker is an option to set part-number-marker parameter
   382  func PartNumberMarker(value int) Option {
   383  	return addParam("part-number-marker", strconv.Itoa(value))
   384  }
   385  
   386  // Sequential is an option to set sequential parameter for InitiateMultipartUpload
   387  func Sequential() Option {
   388  	return addParam("sequential", "")
   389  }
   390  
   391  // WithHashContext is an option to set withHashContext parameter for InitiateMultipartUpload
   392  func WithHashContext() Option {
   393  	return addParam("withHashContext", "")
   394  }
   395  
   396  // EnableMd5 is an option to set x-oss-enable-md5 parameter for InitiateMultipartUpload
   397  func EnableMd5() Option {
   398  	return addParam("x-oss-enable-md5", "")
   399  }
   400  
   401  // EnableSha1 is an option to set x-oss-enable-sha1 parameter for InitiateMultipartUpload
   402  func EnableSha1() Option {
   403  	return addParam("x-oss-enable-sha1", "")
   404  }
   405  
   406  // EnableSha256 is an option to set x-oss-enable-sha256 parameter for InitiateMultipartUpload
   407  func EnableSha256() Option {
   408  	return addParam("x-oss-enable-sha256", "")
   409  }
   410  
   411  // ListType is an option to set List-type parameter for ListObjectsV2
   412  func ListType(value int) Option {
   413  	return addParam("list-type", strconv.Itoa(value))
   414  }
   415  
   416  // StartAfter is an option to set start-after parameter for ListObjectsV2
   417  func StartAfter(value string) Option {
   418  	return addParam("start-after", value)
   419  }
   420  
   421  // ContinuationToken is an option to set Continuation-token parameter for ListObjectsV2
   422  func ContinuationToken(value string) Option {
   423  	if value == "" {
   424  		return addParam("continuation-token", nil)
   425  	}
   426  	return addParam("continuation-token", value)
   427  }
   428  
   429  // FetchOwner is an option to set Fetch-owner parameter for ListObjectsV2
   430  func FetchOwner(value bool) Option {
   431  	if value {
   432  		return addParam("fetch-owner", "true")
   433  	}
   434  	return addParam("fetch-owner", "false")
   435  }
   436  
   437  // DeleteObjectsQuiet false:DeleteObjects in verbose mode; true:DeleteObjects in quite mode. Default is false.
   438  func DeleteObjectsQuiet(isQuiet bool) Option {
   439  	return addArg(deleteObjectsQuiet, isQuiet)
   440  }
   441  
   442  // StorageClass bucket storage class
   443  func StorageClass(value StorageClassType) Option {
   444  	return addArg(storageClass, value)
   445  }
   446  
   447  // RedundancyType bucket data redundancy type
   448  func RedundancyType(value DataRedundancyType) Option {
   449  	return addArg(redundancyType, value)
   450  }
   451  
   452  // RedundancyType bucket data redundancy type
   453  func ObjectHashFunc(value ObjecthashFuncType) Option {
   454  	return addArg(objectHashFunc, value)
   455  }
   456  
   457  // WithContext returns an option that sets the context for requests.
   458  func WithContext(ctx context.Context) Option {
   459  	return addArg(contextArg, ctx)
   460  }
   461  
   462  // Checkpoint configuration
   463  type cpConfig struct {
   464  	IsEnable bool
   465  	FilePath string
   466  	DirPath  string
   467  }
   468  
   469  // Checkpoint sets the isEnable flag and checkpoint file path for DownloadFile/UploadFile.
   470  func Checkpoint(isEnable bool, filePath string) Option {
   471  	return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, FilePath: filePath})
   472  }
   473  
   474  // CheckpointDir sets the isEnable flag and checkpoint dir path for DownloadFile/UploadFile.
   475  func CheckpointDir(isEnable bool, dirPath string) Option {
   476  	return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, DirPath: dirPath})
   477  }
   478  
   479  // Routines DownloadFile/UploadFile routine count
   480  func Routines(n int) Option {
   481  	return addArg(routineNum, n)
   482  }
   483  
   484  // InitCRC Init AppendObject CRC
   485  func InitCRC(initCRC uint64) Option {
   486  	return addArg(initCRC64, initCRC)
   487  }
   488  
   489  // Progress set progress listener
   490  func Progress(listener ProgressListener) Option {
   491  	return addArg(progressListener, listener)
   492  }
   493  
   494  // GetResponseHeader for get response http header
   495  func GetResponseHeader(respHeader *http.Header) Option {
   496  	return addArg(responseHeader, respHeader)
   497  }
   498  
   499  // CallbackResult for get response of call back
   500  func CallbackResult(body *[]byte) Option {
   501  	return addArg(responseBody, body)
   502  }
   503  
   504  // ResponseContentType is an option to set response-content-type param
   505  func ResponseContentType(value string) Option {
   506  	return addParam("response-content-type", value)
   507  }
   508  
   509  // ResponseContentLanguage is an option to set response-content-language param
   510  func ResponseContentLanguage(value string) Option {
   511  	return addParam("response-content-language", value)
   512  }
   513  
   514  // ResponseExpires is an option to set response-expires param
   515  func ResponseExpires(value string) Option {
   516  	return addParam("response-expires", value)
   517  }
   518  
   519  // ResponseCacheControl is an option to set response-cache-control param
   520  func ResponseCacheControl(value string) Option {
   521  	return addParam("response-cache-control", value)
   522  }
   523  
   524  // ResponseContentDisposition is an option to set response-content-disposition param
   525  func ResponseContentDisposition(value string) Option {
   526  	return addParam("response-content-disposition", value)
   527  }
   528  
   529  // ResponseContentEncoding is an option to set response-content-encoding param
   530  func ResponseContentEncoding(value string) Option {
   531  	return addParam("response-content-encoding", value)
   532  }
   533  
   534  // Process is an option to set x-oss-process param
   535  func Process(value string) Option {
   536  	return addParam("x-oss-process", value)
   537  }
   538  
   539  // TrafficLimitParam is a option to set x-oss-traffic-limit
   540  func TrafficLimitParam(value int64) Option {
   541  	return addParam("x-oss-traffic-limit", strconv.FormatInt(value, 10))
   542  }
   543  
   544  // SetHeader Allow users to set personalized http headers
   545  func SetHeader(key string, value interface{}) Option {
   546  	return setHeader(key, value)
   547  }
   548  
   549  // AddParam Allow users to set personalized http params
   550  func AddParam(key string, value interface{}) Option {
   551  	return addParam(key, value)
   552  }
   553  
   554  func setHeader(key string, value interface{}) Option {
   555  	return func(params map[string]optionValue) error {
   556  		if value == nil {
   557  			return nil
   558  		}
   559  		params[key] = optionValue{value, optionHTTP}
   560  		return nil
   561  	}
   562  }
   563  
   564  func addParam(key string, value interface{}) Option {
   565  	return func(params map[string]optionValue) error {
   566  		if value == nil {
   567  			return nil
   568  		}
   569  		params[key] = optionValue{value, optionParam}
   570  		return nil
   571  	}
   572  }
   573  
   574  func addArg(key string, value interface{}) Option {
   575  	return func(params map[string]optionValue) error {
   576  		if value == nil {
   577  			return nil
   578  		}
   579  		params[key] = optionValue{value, optionArg}
   580  		return nil
   581  	}
   582  }
   583  
   584  func handleOptions(headers map[string]string, options []Option) error {
   585  	params := map[string]optionValue{}
   586  	for _, option := range options {
   587  		if option != nil {
   588  			if err := option(params); err != nil {
   589  				return err
   590  			}
   591  		}
   592  	}
   593  
   594  	for k, v := range params {
   595  		if v.Type == optionHTTP {
   596  			headers[k] = v.Value.(string)
   597  		}
   598  	}
   599  	return nil
   600  }
   601  
   602  func GetRawParams(options []Option) (map[string]interface{}, error) {
   603  	// Option
   604  	params := map[string]optionValue{}
   605  	for _, option := range options {
   606  		if option != nil {
   607  			if err := option(params); err != nil {
   608  				return nil, err
   609  			}
   610  		}
   611  	}
   612  
   613  	paramsm := map[string]interface{}{}
   614  	// Serialize
   615  	for k, v := range params {
   616  		if v.Type == optionParam {
   617  			vs := params[k]
   618  			paramsm[k] = vs.Value.(string)
   619  		}
   620  	}
   621  
   622  	return paramsm, nil
   623  }
   624  
   625  func FindOption(options []Option, param string, defaultVal interface{}) (interface{}, error) {
   626  	params := map[string]optionValue{}
   627  	for _, option := range options {
   628  		if option != nil {
   629  			if err := option(params); err != nil {
   630  				return nil, err
   631  			}
   632  		}
   633  	}
   634  
   635  	if val, ok := params[param]; ok {
   636  		return val.Value, nil
   637  	}
   638  	return defaultVal, nil
   639  }
   640  
   641  func IsOptionSet(options []Option, option string) (bool, interface{}, error) {
   642  	params := map[string]optionValue{}
   643  	for _, option := range options {
   644  		if option != nil {
   645  			if err := option(params); err != nil {
   646  				return false, nil, err
   647  			}
   648  		}
   649  	}
   650  
   651  	if val, ok := params[option]; ok {
   652  		return true, val.Value, nil
   653  	}
   654  	return false, nil, nil
   655  }
   656  
   657  func DeleteOption(options []Option, strKey string) []Option {
   658  	var outOption []Option
   659  	params := map[string]optionValue{}
   660  	for _, option := range options {
   661  		if option != nil {
   662  			option(params)
   663  			_, exist := params[strKey]
   664  			if !exist {
   665  				outOption = append(outOption, option)
   666  			} else {
   667  				delete(params, strKey)
   668  			}
   669  		}
   670  	}
   671  	return outOption
   672  }
   673  
   674  func GetRequestId(header http.Header) string {
   675  	return header.Get("x-oss-request-id")
   676  }
   677  
   678  func GetVersionId(header http.Header) string {
   679  	return header.Get("x-oss-version-id")
   680  }
   681  
   682  func GetCopySrcVersionId(header http.Header) string {
   683  	return header.Get("x-oss-copy-source-version-id")
   684  }
   685  
   686  func GetDeleteMark(header http.Header) bool {
   687  	value := header.Get("x-oss-delete-marker")
   688  	if strings.ToUpper(value) == "TRUE" {
   689  		return true
   690  	}
   691  	return false
   692  }
   693  
   694  func GetQosDelayTime(header http.Header) string {
   695  	return header.Get("x-oss-qos-delay-time")
   696  }
   697  
   698  // ForbidOverWrite  is an option to set X-Oss-Forbid-Overwrite
   699  func AllowSameActionOverLap(enabled bool) Option {
   700  	if enabled {
   701  		return setHeader(HTTPHeaderAllowSameActionOverLap, "true")
   702  	} else {
   703  		return setHeader(HTTPHeaderAllowSameActionOverLap, "false")
   704  	}
   705  }
   706  
   707  func GetCallbackBody(options []Option, resp *Response, callbackSet bool) error {
   708  	var err error
   709  
   710  	// get response body
   711  	if callbackSet {
   712  		err = setBody(options, resp)
   713  	} else {
   714  		callback, _ := FindOption(options, HTTPHeaderOssCallback, nil)
   715  		if callback != nil {
   716  			err = setBody(options, resp)
   717  		}
   718  	}
   719  	return err
   720  }
   721  
   722  func setBody(options []Option, resp *Response) error {
   723  	respBody, _ := FindOption(options, responseBody, nil)
   724  	if respBody != nil && resp != nil {
   725  		pRespBody := respBody.(*[]byte)
   726  		pBody, err := ioutil.ReadAll(resp.Body)
   727  		if err != nil {
   728  			return err
   729  		}
   730  		if pBody != nil {
   731  			*pRespBody = pBody
   732  		}
   733  	}
   734  	return nil
   735  }