github.com/chnsz/golangsdk@v0.0.0-20240506093406-85a3fbfa605b/openstack/obs/convert.go (about)

     1  // Copyright 2019 Huawei Technologies Co.,Ltd.
     2  // Licensed under the Apache License, Version 2.0 (the "License"); you may not use
     3  // this file except in compliance with the License.  You may obtain a copy of the
     4  // License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software distributed
     9  // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    10  // CONDITIONS OF ANY KIND, either express or implied.  See the License for the
    11  // specific language governing permissions and limitations under the License.
    12  
    13  package obs
    14  
    15  import (
    16  	"bytes"
    17  	"encoding/json"
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"net/url"
    24  	"reflect"
    25  	"strconv"
    26  	"strings"
    27  	"time"
    28  )
    29  
    30  func cleanHeaderPrefix(header http.Header) map[string][]string {
    31  	responseHeaders := make(map[string][]string)
    32  	for key, value := range header {
    33  		if len(value) > 0 {
    34  			key = strings.ToLower(key)
    35  			if strings.HasPrefix(key, HEADER_PREFIX) || strings.HasPrefix(key, HEADER_PREFIX_OBS) {
    36  				key = key[len(HEADER_PREFIX):]
    37  			}
    38  			responseHeaders[key] = value
    39  		}
    40  	}
    41  	return responseHeaders
    42  }
    43  
    44  // ParseStringToEventType converts string value to EventType value and returns it
    45  func ParseStringToEventType(value string) (ret EventType) {
    46  	switch value {
    47  	case "ObjectCreated:*", "s3:ObjectCreated:*":
    48  		ret = ObjectCreatedAll
    49  	case "ObjectCreated:Put", "s3:ObjectCreated:Put":
    50  		ret = ObjectCreatedPut
    51  	case "ObjectCreated:Post", "s3:ObjectCreated:Post":
    52  		ret = ObjectCreatedPost
    53  	case "ObjectCreated:Copy", "s3:ObjectCreated:Copy":
    54  		ret = ObjectCreatedCopy
    55  	case "ObjectCreated:CompleteMultipartUpload", "s3:ObjectCreated:CompleteMultipartUpload":
    56  		ret = ObjectCreatedCompleteMultipartUpload
    57  	case "ObjectRemoved:*", "s3:ObjectRemoved:*":
    58  		ret = ObjectRemovedAll
    59  	case "ObjectRemoved:Delete", "s3:ObjectRemoved:Delete":
    60  		ret = ObjectRemovedDelete
    61  	case "ObjectRemoved:DeleteMarkerCreated", "s3:ObjectRemoved:DeleteMarkerCreated":
    62  		ret = ObjectRemovedDeleteMarkerCreated
    63  	default:
    64  		ret = ""
    65  	}
    66  	return
    67  }
    68  
    69  // ParseStringToStorageClassType converts string value to StorageClassType value and returns it
    70  func ParseStringToStorageClassType(value string) (ret StorageClassType) {
    71  	switch value {
    72  	case string(StorageClassStandard):
    73  		ret = StorageClassStandard
    74  	case string(storageClassStandardIA), string(StorageClassWarm):
    75  		ret = StorageClassWarm
    76  	case string(storageClassGlacier), string(StorageClassCold):
    77  		ret = StorageClassCold
    78  	case string(StorageClassDeepArchive):
    79  		ret = StorageClassDeepArchive
    80  	default:
    81  		ret = ""
    82  	}
    83  	return
    84  }
    85  
    86  func ParseStringToFSStatusType(value string) (ret FSStatusType) {
    87  	switch value {
    88  	case "Enabled":
    89  		ret = FSStatusEnabled
    90  	case "Disabled":
    91  		ret = FSStatusDisabled
    92  	default:
    93  		ret = ""
    94  	}
    95  	return
    96  }
    97  
    98  func prepareGrantURI(grant Grant) string {
    99  	if grant.Grantee.URI == GroupAllUsers || grant.Grantee.URI == GroupAuthenticatedUsers {
   100  		return fmt.Sprintf("<URI>%s%s</URI>", "http://acs.amazonaws.com/groups/global/", grant.Grantee.URI)
   101  	}
   102  	if grant.Grantee.URI == GroupLogDelivery {
   103  		return fmt.Sprintf("<URI>%s%s</URI>", "http://acs.amazonaws.com/groups/s3/", grant.Grantee.URI)
   104  	}
   105  	return fmt.Sprintf("<URI>%s</URI>", grant.Grantee.URI)
   106  }
   107  
   108  func convertGrantToXML(grant Grant, isObs bool, isBucket bool) string {
   109  	xml := make([]string, 0, 4)
   110  
   111  	if grant.Grantee.Type == GranteeUser {
   112  		if isObs {
   113  			xml = append(xml, "<Grant><Grantee>")
   114  		} else {
   115  			xml = append(xml, fmt.Sprintf("<Grant><Grantee xsi:type=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">", grant.Grantee.Type))
   116  		}
   117  		if grant.Grantee.ID != "" {
   118  			granteeID := XmlTranscoding(grant.Grantee.ID)
   119  			xml = append(xml, fmt.Sprintf("<ID>%s</ID>", granteeID))
   120  		}
   121  		if !isObs && grant.Grantee.DisplayName != "" {
   122  			granteeDisplayName := XmlTranscoding(grant.Grantee.DisplayName)
   123  			xml = append(xml, fmt.Sprintf("<DisplayName>%s</DisplayName>", granteeDisplayName))
   124  		}
   125  		xml = append(xml, "</Grantee>")
   126  	} else {
   127  		if !isObs {
   128  			xml = append(xml, fmt.Sprintf("<Grant><Grantee xsi:type=\"%s\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">", grant.Grantee.Type))
   129  			xml = append(xml, prepareGrantURI(grant))
   130  			xml = append(xml, "</Grantee>")
   131  		} else if grant.Grantee.URI == GroupAllUsers {
   132  			xml = append(xml, "<Grant><Grantee>")
   133  			xml = append(xml, fmt.Sprintf("<Canned>Everyone</Canned>"))
   134  			xml = append(xml, "</Grantee>")
   135  		} else {
   136  			return strings.Join(xml, "")
   137  		}
   138  	}
   139  
   140  	xml = append(xml, fmt.Sprintf("<Permission>%s</Permission>", grant.Permission))
   141  	if isObs && isBucket {
   142  		xml = append(xml, fmt.Sprintf("<Delivered>%t</Delivered>", grant.Delivered))
   143  	}
   144  	xml = append(xml, fmt.Sprintf("</Grant>"))
   145  	return strings.Join(xml, "")
   146  }
   147  
   148  func hasLoggingTarget(input BucketLoggingStatus) bool {
   149  	if input.TargetBucket != "" || input.TargetPrefix != "" || len(input.TargetGrants) > 0 {
   150  		return true
   151  	}
   152  	return false
   153  }
   154  
   155  // ConvertLoggingStatusToXml converts BucketLoggingStatus value to XML data and returns it
   156  func ConvertLoggingStatusToXml(input BucketLoggingStatus, returnMd5 bool, isObs bool) (data string, md5 string) {
   157  	grantsLength := len(input.TargetGrants)
   158  	xml := make([]string, 0, 8+grantsLength)
   159  
   160  	xml = append(xml, "<BucketLoggingStatus>")
   161  	if isObs && input.Agency != "" {
   162  		agency := XmlTranscoding(input.Agency)
   163  		xml = append(xml, fmt.Sprintf("<Agency>%s</Agency>", agency))
   164  	}
   165  	if hasLoggingTarget(input) {
   166  		xml = append(xml, "<LoggingEnabled>")
   167  		if input.TargetBucket != "" {
   168  			xml = append(xml, fmt.Sprintf("<TargetBucket>%s</TargetBucket>", input.TargetBucket))
   169  		}
   170  		if input.TargetPrefix != "" {
   171  			targetPrefix := XmlTranscoding(input.TargetPrefix)
   172  			xml = append(xml, fmt.Sprintf("<TargetPrefix>%s</TargetPrefix>", targetPrefix))
   173  		}
   174  		if grantsLength > 0 {
   175  			xml = append(xml, "<TargetGrants>")
   176  			for _, grant := range input.TargetGrants {
   177  				xml = append(xml, convertGrantToXML(grant, isObs, false))
   178  			}
   179  			xml = append(xml, "</TargetGrants>")
   180  		}
   181  
   182  		xml = append(xml, "</LoggingEnabled>")
   183  	}
   184  	xml = append(xml, "</BucketLoggingStatus>")
   185  	data = strings.Join(xml, "")
   186  	if returnMd5 {
   187  		md5 = Base64Md5([]byte(data))
   188  	}
   189  	return
   190  }
   191  
   192  // ConvertAclToXml converts AccessControlPolicy value to XML data and returns it
   193  func ConvertAclToXml(input AccessControlPolicy, returnMd5 bool, isObs bool) (data string, md5 string) {
   194  	xml := make([]string, 0, 4+len(input.Grants))
   195  	ownerID := XmlTranscoding(input.Owner.ID)
   196  	xml = append(xml, fmt.Sprintf("<AccessControlPolicy><Owner><ID>%s</ID>", ownerID))
   197  	if !isObs && input.Owner.DisplayName != "" {
   198  		ownerDisplayName := XmlTranscoding(input.Owner.DisplayName)
   199  		xml = append(xml, fmt.Sprintf("<DisplayName>%s</DisplayName>", ownerDisplayName))
   200  	}
   201  	if isObs && input.Delivered != "" {
   202  		objectDelivered := XmlTranscoding(input.Delivered)
   203  		xml = append(xml, fmt.Sprintf("</Owner><Delivered>%s</Delivered><AccessControlList>", objectDelivered))
   204  	} else {
   205  		xml = append(xml, "</Owner><AccessControlList>")
   206  	}
   207  	for _, grant := range input.Grants {
   208  		xml = append(xml, convertGrantToXML(grant, isObs, false))
   209  	}
   210  	xml = append(xml, "</AccessControlList></AccessControlPolicy>")
   211  	data = strings.Join(xml, "")
   212  	if returnMd5 {
   213  		md5 = Base64Md5([]byte(data))
   214  	}
   215  	return
   216  }
   217  
   218  func convertBucketACLToXML(input AccessControlPolicy, returnMd5 bool, isObs bool) (data string, md5 string) {
   219  	xml := make([]string, 0, 4+len(input.Grants))
   220  	ownerID := XmlTranscoding(input.Owner.ID)
   221  	xml = append(xml, fmt.Sprintf("<AccessControlPolicy><Owner><ID>%s</ID>", ownerID))
   222  	if !isObs && input.Owner.DisplayName != "" {
   223  		ownerDisplayName := XmlTranscoding(input.Owner.DisplayName)
   224  		xml = append(xml, fmt.Sprintf("<DisplayName>%s</DisplayName>", ownerDisplayName))
   225  	}
   226  
   227  	xml = append(xml, "</Owner><AccessControlList>")
   228  
   229  	for _, grant := range input.Grants {
   230  		xml = append(xml, convertGrantToXML(grant, isObs, true))
   231  	}
   232  	xml = append(xml, "</AccessControlList></AccessControlPolicy>")
   233  	data = strings.Join(xml, "")
   234  	if returnMd5 {
   235  		md5 = Base64Md5([]byte(data))
   236  	}
   237  	return
   238  }
   239  
   240  func convertConditionToXML(condition Condition) string {
   241  	xml := make([]string, 0, 2)
   242  	if condition.KeyPrefixEquals != "" {
   243  		keyPrefixEquals := XmlTranscoding(condition.KeyPrefixEquals)
   244  		xml = append(xml, fmt.Sprintf("<KeyPrefixEquals>%s</KeyPrefixEquals>", keyPrefixEquals))
   245  	}
   246  	if condition.HttpErrorCodeReturnedEquals != "" {
   247  		xml = append(xml, fmt.Sprintf("<HttpErrorCodeReturnedEquals>%s</HttpErrorCodeReturnedEquals>", condition.HttpErrorCodeReturnedEquals))
   248  	}
   249  	if len(xml) > 0 {
   250  		return fmt.Sprintf("<Condition>%s</Condition>", strings.Join(xml, ""))
   251  	}
   252  	return ""
   253  }
   254  
   255  func prepareRoutingRule(input BucketWebsiteConfiguration) string {
   256  	xml := make([]string, 0, len(input.RoutingRules)*10)
   257  	for _, routingRule := range input.RoutingRules {
   258  		xml = append(xml, "<RoutingRule>")
   259  		xml = append(xml, "<Redirect>")
   260  		if routingRule.Redirect.Protocol != "" {
   261  			xml = append(xml, fmt.Sprintf("<Protocol>%s</Protocol>", routingRule.Redirect.Protocol))
   262  		}
   263  		if routingRule.Redirect.HostName != "" {
   264  			xml = append(xml, fmt.Sprintf("<HostName>%s</HostName>", routingRule.Redirect.HostName))
   265  		}
   266  		if routingRule.Redirect.ReplaceKeyPrefixWith != "" {
   267  			replaceKeyPrefixWith := XmlTranscoding(routingRule.Redirect.ReplaceKeyPrefixWith)
   268  			xml = append(xml, fmt.Sprintf("<ReplaceKeyPrefixWith>%s</ReplaceKeyPrefixWith>", replaceKeyPrefixWith))
   269  		}
   270  
   271  		if routingRule.Redirect.ReplaceKeyWith != "" {
   272  			replaceKeyWith := XmlTranscoding(routingRule.Redirect.ReplaceKeyWith)
   273  			xml = append(xml, fmt.Sprintf("<ReplaceKeyWith>%s</ReplaceKeyWith>", replaceKeyWith))
   274  		}
   275  		if routingRule.Redirect.HttpRedirectCode != "" {
   276  			xml = append(xml, fmt.Sprintf("<HttpRedirectCode>%s</HttpRedirectCode>", routingRule.Redirect.HttpRedirectCode))
   277  		}
   278  		xml = append(xml, "</Redirect>")
   279  
   280  		if ret := convertConditionToXML(routingRule.Condition); ret != "" {
   281  			xml = append(xml, ret)
   282  		}
   283  		xml = append(xml, "</RoutingRule>")
   284  	}
   285  	return strings.Join(xml, "")
   286  }
   287  
   288  // ConvertWebsiteConfigurationToXml converts BucketWebsiteConfiguration value to XML data and returns it
   289  func ConvertWebsiteConfigurationToXml(input BucketWebsiteConfiguration, returnMd5 bool) (data string, md5 string) {
   290  	routingRuleLength := len(input.RoutingRules)
   291  	xml := make([]string, 0, 6+routingRuleLength*10)
   292  	xml = append(xml, "<WebsiteConfiguration>")
   293  
   294  	if input.RedirectAllRequestsTo.HostName != "" {
   295  		xml = append(xml, fmt.Sprintf("<RedirectAllRequestsTo><HostName>%s</HostName>", input.RedirectAllRequestsTo.HostName))
   296  		if input.RedirectAllRequestsTo.Protocol != "" {
   297  			xml = append(xml, fmt.Sprintf("<Protocol>%s</Protocol>", input.RedirectAllRequestsTo.Protocol))
   298  		}
   299  		xml = append(xml, "</RedirectAllRequestsTo>")
   300  	} else {
   301  		if input.IndexDocument.Suffix != "" {
   302  			indexDocumentSuffix := XmlTranscoding(input.IndexDocument.Suffix)
   303  			xml = append(xml, fmt.Sprintf("<IndexDocument><Suffix>%s</Suffix></IndexDocument>", indexDocumentSuffix))
   304  		}
   305  		if input.ErrorDocument.Key != "" {
   306  			errorDocumentKey := XmlTranscoding(input.ErrorDocument.Key)
   307  			xml = append(xml, fmt.Sprintf("<ErrorDocument><Key>%s</Key></ErrorDocument>", errorDocumentKey))
   308  		}
   309  		if routingRuleLength > 0 {
   310  			xml = append(xml, "<RoutingRules>")
   311  			xml = append(xml, prepareRoutingRule(input))
   312  			xml = append(xml, "</RoutingRules>")
   313  		}
   314  	}
   315  
   316  	xml = append(xml, "</WebsiteConfiguration>")
   317  	data = strings.Join(xml, "")
   318  	if returnMd5 {
   319  		md5 = Base64Md5([]byte(data))
   320  	}
   321  	return
   322  }
   323  
   324  func convertTransitionsToXML(transitions []Transition, isObs bool) string {
   325  	if length := len(transitions); length > 0 {
   326  		xml := make([]string, 0, length)
   327  		for _, transition := range transitions {
   328  			var temp string
   329  			if transition.Days > 0 {
   330  				temp = fmt.Sprintf("<Days>%d</Days>", transition.Days)
   331  			} else if !transition.Date.IsZero() {
   332  				temp = fmt.Sprintf("<Date>%s</Date>", transition.Date.UTC().Format(ISO8601_MIDNIGHT_DATE_FORMAT))
   333  			}
   334  			if temp != "" {
   335  				if !isObs {
   336  					storageClass := string(transition.StorageClass)
   337  					if transition.StorageClass == StorageClassWarm {
   338  						storageClass = string(storageClassStandardIA)
   339  					} else if transition.StorageClass == StorageClassCold {
   340  						storageClass = string(storageClassGlacier)
   341  					}
   342  					xml = append(xml, fmt.Sprintf("<Transition>%s<StorageClass>%s</StorageClass></Transition>", temp, storageClass))
   343  				} else {
   344  					xml = append(xml, fmt.Sprintf("<Transition>%s<StorageClass>%s</StorageClass></Transition>", temp, transition.StorageClass))
   345  				}
   346  			}
   347  		}
   348  		return strings.Join(xml, "")
   349  	}
   350  	return ""
   351  }
   352  
   353  func convertLifeCycleFilterToXML(filter LifecycleFilter) string {
   354  	if filter.Prefix == "" && len(filter.Tags) == 0 {
   355  		return ""
   356  	}
   357  	data, err := TransToXml(filter)
   358  	if err != nil {
   359  		return ""
   360  	}
   361  	return string(data)
   362  }
   363  
   364  func convertExpirationToXML(expiration Expiration) string {
   365  	if expiration.Days > 0 {
   366  		return fmt.Sprintf("<Expiration><Days>%d</Days></Expiration>", expiration.Days)
   367  	} else if !expiration.Date.IsZero() {
   368  		return fmt.Sprintf("<Expiration><Date>%s</Date></Expiration>", expiration.Date.UTC().Format(ISO8601_MIDNIGHT_DATE_FORMAT))
   369  	} else if expiration.ExpiredObjectDeleteMarker != "" {
   370  		return fmt.Sprintf("<Expiration><ExpiredObjectDeleteMarker>%s</ExpiredObjectDeleteMarker></Expiration>", expiration.ExpiredObjectDeleteMarker)
   371  	}
   372  	return ""
   373  }
   374  
   375  func convertNoncurrentVersionTransitionsToXML(noncurrentVersionTransitions []NoncurrentVersionTransition, isObs bool) string {
   376  	if length := len(noncurrentVersionTransitions); length > 0 {
   377  		xml := make([]string, 0, length)
   378  		for _, noncurrentVersionTransition := range noncurrentVersionTransitions {
   379  			if noncurrentVersionTransition.NoncurrentDays > 0 {
   380  				storageClass := string(noncurrentVersionTransition.StorageClass)
   381  				if !isObs {
   382  					if storageClass == string(StorageClassWarm) {
   383  						storageClass = string(storageClassStandardIA)
   384  					} else if storageClass == string(StorageClassCold) {
   385  						storageClass = string(storageClassGlacier)
   386  					}
   387  				}
   388  				xml = append(xml, fmt.Sprintf("<NoncurrentVersionTransition><NoncurrentDays>%d</NoncurrentDays>"+
   389  					"<StorageClass>%s</StorageClass></NoncurrentVersionTransition>",
   390  					noncurrentVersionTransition.NoncurrentDays, storageClass))
   391  			}
   392  		}
   393  		return strings.Join(xml, "")
   394  	}
   395  	return ""
   396  }
   397  func convertNoncurrentVersionExpirationToXML(noncurrentVersionExpiration NoncurrentVersionExpiration) string {
   398  	if noncurrentVersionExpiration.NoncurrentDays > 0 {
   399  		return fmt.Sprintf("<NoncurrentVersionExpiration><NoncurrentDays>%d</NoncurrentDays></NoncurrentVersionExpiration>", noncurrentVersionExpiration.NoncurrentDays)
   400  	}
   401  	return ""
   402  }
   403  
   404  func convertAbortIncompleteMultipartUploadToXML(abortIncompleteMultipartUpload AbortIncompleteMultipartUpload) string {
   405  	if abortIncompleteMultipartUpload.DaysAfterInitiation > 0 {
   406  		return fmt.Sprintf("<AbortIncompleteMultipartUpload><DaysAfterInitiation>%d</DaysAfterInitiation></AbortIncompleteMultipartUpload>", abortIncompleteMultipartUpload.DaysAfterInitiation)
   407  	}
   408  	return ""
   409  }
   410  
   411  // ConvertLifecycleConfigurationToXml converts BucketLifecycleConfiguration value to XML data and returns it
   412  func ConvertLifecycleConfigurationToXml(input BucketLifecycleConfiguration, returnMd5 bool, isObs bool) (data string, md5 string) {
   413  	xml := make([]string, 0, 2+len(input.LifecycleRules)*9)
   414  	xml = append(xml, "<LifecycleConfiguration>")
   415  	for _, lifecycleRule := range input.LifecycleRules {
   416  		xml = append(xml, "<Rule>")
   417  		if lifecycleRule.ID != "" {
   418  			lifecycleRuleID := XmlTranscoding(lifecycleRule.ID)
   419  			xml = append(xml, fmt.Sprintf("<ID>%s</ID>", lifecycleRuleID))
   420  		}
   421  		lifecycleRulePrefix := XmlTranscoding(lifecycleRule.Prefix)
   422  		lifecycleRuleFilter := convertLifeCycleFilterToXML(lifecycleRule.Filter)
   423  		if lifecycleRulePrefix != "" || (lifecycleRulePrefix == "" && lifecycleRuleFilter == "") {
   424  			xml = append(xml, fmt.Sprintf("<Prefix>%s</Prefix>", lifecycleRulePrefix))
   425  		}
   426  		if lifecycleRuleFilter != "" {
   427  			xml = append(xml, lifecycleRuleFilter)
   428  		}
   429  		xml = append(xml, fmt.Sprintf("<Status>%s</Status>", lifecycleRule.Status))
   430  		if ret := convertTransitionsToXML(lifecycleRule.Transitions, isObs); ret != "" {
   431  			xml = append(xml, ret)
   432  		}
   433  		if ret := convertExpirationToXML(lifecycleRule.Expiration); ret != "" {
   434  			xml = append(xml, ret)
   435  		}
   436  		if ret := convertNoncurrentVersionTransitionsToXML(lifecycleRule.NoncurrentVersionTransitions, isObs); ret != "" {
   437  			xml = append(xml, ret)
   438  		}
   439  		if ret := convertNoncurrentVersionExpirationToXML(lifecycleRule.NoncurrentVersionExpiration); ret != "" {
   440  			xml = append(xml, ret)
   441  		}
   442  		if ret := convertAbortIncompleteMultipartUploadToXML(lifecycleRule.AbortIncompleteMultipartUpload); ret != "" {
   443  			xml = append(xml, ret)
   444  		}
   445  		xml = append(xml, "</Rule>")
   446  	}
   447  	xml = append(xml, "</LifecycleConfiguration>")
   448  	data = strings.Join(xml, "")
   449  	if returnMd5 {
   450  		md5 = Base64Md5([]byte(data))
   451  	}
   452  	return
   453  }
   454  
   455  // ConvertEncryptionConfigurationToXml converts BucketEncryptionConfiguration value to XML data and returns it
   456  func ConvertEncryptionConfigurationToXml(input BucketEncryptionConfiguration, returnMd5 bool, isObs bool) (data string, md5 string) {
   457  	xml := make([]string, 0, 5)
   458  	xml = append(xml, "<ServerSideEncryptionConfiguration><Rule><ApplyServerSideEncryptionByDefault>")
   459  
   460  	algorithm := XmlTranscoding(input.SSEAlgorithm)
   461  	xml = append(xml, fmt.Sprintf("<SSEAlgorithm>%s</SSEAlgorithm>", algorithm))
   462  
   463  	if input.KMSMasterKeyID != "" {
   464  		kmsKeyID := XmlTranscoding(input.KMSMasterKeyID)
   465  		xml = append(xml, fmt.Sprintf("<KMSMasterKeyID>%s</KMSMasterKeyID>", kmsKeyID))
   466  	}
   467  	if input.ProjectID != "" {
   468  		projectID := XmlTranscoding(input.ProjectID)
   469  		xml = append(xml, fmt.Sprintf("<ProjectID>%s</ProjectID>", projectID))
   470  	}
   471  
   472  	xml = append(xml, "</ApplyServerSideEncryptionByDefault></Rule></ServerSideEncryptionConfiguration>")
   473  	data = strings.Join(xml, "")
   474  	if returnMd5 {
   475  		md5 = Base64Md5([]byte(data))
   476  	}
   477  	return
   478  }
   479  
   480  // convertReplicationConfigurationToXml converts BucketReplicationConfiguration value to XML data and returns it
   481  func convertReplicationConfigurationToXml(input BucketReplicationConfiguration, returnMd5 bool, isObs bool) (data string, md5 string) {
   482  	xml := make([]string, 0, 3+len(input.ReplicationRules)*6)
   483  
   484  	xml = append(xml, "<ReplicationConfiguration>")
   485  	xml = append(xml, fmt.Sprintf("<Agency>%s</Agency>", XmlTranscoding(input.Agency)))
   486  
   487  	for _, rule := range input.ReplicationRules {
   488  		xml = append(xml, "<Rule>")
   489  		xml = append(xml, fmt.Sprintf("<Status>%s</Status>", rule.Status))
   490  		xml = append(xml, fmt.Sprintf("<Prefix>%s</Prefix>", XmlTranscoding(rule.Prefix)))
   491  
   492  		xml = append(xml, fmt.Sprintf("<Destination><Bucket>%s</Bucket>", XmlTranscoding(rule.DestinationBucket)))
   493  		if rule.StorageClass != "" {
   494  			storageClass := string(rule.StorageClass)
   495  			if !isObs {
   496  				if storageClass == string(StorageClassWarm) {
   497  					storageClass = string(storageClassStandardIA)
   498  				} else if storageClass == string(StorageClassCold) {
   499  					storageClass = string(storageClassGlacier)
   500  				}
   501  			}
   502  			xml = append(xml, fmt.Sprintf("<StorageClass>%s</StorageClass>", storageClass))
   503  		}
   504  		if rule.DeleteDate != "" {
   505  			xml = append(xml, fmt.Sprintf("<DeleteDate>%s</DeleteDate>", rule.DeleteDate))
   506  		}
   507  		xml = append(xml, "</Destination>")
   508  
   509  		if rule.ID != "" {
   510  			xml = append(xml, fmt.Sprintf("<ID>%s</ID>", XmlTranscoding(rule.ID)))
   511  		}
   512  
   513  		if rule.HistoricalObjectReplication != "" {
   514  			xml = append(xml, fmt.Sprintf("<HistoricalObjectReplication>%s</HistoricalObjectReplication>",
   515  				rule.HistoricalObjectReplication))
   516  		}
   517  		xml = append(xml, "</Rule>")
   518  	}
   519  	xml = append(xml, "</ReplicationConfiguration>")
   520  	data = strings.Join(xml, "")
   521  	if returnMd5 {
   522  		md5 = Base64Md5([]byte(data))
   523  	}
   524  	return
   525  }
   526  
   527  func converntFilterRulesToXML(filterRules []FilterRule, isObs bool) string {
   528  	if length := len(filterRules); length > 0 {
   529  		xml := make([]string, 0, length*4)
   530  		for _, filterRule := range filterRules {
   531  			xml = append(xml, "<FilterRule>")
   532  			if filterRule.Name != "" {
   533  				filterRuleName := XmlTranscoding(filterRule.Name)
   534  				xml = append(xml, fmt.Sprintf("<Name>%s</Name>", filterRuleName))
   535  			}
   536  			if filterRule.Value != "" {
   537  				filterRuleValue := XmlTranscoding(filterRule.Value)
   538  				xml = append(xml, fmt.Sprintf("<Value>%s</Value>", filterRuleValue))
   539  			}
   540  			xml = append(xml, "</FilterRule>")
   541  		}
   542  		if !isObs {
   543  			return fmt.Sprintf("<Filter><S3Key>%s</S3Key></Filter>", strings.Join(xml, ""))
   544  		}
   545  		return fmt.Sprintf("<Filter><Object>%s</Object></Filter>", strings.Join(xml, ""))
   546  	}
   547  	return ""
   548  }
   549  
   550  func converntEventsToXML(events []EventType, isObs bool) string {
   551  	if length := len(events); length > 0 {
   552  		xml := make([]string, 0, length)
   553  		if !isObs {
   554  			for _, event := range events {
   555  				xml = append(xml, fmt.Sprintf("<Event>%s%s</Event>", "s3:", event))
   556  			}
   557  		} else {
   558  			for _, event := range events {
   559  				xml = append(xml, fmt.Sprintf("<Event>%s</Event>", event))
   560  			}
   561  		}
   562  		return strings.Join(xml, "")
   563  	}
   564  	return ""
   565  }
   566  
   567  func converntConfigureToXML(topicConfiguration TopicConfiguration, xmlElem string, isObs bool) string {
   568  	xml := make([]string, 0, 6)
   569  	xml = append(xml, xmlElem)
   570  	if topicConfiguration.ID != "" {
   571  		topicConfigurationID := XmlTranscoding(topicConfiguration.ID)
   572  		xml = append(xml, fmt.Sprintf("<Id>%s</Id>", topicConfigurationID))
   573  	}
   574  	topicConfigurationTopic := XmlTranscoding(topicConfiguration.Topic)
   575  	xml = append(xml, fmt.Sprintf("<Topic>%s</Topic>", topicConfigurationTopic))
   576  
   577  	if ret := converntEventsToXML(topicConfiguration.Events, isObs); ret != "" {
   578  		xml = append(xml, ret)
   579  	}
   580  	if ret := converntFilterRulesToXML(topicConfiguration.FilterRules, isObs); ret != "" {
   581  		xml = append(xml, ret)
   582  	}
   583  	tempElem := xmlElem[0:1] + "/" + xmlElem[1:]
   584  	xml = append(xml, tempElem)
   585  	return strings.Join(xml, "")
   586  }
   587  
   588  // ConverntObsRestoreToXml converts RestoreObjectInput value to XML data and returns it
   589  func ConverntObsRestoreToXml(restoreObjectInput RestoreObjectInput) string {
   590  	xml := make([]string, 0, 2)
   591  	xml = append(xml, fmt.Sprintf("<RestoreRequest><Days>%d</Days>", restoreObjectInput.Days))
   592  	if restoreObjectInput.Tier != "Bulk" {
   593  		xml = append(xml, fmt.Sprintf("<RestoreJob><Tier>%s</Tier></RestoreJob>", restoreObjectInput.Tier))
   594  	}
   595  	xml = append(xml, fmt.Sprintf("</RestoreRequest>"))
   596  	data := strings.Join(xml, "")
   597  	return data
   598  }
   599  
   600  // ConvertNotificationToXml converts BucketNotification value to XML data and returns it
   601  func ConvertNotificationToXml(input BucketNotification, returnMd5 bool, isObs bool) (data string, md5 string) {
   602  	xml := make([]string, 0, 2+len(input.TopicConfigurations)*6)
   603  	xml = append(xml, "<NotificationConfiguration>")
   604  	for _, topicConfiguration := range input.TopicConfigurations {
   605  		ret := converntConfigureToXML(topicConfiguration, "<TopicConfiguration>", isObs)
   606  		xml = append(xml, ret)
   607  	}
   608  	xml = append(xml, "</NotificationConfiguration>")
   609  	data = strings.Join(xml, "")
   610  	if returnMd5 {
   611  		md5 = Base64Md5([]byte(data))
   612  	}
   613  	return
   614  }
   615  
   616  // ConvertCompleteMultipartUploadInputToXml converts CompleteMultipartUploadInput value to XML data and returns it
   617  func ConvertCompleteMultipartUploadInputToXml(input CompleteMultipartUploadInput, returnMd5 bool) (data string, md5 string) {
   618  	xml := make([]string, 0, 2+len(input.Parts)*4)
   619  	xml = append(xml, "<CompleteMultipartUpload>")
   620  	for _, part := range input.Parts {
   621  		xml = append(xml, "<Part>")
   622  		xml = append(xml, fmt.Sprintf("<PartNumber>%d</PartNumber>", part.PartNumber))
   623  		xml = append(xml, fmt.Sprintf("<ETag>%s</ETag>", part.ETag))
   624  		xml = append(xml, "</Part>")
   625  	}
   626  	xml = append(xml, "</CompleteMultipartUpload>")
   627  	data = strings.Join(xml, "")
   628  	if returnMd5 {
   629  		md5 = Base64Md5([]byte(data))
   630  	}
   631  	return
   632  }
   633  
   634  func convertDeleteObjectsToXML(input DeleteObjectsInput) (data string, md5 string) {
   635  	xml := make([]string, 0, 4+len(input.Objects)*4)
   636  	xml = append(xml, "<Delete>")
   637  	if input.Quiet {
   638  		xml = append(xml, fmt.Sprintf("<Quiet>%t</Quiet>", input.Quiet))
   639  	}
   640  	if input.EncodingType != "" {
   641  		encodingType := XmlTranscoding(input.EncodingType)
   642  		xml = append(xml, fmt.Sprintf("<EncodingType>%s</EncodingType>", encodingType))
   643  	}
   644  	for _, obj := range input.Objects {
   645  		xml = append(xml, "<Object>")
   646  		key := XmlTranscoding(obj.Key)
   647  		xml = append(xml, fmt.Sprintf("<Key>%s</Key>", key))
   648  		if obj.VersionId != "" {
   649  			xml = append(xml, fmt.Sprintf("<VersionId>%s</VersionId>", obj.VersionId))
   650  		}
   651  		xml = append(xml, "</Object>")
   652  	}
   653  	xml = append(xml, "</Delete>")
   654  	data = strings.Join(xml, "")
   655  	md5 = Base64Md5([]byte(data))
   656  	return
   657  }
   658  
   659  func parseSseHeader(responseHeaders map[string][]string) (sseHeader ISseHeader) {
   660  	if ret, ok := responseHeaders[HEADER_SSEC_ENCRYPTION]; ok {
   661  		sseCHeader := SseCHeader{Encryption: ret[0]}
   662  		if ret, ok = responseHeaders[HEADER_SSEC_KEY_MD5]; ok {
   663  			sseCHeader.KeyMD5 = ret[0]
   664  		}
   665  		sseHeader = sseCHeader
   666  	} else if ret, ok := responseHeaders[HEADER_SSEKMS_ENCRYPTION]; ok {
   667  		sseKmsHeader := SseKmsHeader{Encryption: ret[0]}
   668  		if ret, ok = responseHeaders[HEADER_SSEKMS_KEY]; ok {
   669  			sseKmsHeader.Key = ret[0]
   670  		} else if ret, ok = responseHeaders[HEADER_SSEKMS_ENCRYPT_KEY_OBS]; ok {
   671  			sseKmsHeader.Key = ret[0]
   672  		}
   673  		sseHeader = sseKmsHeader
   674  	}
   675  	return
   676  }
   677  
   678  func parseCorsHeader(output BaseModel) (AllowOrigin, AllowHeader, AllowMethod, ExposeHeader string, MaxAgeSeconds int) {
   679  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_ORIGIN]; ok {
   680  		AllowOrigin = ret[0]
   681  	}
   682  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_HEADERS]; ok {
   683  		AllowHeader = ret[0]
   684  	}
   685  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_MAX_AGE]; ok {
   686  		MaxAgeSeconds = StringToInt(ret[0], 0)
   687  	}
   688  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_METHODS]; ok {
   689  		AllowMethod = ret[0]
   690  	}
   691  	if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_EXPOSE_HEADERS]; ok {
   692  		ExposeHeader = ret[0]
   693  	}
   694  	return
   695  }
   696  
   697  func parseUnCommonHeader(output *GetObjectMetadataOutput) {
   698  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   699  		output.VersionId = ret[0]
   700  	}
   701  	if ret, ok := output.ResponseHeaders[HEADER_WEBSITE_REDIRECT_LOCATION]; ok {
   702  		output.WebsiteRedirectLocation = ret[0]
   703  	}
   704  	if ret, ok := output.ResponseHeaders[HEADER_EXPIRATION]; ok {
   705  		output.Expiration = ret[0]
   706  	}
   707  	if ret, ok := output.ResponseHeaders[HEADER_RESTORE]; ok {
   708  		output.Restore = ret[0]
   709  	}
   710  	if ret, ok := output.ResponseHeaders[HEADER_OBJECT_TYPE]; ok {
   711  		output.ObjectType = ret[0]
   712  	}
   713  	if ret, ok := output.ResponseHeaders[HEADER_NEXT_APPEND_POSITION]; ok {
   714  		output.NextAppendPosition = ret[0]
   715  	}
   716  }
   717  
   718  func parseStandardMetadataHeader(output *GetObjectMetadataOutput) {
   719  	httpHeader := HttpHeader{}
   720  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok {
   721  		httpHeader.ContentType = ret[0]
   722  	}
   723  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok {
   724  		httpHeader.ContentEncoding = ret[0]
   725  	}
   726  	if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok {
   727  		httpHeader.CacheControl = ret[0]
   728  	}
   729  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok {
   730  		httpHeader.ContentDisposition = ret[0]
   731  	}
   732  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok {
   733  		httpHeader.ContentLanguage = ret[0]
   734  	}
   735  	if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok {
   736  		httpHeader.HttpExpires = ret[0]
   737  	}
   738  	output.HttpHeader = httpHeader
   739  }
   740  
   741  // ParseGetObjectMetadataOutput sets GetObjectMetadataOutput field values with response headers
   742  func ParseGetObjectMetadataOutput(output *GetObjectMetadataOutput) {
   743  	output.AllowOrigin, output.AllowHeader, output.AllowMethod, output.ExposeHeader, output.MaxAgeSeconds = parseCorsHeader(output.BaseModel)
   744  	parseUnCommonHeader(output)
   745  	parseStandardMetadataHeader(output)
   746  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   747  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   748  	}
   749  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
   750  		output.ETag = ret[0]
   751  	}
   752  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok {
   753  		output.ContentType = ret[0]
   754  	}
   755  
   756  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   757  	if ret, ok := output.ResponseHeaders[HEADER_LASTMODIFIED]; ok {
   758  		ret, err := time.Parse(time.RFC1123, ret[0])
   759  		if err == nil {
   760  			output.LastModified = ret
   761  		}
   762  	}
   763  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LENGTH]; ok {
   764  		output.ContentLength = StringToInt64(ret[0], 0)
   765  	}
   766  
   767  	output.Metadata = make(map[string]string)
   768  
   769  	for key, value := range output.ResponseHeaders {
   770  		if strings.HasPrefix(key, PREFIX_META) {
   771  			_key := key[len(PREFIX_META):]
   772  			output.ResponseHeaders[_key] = value
   773  			output.Metadata[_key] = value[0]
   774  			delete(output.ResponseHeaders, key)
   775  		}
   776  	}
   777  
   778  }
   779  
   780  // ParseCopyObjectOutput sets CopyObjectOutput field values with response headers
   781  func ParseCopyObjectOutput(output *CopyObjectOutput) {
   782  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   783  		output.VersionId = ret[0]
   784  	}
   785  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   786  	if ret, ok := output.ResponseHeaders[HEADER_COPY_SOURCE_VERSION_ID]; ok {
   787  		output.CopySourceVersionId = ret[0]
   788  	}
   789  }
   790  
   791  // ParsePutObjectOutput sets PutObjectOutput field values with response headers
   792  func ParsePutObjectOutput(output *PutObjectOutput) {
   793  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   794  		output.VersionId = ret[0]
   795  	}
   796  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   797  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   798  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   799  	}
   800  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
   801  		output.ETag = ret[0]
   802  	}
   803  }
   804  
   805  // ParseInitiateMultipartUploadOutput sets InitiateMultipartUploadOutput field values with response headers
   806  func ParseInitiateMultipartUploadOutput(output *InitiateMultipartUploadOutput) {
   807  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   808  }
   809  
   810  // ParseUploadPartOutput sets UploadPartOutput field values with response headers
   811  func ParseUploadPartOutput(output *UploadPartOutput) {
   812  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   813  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
   814  		output.ETag = ret[0]
   815  	}
   816  }
   817  
   818  // ParseCompleteMultipartUploadOutput sets CompleteMultipartUploadOutput field values with response headers
   819  func ParseCompleteMultipartUploadOutput(output *CompleteMultipartUploadOutput) {
   820  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   821  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   822  		output.VersionId = ret[0]
   823  	}
   824  }
   825  
   826  // ParseCopyPartOutput sets CopyPartOutput field values with response headers
   827  func ParseCopyPartOutput(output *CopyPartOutput) {
   828  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
   829  }
   830  
   831  // ParseStringToAvailableZoneType converts string value to AvailableZoneType value and returns it
   832  func ParseStringToAvailableZoneType(value string) (ret AvailableZoneType) {
   833  	switch value {
   834  	case "3az":
   835  		ret = AvailableZoneMultiAz
   836  	default:
   837  		ret = ""
   838  	}
   839  	return
   840  }
   841  
   842  // ParseGetBucketMetadataOutput sets GetBucketMetadataOutput field values with response headers
   843  func ParseGetBucketMetadataOutput(output *GetBucketMetadataOutput) {
   844  	output.AllowOrigin, output.AllowHeader, output.AllowMethod, output.ExposeHeader, output.MaxAgeSeconds = parseCorsHeader(output.BaseModel)
   845  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS]; ok {
   846  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   847  	} else if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   848  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   849  	}
   850  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_OBS]; ok {
   851  		output.Version = ret[0]
   852  	}
   853  	if ret, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok {
   854  		output.Location = ret[0]
   855  	} else if ret, ok := output.ResponseHeaders[HEADER_BUCKET_LOCATION_OBS]; ok {
   856  		output.Location = ret[0]
   857  	}
   858  	if ret, ok := output.ResponseHeaders[HEADER_EPID_HEADERS]; ok {
   859  		output.Epid = ret[0]
   860  	}
   861  	if ret, ok := output.ResponseHeaders[HEADER_AZ_REDUNDANCY]; ok {
   862  		output.AZRedundancy = ParseStringToAvailableZoneType(ret[0])
   863  	}
   864  	if ret, ok := output.ResponseHeaders[HEADER_BUCKET_REDUNDANCY]; ok {
   865  		output.BucketRedundancy = parseStringToBucketRedundancy(ret[0])
   866  	}
   867  	if ret, ok := output.ResponseHeaders[headerFSFileInterface]; ok {
   868  		output.FSStatus = parseStringToFSStatusType(ret[0])
   869  	} else {
   870  		output.FSStatus = FSStatusDisabled
   871  	}
   872  }
   873  
   874  func parseContentHeader(output *SetObjectMetadataOutput) {
   875  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok {
   876  		output.ContentDisposition = ret[0]
   877  	}
   878  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok {
   879  		output.ContentEncoding = ret[0]
   880  	}
   881  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok {
   882  		output.ContentLanguage = ret[0]
   883  	}
   884  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok {
   885  		output.ContentType = ret[0]
   886  	}
   887  }
   888  
   889  // ParseSetObjectMetadataOutput sets SetObjectMetadataOutput field values with response headers
   890  func ParseSetObjectMetadataOutput(output *SetObjectMetadataOutput) {
   891  	if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS]; ok {
   892  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   893  	} else if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok {
   894  		output.StorageClass = ParseStringToStorageClassType(ret[0])
   895  	}
   896  	if ret, ok := output.ResponseHeaders[HEADER_METADATA_DIRECTIVE]; ok {
   897  		output.MetadataDirective = MetadataDirectiveType(ret[0])
   898  	}
   899  	if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok {
   900  		output.CacheControl = ret[0]
   901  	}
   902  	parseContentHeader(output)
   903  	if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok {
   904  		output.Expires = ret[0]
   905  	}
   906  	if ret, ok := output.ResponseHeaders[HEADER_WEBSITE_REDIRECT_LOCATION]; ok {
   907  		output.WebsiteRedirectLocation = ret[0]
   908  	}
   909  	output.Metadata = make(map[string]string)
   910  
   911  	for key, value := range output.ResponseHeaders {
   912  		if strings.HasPrefix(key, PREFIX_META) {
   913  			_key := key[len(PREFIX_META):]
   914  			output.ResponseHeaders[_key] = value
   915  			output.Metadata[_key] = value[0]
   916  			delete(output.ResponseHeaders, key)
   917  		}
   918  	}
   919  }
   920  
   921  // ParseDeleteObjectOutput sets DeleteObjectOutput field values with response headers
   922  func ParseDeleteObjectOutput(output *DeleteObjectOutput) {
   923  	if versionID, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
   924  		output.VersionId = versionID[0]
   925  	}
   926  
   927  	if deleteMarker, ok := output.ResponseHeaders[HEADER_DELETE_MARKER]; ok {
   928  		output.DeleteMarker = deleteMarker[0] == "true"
   929  	}
   930  }
   931  
   932  // ParseGetObjectOutput sets GetObjectOutput field values with response headers
   933  func ParseGetObjectOutput(output *GetObjectOutput) {
   934  	ParseGetObjectMetadataOutput(&output.GetObjectMetadataOutput)
   935  	if ret, ok := output.ResponseHeaders[HEADER_DELETE_MARKER]; ok {
   936  		output.DeleteMarker = ret[0] == "true"
   937  	}
   938  	if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok {
   939  		output.CacheControl = ret[0]
   940  	}
   941  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok {
   942  		output.ContentDisposition = ret[0]
   943  	}
   944  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok {
   945  		output.ContentEncoding = ret[0]
   946  	}
   947  	if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok {
   948  		output.ContentLanguage = ret[0]
   949  	}
   950  	if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok {
   951  		output.Expires = ret[0]
   952  	}
   953  }
   954  
   955  // ConvertRequestToIoReaderV2 converts req to XML data
   956  func ConvertRequestToIoReaderV2(req interface{}) (io.Reader, string, error) {
   957  	data, err := TransToXml(req)
   958  	if err == nil {
   959  		return bytes.NewReader(data), Base64Md5(data), nil
   960  	}
   961  	return nil, "", err
   962  }
   963  
   964  // ConvertRequestToIoReader converts req to XML data
   965  func ConvertRequestToIoReader(req interface{}) (io.Reader, error) {
   966  	body, err := TransToXml(req)
   967  	if err == nil {
   968  		return bytes.NewReader(body), nil
   969  	}
   970  	return nil, err
   971  }
   972  
   973  func parseResponseBodyOutput(s reflect.Type, baseModel IBaseModel, body []byte) {
   974  	for i := 0; i < s.NumField(); i++ {
   975  		if s.Field(i).Tag == "json:\"body\"" {
   976  			reflect.ValueOf(baseModel).Elem().FieldByName(s.Field(i).Name).SetString(string(body))
   977  			break
   978  		}
   979  	}
   980  }
   981  
   982  // ParseCallbackResponseToBaseModel gets response from Callback Service
   983  func ParseCallbackResponseToBaseModel(resp *http.Response, baseModel IBaseModel, isObs bool) error {
   984  	baseModel.setStatusCode(resp.StatusCode)
   985  	responseHeaders := cleanHeaderPrefix(resp.Header)
   986  	baseModel.setResponseHeaders(responseHeaders)
   987  	if values, ok := responseHeaders[HEADER_REQUEST_ID]; ok {
   988  		baseModel.setRequestID(values[0])
   989  	}
   990  	readCloser, ok := baseModel.(ICallbackReadCloser)
   991  	if !ok {
   992  		return errors.New("Failed to set CallbackBody with resp's body.")
   993  	}
   994  	readCloser.setCallbackReadCloser(resp.Body)
   995  	return nil
   996  }
   997  
   998  // ParseResponseToBaseModel gets response from OBS
   999  func ParseResponseToBaseModel(resp *http.Response, baseModel IBaseModel, xmlResult bool, isObs bool) (err error) {
  1000  	readCloser, ok := baseModel.(IReadCloser)
  1001  	if !ok {
  1002  		defer func() {
  1003  			errMsg := resp.Body.Close()
  1004  			if errMsg != nil {
  1005  				doLog(LEVEL_WARN, "Failed to close response body")
  1006  			}
  1007  		}()
  1008  		var body []byte
  1009  		body, err = ioutil.ReadAll(resp.Body)
  1010  		if err == nil && len(body) > 0 {
  1011  			if xmlResult {
  1012  				err = ParseXml(body, baseModel)
  1013  			} else {
  1014  				s := reflect.TypeOf(baseModel).Elem()
  1015  				name := reflect.TypeOf(baseModel).Elem().Name()
  1016  				if name == "GetBucketPolicyOutput" || name == "GetBucketMirrorBackToSourceOuput" {
  1017  					parseResponseBodyOutput(s, baseModel, body)
  1018  				} else {
  1019  					err = parseJSON(body, baseModel)
  1020  				}
  1021  			}
  1022  			if err != nil {
  1023  				doLog(LEVEL_ERROR, "Unmarshal error: %v", err)
  1024  			}
  1025  		}
  1026  	} else {
  1027  		readCloser.setReadCloser(resp.Body)
  1028  	}
  1029  
  1030  	baseModel.setStatusCode(resp.StatusCode)
  1031  	responseHeaders := cleanHeaderPrefix(resp.Header)
  1032  	baseModel.setResponseHeaders(responseHeaders)
  1033  	if values, ok := responseHeaders[HEADER_REQUEST_ID]; ok {
  1034  		baseModel.setRequestID(values[0])
  1035  	}
  1036  	return
  1037  }
  1038  
  1039  // ParseResponseToObsError gets obsError from OBS
  1040  func ParseResponseToObsError(resp *http.Response, isObs bool) error {
  1041  	isJson := false
  1042  	if contentType, ok := resp.Header[HEADER_CONTENT_TYPE_CAML]; ok {
  1043  		jsonType, _ := mimeTypes["json"]
  1044  		isJson = contentType[0] == jsonType
  1045  	}
  1046  	obsError := ObsError{}
  1047  	respError := ParseResponseToBaseModel(resp, &obsError, !isJson, isObs)
  1048  	if respError != nil {
  1049  		doLog(LEVEL_WARN, "Parse response to BaseModel with error: %v", respError)
  1050  	}
  1051  	obsError.Status = resp.Status
  1052  	responseHeaders := cleanHeaderPrefix(resp.Header)
  1053  	if values, ok := responseHeaders[HEADER_ERROR_MESSAGE]; ok {
  1054  		obsError.Message = values[0]
  1055  	}
  1056  	if values, ok := responseHeaders[HEADER_ERROR_CODE]; ok {
  1057  		obsError.Code = values[0]
  1058  	}
  1059  	return obsError
  1060  }
  1061  
  1062  // convertFetchPolicyToJSON converts SetBucketFetchPolicyInput into json format
  1063  func convertFetchPolicyToJSON(input SetBucketFetchPolicyInput) (data string, err error) {
  1064  	fetch := map[string]SetBucketFetchPolicyInput{"fetch": input}
  1065  	json, err := json.Marshal(fetch)
  1066  	if err != nil {
  1067  		return "", err
  1068  	}
  1069  	data = string(json)
  1070  	return
  1071  }
  1072  
  1073  // convertFetchJobToJSON converts SetBucketFetchJobInput into json format
  1074  func convertFetchJobToJSON(input SetBucketFetchJobInput) (data string, err error) {
  1075  	objectHeaders := make(map[string]string)
  1076  	for key, value := range input.ObjectHeaders {
  1077  		if value != "" {
  1078  			_key := strings.ToLower(key)
  1079  			if !strings.HasPrefix(key, HEADER_PREFIX_OBS) {
  1080  				_key = HEADER_PREFIX_META_OBS + _key
  1081  			}
  1082  			objectHeaders[_key] = value
  1083  		}
  1084  	}
  1085  	input.ObjectHeaders = objectHeaders
  1086  	json, err := json.Marshal(input)
  1087  	if err != nil {
  1088  		return "", err
  1089  	}
  1090  	data = string(json)
  1091  	return
  1092  }
  1093  
  1094  func parseStringToFSStatusType(value string) (ret FSStatusType) {
  1095  	switch value {
  1096  	case "Enabled":
  1097  		ret = FSStatusEnabled
  1098  	case "Disabled":
  1099  		ret = FSStatusDisabled
  1100  	default:
  1101  		ret = ""
  1102  	}
  1103  	return
  1104  }
  1105  
  1106  func parseStringToBucketRedundancy(value string) (ret BucketRedundancyType) {
  1107  	switch value {
  1108  	case "FUSION":
  1109  		ret = BucketRedundancyFusion
  1110  	case "CLASSIC":
  1111  		ret = BucketRedundancyClassic
  1112  	default:
  1113  		ret = ""
  1114  	}
  1115  	return
  1116  }
  1117  
  1118  func decodeListObjectsOutput(output *ListObjectsOutput) (err error) {
  1119  	output.Delimiter, err = url.QueryUnescape(output.Delimiter)
  1120  	if err != nil {
  1121  		return
  1122  	}
  1123  	output.Marker, err = url.QueryUnescape(output.Marker)
  1124  	if err != nil {
  1125  		return
  1126  	}
  1127  	output.NextMarker, err = url.QueryUnescape(output.NextMarker)
  1128  	if err != nil {
  1129  		return
  1130  	}
  1131  	output.Prefix, err = url.QueryUnescape(output.Prefix)
  1132  	if err != nil {
  1133  		return
  1134  	}
  1135  	for index, value := range output.CommonPrefixes {
  1136  		output.CommonPrefixes[index], err = url.QueryUnescape(value)
  1137  		if err != nil {
  1138  			return
  1139  		}
  1140  	}
  1141  	for index, content := range output.Contents {
  1142  		output.Contents[index].Key, err = url.QueryUnescape(content.Key)
  1143  		if err != nil {
  1144  			return
  1145  		}
  1146  	}
  1147  	return
  1148  }
  1149  
  1150  func decodeListVersionsOutput(output *ListVersionsOutput) (err error) {
  1151  	output.Delimiter, err = url.QueryUnescape(output.Delimiter)
  1152  	if err != nil {
  1153  		return
  1154  	}
  1155  	output.KeyMarker, err = url.QueryUnescape(output.KeyMarker)
  1156  	if err != nil {
  1157  		return
  1158  	}
  1159  	output.NextKeyMarker, err = url.QueryUnescape(output.NextKeyMarker)
  1160  	if err != nil {
  1161  		return
  1162  	}
  1163  	output.Prefix, err = url.QueryUnescape(output.Prefix)
  1164  	if err != nil {
  1165  		return
  1166  	}
  1167  	for index, version := range output.Versions {
  1168  		output.Versions[index].Key, err = url.QueryUnescape(version.Key)
  1169  		if err != nil {
  1170  			return
  1171  		}
  1172  	}
  1173  	for index, deleteMarker := range output.DeleteMarkers {
  1174  		output.DeleteMarkers[index].Key, err = url.QueryUnescape(deleteMarker.Key)
  1175  		if err != nil {
  1176  			return
  1177  		}
  1178  	}
  1179  	for index, value := range output.CommonPrefixes {
  1180  		output.CommonPrefixes[index], err = url.QueryUnescape(value)
  1181  		if err != nil {
  1182  			return
  1183  		}
  1184  	}
  1185  	return
  1186  }
  1187  
  1188  func decodeDeleteObjectsOutput(output *DeleteObjectsOutput) (err error) {
  1189  	for index, object := range output.Deleteds {
  1190  		output.Deleteds[index].Key, err = url.QueryUnescape(object.Key)
  1191  		if err != nil {
  1192  			return
  1193  		}
  1194  	}
  1195  	for index, object := range output.Errors {
  1196  		output.Errors[index].Key, err = url.QueryUnescape(object.Key)
  1197  		if err != nil {
  1198  			return
  1199  		}
  1200  	}
  1201  	return
  1202  }
  1203  
  1204  func decodeListMultipartUploadsOutput(output *ListMultipartUploadsOutput) (err error) {
  1205  	output.Delimiter, err = url.QueryUnescape(output.Delimiter)
  1206  	if err != nil {
  1207  		return
  1208  	}
  1209  	output.Prefix, err = url.QueryUnescape(output.Prefix)
  1210  	if err != nil {
  1211  		return
  1212  	}
  1213  	output.KeyMarker, err = url.QueryUnescape(output.KeyMarker)
  1214  	if err != nil {
  1215  		return
  1216  	}
  1217  	output.NextKeyMarker, err = url.QueryUnescape(output.NextKeyMarker)
  1218  	if err != nil {
  1219  		return
  1220  	}
  1221  	for index, value := range output.CommonPrefixes {
  1222  		output.CommonPrefixes[index], err = url.QueryUnescape(value)
  1223  		if err != nil {
  1224  			return
  1225  		}
  1226  	}
  1227  	for index, upload := range output.Uploads {
  1228  		output.Uploads[index].Key, err = url.QueryUnescape(upload.Key)
  1229  		if err != nil {
  1230  			return
  1231  		}
  1232  	}
  1233  	return
  1234  }
  1235  
  1236  func decodeListPartsOutput(output *ListPartsOutput) (err error) {
  1237  	output.Key, err = url.QueryUnescape(output.Key)
  1238  	return
  1239  }
  1240  
  1241  func decodeInitiateMultipartUploadOutput(output *InitiateMultipartUploadOutput) (err error) {
  1242  	output.Key, err = url.QueryUnescape(output.Key)
  1243  	return
  1244  }
  1245  
  1246  func decodeCompleteMultipartUploadOutput(output *CompleteMultipartUploadOutput) (err error) {
  1247  	output.Key, err = url.QueryUnescape(output.Key)
  1248  	return
  1249  }
  1250  
  1251  // ParseAppendObjectOutput sets AppendObjectOutput field values with response headers
  1252  func ParseAppendObjectOutput(output *AppendObjectOutput) (err error) {
  1253  	if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok {
  1254  		output.VersionId = ret[0]
  1255  	}
  1256  	output.SseHeader = parseSseHeader(output.ResponseHeaders)
  1257  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
  1258  		output.ETag = ret[0]
  1259  	}
  1260  	if ret, ok := output.ResponseHeaders[HEADER_NEXT_APPEND_POSITION]; ok {
  1261  		output.NextAppendPosition, err = strconv.ParseInt(ret[0], 10, 64)
  1262  		if err != nil {
  1263  			err = fmt.Errorf("failed to parse next append position with error [%v]", err)
  1264  		}
  1265  	}
  1266  	return
  1267  }
  1268  
  1269  // ParseModifyObjectOutput sets ModifyObjectOutput field values with response headers
  1270  func ParseModifyObjectOutput(output *ModifyObjectOutput) {
  1271  	if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok {
  1272  		output.ETag = ret[0]
  1273  	}
  1274  }
  1275  
  1276  func ParseGetBucketFSStatusOutput(output *GetBucketFSStatusOutput) {
  1277  	ParseGetBucketMetadataOutput(&output.GetBucketMetadataOutput)
  1278  
  1279  	if ret, ok := output.ResponseHeaders[HEADER_FS_FILE_INTERFACE_OBS]; ok {
  1280  		output.FSStatus = ParseStringToFSStatusType(ret[0])
  1281  	}
  1282  }
  1283  
  1284  func ParseGetAttributeOutput(output *GetAttributeOutput) {
  1285  	ParseGetObjectMetadataOutput(&output.GetObjectMetadataOutput)
  1286  	if ret, ok := output.ResponseHeaders[HEADER_MODE]; ok {
  1287  		output.Mode = StringToInt(ret[0], -1)
  1288  	} else {
  1289  		output.Mode = -1
  1290  	}
  1291  }
  1292  
  1293  func ParseNewFolderOutput(output *NewFolderOutput) {
  1294  	ParsePutObjectOutput(&output.PutObjectOutput)
  1295  }