yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/huawei/obs/trait.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Copyright 2019 Huawei Technologies Co.,Ltd.
    16  // Licensed under the Apache License, Version 2.0 (the "License"); you may not use
    17  // this file except in compliance with the License.  You may obtain a copy of the
    18  // License at
    19  //
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  //
    22  // Unless required by applicable law or agreed to in writing, software distributed
    23  // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    24  // CONDITIONS OF ANY KIND, either express or implied.  See the License for the
    25  // specific language governing permissions and limitations under the License.
    26  
    27  package obs
    28  
    29  import (
    30  	"bytes"
    31  	"fmt"
    32  	"io"
    33  	"os"
    34  	"strings"
    35  )
    36  
    37  type IReadCloser interface {
    38  	setReadCloser(body io.ReadCloser)
    39  }
    40  
    41  func (output *GetObjectOutput) setReadCloser(body io.ReadCloser) {
    42  	output.Body = body
    43  }
    44  
    45  func setHeaders(headers map[string][]string, header string, headerValue []string, isObs bool) {
    46  	if isObs {
    47  		header = HEADER_PREFIX_OBS + header
    48  		headers[header] = headerValue
    49  	} else {
    50  		header = HEADER_PREFIX + header
    51  		headers[header] = headerValue
    52  	}
    53  }
    54  
    55  func setHeadersNext(headers map[string][]string, header string, headerNext string, headerValue []string, isObs bool) {
    56  	if isObs {
    57  		headers[header] = headerValue
    58  	} else {
    59  		headers[headerNext] = headerValue
    60  	}
    61  }
    62  
    63  type IBaseModel interface {
    64  	setStatusCode(statusCode int)
    65  
    66  	setRequestId(requestId string)
    67  
    68  	setResponseHeaders(responseHeaders map[string][]string)
    69  }
    70  
    71  type ISerializable interface {
    72  	trans(isObs bool) (map[string]string, map[string][]string, interface{}, error)
    73  }
    74  
    75  type DefaultSerializable struct {
    76  	params  map[string]string
    77  	headers map[string][]string
    78  	data    interface{}
    79  }
    80  
    81  func (input DefaultSerializable) trans(isObs bool) (map[string]string, map[string][]string, interface{}, error) {
    82  	return input.params, input.headers, input.data, nil
    83  }
    84  
    85  var defaultSerializable = &DefaultSerializable{}
    86  
    87  func newSubResourceSerial(subResource SubResourceType) *DefaultSerializable {
    88  	return &DefaultSerializable{map[string]string{string(subResource): ""}, nil, nil}
    89  }
    90  
    91  func trans(subResource SubResourceType, input interface{}) (params map[string]string, headers map[string][]string, data interface{}, err error) {
    92  	params = map[string]string{string(subResource): ""}
    93  	data, err = ConvertRequestToIoReader(input)
    94  	return
    95  }
    96  
    97  func (baseModel *BaseModel) setStatusCode(statusCode int) {
    98  	baseModel.StatusCode = statusCode
    99  }
   100  
   101  func (baseModel *BaseModel) setRequestId(requestId string) {
   102  	baseModel.RequestId = requestId
   103  }
   104  
   105  func (baseModel *BaseModel) setResponseHeaders(responseHeaders map[string][]string) {
   106  	baseModel.ResponseHeaders = responseHeaders
   107  }
   108  
   109  func (input ListBucketsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   110  	headers = make(map[string][]string)
   111  	if input.QueryLocation && !isObs {
   112  		setHeaders(headers, HEADER_LOCATION_AMZ, []string{"true"}, isObs)
   113  	}
   114  	return
   115  }
   116  
   117  func (input CreateBucketInput) prepareGrantHeaders(headers map[string][]string, isObs bool) {
   118  	if grantReadId := input.GrantReadId; grantReadId != "" {
   119  		setHeaders(headers, HEADER_GRANT_READ_OBS, []string{grantReadId}, isObs)
   120  	}
   121  	if grantWriteId := input.GrantWriteId; grantWriteId != "" {
   122  		setHeaders(headers, HEADER_GRANT_WRITE_OBS, []string{grantWriteId}, isObs)
   123  	}
   124  	if grantReadAcpId := input.GrantReadAcpId; grantReadAcpId != "" {
   125  		setHeaders(headers, HEADER_GRANT_READ_ACP_OBS, []string{grantReadAcpId}, isObs)
   126  	}
   127  	if grantWriteAcpId := input.GrantWriteAcpId; grantWriteAcpId != "" {
   128  		setHeaders(headers, HEADER_GRANT_WRITE_ACP_OBS, []string{grantWriteAcpId}, isObs)
   129  	}
   130  	if grantFullControlId := input.GrantFullControlId; grantFullControlId != "" {
   131  		setHeaders(headers, HEADER_GRANT_FULL_CONTROL_OBS, []string{grantFullControlId}, isObs)
   132  	}
   133  	if grantReadDeliveredId := input.GrantReadDeliveredId; grantReadDeliveredId != "" {
   134  		setHeaders(headers, HEADER_GRANT_READ_DELIVERED_OBS, []string{grantReadDeliveredId}, true)
   135  	}
   136  	if grantFullControlDeliveredId := input.GrantFullControlDeliveredId; grantFullControlDeliveredId != "" {
   137  		setHeaders(headers, HEADER_GRANT_FULL_CONTROL_DELIVERED_OBS, []string{grantFullControlDeliveredId}, true)
   138  	}
   139  }
   140  
   141  func (input CreateBucketInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   142  	headers = make(map[string][]string)
   143  	if acl := string(input.ACL); acl != "" {
   144  		setHeaders(headers, HEADER_ACL, []string{acl}, isObs)
   145  	}
   146  	if storageClass := string(input.StorageClass); storageClass != "" {
   147  		if !isObs {
   148  			if storageClass == string(StorageClassWarm) {
   149  				storageClass = string(storageClassStandardIA)
   150  			} else if storageClass == string(StorageClassCold) {
   151  				storageClass = string(storageClassGlacier)
   152  			}
   153  		}
   154  		setHeadersNext(headers, HEADER_STORAGE_CLASS_OBS, HEADER_STORAGE_CLASS, []string{storageClass}, isObs)
   155  		if epid := input.Epid; epid != "" {
   156  			setHeaders(headers, HEADER_EPID_HEADERS, []string{epid}, isObs)
   157  		}
   158  	}
   159  	input.prepareGrantHeaders(headers, isObs)
   160  	if location := strings.TrimSpace(input.Location); location != "" {
   161  		input.Location = location
   162  
   163  		xml := make([]string, 0, 3)
   164  		xml = append(xml, "<CreateBucketConfiguration>")
   165  		if isObs {
   166  			xml = append(xml, fmt.Sprintf("<Location>%s</Location>", input.Location))
   167  		} else {
   168  			xml = append(xml, fmt.Sprintf("<LocationConstraint>%s</LocationConstraint>", input.Location))
   169  		}
   170  		xml = append(xml, "</CreateBucketConfiguration>")
   171  
   172  		data = strings.Join(xml, "")
   173  	}
   174  	return
   175  }
   176  
   177  func (input SetBucketStoragePolicyInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   178  	xml := make([]string, 0, 1)
   179  	if !isObs {
   180  		storageClass := "STANDARD"
   181  		if input.StorageClass == StorageClassWarm {
   182  			storageClass = string(storageClassStandardIA)
   183  		} else if input.StorageClass == StorageClassCold {
   184  			storageClass = string(storageClassGlacier)
   185  		}
   186  		params = map[string]string{string(SubResourceStoragePolicy): ""}
   187  		xml = append(xml, fmt.Sprintf("<StoragePolicy><DefaultStorageClass>%s</DefaultStorageClass></StoragePolicy>", storageClass))
   188  	} else {
   189  		if input.StorageClass != StorageClassWarm && input.StorageClass != StorageClassCold {
   190  			input.StorageClass = StorageClassStandard
   191  		}
   192  		params = map[string]string{string(SubResourceStorageClass): ""}
   193  		xml = append(xml, fmt.Sprintf("<StorageClass>%s</StorageClass>", input.StorageClass))
   194  	}
   195  	data = strings.Join(xml, "")
   196  	return
   197  }
   198  
   199  func (input ListObjsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   200  	params = make(map[string]string)
   201  	if input.Prefix != "" {
   202  		params["prefix"] = input.Prefix
   203  	}
   204  	if input.Delimiter != "" {
   205  		params["delimiter"] = input.Delimiter
   206  	}
   207  	if input.MaxKeys > 0 {
   208  		params["max-keys"] = IntToString(input.MaxKeys)
   209  	}
   210  	headers = make(map[string][]string)
   211  	if origin := strings.TrimSpace(input.Origin); origin != "" {
   212  		headers[HEADER_ORIGIN_CAMEL] = []string{origin}
   213  	}
   214  	if requestHeader := strings.TrimSpace(input.RequestHeader); requestHeader != "" {
   215  		headers[HEADER_ACCESS_CONTROL_REQUEST_HEADER_CAMEL] = []string{requestHeader}
   216  	}
   217  	return
   218  }
   219  
   220  func (input ListObjectsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   221  	params, headers, data, err = input.ListObjsInput.trans(isObs)
   222  	if err != nil {
   223  		return
   224  	}
   225  	if input.Marker != "" {
   226  		params["marker"] = input.Marker
   227  	}
   228  	return
   229  }
   230  
   231  func (input ListVersionsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   232  	params, headers, data, err = input.ListObjsInput.trans(isObs)
   233  	if err != nil {
   234  		return
   235  	}
   236  	params[string(SubResourceVersions)] = ""
   237  	if input.KeyMarker != "" {
   238  		params["key-marker"] = input.KeyMarker
   239  	}
   240  	if input.VersionIdMarker != "" {
   241  		params["version-id-marker"] = input.VersionIdMarker
   242  	}
   243  	return
   244  }
   245  
   246  func (input ListMultipartUploadsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   247  	params = map[string]string{string(SubResourceUploads): ""}
   248  	if input.Prefix != "" {
   249  		params["prefix"] = input.Prefix
   250  	}
   251  	if input.Delimiter != "" {
   252  		params["delimiter"] = input.Delimiter
   253  	}
   254  	if input.MaxUploads > 0 {
   255  		params["max-uploads"] = IntToString(input.MaxUploads)
   256  	}
   257  	if input.KeyMarker != "" {
   258  		params["key-marker"] = input.KeyMarker
   259  	}
   260  	if input.UploadIdMarker != "" {
   261  		params["upload-id-marker"] = input.UploadIdMarker
   262  	}
   263  	return
   264  }
   265  
   266  func (input SetBucketQuotaInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   267  	return trans(SubResourceQuota, input)
   268  }
   269  
   270  func (input SetBucketAclInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   271  	params = map[string]string{string(SubResourceAcl): ""}
   272  	headers = make(map[string][]string)
   273  
   274  	if acl := string(input.ACL); acl != "" {
   275  		setHeaders(headers, HEADER_ACL, []string{acl}, isObs)
   276  	} else {
   277  		data, _ = convertBucketAclToXml(input.AccessControlPolicy, false, isObs)
   278  	}
   279  	return
   280  }
   281  
   282  func (input SetBucketPolicyInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   283  	params = map[string]string{string(SubResourcePolicy): ""}
   284  	data = strings.NewReader(input.Policy)
   285  	return
   286  }
   287  
   288  func (input SetBucketCorsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   289  	params = map[string]string{string(SubResourceCors): ""}
   290  	data, md5, err := ConvertRequestToIoReaderV2(input)
   291  	if err != nil {
   292  		return
   293  	}
   294  	headers = map[string][]string{HEADER_MD5_CAMEL: []string{md5}}
   295  	return
   296  }
   297  
   298  func (input SetBucketVersioningInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   299  	return trans(SubResourceVersioning, input)
   300  }
   301  
   302  func (input SetBucketWebsiteConfigurationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   303  	params = map[string]string{string(SubResourceWebsite): ""}
   304  	data, _ = ConvertWebsiteConfigurationToXml(input.BucketWebsiteConfiguration, false)
   305  	return
   306  }
   307  
   308  func (input GetBucketMetadataInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   309  	headers = make(map[string][]string)
   310  	if origin := strings.TrimSpace(input.Origin); origin != "" {
   311  		headers[HEADER_ORIGIN_CAMEL] = []string{origin}
   312  	}
   313  	if requestHeader := strings.TrimSpace(input.RequestHeader); requestHeader != "" {
   314  		headers[HEADER_ACCESS_CONTROL_REQUEST_HEADER_CAMEL] = []string{requestHeader}
   315  	}
   316  	return
   317  }
   318  
   319  func (input SetBucketLoggingConfigurationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   320  	params = map[string]string{string(SubResourceLogging): ""}
   321  	data, _ = ConvertLoggingStatusToXml(input.BucketLoggingStatus, false, isObs)
   322  	return
   323  }
   324  
   325  func (input SetBucketLifecycleConfigurationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   326  	params = map[string]string{string(SubResourceLifecycle): ""}
   327  	data, md5 := ConvertLifecyleConfigurationToXml(input.BucketLifecyleConfiguration, true, isObs)
   328  	headers = map[string][]string{HEADER_MD5_CAMEL: []string{md5}}
   329  	return
   330  }
   331  
   332  func (input SetBucketTaggingInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   333  	params = map[string]string{string(SubResourceTagging): ""}
   334  	data, md5, err := ConvertRequestToIoReaderV2(input)
   335  	if err != nil {
   336  		return
   337  	}
   338  	headers = map[string][]string{HEADER_MD5_CAMEL: []string{md5}}
   339  	return
   340  }
   341  
   342  func (input SetBucketNotificationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   343  	params = map[string]string{string(SubResourceNotification): ""}
   344  	data, _ = ConvertNotificationToXml(input.BucketNotification, false, isObs)
   345  	return
   346  }
   347  
   348  func (input DeleteObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   349  	params = make(map[string]string)
   350  	if input.VersionId != "" {
   351  		params[PARAM_VERSION_ID] = input.VersionId
   352  	}
   353  	return
   354  }
   355  
   356  func (input DeleteObjectsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   357  	params = map[string]string{string(SubResourceDelete): ""}
   358  	data, md5, err := ConvertRequestToIoReaderV2(input)
   359  	if err != nil {
   360  		return
   361  	}
   362  	headers = map[string][]string{HEADER_MD5_CAMEL: []string{md5}}
   363  	return
   364  }
   365  
   366  func (input SetObjectAclInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   367  	params = map[string]string{string(SubResourceAcl): ""}
   368  	if input.VersionId != "" {
   369  		params[PARAM_VERSION_ID] = input.VersionId
   370  	}
   371  	headers = make(map[string][]string)
   372  	if acl := string(input.ACL); acl != "" {
   373  		setHeaders(headers, HEADER_ACL, []string{acl}, isObs)
   374  	} else {
   375  		data, _ = ConvertAclToXml(input.AccessControlPolicy, false, isObs)
   376  	}
   377  	return
   378  }
   379  
   380  func (input GetObjectAclInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   381  	params = map[string]string{string(SubResourceAcl): ""}
   382  	if input.VersionId != "" {
   383  		params[PARAM_VERSION_ID] = input.VersionId
   384  	}
   385  	return
   386  }
   387  
   388  func (input RestoreObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   389  	params = map[string]string{string(SubResourceRestore): ""}
   390  	if input.VersionId != "" {
   391  		params[PARAM_VERSION_ID] = input.VersionId
   392  	}
   393  	if !isObs {
   394  		data, err = ConvertRequestToIoReader(input)
   395  	} else {
   396  		data = ConverntObsRestoreToXml(input)
   397  	}
   398  	return
   399  }
   400  
   401  func (header SseKmsHeader) GetEncryption() string {
   402  	if header.Encryption != "" {
   403  		return header.Encryption
   404  	}
   405  	if !header.isObs {
   406  		return DEFAULT_SSE_KMS_ENCRYPTION
   407  	}
   408  	return DEFAULT_SSE_KMS_ENCRYPTION_OBS
   409  }
   410  
   411  func (header SseKmsHeader) GetKey() string {
   412  	return header.Key
   413  }
   414  
   415  func (header SseCHeader) GetEncryption() string {
   416  	if header.Encryption != "" {
   417  		return header.Encryption
   418  	}
   419  	return DEFAULT_SSE_C_ENCRYPTION
   420  }
   421  
   422  func (header SseCHeader) GetKey() string {
   423  	return header.Key
   424  }
   425  
   426  func (header SseCHeader) GetKeyMD5() string {
   427  	if header.KeyMD5 != "" {
   428  		return header.KeyMD5
   429  	}
   430  
   431  	if ret, err := Base64Decode(header.GetKey()); err == nil {
   432  		return Base64Md5(ret)
   433  	}
   434  	return ""
   435  }
   436  
   437  func setSseHeader(headers map[string][]string, sseHeader ISseHeader, sseCOnly bool, isObs bool) {
   438  	if sseHeader != nil {
   439  		if sseCHeader, ok := sseHeader.(SseCHeader); ok {
   440  			setHeaders(headers, HEADER_SSEC_ENCRYPTION, []string{sseCHeader.GetEncryption()}, isObs)
   441  			setHeaders(headers, HEADER_SSEC_KEY, []string{sseCHeader.GetKey()}, isObs)
   442  			setHeaders(headers, HEADER_SSEC_KEY_MD5, []string{sseCHeader.GetEncryption()}, isObs)
   443  		} else if sseKmsHeader, ok := sseHeader.(SseKmsHeader); !sseCOnly && ok {
   444  			sseKmsHeader.isObs = isObs
   445  			setHeaders(headers, HEADER_SSEKMS_ENCRYPTION, []string{sseKmsHeader.GetEncryption()}, isObs)
   446  			setHeadersNext(headers, HEADER_SSEKMS_KEY_OBS, HEADER_SSEKMS_KEY_AMZ, []string{sseKmsHeader.GetKey()}, isObs)
   447  		}
   448  	}
   449  }
   450  
   451  func (input GetObjectMetadataInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   452  	params = make(map[string]string)
   453  	if input.VersionId != "" {
   454  		params[PARAM_VERSION_ID] = input.VersionId
   455  	}
   456  	headers = make(map[string][]string)
   457  
   458  	if input.Origin != "" {
   459  		headers[HEADER_ORIGIN_CAMEL] = []string{input.Origin}
   460  	}
   461  
   462  	if input.RequestHeader != "" {
   463  		headers[HEADER_ACCESS_CONTROL_REQUEST_HEADER_CAMEL] = []string{input.RequestHeader}
   464  	}
   465  	setSseHeader(headers, input.SseHeader, true, isObs)
   466  	return
   467  }
   468  
   469  func (input SetObjectMetadataInput) prepareContentHeaders(headers map[string][]string) {
   470  	if input.ContentDisposition != "" {
   471  		headers[HEADER_CONTENT_DISPOSITION_CAMEL] = []string{input.ContentDisposition}
   472  	}
   473  	if input.ContentEncoding != "" {
   474  		headers[HEADER_CONTENT_ENCODING_CAMEL] = []string{input.ContentEncoding}
   475  	}
   476  	if input.ContentLanguage != "" {
   477  		headers[HEADER_CONTENT_LANGUAGE_CAMEL] = []string{input.ContentLanguage}
   478  	}
   479  
   480  	if input.ContentType != "" {
   481  		headers[HEADER_CONTENT_TYPE_CAML] = []string{input.ContentType}
   482  	}
   483  }
   484  
   485  func (input SetObjectMetadataInput) prepareStorageClass(headers map[string][]string, isObs bool) {
   486  	if storageClass := string(input.StorageClass); storageClass != "" {
   487  		if !isObs {
   488  			if storageClass == string(StorageClassWarm) {
   489  				storageClass = string(storageClassStandardIA)
   490  			} else if storageClass == string(StorageClassCold) {
   491  				storageClass = string(storageClassGlacier)
   492  			}
   493  		}
   494  		setHeaders(headers, HEADER_STORAGE_CLASS2, []string{storageClass}, isObs)
   495  	}
   496  }
   497  
   498  func (input SetObjectMetadataInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   499  	params = make(map[string]string)
   500  	params = map[string]string{string(SubResourceMetadata): ""}
   501  	if input.VersionId != "" {
   502  		params[PARAM_VERSION_ID] = input.VersionId
   503  	}
   504  	headers = make(map[string][]string)
   505  
   506  	if directive := string(input.MetadataDirective); directive != "" {
   507  		setHeaders(headers, HEADER_METADATA_DIRECTIVE, []string{string(input.MetadataDirective)}, isObs)
   508  	} else {
   509  		setHeaders(headers, HEADER_METADATA_DIRECTIVE, []string{string(ReplaceNew)}, isObs)
   510  	}
   511  	if input.CacheControl != "" {
   512  		headers[HEADER_CACHE_CONTROL_CAMEL] = []string{input.CacheControl}
   513  	}
   514  	input.prepareContentHeaders(headers)
   515  	if input.Expires != "" {
   516  		headers[HEADER_EXPIRES_CAMEL] = []string{input.Expires}
   517  	}
   518  	if input.WebsiteRedirectLocation != "" {
   519  		setHeaders(headers, HEADER_WEBSITE_REDIRECT_LOCATION, []string{input.WebsiteRedirectLocation}, isObs)
   520  	}
   521  	input.prepareStorageClass(headers, isObs)
   522  	if input.Metadata != nil {
   523  		for key, value := range input.Metadata {
   524  			key = strings.TrimSpace(key)
   525  			setHeadersNext(headers, HEADER_PREFIX_META_OBS+key, HEADER_PREFIX_META+key, []string{value}, isObs)
   526  		}
   527  	}
   528  	return
   529  }
   530  
   531  func (input GetObjectInput) prepareResponseParams(params map[string]string) {
   532  	if input.ResponseCacheControl != "" {
   533  		params[PARAM_RESPONSE_CACHE_CONTROL] = input.ResponseCacheControl
   534  	}
   535  	if input.ResponseContentDisposition != "" {
   536  		params[PARAM_RESPONSE_CONTENT_DISPOSITION] = input.ResponseContentDisposition
   537  	}
   538  	if input.ResponseContentEncoding != "" {
   539  		params[PARAM_RESPONSE_CONTENT_ENCODING] = input.ResponseContentEncoding
   540  	}
   541  	if input.ResponseContentLanguage != "" {
   542  		params[PARAM_RESPONSE_CONTENT_LANGUAGE] = input.ResponseContentLanguage
   543  	}
   544  	if input.ResponseContentType != "" {
   545  		params[PARAM_RESPONSE_CONTENT_TYPE] = input.ResponseContentType
   546  	}
   547  	if input.ResponseExpires != "" {
   548  		params[PARAM_RESPONSE_EXPIRES] = input.ResponseExpires
   549  	}
   550  }
   551  
   552  func (input GetObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   553  	params, headers, data, err = input.GetObjectMetadataInput.trans(isObs)
   554  	if err != nil {
   555  		return
   556  	}
   557  	input.prepareResponseParams(params)
   558  	if input.ImageProcess != "" {
   559  		params[PARAM_IMAGE_PROCESS] = input.ImageProcess
   560  	}
   561  	if input.RangeStart >= 0 && input.RangeEnd > input.RangeStart {
   562  		headers[HEADER_RANGE] = []string{fmt.Sprintf("bytes=%d-%d", input.RangeStart, input.RangeEnd)}
   563  	}
   564  
   565  	if input.IfMatch != "" {
   566  		headers[HEADER_IF_MATCH] = []string{input.IfMatch}
   567  	}
   568  	if input.IfNoneMatch != "" {
   569  		headers[HEADER_IF_NONE_MATCH] = []string{input.IfNoneMatch}
   570  	}
   571  	if !input.IfModifiedSince.IsZero() {
   572  		headers[HEADER_IF_MODIFIED_SINCE] = []string{FormatUtcToRfc1123(input.IfModifiedSince)}
   573  	}
   574  	if !input.IfUnmodifiedSince.IsZero() {
   575  		headers[HEADER_IF_UNMODIFIED_SINCE] = []string{FormatUtcToRfc1123(input.IfUnmodifiedSince)}
   576  	}
   577  	return
   578  }
   579  
   580  func (input ObjectOperationInput) prepareGrantHeaders(headers map[string][]string) {
   581  	if GrantReadId := input.GrantReadId; GrantReadId != "" {
   582  		setHeaders(headers, HEADER_GRANT_READ_OBS, []string{GrantReadId}, true)
   583  	}
   584  	if GrantReadAcpId := input.GrantReadAcpId; GrantReadAcpId != "" {
   585  		setHeaders(headers, HEADER_GRANT_READ_ACP_OBS, []string{GrantReadAcpId}, true)
   586  	}
   587  	if GrantWriteAcpId := input.GrantWriteAcpId; GrantWriteAcpId != "" {
   588  		setHeaders(headers, HEADER_GRANT_WRITE_ACP_OBS, []string{GrantWriteAcpId}, true)
   589  	}
   590  	if GrantFullControlId := input.GrantFullControlId; GrantFullControlId != "" {
   591  		setHeaders(headers, HEADER_GRANT_FULL_CONTROL_OBS, []string{GrantFullControlId}, true)
   592  	}
   593  }
   594  
   595  func (input ObjectOperationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   596  	headers = make(map[string][]string)
   597  	params = make(map[string]string)
   598  	if acl := string(input.ACL); acl != "" {
   599  		setHeaders(headers, HEADER_ACL, []string{acl}, isObs)
   600  	}
   601  	input.prepareGrantHeaders(headers)
   602  	if storageClass := string(input.StorageClass); storageClass != "" {
   603  		if !isObs {
   604  			if storageClass == string(StorageClassWarm) {
   605  				storageClass = string(storageClassStandardIA)
   606  			} else if storageClass == string(StorageClassCold) {
   607  				storageClass = string(storageClassGlacier)
   608  			}
   609  		}
   610  		setHeaders(headers, HEADER_STORAGE_CLASS2, []string{storageClass}, isObs)
   611  	}
   612  	if input.WebsiteRedirectLocation != "" {
   613  		setHeaders(headers, HEADER_WEBSITE_REDIRECT_LOCATION, []string{input.WebsiteRedirectLocation}, isObs)
   614  
   615  	}
   616  	setSseHeader(headers, input.SseHeader, false, isObs)
   617  	if input.Expires != 0 {
   618  		setHeaders(headers, HEADER_EXPIRES, []string{Int64ToString(input.Expires)}, true)
   619  	}
   620  	if input.Metadata != nil {
   621  		for key, value := range input.Metadata {
   622  			key = strings.TrimSpace(key)
   623  			setHeadersNext(headers, HEADER_PREFIX_META_OBS+key, HEADER_PREFIX_META+key, []string{value}, isObs)
   624  		}
   625  	}
   626  	return
   627  }
   628  
   629  func (input PutObjectBasicInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   630  	params, headers, data, err = input.ObjectOperationInput.trans(isObs)
   631  	if err != nil {
   632  		return
   633  	}
   634  
   635  	if input.ContentMD5 != "" {
   636  		headers[HEADER_MD5_CAMEL] = []string{input.ContentMD5}
   637  	}
   638  
   639  	if input.ContentLength > 0 {
   640  		headers[HEADER_CONTENT_LENGTH_CAMEL] = []string{Int64ToString(input.ContentLength)}
   641  	}
   642  	if input.ContentType != "" {
   643  		headers[HEADER_CONTENT_TYPE_CAML] = []string{input.ContentType}
   644  	}
   645  
   646  	return
   647  }
   648  
   649  func (input PutObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   650  	params, headers, data, err = input.PutObjectBasicInput.trans(isObs)
   651  	if err != nil {
   652  		return
   653  	}
   654  	if input.Body != nil {
   655  		data = input.Body
   656  	}
   657  	return
   658  }
   659  
   660  func (input CopyObjectInput) prepareReplaceHeaders(headers map[string][]string) {
   661  	if input.CacheControl != "" {
   662  		headers[HEADER_CACHE_CONTROL] = []string{input.CacheControl}
   663  	}
   664  	if input.ContentDisposition != "" {
   665  		headers[HEADER_CONTENT_DISPOSITION] = []string{input.ContentDisposition}
   666  	}
   667  	if input.ContentEncoding != "" {
   668  		headers[HEADER_CONTENT_ENCODING] = []string{input.ContentEncoding}
   669  	}
   670  	if input.ContentLanguage != "" {
   671  		headers[HEADER_CONTENT_LANGUAGE] = []string{input.ContentLanguage}
   672  	}
   673  	if input.ContentType != "" {
   674  		headers[HEADER_CONTENT_TYPE] = []string{input.ContentType}
   675  	}
   676  	if input.Expires != "" {
   677  		headers[HEADER_EXPIRES] = []string{input.Expires}
   678  	}
   679  }
   680  
   681  func (input CopyObjectInput) prepareCopySourceHeaders(headers map[string][]string, isObs bool) {
   682  	if input.CopySourceIfMatch != "" {
   683  		setHeaders(headers, HEADER_COPY_SOURCE_IF_MATCH, []string{input.CopySourceIfMatch}, isObs)
   684  	}
   685  	if input.CopySourceIfNoneMatch != "" {
   686  		setHeaders(headers, HEADER_COPY_SOURCE_IF_NONE_MATCH, []string{input.CopySourceIfNoneMatch}, isObs)
   687  	}
   688  	if !input.CopySourceIfModifiedSince.IsZero() {
   689  		setHeaders(headers, HEADER_COPY_SOURCE_IF_MODIFIED_SINCE, []string{FormatUtcToRfc1123(input.CopySourceIfModifiedSince)}, isObs)
   690  	}
   691  	if !input.CopySourceIfUnmodifiedSince.IsZero() {
   692  		setHeaders(headers, HEADER_COPY_SOURCE_IF_UNMODIFIED_SINCE, []string{FormatUtcToRfc1123(input.CopySourceIfUnmodifiedSince)}, isObs)
   693  	}
   694  }
   695  
   696  func (input CopyObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   697  	params, headers, data, err = input.ObjectOperationInput.trans(isObs)
   698  	if err != nil {
   699  		return
   700  	}
   701  
   702  	var copySource string
   703  	if input.CopySourceVersionId != "" {
   704  		copySource = fmt.Sprintf("%s/%s?versionId=%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false), input.CopySourceVersionId)
   705  	} else {
   706  		copySource = fmt.Sprintf("%s/%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false))
   707  	}
   708  	setHeaders(headers, HEADER_COPY_SOURCE, []string{copySource}, isObs)
   709  
   710  	if directive := string(input.MetadataDirective); directive != "" {
   711  		setHeaders(headers, HEADER_METADATA_DIRECTIVE, []string{directive}, isObs)
   712  	}
   713  
   714  	if input.MetadataDirective == ReplaceMetadata {
   715  		input.prepareReplaceHeaders(headers)
   716  	}
   717  
   718  	input.prepareCopySourceHeaders(headers, isObs)
   719  	if input.SourceSseHeader != nil {
   720  		if sseCHeader, ok := input.SourceSseHeader.(SseCHeader); ok {
   721  			setHeaders(headers, HEADER_SSEC_COPY_SOURCE_ENCRYPTION, []string{sseCHeader.GetEncryption()}, isObs)
   722  			setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY, []string{sseCHeader.GetKey()}, isObs)
   723  			setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY_MD5, []string{sseCHeader.GetKeyMD5()}, isObs)
   724  		}
   725  	}
   726  	if input.SuccessActionRedirect != "" {
   727  		headers[HEADER_SUCCESS_ACTION_REDIRECT] = []string{input.SuccessActionRedirect}
   728  	}
   729  	return
   730  }
   731  
   732  func (input AbortMultipartUploadInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   733  	params = map[string]string{"uploadId": input.UploadId}
   734  	return
   735  }
   736  
   737  func (input InitiateMultipartUploadInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   738  	params, headers, data, err = input.ObjectOperationInput.trans(isObs)
   739  	if err != nil {
   740  		return
   741  	}
   742  	if input.ContentType != "" {
   743  		headers[HEADER_CONTENT_TYPE_CAML] = []string{input.ContentType}
   744  	}
   745  	params[string(SubResourceUploads)] = ""
   746  	return
   747  }
   748  
   749  func (input UploadPartInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   750  	params = map[string]string{"uploadId": input.UploadId, "partNumber": IntToString(input.PartNumber)}
   751  	headers = make(map[string][]string)
   752  	setSseHeader(headers, input.SseHeader, true, isObs)
   753  	if input.ContentMD5 != "" {
   754  		headers[HEADER_MD5_CAMEL] = []string{input.ContentMD5}
   755  	}
   756  	if input.Body != nil {
   757  		data = input.Body
   758  	}
   759  	return
   760  }
   761  
   762  func (input CompleteMultipartUploadInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   763  	params = map[string]string{"uploadId": input.UploadId}
   764  	data, _ = ConvertCompleteMultipartUploadInputToXml(input, false)
   765  	return
   766  }
   767  
   768  func (input ListPartsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   769  	params = map[string]string{"uploadId": input.UploadId}
   770  	if input.MaxParts > 0 {
   771  		params["max-parts"] = IntToString(input.MaxParts)
   772  	}
   773  	if input.PartNumberMarker > 0 {
   774  		params["part-number-marker"] = IntToString(input.PartNumberMarker)
   775  	}
   776  	return
   777  }
   778  
   779  func (input CopyPartInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) {
   780  	params = map[string]string{"uploadId": input.UploadId, "partNumber": IntToString(input.PartNumber)}
   781  	headers = make(map[string][]string, 1)
   782  	var copySource string
   783  	if input.CopySourceVersionId != "" {
   784  		copySource = fmt.Sprintf("%s/%s?versionId=%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false), input.CopySourceVersionId)
   785  	} else {
   786  		copySource = fmt.Sprintf("%s/%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false))
   787  	}
   788  	setHeaders(headers, HEADER_COPY_SOURCE, []string{copySource}, isObs)
   789  	if input.CopySourceRangeStart >= 0 && input.CopySourceRangeEnd > input.CopySourceRangeStart {
   790  		setHeaders(headers, HEADER_COPY_SOURCE_RANGE, []string{fmt.Sprintf("bytes=%d-%d", input.CopySourceRangeStart, input.CopySourceRangeEnd)}, isObs)
   791  	}
   792  
   793  	setSseHeader(headers, input.SseHeader, true, isObs)
   794  	if input.SourceSseHeader != nil {
   795  		if sseCHeader, ok := input.SourceSseHeader.(SseCHeader); ok {
   796  			setHeaders(headers, HEADER_SSEC_COPY_SOURCE_ENCRYPTION, []string{sseCHeader.GetEncryption()}, isObs)
   797  			setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY, []string{sseCHeader.GetKey()}, isObs)
   798  			setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY_MD5, []string{sseCHeader.GetKeyMD5()}, isObs)
   799  		}
   800  
   801  	}
   802  	return
   803  }
   804  
   805  type partSlice []Part
   806  
   807  func (parts partSlice) Len() int {
   808  	return len(parts)
   809  }
   810  
   811  func (parts partSlice) Less(i, j int) bool {
   812  	return parts[i].PartNumber < parts[j].PartNumber
   813  }
   814  
   815  func (parts partSlice) Swap(i, j int) {
   816  	parts[i], parts[j] = parts[j], parts[i]
   817  }
   818  
   819  type readerWrapper struct {
   820  	reader      io.Reader
   821  	mark        int64
   822  	totalCount  int64
   823  	readedCount int64
   824  }
   825  
   826  func (rw *readerWrapper) seek(offset int64, whence int) (int64, error) {
   827  	if r, ok := rw.reader.(*strings.Reader); ok {
   828  		return r.Seek(offset, whence)
   829  	} else if r, ok := rw.reader.(*bytes.Reader); ok {
   830  		return r.Seek(offset, whence)
   831  	} else if r, ok := rw.reader.(*os.File); ok {
   832  		return r.Seek(offset, whence)
   833  	}
   834  	return offset, nil
   835  }
   836  
   837  func (rw *readerWrapper) Read(p []byte) (n int, err error) {
   838  	if rw.totalCount == 0 {
   839  		return 0, io.EOF
   840  	}
   841  	if rw.totalCount > 0 {
   842  		n, err = rw.reader.Read(p)
   843  		readedOnce := int64(n)
   844  		remainCount := rw.totalCount - rw.readedCount
   845  		if remainCount > readedOnce {
   846  			rw.readedCount += readedOnce
   847  			return n, err
   848  		}
   849  		rw.readedCount += remainCount
   850  		return int(remainCount), io.EOF
   851  	}
   852  	return rw.reader.Read(p)
   853  }
   854  
   855  type fileReaderWrapper struct {
   856  	readerWrapper
   857  	filePath string
   858  }