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