yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/huawei/obs/convert.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  	"io/ioutil"
    34  	"net/http"
    35  	"reflect"
    36  	"strings"
    37  	"time"
    38  )
    39  
    40  func cleanHeaderPrefix(header http.Header) map[string][]string {
    41  	responseHeaders := make(map[string][]string)
    42  	for key, value := range header {
    43  		if len(value) > 0 {
    44  			key = strings.ToLower(key)
    45  			if strings.HasPrefix(key, HEADER_PREFIX) || strings.HasPrefix(key, HEADER_PREFIX_OBS) {
    46  				key = key[len(HEADER_PREFIX):]
    47  			}
    48  			responseHeaders[key] = value
    49  		}
    50  	}
    51  	return responseHeaders
    52  }
    53  
    54  func ParseStringToEventType(value string) (ret EventType) {
    55  	switch value {
    56  	case "ObjectCreated:*", "s3:ObjectCreated:*":
    57  		ret = ObjectCreatedAll
    58  	case "ObjectCreated:Put", "s3:ObjectCreated:Put":
    59  		ret = ObjectCreatedPut
    60  	case "ObjectCreated:Post", "s3:ObjectCreated:Post":
    61  		ret = ObjectCreatedPost
    62  	case "ObjectCreated:Copy", "s3:ObjectCreated:Copy":
    63  		ret = ObjectCreatedCopy
    64  	case "ObjectCreated:CompleteMultipartUpload", "s3:ObjectCreated:CompleteMultipartUpload":
    65  		ret = ObjectCreatedCompleteMultipartUpload
    66  	case "ObjectRemoved:*", "s3:ObjectRemoved:*":
    67  		ret = ObjectRemovedAll
    68  	case "ObjectRemoved:Delete", "s3:ObjectRemoved:Delete":
    69  		ret = ObjectRemovedDelete
    70  	case "ObjectRemoved:DeleteMarkerCreated", "s3:ObjectRemoved:DeleteMarkerCreated":
    71  		ret = ObjectRemovedDeleteMarkerCreated
    72  	default:
    73  		ret = ""
    74  	}
    75  	return
    76  }
    77  
    78  func ParseStringToStorageClassType(value string) (ret StorageClassType) {
    79  	switch value {
    80  	case "STANDARD":
    81  		ret = StorageClassStandard
    82  	case "STANDARD_IA", "WARM":
    83  		ret = StorageClassWarm
    84  	case "GLACIER", "COLD":
    85  		ret = StorageClassCold
    86  	default:
    87  		ret = ""
    88  	}
    89  	return
    90  }
    91  
    92  func prepareGrantURI(grant Grant) string {
    93  	if grant.Grantee.URI == GroupAllUsers || grant.Grantee.URI == GroupAuthenticatedUsers {
    94  		return fmt.Sprintf("<URI>%s%s</URI>", "http://acs.amazonaws.com/groups/global/", grant.Grantee.URI)
    95  	}
    96  	if grant.Grantee.URI == GroupLogDelivery {
    97  		return fmt.Sprintf("<URI>%s%s</URI>", "http://acs.amazonaws.com/groups/s3/", grant.Grantee.URI)
    98  	}
    99  	return fmt.Sprintf("<URI>%s</URI>", grant.Grantee.URI)
   100  }
   101  
   102  func convertGrantToXml(grant Grant, isObs bool, isBucket bool) string {
   103  	xml := make([]string, 0, 4)
   104  
   105  	if grant.Grantee.Type == GranteeUser {
   106  		if isObs {
   107  			xml = append(xml, "<Grant><Grantee>")
   108  		} else {
   109  			xml = append(xml, fmt.Sprintf("<Grant><Grantee xsi:type=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">", grant.Grantee.Type))
   110  		}
   111  		if grant.Grantee.ID != "" {
   112  			granteeID := XmlTranscoding(grant.Grantee.ID)
   113  			xml = append(xml, fmt.Sprintf("<ID>%s</ID>", granteeID))
   114  		}
   115  		if !isObs && grant.Grantee.DisplayName != "" {
   116  			granteeDisplayName := XmlTranscoding(grant.Grantee.DisplayName)
   117  			xml = append(xml, fmt.Sprintf("<DisplayName>%s</DisplayName>", granteeDisplayName))
   118  		}
   119  		xml = append(xml, "</Grantee>")
   120  	} else {
   121  		if !isObs {
   122  			xml = append(xml, fmt.Sprintf("<Grant><Grantee xsi:type=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">", grant.Grantee.Type))
   123  			xml = append(xml, prepareGrantURI(grant))
   124  			xml = append(xml, "</Grantee>")
   125  		} else if grant.Grantee.URI == GroupAllUsers {
   126  			xml = append(xml, "<Grant><Grantee>")
   127  			xml = append(xml, fmt.Sprintf("<Canned>Everyone</Canned>"))
   128  			xml = append(xml, "</Grantee>")
   129  		} else {
   130  			return strings.Join(xml, "")
   131  		}
   132  	}
   133  
   134  	xml = append(xml, fmt.Sprintf("<Permission>%s</Permission>", grant.Permission))
   135  	if isObs && isBucket {
   136  		xml = append(xml, fmt.Sprintf("<Delivered>%t</Delivered>", grant.Delivered))
   137  	}
   138  	xml = append(xml, fmt.Sprintf("</Grant>"))
   139  	return strings.Join(xml, "")
   140  }
   141  
   142  func hasLoggingTarget(input BucketLoggingStatus) bool {
   143  	if input.TargetBucket != "" || input.TargetPrefix != "" || len(input.TargetGrants) > 0 {
   144  		return true
   145  	}
   146  	return false
   147  }
   148  
   149  func ConvertLoggingStatusToXml(input BucketLoggingStatus, returnMd5 bool, isObs bool) (data string, md5 string) {
   150  	grantsLength := len(input.TargetGrants)
   151  	xml := make([]string, 0, 8+grantsLength)
   152  
   153  	xml = append(xml, "<BucketLoggingStatus>")
   154  	if isObs && input.Agency != "" {
   155  		agency := XmlTranscoding(input.Agency)
   156  		xml = append(xml, fmt.Sprintf("<Agency>%s</Agency>", agency))
   157  	}
   158  	if hasLoggingTarget(input) {
   159  		xml = append(xml, "<LoggingEnabled>")
   160  		if input.TargetBucket != "" {
   161  			xml = append(xml, fmt.Sprintf("<TargetBucket>%s</TargetBucket>", input.TargetBucket))
   162  		}
   163  		if input.TargetPrefix != "" {
   164  			targetPrefix := XmlTranscoding(input.TargetPrefix)
   165  			xml = append(xml, fmt.Sprintf("<TargetPrefix>%s</TargetPrefix>", targetPrefix))
   166  		}
   167  		if grantsLength > 0 {
   168  			xml = append(xml, "<TargetGrants>")
   169  			for _, grant := range input.TargetGrants {
   170  				xml = append(xml, convertGrantToXml(grant, isObs, false))
   171  			}
   172  			xml = append(xml, "</TargetGrants>")
   173  		}
   174  
   175  		xml = append(xml, "</LoggingEnabled>")
   176  	}
   177  	xml = append(xml, "</BucketLoggingStatus>")
   178  	data = strings.Join(xml, "")
   179  	if returnMd5 {
   180  		md5 = Base64Md5([]byte(data))
   181  	}
   182  	return
   183  }
   184  
   185  func ConvertAclToXml(input AccessControlPolicy, returnMd5 bool, isObs bool) (data string, md5 string) {
   186  	xml := make([]string, 0, 4+len(input.Grants))
   187  	ownerID := XmlTranscoding(input.Owner.ID)
   188  	xml = append(xml, fmt.Sprintf("<AccessControlPolicy><Owner><ID>%s</ID>", ownerID))
   189  	if !isObs && input.Owner.DisplayName != "" {
   190  		ownerDisplayName := XmlTranscoding(input.Owner.DisplayName)
   191  		xml = append(xml, fmt.Sprintf("<DisplayName>%s</DisplayName>", ownerDisplayName))
   192  	}
   193  	if isObs && input.Delivered != "" {
   194  		objectDelivered := XmlTranscoding(input.Delivered)
   195  		xml = append(xml, fmt.Sprintf("</Owner><Delivered>%s</Delivered><AccessControlList>", objectDelivered))
   196  	} else {
   197  		xml = append(xml, "</Owner><AccessControlList>")
   198  	}
   199  	for _, grant := range input.Grants {
   200  		xml = append(xml, convertGrantToXml(grant, isObs, false))
   201  	}
   202  	xml = append(xml, "</AccessControlList></AccessControlPolicy>")
   203  	data = strings.Join(xml, "")
   204  	if returnMd5 {
   205  		md5 = Base64Md5([]byte(data))
   206  	}
   207  	return
   208  }
   209  
   210  func convertBucketAclToXml(input AccessControlPolicy, returnMd5 bool, isObs bool) (data string, md5 string) {
   211  	xml := make([]string, 0, 4+len(input.Grants))
   212  	ownerID := XmlTranscoding(input.Owner.ID)
   213  	xml = append(xml, fmt.Sprintf("<AccessControlPolicy><Owner><ID>%s</ID>", ownerID))
   214  	if !isObs && input.Owner.DisplayName != "" {
   215  		ownerDisplayName := XmlTranscoding(input.Owner.DisplayName)
   216  		xml = append(xml, fmt.Sprintf("<DisplayName>%s</DisplayName>", ownerDisplayName))
   217  	}
   218  
   219  	xml = append(xml, "</Owner><AccessControlList>")
   220  
   221  	for _, grant := range input.Grants {
   222  		xml = append(xml, convertGrantToXml(grant, isObs, true))
   223  	}
   224  	xml = append(xml, "</AccessControlList></AccessControlPolicy>")
   225  	data = strings.Join(xml, "")
   226  	if returnMd5 {
   227  		md5 = Base64Md5([]byte(data))
   228  	}
   229  	return
   230  }
   231  
   232  func convertConditionToXml(condition Condition) string {
   233  	xml := make([]string, 0, 2)
   234  	if condition.KeyPrefixEquals != "" {
   235  		keyPrefixEquals := XmlTranscoding(condition.KeyPrefixEquals)
   236  		xml = append(xml, fmt.Sprintf("<KeyPrefixEquals>%s</KeyPrefixEquals>", keyPrefixEquals))
   237  	}
   238  	if condition.HttpErrorCodeReturnedEquals != "" {
   239  		xml = append(xml, fmt.Sprintf("<HttpErrorCodeReturnedEquals>%s</HttpErrorCodeReturnedEquals>", condition.HttpErrorCodeReturnedEquals))
   240  	}
   241  	if len(xml) > 0 {
   242  		return fmt.Sprintf("<Condition>%s</Condition>", strings.Join(xml, ""))
   243  	}
   244  	return ""
   245  }
   246  
   247  func prepareRoutingRule(input BucketWebsiteConfiguration) string {
   248  	xml := make([]string, 0, len(input.RoutingRules)*10)
   249  	for _, routingRule := range input.RoutingRules {
   250  		xml = append(xml, "<RoutingRule>")
   251  		xml = append(xml, "<Redirect>")
   252  		if routingRule.Redirect.Protocol != "" {
   253  			xml = append(xml, fmt.Sprintf("<Protocol>%s</Protocol>", routingRule.Redirect.Protocol))
   254  		}
   255  		if routingRule.Redirect.HostName != "" {
   256  			xml = append(xml, fmt.Sprintf("<HostName>%s</HostName>", routingRule.Redirect.HostName))
   257  		}
   258  		if routingRule.Redirect.ReplaceKeyPrefixWith != "" {
   259  			replaceKeyPrefixWith := XmlTranscoding(routingRule.Redirect.ReplaceKeyPrefixWith)
   260  			xml = append(xml, fmt.Sprintf("<ReplaceKeyPrefixWith>%s</ReplaceKeyPrefixWith>", replaceKeyPrefixWith))
   261  		}
   262  
   263  		if routingRule.Redirect.ReplaceKeyWith != "" {
   264  			replaceKeyWith := XmlTranscoding(routingRule.Redirect.ReplaceKeyWith)
   265  			xml = append(xml, fmt.Sprintf("<ReplaceKeyWith>%s</ReplaceKeyWith>", replaceKeyWith))
   266  		}
   267  		if routingRule.Redirect.HttpRedirectCode != "" {
   268  			xml = append(xml, fmt.Sprintf("<HttpRedirectCode>%s</HttpRedirectCode>", routingRule.Redirect.HttpRedirectCode))
   269  		}
   270  		xml = append(xml, "</Redirect>")
   271  
   272  		if ret := convertConditionToXml(routingRule.Condition); ret != "" {
   273  			xml = append(xml, ret)
   274  		}
   275  		xml = append(xml, "</RoutingRule>")
   276  	}
   277  	return strings.Join(xml, "")
   278  }
   279  
   280  func ConvertWebsiteConfigurationToXml(input BucketWebsiteConfiguration, returnMd5 bool) (data string, md5 string) {
   281  	routingRuleLength := len(input.RoutingRules)
   282  	xml := make([]string, 0, 6+routingRuleLength*10)
   283  	xml = append(xml, "<WebsiteConfiguration>")
   284  
   285  	if input.RedirectAllRequestsTo.HostName != "" {
   286  		xml = append(xml, fmt.Sprintf("<RedirectAllRequestsTo><HostName>%s</HostName>", input.RedirectAllRequestsTo.HostName))
   287  		if input.RedirectAllRequestsTo.Protocol != "" {
   288  			xml = append(xml, fmt.Sprintf("<Protocol>%s</Protocol>", input.RedirectAllRequestsTo.Protocol))
   289  		}
   290  		xml = append(xml, "</RedirectAllRequestsTo>")
   291  	} else {
   292  		if input.IndexDocument.Suffix != "" {
   293  			indexDocumentSuffix := XmlTranscoding(input.IndexDocument.Suffix)
   294  			xml = append(xml, fmt.Sprintf("<IndexDocument><Suffix>%s</Suffix></IndexDocument>", indexDocumentSuffix))
   295  		}
   296  		if input.ErrorDocument.Key != "" {
   297  			errorDocumentKey := XmlTranscoding(input.ErrorDocument.Key)
   298  			xml = append(xml, fmt.Sprintf("<ErrorDocument><Key>%s</Key></ErrorDocument>", errorDocumentKey))
   299  		}
   300  		if routingRuleLength > 0 {
   301  			xml = append(xml, "<RoutingRules>")
   302  			xml = append(xml, prepareRoutingRule(input))
   303  			xml = append(xml, "</RoutingRules>")
   304  		}
   305  	}
   306  
   307  	xml = append(xml, "</WebsiteConfiguration>")
   308  	data = strings.Join(xml, "")
   309  	if returnMd5 {
   310  		md5 = Base64Md5([]byte(data))
   311  	}
   312  	return
   313  }
   314  
   315  func convertTransitionsToXml(transitions []Transition, isObs bool) string {
   316  	if length := len(transitions); length > 0 {
   317  		xml := make([]string, 0, length)
   318  		for _, transition := range transitions {
   319  			var temp string
   320  			if transition.Days > 0 {
   321  				temp = fmt.Sprintf("<Days>%d</Days>", transition.Days)
   322  			} else if !transition.Date.IsZero() {
   323  				temp = fmt.Sprintf("<Date>%s</Date>", transition.Date.UTC().Format(ISO8601_MIDNIGHT_DATE_FORMAT))
   324  			}
   325  			if temp != "" {
   326  				if !isObs {
   327  					storageClass := string(transition.StorageClass)
   328  					if transition.StorageClass == StorageClassWarm {
   329  						storageClass = string(storageClassStandardIA)
   330  					} else if transition.StorageClass == StorageClassCold {
   331  						storageClass = string(storageClassGlacier)
   332  					}
   333  					xml = append(xml, fmt.Sprintf("<Transition>%s<StorageClass>%s</StorageClass></Transition>", temp, storageClass))
   334  				} else {
   335  					xml = append(xml, fmt.Sprintf("<Transition>%s<StorageClass>%s</StorageClass></Transition>", temp, transition.StorageClass))
   336  				}
   337  			}
   338  		}
   339  		return strings.Join(xml, "")
   340  	}
   341  	return ""
   342  }
   343  
   344  func convertExpirationToXml(expiration Expiration) string {
   345  	if expiration.Days > 0 {
   346  		return fmt.Sprintf("<Expiration><Days>%d</Days></Expiration>", expiration.Days)
   347  	} else if !expiration.Date.IsZero() {
   348  		return fmt.Sprintf("<Expiration><Date>%s</Date></Expiration>", expiration.Date.UTC().Format(ISO8601_MIDNIGHT_DATE_FORMAT))
   349  	}
   350  	return ""
   351  }
   352  func convertNoncurrentVersionTransitionsToXml(noncurrentVersionTransitions []NoncurrentVersionTransition, isObs bool) string {
   353  	if length := len(noncurrentVersionTransitions); length > 0 {
   354  		xml := make([]string, 0, length)
   355  		for _, noncurrentVersionTransition := range noncurrentVersionTransitions {
   356  			if noncurrentVersionTransition.NoncurrentDays > 0 {
   357  				storageClass := string(noncurrentVersionTransition.StorageClass)
   358  				if !isObs {
   359  					if storageClass == string(StorageClassWarm) {
   360  						storageClass = string(storageClassStandardIA)
   361  					} else if storageClass == string(StorageClassCold) {
   362  						storageClass = string(storageClassGlacier)
   363  					}
   364  				}
   365  				xml = append(xml, fmt.Sprintf("<NoncurrentVersionTransition><NoncurrentDays>%d</NoncurrentDays>"+
   366  					"<StorageClass>%s</StorageClass></NoncurrentVersionTransition>",
   367  					noncurrentVersionTransition.NoncurrentDays, storageClass))
   368  			}
   369  		}
   370  		return strings.Join(xml, "")
   371  	}
   372  	return ""
   373  }
   374  func convertNoncurrentVersionExpirationToXml(noncurrentVersionExpiration NoncurrentVersionExpiration) string {
   375  	if noncurrentVersionExpiration.NoncurrentDays > 0 {
   376  		return fmt.Sprintf("<NoncurrentVersionExpiration><NoncurrentDays>%d</NoncurrentDays></NoncurrentVersionExpiration>", noncurrentVersionExpiration.NoncurrentDays)
   377  	}
   378  	return ""
   379  }
   380  
   381  func ConvertLifecyleConfigurationToXml(input BucketLifecyleConfiguration, returnMd5 bool, isObs bool) (data string, md5 string) {
   382  	xml := make([]string, 0, 2+len(input.LifecycleRules)*9)
   383  	xml = append(xml, "<LifecycleConfiguration>")
   384  	for _, lifecyleRule := range input.LifecycleRules {
   385  		xml = append(xml, "<Rule>")
   386  		if lifecyleRule.ID != "" {
   387  			lifecyleRuleID := XmlTranscoding(lifecyleRule.ID)
   388  			xml = append(xml, fmt.Sprintf("<ID>%s</ID>", lifecyleRuleID))
   389  		}
   390  		lifecyleRulePrefix := XmlTranscoding(lifecyleRule.Prefix)
   391  		xml = append(xml, fmt.Sprintf("<Prefix>%s</Prefix>", lifecyleRulePrefix))
   392  		xml = append(xml, fmt.Sprintf("<Status>%s</Status>", lifecyleRule.Status))
   393  		if ret := convertTransitionsToXml(lifecyleRule.Transitions, isObs); ret != "" {
   394  			xml = append(xml, ret)
   395  		}
   396  		if ret := convertExpirationToXml(lifecyleRule.Expiration); ret != "" {
   397  			xml = append(xml, ret)
   398  		}
   399  		if ret := convertNoncurrentVersionTransitionsToXml(lifecyleRule.NoncurrentVersionTransitions, isObs); ret != "" {
   400  			xml = append(xml, ret)
   401  		}
   402  		if ret := convertNoncurrentVersionExpirationToXml(lifecyleRule.NoncurrentVersionExpiration); ret != "" {
   403  			xml = append(xml, ret)
   404  		}
   405  		xml = append(xml, "</Rule>")
   406  	}
   407  	xml = append(xml, "</LifecycleConfiguration>")
   408  	data = strings.Join(xml, "")
   409  	if returnMd5 {
   410  		md5 = Base64Md5([]byte(data))
   411  	}
   412  	return
   413  }
   414  
   415  func converntFilterRulesToXml(filterRules []FilterRule, isObs bool) string {
   416  	if length := len(filterRules); length > 0 {
   417  		xml := make([]string, 0, length*4)
   418  		for _, filterRule := range filterRules {
   419  			xml = append(xml, "<FilterRule>")
   420  			if filterRule.Name != "" {
   421  				filterRuleName := XmlTranscoding(filterRule.Name)
   422  				xml = append(xml, fmt.Sprintf("<Name>%s</Name>", filterRuleName))
   423  			}
   424  			if filterRule.Value != "" {
   425  				filterRuleValue := XmlTranscoding(filterRule.Value)
   426  				xml = append(xml, fmt.Sprintf("<Value>%s</Value>", filterRuleValue))
   427  			}
   428  			xml = append(xml, "</FilterRule>")
   429  		}
   430  		if !isObs {
   431  			return fmt.Sprintf("<Filter><S3Key>%s</S3Key></Filter>", strings.Join(xml, ""))
   432  		}
   433  		return fmt.Sprintf("<Filter><Object>%s</Object></Filter>", strings.Join(xml, ""))
   434  	}
   435  	return ""
   436  }
   437  
   438  func converntEventsToXml(events []EventType, isObs bool) string {
   439  	if length := len(events); length > 0 {
   440  		xml := make([]string, 0, length)
   441  		if !isObs {
   442  			for _, event := range events {
   443  				xml = append(xml, fmt.Sprintf("<Event>%s%s</Event>", "s3:", event))
   444  			}
   445  		} else {
   446  			for _, event := range events {
   447  				xml = append(xml, fmt.Sprintf("<Event>%s</Event>", event))
   448  			}
   449  		}
   450  		return strings.Join(xml, "")
   451  	}
   452  	return ""
   453  }
   454  
   455  func converntConfigureToXml(topicConfiguration TopicConfiguration, xmlElem string, isObs bool) string {
   456  	xml := make([]string, 0, 6)
   457  	xml = append(xml, xmlElem)
   458  	if topicConfiguration.ID != "" {
   459  		topicConfigurationID := XmlTranscoding(topicConfiguration.ID)
   460  		xml = append(xml, fmt.Sprintf("<Id>%s</Id>", topicConfigurationID))
   461  	}
   462  	topicConfigurationTopic := XmlTranscoding(topicConfiguration.Topic)
   463  	xml = append(xml, fmt.Sprintf("<Topic>%s</Topic>", topicConfigurationTopic))
   464  
   465  	if ret := converntEventsToXml(topicConfiguration.Events, isObs); ret != "" {
   466  		xml = append(xml, ret)
   467  	}
   468  	if ret := converntFilterRulesToXml(topicConfiguration.FilterRules, isObs); ret != "" {
   469  		xml = append(xml, ret)
   470  	}
   471  	tempElem := xmlElem[0:1] + "/" + xmlElem[1:]
   472  	xml = append(xml, tempElem)
   473  	return strings.Join(xml, "")
   474  }
   475  
   476  func ConverntObsRestoreToXml(restoreObjectInput RestoreObjectInput) string {
   477  	xml := make([]string, 0, 2)
   478  	xml = append(xml, fmt.Sprintf("<RestoreRequest><Days>%d</Days>", restoreObjectInput.Days))
   479  	if restoreObjectInput.Tier != "Bulk" {
   480  		xml = append(xml, fmt.Sprintf("<RestoreJob><Tier>%s</Tier></RestoreJob>", restoreObjectInput.Tier))
   481  	}
   482  	xml = append(xml, fmt.Sprintf("</RestoreRequest>"))
   483  	data := strings.Join(xml, "")
   484  	return data
   485  }
   486  
   487  func ConvertNotificationToXml(input BucketNotification, returnMd5 bool, isObs bool) (data string, md5 string) {
   488  	xml := make([]string, 0, 2+len(input.TopicConfigurations)*6)
   489  	xml = append(xml, "<NotificationConfiguration>")
   490  	for _, topicConfiguration := range input.TopicConfigurations {
   491  		ret := converntConfigureToXml(topicConfiguration, "<TopicConfiguration>", isObs)
   492  		xml = append(xml, ret)
   493  	}
   494  	xml = append(xml, "</NotificationConfiguration>")
   495  	data = strings.Join(xml, "")
   496  	if returnMd5 {
   497  		md5 = Base64Md5([]byte(data))
   498  	}
   499  	return
   500  }
   501  
   502  func ConvertCompleteMultipartUploadInputToXml(input CompleteMultipartUploadInput, returnMd5 bool) (data string, md5 string) {
   503  	xml := make([]string, 0, 2+len(input.Parts)*4)
   504  	xml = append(xml, "<CompleteMultipartUpload>")
   505  	for _, part := range input.Parts {
   506  		xml = append(xml, "<Part>")
   507  		xml = append(xml, fmt.Sprintf("<PartNumber>%d</PartNumber>", part.PartNumber))
   508  		xml = append(xml, fmt.Sprintf("<ETag>%s</ETag>", part.ETag))
   509  		xml = append(xml, "</Part>")
   510  	}
   511  	xml = append(xml, "</CompleteMultipartUpload>")
   512  	data = strings.Join(xml, "")
   513  	if returnMd5 {
   514  		md5 = Base64Md5([]byte(data))
   515  	}
   516  	return
   517  }
   518  
   519  func parseSseHeader(responseHeaders map[string][]string) (sseHeader ISseHeader) {
   520  	if ret, ok := responseHeaders[HEADER_SSEC_ENCRYPTION]; ok {
   521  		sseCHeader := SseCHeader{Encryption: ret[0]}
   522  		if ret, ok = responseHeaders[HEADER_SSEC_KEY_MD5]; ok {
   523  			sseCHeader.KeyMD5 = ret[0]
   524  		}
   525  		sseHeader = sseCHeader
   526  	} else if ret, ok := responseHeaders[HEADER_SSEKMS_ENCRYPTION]; ok {
   527  		sseKmsHeader := SseKmsHeader{Encryption: ret[0]}
   528  		if ret, ok = responseHeaders[HEADER_SSEKMS_KEY]; ok {
   529  			sseKmsHeader.Key = ret[0]
   530  		} else if ret, ok = responseHeaders[HEADER_SSEKMS_ENCRYPT_KEY_OBS]; ok {
   531  			sseKmsHeader.Key = ret[0]
   532  		}
   533  		sseHeader = sseKmsHeader
   534  	}
   535  	return
   536  }
   537  
   538  func parseCorsHeader(output BaseModel) (AllowOrigin, AllowHeader, AllowMethod, ExposeHeader string, MaxAgeSeconds int) {
   539  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_ORIGIN]; ok {
   540  		AllowOrigin = ret[0]
   541  	}
   542  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_HEADERS]; ok {
   543  		AllowHeader = ret[0]
   544  	}
   545  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_MAX_AGE]; ok {
   546  		MaxAgeSeconds = StringToInt(ret[0], 0)
   547  	}
   548  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_METHODS]; ok {
   549  		AllowMethod = ret[0]
   550  	}
   551  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_EXPOSE_HEADERS]; ok {
   552  		ExposeHeader = ret[0]
   553  	}
   554  	return
   555  }
   556  
   557  func parseUnCommonHeader(output *GetObjectMetadataOutput) {
   558  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   559  		output.VersionId = ret[0]
   560  	}
   561  	if ret, ok := output.ResponseHeaders[HEADER_WEBSITE_REDIRECT_LOCATION]; ok {
   562  		output.WebsiteRedirectLocation = ret[0]
   563  	}
   564  	if ret, ok := output.ResponseHeaders[HEADER_EXPIRATION]; ok {
   565  		output.Expiration = ret[0]
   566  	}
   567  	if ret, ok := output.ResponseHeaders[HEADER_RESTORE]; ok {
   568  		output.Restore = ret[0]
   569  	}
   570  	if ret, ok := output.ResponseHeaders[HEADER_OBJECT_TYPE]; ok {
   571  		output.ObjectType = ret[0]
   572  	}
   573  	if ret, ok := output.ResponseHeaders[HEADER_NEXT_APPEND_POSITION]; ok {
   574  		output.NextAppendPosition = ret[0]
   575  	}
   576  }
   577  
   578  func ParseGetObjectMetadataOutput(output *GetObjectMetadataOutput) {
   579  	output.AllowOrigin, output.AllowHeader, output.AllowMethod, output.ExposeHeader, output.MaxAgeSeconds = parseCorsHeader(output.BaseModel)
   580  	parseUnCommonHeader(output)
   581  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   582  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   583  	}
   584  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
   585  		output.ETag = ret[0]
   586  	}
   587  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok {
   588  		output.ContentType = ret[0]
   589  	}
   590  
   591  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   592  	if ret, ok := output.ResponseHeaders[HEADER_LASTMODIFIED]; ok {
   593  		ret, err := time.Parse(time.RFC1123, ret[0])
   594  		if err == nil {
   595  			output.LastModified = ret
   596  		}
   597  	}
   598  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LENGTH]; ok {
   599  		output.ContentLength = StringToInt64(ret[0], 0)
   600  	}
   601  
   602  	output.Metadata = make(map[string]string)
   603  
   604  	for key, value := range output.ResponseHeaders {
   605  		if strings.HasPrefix(key, PREFIX_META) {
   606  			_key := key[len(PREFIX_META):]
   607  			output.ResponseHeaders[_key] = value
   608  			output.Metadata[_key] = value[0]
   609  			delete(output.ResponseHeaders, key)
   610  		}
   611  	}
   612  
   613  }
   614  
   615  func ParseCopyObjectOutput(output *CopyObjectOutput) {
   616  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   617  		output.VersionId = ret[0]
   618  	}
   619  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   620  	if ret, ok := output.ResponseHeaders[HEADER_COPY_SOURCE_VERSION_ID]; ok {
   621  		output.CopySourceVersionId = ret[0]
   622  	}
   623  }
   624  
   625  func ParsePutObjectOutput(output *PutObjectOutput) {
   626  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   627  		output.VersionId = ret[0]
   628  	}
   629  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   630  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   631  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   632  	}
   633  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
   634  		output.ETag = ret[0]
   635  	}
   636  }
   637  
   638  func ParseInitiateMultipartUploadOutput(output *InitiateMultipartUploadOutput) {
   639  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   640  }
   641  
   642  func ParseUploadPartOutput(output *UploadPartOutput) {
   643  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   644  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
   645  		output.ETag = ret[0]
   646  	}
   647  }
   648  
   649  func ParseCompleteMultipartUploadOutput(output *CompleteMultipartUploadOutput) {
   650  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   651  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   652  		output.VersionId = ret[0]
   653  	}
   654  }
   655  
   656  func ParseCopyPartOutput(output *CopyPartOutput) {
   657  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   658  }
   659  
   660  func ParseGetBucketMetadataOutput(output *GetBucketMetadataOutput) {
   661  	output.AllowOrigin, output.AllowHeader, output.AllowMethod, output.ExposeHeader, output.MaxAgeSeconds = parseCorsHeader(output.BaseModel)
   662  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS]; ok {
   663  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   664  	} else if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   665  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   666  	}
   667  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_OBS]; ok {
   668  		output.Version = ret[0]
   669  	}
   670  	if ret, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok {
   671  		output.Location = ret[0]
   672  	} else if ret, ok := output.ResponseHeaders[HEADER_BUCKET_LOCATION_OBS]; ok {
   673  		output.Location = ret[0]
   674  	}
   675  	if ret, ok := output.ResponseHeaders[HEADER_EPID_HEADERS]; ok {
   676  		output.Epid = ret[0]
   677  	}
   678  }
   679  
   680  func parseContentHeader(output *SetObjectMetadataOutput) {
   681  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok {
   682  		output.ContentDisposition = ret[0]
   683  	}
   684  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok {
   685  		output.ContentEncoding = ret[0]
   686  	}
   687  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok {
   688  		output.ContentLanguage = ret[0]
   689  	}
   690  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok {
   691  		output.ContentType = ret[0]
   692  	}
   693  }
   694  
   695  func ParseSetObjectMetadataOutput(output *SetObjectMetadataOutput) {
   696  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS]; ok {
   697  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   698  	} else if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   699  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   700  	}
   701  	if ret, ok := output.ResponseHeaders[HEADER_METADATA_DIRECTIVE]; ok {
   702  		output.MetadataDirective = MetadataDirectiveType(ret[0])
   703  	}
   704  	if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok {
   705  		output.CacheControl = ret[0]
   706  	}
   707  	parseContentHeader(output)
   708  	if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok {
   709  		output.Expires = ret[0]
   710  	}
   711  	if ret, ok := output.ResponseHeaders[HEADER_WEBSITE_REDIRECT_LOCATION]; ok {
   712  		output.WebsiteRedirectLocation = ret[0]
   713  	}
   714  	output.Metadata = make(map[string]string)
   715  
   716  	for key, value := range output.ResponseHeaders {
   717  		if strings.HasPrefix(key, PREFIX_META) {
   718  			_key := key[len(PREFIX_META):]
   719  			output.ResponseHeaders[_key] = value
   720  			output.Metadata[_key] = value[0]
   721  			delete(output.ResponseHeaders, key)
   722  		}
   723  	}
   724  }
   725  func ParseDeleteObjectOutput(output *DeleteObjectOutput) {
   726  	if versionId, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   727  		output.VersionId = versionId[0]
   728  	}
   729  
   730  	if deleteMarker, ok := output.ResponseHeaders[HEADER_DELETE_MARKER]; ok {
   731  		output.DeleteMarker = deleteMarker[0] == "true"
   732  	}
   733  }
   734  
   735  func ParseGetObjectOutput(output *GetObjectOutput) {
   736  	ParseGetObjectMetadataOutput(&output.GetObjectMetadataOutput)
   737  	if ret, ok := output.ResponseHeaders[HEADER_DELETE_MARKER]; ok {
   738  		output.DeleteMarker = ret[0] == "true"
   739  	}
   740  	if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok {
   741  		output.CacheControl = ret[0]
   742  	}
   743  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok {
   744  		output.ContentDisposition = ret[0]
   745  	}
   746  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok {
   747  		output.ContentEncoding = ret[0]
   748  	}
   749  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok {
   750  		output.ContentLanguage = ret[0]
   751  	}
   752  	if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok {
   753  		output.Expires = ret[0]
   754  	}
   755  }
   756  
   757  func ConvertRequestToIoReaderV2(req interface{}) (io.Reader, string, error) {
   758  	data, err := TransToXml(req)
   759  	if err == nil {
   760  		if isDebugLogEnabled() {
   761  			doLog(LEVEL_DEBUG, "Do http request with data: %s", string(data))
   762  		}
   763  		return bytes.NewReader(data), Base64Md5(data), nil
   764  	}
   765  	return nil, "", err
   766  }
   767  
   768  func ConvertRequestToIoReader(req interface{}) (io.Reader, error) {
   769  	body, err := TransToXml(req)
   770  	if err == nil {
   771  		if isDebugLogEnabled() {
   772  			doLog(LEVEL_DEBUG, "Do http request with data: %s", string(body))
   773  		}
   774  		return bytes.NewReader(body), nil
   775  	}
   776  	return nil, err
   777  }
   778  
   779  func ParseResponseToBaseModel(resp *http.Response, baseModel IBaseModel, xmlResult bool, isObs bool) (err error) {
   780  	readCloser, ok := baseModel.(IReadCloser)
   781  	if !ok {
   782  		defer func() {
   783  			errMsg := resp.Body.Close()
   784  			if errMsg != nil {
   785  				doLog(LEVEL_WARN, "Failed to close response with reason: %v", errMsg)
   786  			}
   787  		}()
   788  		body, err := ioutil.ReadAll(resp.Body)
   789  		if err == nil && len(body) > 0 {
   790  			if xmlResult {
   791  				err = ParseXml(body, baseModel)
   792  				if err != nil {
   793  					doLog(LEVEL_ERROR, "Unmarshal error: %v", err)
   794  				}
   795  			} else {
   796  				s := reflect.TypeOf(baseModel).Elem()
   797  				for i := 0; i < s.NumField(); i++ {
   798  					if s.Field(i).Tag == "json:\"body\"" {
   799  						reflect.ValueOf(baseModel).Elem().FieldByName(s.Field(i).Name).SetString(string(body))
   800  						break
   801  					}
   802  				}
   803  			}
   804  		}
   805  	} else {
   806  		readCloser.setReadCloser(resp.Body)
   807  	}
   808  
   809  	baseModel.setStatusCode(resp.StatusCode)
   810  	responseHeaders := cleanHeaderPrefix(resp.Header)
   811  	baseModel.setResponseHeaders(responseHeaders)
   812  	if values, ok := responseHeaders[HEADER_REQUEST_ID]; ok {
   813  		baseModel.setRequestId(values[0])
   814  	}
   815  	return
   816  }
   817  
   818  func ParseResponseToObsError(resp *http.Response, isObs bool) error {
   819  	obsError := ObsError{}
   820  	respError := ParseResponseToBaseModel(resp, &obsError, true, isObs)
   821  	if respError != nil {
   822  		doLog(LEVEL_WARN, "Parse response to BaseModel with error: %v", respError)
   823  	}
   824  	obsError.Status = resp.Status
   825  	return obsError
   826  }