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 }