From f619fd354b82f15266a221143d1673a4a837a0fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 13:30:00 +0000 Subject: [PATCH] chore(deps): Bump github.com/thanos-io/thanos from 0.41.0 to 0.42.0 Bumps [github.com/thanos-io/thanos](https://github.com/thanos-io/thanos) from 0.41.0 to 0.42.0. - [Release notes](https://github.com/thanos-io/thanos/releases) - [Changelog](https://github.com/thanos-io/thanos/blob/main/CHANGELOG.md) - [Commits](https://github.com/thanos-io/thanos/compare/v0.41.0...v0.42.0) --- updated-dependencies: - dependency-name: github.com/thanos-io/thanos dependency-version: 0.42.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 19 +- go.sum | 51 +- .../VictoriaMetrics/easyproto/reader.go | 379 ++ .../aliyun/aliyun-oss-go-sdk/LICENSE | 14 + .../aliyun/aliyun-oss-go-sdk/oss/auth.go | 339 ++ .../aliyun/aliyun-oss-go-sdk/oss/bucket.go | 1321 +++++ .../aliyun/aliyun-oss-go-sdk/oss/client.go | 2956 +++++++++++ .../aliyun/aliyun-oss-go-sdk/oss/conf.go | 301 ++ .../aliyun/aliyun-oss-go-sdk/oss/conn.go | 1021 ++++ .../aliyun/aliyun-oss-go-sdk/oss/const.go | 273 + .../aliyun/aliyun-oss-go-sdk/oss/crc.go | 123 + .../aliyun/aliyun-oss-go-sdk/oss/download.go | 567 +++ .../aliyun/aliyun-oss-go-sdk/oss/error.go | 136 + .../aliyun-oss-go-sdk/oss/limit_reader_1_6.go | 29 + .../aliyun-oss-go-sdk/oss/limit_reader_1_7.go | 91 + .../aliyun-oss-go-sdk/oss/livechannel.go | 257 + .../aliyun/aliyun-oss-go-sdk/oss/mime.go | 594 +++ .../aliyun/aliyun-oss-go-sdk/oss/model.go | 69 + .../aliyun/aliyun-oss-go-sdk/oss/multicopy.go | 474 ++ .../aliyun/aliyun-oss-go-sdk/oss/multipart.go | 320 ++ .../aliyun/aliyun-oss-go-sdk/oss/option.go | 735 +++ .../aliyun/aliyun-oss-go-sdk/oss/progress.go | 116 + .../aliyun-oss-go-sdk/oss/redirect_1_6.go | 12 + .../aliyun-oss-go-sdk/oss/redirect_1_7.go | 13 + .../aliyun-oss-go-sdk/oss/select_object.go | 197 + .../oss/select_object_type.go | 365 ++ .../aliyun-oss-go-sdk/oss/transport_1_6.go | 42 + .../aliyun-oss-go-sdk/oss/transport_1_7.go | 45 + .../aliyun/aliyun-oss-go-sdk/oss/type.go | 1695 +++++++ .../aliyun/aliyun-oss-go-sdk/oss/upload.go | 578 +++ .../aliyun/aliyun-oss-go-sdk/oss/utils.go | 674 +++ vendor/github.com/baidubce/bce-sdk-go/LICENSE | 177 + .../baidubce/bce-sdk-go/auth/credentials.go | 62 + .../baidubce/bce-sdk-go/auth/signer.go | 184 + .../baidubce/bce-sdk-go/bce/builder.go | 189 + .../baidubce/bce-sdk-go/bce/client.go | 279 ++ .../baidubce/bce-sdk-go/bce/config.go | 82 + .../baidubce/bce-sdk-go/bce/error.go | 64 + .../baidubce/bce-sdk-go/bce/request.go | 224 + .../baidubce/bce-sdk-go/bce/response.go | 128 + .../baidubce/bce-sdk-go/bce/retry.go | 124 + .../baidubce/bce-sdk-go/http/client.go | 198 + .../baidubce/bce-sdk-go/http/constants.go | 93 + .../baidubce/bce-sdk-go/http/request.go | 237 + .../baidubce/bce-sdk-go/http/response.go | 74 + .../bce-sdk-go/services/bos/api/bucket.go | 1387 +++++ .../bce-sdk-go/services/bos/api/model.go | 722 +++ .../bce-sdk-go/services/bos/api/multipart.go | 491 ++ .../bce-sdk-go/services/bos/api/object.go | 1164 +++++ .../bce-sdk-go/services/bos/api/util.go | 481 ++ .../bce-sdk-go/services/bos/client.go | 2637 ++++++++++ .../bce-sdk-go/services/sts/api/mode.go | 30 + .../bce-sdk-go/services/sts/api/sts.go | 140 + .../bce-sdk-go/services/sts/client.go | 74 + .../baidubce/bce-sdk-go/util/log/logger.go | 393 ++ .../baidubce/bce-sdk-go/util/log/util.go | 227 + .../baidubce/bce-sdk-go/util/mime.go | 664 +++ .../baidubce/bce-sdk-go/util/string.go | 88 + .../baidubce/bce-sdk-go/util/time.go | 46 + vendor/github.com/clbanning/mxj/LICENSE | 55 + vendor/github.com/clbanning/mxj/anyxml.go | 189 + .../clbanning/mxj/atomFeedString.xml | 54 + vendor/github.com/clbanning/mxj/doc.go | 134 + .../github.com/clbanning/mxj/escapechars.go | 54 + vendor/github.com/clbanning/mxj/exists.go | 7 + vendor/github.com/clbanning/mxj/files.go | 287 ++ .../clbanning/mxj/files_test.badjson | 2 + .../clbanning/mxj/files_test.badxml | 9 + .../github.com/clbanning/mxj/files_test.json | 2 + .../github.com/clbanning/mxj/files_test.xml | 9 + .../clbanning/mxj/files_test_dup.json | 1 + .../clbanning/mxj/files_test_dup.xml | 1 + .../clbanning/mxj/files_test_indent.json | 12 + .../clbanning/mxj/files_test_indent.xml | 8 + vendor/github.com/clbanning/mxj/gob.go | 35 + vendor/github.com/clbanning/mxj/json.go | 323 ++ vendor/github.com/clbanning/mxj/keyvalues.go | 671 +++ vendor/github.com/clbanning/mxj/leafnode.go | 112 + vendor/github.com/clbanning/mxj/misc.go | 86 + vendor/github.com/clbanning/mxj/mxj.go | 128 + vendor/github.com/clbanning/mxj/newmap.go | 184 + vendor/github.com/clbanning/mxj/readme.md | 179 + vendor/github.com/clbanning/mxj/remove.go | 37 + vendor/github.com/clbanning/mxj/rename.go | 54 + vendor/github.com/clbanning/mxj/set.go | 26 + .../github.com/clbanning/mxj/setfieldsep.go | 20 + vendor/github.com/clbanning/mxj/songtext.xml | 29 + vendor/github.com/clbanning/mxj/strict.go | 30 + vendor/github.com/clbanning/mxj/struct.go | 54 + .../github.com/clbanning/mxj/updatevalues.go | 256 + vendor/github.com/clbanning/mxj/xml.go | 1139 +++++ vendor/github.com/clbanning/mxj/xmlseq.go | 828 +++ vendor/github.com/gofrs/flock/.gitignore | 24 + vendor/github.com/gofrs/flock/.golangci.yml | 116 + vendor/github.com/gofrs/flock/LICENSE | 28 + vendor/github.com/gofrs/flock/Makefile | 15 + vendor/github.com/gofrs/flock/README.md | 45 + vendor/github.com/gofrs/flock/SECURITY.md | 21 + vendor/github.com/gofrs/flock/build.sh | 18 + vendor/github.com/gofrs/flock/flock.go | 222 + vendor/github.com/gofrs/flock/flock_others.go | 45 + vendor/github.com/gofrs/flock/flock_unix.go | 211 + .../gofrs/flock/flock_unix_fcntl.go | 393 ++ .../github.com/gofrs/flock/flock_windows.go | 160 + .../github.com/google/go-querystring/LICENSE | 27 + .../google/go-querystring/query/encode.go | 357 ++ .../huaweicloud-sdk-go-obs/LICENSE | 201 + .../huaweicloud-sdk-go-obs/obs/auth.go | 347 ++ .../huaweicloud-sdk-go-obs/obs/authV2.go | 55 + .../huaweicloud-sdk-go-obs/obs/authV4.go | 136 + .../huaweicloud-sdk-go-obs/obs/callback.go | 49 + .../huaweicloud-sdk-go-obs/obs/client_base.go | 68 + .../obs/client_bucket.go | 869 ++++ .../obs/client_object.go | 568 +++ .../obs/client_other.go | 49 + .../huaweicloud-sdk-go-obs/obs/client_part.go | 254 + .../obs/client_resume.go | 59 + .../huaweicloud-sdk-go-obs/obs/conf.go | 563 +++ .../huaweicloud-sdk-go-obs/obs/const.go | 327 ++ .../huaweicloud-sdk-go-obs/obs/convert.go | 1313 +++++ .../huaweicloud-sdk-go-obs/obs/error.go | 36 + .../huaweicloud-sdk-go-obs/obs/extension.go | 103 + .../huaweicloud-sdk-go-obs/obs/http.go | 683 +++ .../huaweicloud-sdk-go-obs/obs/log.go | 394 ++ .../huaweicloud-sdk-go-obs/obs/mime.go | 404 ++ .../huaweicloud-sdk-go-obs/obs/model_base.go | 407 ++ .../obs/model_bucket.go | 437 ++ .../obs/model_header.go | 33 + .../obs/model_object.go | 432 ++ .../huaweicloud-sdk-go-obs/obs/model_other.go | 73 + .../huaweicloud-sdk-go-obs/obs/model_part.go | 173 + .../obs/model_response.go | 68 + .../huaweicloud-sdk-go-obs/obs/pool.go | 542 ++ .../huaweicloud-sdk-go-obs/obs/progress.go | 108 + .../huaweicloud-sdk-go-obs/obs/provider.go | 242 + .../obs/temporary_createSignedUrl.go | 65 + .../obs/temporary_other.go | 120 + .../obs/temporary_signedUrl.go | 758 +++ .../huaweicloud-sdk-go-obs/obs/trait_base.go | 154 + .../obs/trait_bucket.go | 352 ++ .../obs/trait_object.go | 532 ++ .../huaweicloud-sdk-go-obs/obs/trait_other.go | 75 + .../huaweicloud-sdk-go-obs/obs/trait_part.go | 140 + .../huaweicloud-sdk-go-obs/obs/transfer.go | 925 ++++ .../huaweicloud-sdk-go-obs/obs/type.go | 372 ++ .../huaweicloud-sdk-go-obs/obs/util.go | 661 +++ .../mitchellh/mapstructure/CHANGELOG.md | 96 + .../github.com/mitchellh/mapstructure/LICENSE | 21 + .../mitchellh/mapstructure/README.md | 46 + .../mitchellh/mapstructure/decode_hooks.go | 279 ++ .../mitchellh/mapstructure/error.go | 50 + .../mitchellh/mapstructure/mapstructure.go | 1540 ++++++ .../mozillazg/go-httpheader/.bumpversion.cfg | 7 + .../mozillazg/go-httpheader/.gitignore | 27 + .../mozillazg/go-httpheader/CHANGELOG.md | 35 + .../mozillazg/go-httpheader/LICENSE | 21 + .../mozillazg/go-httpheader/Makefile | 15 + .../mozillazg/go-httpheader/README.md | 69 + .../mozillazg/go-httpheader/decode.go | 300 ++ .../mozillazg/go-httpheader/encode.go | 297 ++ .../oracle/oci-go-sdk/v65/LICENSE.txt | 102 + .../oracle/oci-go-sdk/v65/NOTICE.txt | 1 + .../v65/common/auth/certificate_retriever.go | 262 + .../v65/common/auth/configuration.go | 115 + .../v65/common/auth/dispatcher_modifier.go | 41 + .../v65/common/auth/federation_client.go | 583 +++ ...federation_client_oke_workload_identity.go | 221 + ...nce_principal_delegation_token_provider.go | 95 + .../auth/instance_principal_key_provider.go | 169 + .../oracle/oci-go-sdk/v65/common/auth/jwt.go | 71 + ...rce_principal_delegation_token_provider.go | 90 + .../auth/resource_principal_key_provider.go | 485 ++ .../resource_principal_token_path_provider.go | 247 + .../v65/common/auth/resource_principals_v1.go | 377 ++ .../v65/common/auth/resource_principals_v3.go | 351 ++ .../oci-go-sdk/v65/common/auth/utils.go | 98 + .../oci-go-sdk/v65/common/circuit_breaker.go | 410 ++ .../oracle/oci-go-sdk/v65/common/client.go | 748 +++ .../oracle/oci-go-sdk/v65/common/common.go | 625 +++ .../oci-go-sdk/v65/common/configuration.go | 820 +++ .../oracle/oci-go-sdk/v65/common/errors.go | 306 ++ .../v65/common/eventual_consistency.go | 467 ++ .../oracle/oci-go-sdk/v65/common/helpers.go | 308 ++ .../oracle/oci-go-sdk/v65/common/http.go | 1144 +++++ .../oci-go-sdk/v65/common/http_signer.go | 270 + .../oracle/oci-go-sdk/v65/common/log.go | 231 + .../v65/common/oci_http_transport_wrapper.go | 120 + .../oracle/oci-go-sdk/v65/common/regions.go | 341 ++ .../oracle/oci-go-sdk/v65/common/regions.json | 440 ++ .../oracle/oci-go-sdk/v65/common/retry.go | 911 ++++ .../oracle/oci-go-sdk/v65/common/sseReader.go | 92 + .../v65/common/tls_config_provider.go | 156 + .../v65/common/transport_template_provider.go | 53 + .../v65/common/utils/opc_request_id.go | 30 + .../oracle/oci-go-sdk/v65/common/version.go | 37 + ...abort_multipart_upload_request_response.go | 146 + .../objectstorage/access_target_details.go | 48 + .../v65/objectstorage/archival_state.go | 62 + .../oci-go-sdk/v65/objectstorage/bucket.go | 316 ++ .../v65/objectstorage/bucket_summary.go | 69 + .../cancel_work_request_request_response.go | 105 + .../v65/objectstorage/checksum_algorithm.go | 62 + .../commit_multipart_upload_details.go | 47 + .../commit_multipart_upload_part_details.go | 46 + ...ommit_multipart_upload_request_response.go | 193 + .../v65/objectstorage/copy_object_details.go | 85 + .../copy_object_request_response.go | 160 + .../objectstorage/create_bucket_details.go | 234 + .../create_bucket_request_response.go | 117 + .../create_multipart_upload_details.go | 86 + ...reate_multipart_upload_request_response.go | 208 + ...create_preauthenticated_request_details.go | 124 + ...eauthenticated_request_request_response.go | 125 + .../create_private_endpoint_details.go | 82 + ...reate_private_endpoint_request_response.go | 112 + .../create_replication_policy_details.go | 48 + ...ate_replication_policy_request_response.go | 125 + .../create_retention_rule_details.go | 50 + .../create_retention_rule_request_response.go | 127 + .../delete_bucket_request_response.go | 124 + ...bject_lifecycle_policy_request_response.go | 124 + .../delete_object_request_response.go | 151 + ...eauthenticated_request_request_response.go | 133 + ...elete_private_endpoint_request_response.go | 128 + ...ete_replication_policy_request_response.go | 132 + .../delete_retention_rule_request_response.go | 137 + .../oci-go-sdk/v65/objectstorage/duration.go | 92 + .../oci-go-sdk/v65/objectstorage/fqdns.go | 42 + .../get_bucket_request_response.go | 199 + ...get_namespace_metadata_request_response.go | 108 + .../get_namespace_request_response.go | 92 + ...bject_lifecycle_policy_request_response.go | 125 + .../get_object_request_response.go | 372 ++ ...eauthenticated_request_request_response.go | 136 + .../get_private_endpoint_request_response.go | 141 + ...get_replication_policy_request_response.go | 135 + .../get_retention_rule_request_response.go | 141 + .../get_work_request_request_response.go | 111 + .../head_bucket_request_response.go | 138 + .../head_object_request_response.go | 339 ++ .../list_buckets_request_response.go | 187 + ...multipart_upload_parts_request_response.go | 167 + ...list_multipart_uploads_request_response.go | 140 + .../list_object_versions_request_response.go | 235 + .../v65/objectstorage/list_objects.go | 51 + .../list_objects_request_response.go | 153 + ...authenticated_requests_request_response.go | 143 + ...list_private_endpoints_request_response.go | 195 + ...t_replication_policies_request_response.go | 139 + ...st_replication_sources_request_response.go | 139 + .../list_retention_rules_request_response.go | 135 + ...st_work_request_errors_request_response.go | 126 + ...list_work_request_logs_request_response.go | 126 + .../list_work_requests_request_response.go | 129 + .../make_bucket_writable_request_response.go | 119 + .../v65/objectstorage/multipart_upload.go | 66 + .../multipart_upload_part_summary.go | 53 + .../v65/objectstorage/namespace_metadata.go | 47 + .../objectstorage/object_lifecycle_policy.go | 47 + .../objectstorage/object_lifecycle_rule.go | 121 + .../v65/objectstorage/object_name_filter.go | 84 + .../v65/objectstorage/object_summary.go | 71 + .../object_version_collection.go | 46 + .../objectstorage/object_version_summary.go | 77 + .../v65/objectstorage/objectstorage_client.go | 3824 ++++++++++++++ .../v65/objectstorage/pattern_details.go | 78 + .../objectstorage/preauthenticated_request.go | 183 + .../preauthenticated_request_summary.go | 126 + .../v65/objectstorage/prefix_fqdns.go | 47 + .../v65/objectstorage/private_endpoint.go | 170 + .../objectstorage/private_endpoint_summary.go | 75 + .../put_object_lifecycle_policy_details.go | 41 + ...bject_lifecycle_policy_request_response.go | 137 + .../put_object_request_response.go | 366 ++ .../reencrypt_bucket_request_response.go | 123 + .../objectstorage/reencrypt_object_details.go | 56 + .../reencrypt_object_request_response.go | 139 + .../objectstorage/rename_object_details.go | 56 + .../rename_object_request_response.go | 131 + .../v65/objectstorage/replication_policy.go | 109 + .../replication_policy_summary.go | 109 + .../v65/objectstorage/replication_source.go | 47 + .../objectstorage/restore_objects_details.go | 48 + .../restore_objects_request_response.go | 122 + .../v65/objectstorage/retention_rule.go | 59 + .../retention_rule_collection.go | 41 + .../objectstorage/retention_rule_details.go | 50 + .../objectstorage/retention_rule_summary.go | 59 + .../objectstorage/sse_customer_key_details.go | 89 + .../v65/objectstorage/storage_tier.go | 62 + .../objectstorage/transfer/file_uploader.go | 220 + .../transfer/file_uploader_req_resp.go | 44 + .../transfer/multipart_manifest.go | 211 + .../transfer/mutipart_uploader.go | 161 + .../objectstorage/transfer/stream_uploader.go | 92 + .../transfer/stream_uploader_req_resp.go | 58 + .../objectstorage/transfer/upload_manager.go | 192 + .../transfer/upload_manager_req_resp.go | 257 + .../objectstorage/update_bucket_details.go | 188 + .../update_bucket_request_response.go | 133 + .../update_namespace_metadata_details.go | 45 + ...ate_namespace_metadata_request_response.go | 111 + .../update_object_storage_tier_details.go | 54 + ...te_object_storage_tier_request_response.go | 122 + .../update_private_endpoint_details.go | 59 + ...pdate_private_endpoint_request_response.go | 131 + .../update_retention_rule_details.go | 50 + .../update_retention_rule_request_response.go | 146 + .../upload_part_request_response.go | 289 ++ .../v65/objectstorage/work_request.go | 189 + .../v65/objectstorage/work_request_error.go | 48 + .../objectstorage/work_request_log_entry.go | 45 + .../objectstorage/work_request_resource.go | 118 + .../work_request_resource_metadata_key.go | 70 + .../v65/objectstorage/work_request_summary.go | 189 + .../tencentyun/cos-go-sdk-v5/.bumpversion.cfg | 7 + .../tencentyun/cos-go-sdk-v5/.gitignore | 39 + .../tencentyun/cos-go-sdk-v5/.travis.yml | 32 + .../tencentyun/cos-go-sdk-v5/CHANGELOG.md | 1165 +++++ .../tencentyun/cos-go-sdk-v5/LICENSE | 21 + .../tencentyun/cos-go-sdk-v5/Makefile | 22 + .../tencentyun/cos-go-sdk-v5/README.md | 106 + .../tencentyun/cos-go-sdk-v5/auth.go | 767 +++ .../tencentyun/cos-go-sdk-v5/batch.go | 291 ++ .../tencentyun/cos-go-sdk-v5/bucket.go | 366 ++ .../cos-go-sdk-v5/bucket_accelerate.go | 37 + .../tencentyun/cos-go-sdk-v5/bucket_acl.go | 62 + .../tencentyun/cos-go-sdk-v5/bucket_cors.go | 73 + .../tencentyun/cos-go-sdk-v5/bucket_domain.go | 133 + .../cos-go-sdk-v5/bucket_encryption.go | 52 + .../bucket_intelligenttiering.go | 142 + .../cos-go-sdk-v5/bucket_inventory.go | 154 + .../cos-go-sdk-v5/bucket_lifecycle.go | 137 + .../cos-go-sdk-v5/bucket_location.go | 28 + .../cos-go-sdk-v5/bucket_logging.go | 50 + .../cos-go-sdk-v5/bucket_object_lock.go | 82 + .../tencentyun/cos-go-sdk-v5/bucket_origin.go | 193 + .../tencentyun/cos-go-sdk-v5/bucket_part.go | 59 + .../tencentyun/cos-go-sdk-v5/bucket_policy.go | 77 + .../cos-go-sdk-v5/bucket_referer.go | 58 + .../cos-go-sdk-v5/bucket_replication.go | 87 + .../cos-go-sdk-v5/bucket_tagging.go | 69 + .../cos-go-sdk-v5/bucket_version.go | 42 + .../cos-go-sdk-v5/bucket_website.go | 77 + .../github.com/tencentyun/cos-go-sdk-v5/ci.go | 2875 +++++++++++ .../tencentyun/cos-go-sdk-v5/ci_doc.go | 434 ++ .../cos-go-sdk-v5/ci_fileprocess.go | 207 + .../tencentyun/cos-go-sdk-v5/ci_media.go | 4461 +++++++++++++++++ .../cos-go-sdk-v5/ci_metainsight.go | 616 +++ .../tencentyun/cos-go-sdk-v5/cos.go | 770 +++ .../tencentyun/cos-go-sdk-v5/doc.go | 3 + .../tencentyun/cos-go-sdk-v5/error.go | 112 + .../tencentyun/cos-go-sdk-v5/helper.go | 480 ++ .../tencentyun/cos-go-sdk-v5/object.go | 2189 ++++++++ .../tencentyun/cos-go-sdk-v5/object_acl.go | 84 + .../tencentyun/cos-go-sdk-v5/object_part.go | 647 +++ .../tencentyun/cos-go-sdk-v5/object_select.go | 445 ++ .../tencentyun/cos-go-sdk-v5/progress.go | 160 + .../tencentyun/cos-go-sdk-v5/service.go | 53 + .../thanos-io/objstore/client/factory.go | 85 + .../thanos-io/objstore/clientutil/parse.go | 65 + .../thanos-io/objstore/providers/bos/bos.go | 443 ++ .../thanos-io/objstore/providers/cos/cos.go | 594 +++ .../thanos-io/objstore/providers/obs/obs.go | 451 ++ .../objstore/providers/oci/helper.go | 276 + .../thanos-io/objstore/providers/oci/oci.go | 438 ++ .../thanos-io/objstore/providers/oss/oss.go | 430 ++ .../thanos-io/promql-engine/engine/engine.go | 5 +- .../thanos-io/promql-engine/engine/explain.go | 26 +- .../thanos-io/thanos/pkg/block/block.go | 13 + .../thanos-io/thanos/pkg/block/fetcher.go | 281 +- .../thanos-io/thanos/pkg/block/index.go | 2 +- .../thanos/pkg/cacheutil/redis_client.go | 57 +- .../thanos-io/thanos/pkg/compact/compact.go | 20 +- .../pkg/discovery/dns/godns/resolver.go | 20 + .../pkg/discovery/dns/miekgdns/resolver.go | 51 + .../thanos/pkg/discovery/dns/provider.go | 1 + .../thanos/pkg/discovery/dns/resolver.go | 33 +- .../pkg/exemplars/exemplarspb/custom.go | 3 +- .../thanos/pkg/extgrpc/snappy/snappy.go | 54 +- .../thanos-io/thanos/pkg/filter/cuckoo.go | 2 +- .../thanos-io/thanos/pkg/logging/journald.go | 120 + .../thanos-io/thanos/pkg/logging/logger.go | 20 +- .../thanos-io/thanos/pkg/pool/worker_pool.go | 27 +- .../thanos/pkg/promclient/promclient.go | 9 +- .../thanos-io/thanos/pkg/query/endpointset.go | 30 +- .../thanos/pkg/query/fanout/tracker.go | 87 + .../thanos-io/thanos/pkg/query/querier.go | 10 + .../thanos-io/thanos/pkg/shipper/shipper.go | 76 +- .../thanos/pkg/status/statuspb/custom.go | 58 +- .../thanos/pkg/status/statuspb/rpc.pb.go | 150 +- .../thanos/pkg/status/statuspb/rpc.proto | 2 + .../thanos-io/thanos/pkg/store/bucket.go | 31 +- .../thanos/pkg/store/labelpb/types.pb.go | 482 +- .../thanos/pkg/store/labelpb/types.proto | 15 + .../thanos-io/thanos/pkg/store/proxy.go | 78 +- .../thanos-io/thanos/pkg/store/proxy_merge.go | 54 +- .../thanos-io/thanos/pkg/store/tsdb.go | 31 +- .../thanos-io/thanos/pkg/tenancy/tenancy.go | 2 +- .../thanos-io/thanos/pkg/tls/options.go | 105 +- vendor/github.com/youmark/pkcs8/.gitignore | 23 + vendor/github.com/youmark/pkcs8/LICENSE | 21 + vendor/github.com/youmark/pkcs8/README | 1 + vendor/github.com/youmark/pkcs8/README.md | 22 + vendor/github.com/youmark/pkcs8/cipher.go | 60 + .../github.com/youmark/pkcs8/cipher_3des.go | 24 + vendor/github.com/youmark/pkcs8/cipher_aes.go | 84 + vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go | 91 + vendor/github.com/youmark/pkcs8/kdf_scrypt.go | 62 + vendor/github.com/youmark/pkcs8/pkcs8.go | 309 ++ vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 30 + vendor/golang.org/x/crypto/scrypt/scrypt.go | 215 + vendor/modules.txt | 65 +- 413 files changed, 99596 insertions(+), 283 deletions(-) create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/LICENSE create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/crc.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/download.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/model.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multicopy.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go create mode 100644 vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/LICENSE create mode 100644 vendor/github.com/baidubce/bce-sdk-go/auth/credentials.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/auth/signer.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/bce/builder.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/bce/client.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/bce/config.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/bce/error.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/bce/request.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/bce/response.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/bce/retry.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/http/client.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/http/constants.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/http/request.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/http/response.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/bos/api/bucket.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/bos/api/model.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/bos/api/multipart.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/bos/api/object.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/bos/api/util.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/bos/client.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/sts/api/mode.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/sts/api/sts.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/services/sts/client.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/util/log/logger.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/util/log/util.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/util/mime.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/util/string.go create mode 100644 vendor/github.com/baidubce/bce-sdk-go/util/time.go create mode 100644 vendor/github.com/clbanning/mxj/LICENSE create mode 100644 vendor/github.com/clbanning/mxj/anyxml.go create mode 100644 vendor/github.com/clbanning/mxj/atomFeedString.xml create mode 100644 vendor/github.com/clbanning/mxj/doc.go create mode 100644 vendor/github.com/clbanning/mxj/escapechars.go create mode 100644 vendor/github.com/clbanning/mxj/exists.go create mode 100644 vendor/github.com/clbanning/mxj/files.go create mode 100644 vendor/github.com/clbanning/mxj/files_test.badjson create mode 100644 vendor/github.com/clbanning/mxj/files_test.badxml create mode 100644 vendor/github.com/clbanning/mxj/files_test.json create mode 100644 vendor/github.com/clbanning/mxj/files_test.xml create mode 100644 vendor/github.com/clbanning/mxj/files_test_dup.json create mode 100644 vendor/github.com/clbanning/mxj/files_test_dup.xml create mode 100644 vendor/github.com/clbanning/mxj/files_test_indent.json create mode 100644 vendor/github.com/clbanning/mxj/files_test_indent.xml create mode 100644 vendor/github.com/clbanning/mxj/gob.go create mode 100644 vendor/github.com/clbanning/mxj/json.go create mode 100644 vendor/github.com/clbanning/mxj/keyvalues.go create mode 100644 vendor/github.com/clbanning/mxj/leafnode.go create mode 100644 vendor/github.com/clbanning/mxj/misc.go create mode 100644 vendor/github.com/clbanning/mxj/mxj.go create mode 100644 vendor/github.com/clbanning/mxj/newmap.go create mode 100644 vendor/github.com/clbanning/mxj/readme.md create mode 100644 vendor/github.com/clbanning/mxj/remove.go create mode 100644 vendor/github.com/clbanning/mxj/rename.go create mode 100644 vendor/github.com/clbanning/mxj/set.go create mode 100644 vendor/github.com/clbanning/mxj/setfieldsep.go create mode 100644 vendor/github.com/clbanning/mxj/songtext.xml create mode 100644 vendor/github.com/clbanning/mxj/strict.go create mode 100644 vendor/github.com/clbanning/mxj/struct.go create mode 100644 vendor/github.com/clbanning/mxj/updatevalues.go create mode 100644 vendor/github.com/clbanning/mxj/xml.go create mode 100644 vendor/github.com/clbanning/mxj/xmlseq.go create mode 100644 vendor/github.com/gofrs/flock/.gitignore create mode 100644 vendor/github.com/gofrs/flock/.golangci.yml create mode 100644 vendor/github.com/gofrs/flock/LICENSE create mode 100644 vendor/github.com/gofrs/flock/Makefile create mode 100644 vendor/github.com/gofrs/flock/README.md create mode 100644 vendor/github.com/gofrs/flock/SECURITY.md create mode 100644 vendor/github.com/gofrs/flock/build.sh create mode 100644 vendor/github.com/gofrs/flock/flock.go create mode 100644 vendor/github.com/gofrs/flock/flock_others.go create mode 100644 vendor/github.com/gofrs/flock/flock_unix.go create mode 100644 vendor/github.com/gofrs/flock/flock_unix_fcntl.go create mode 100644 vendor/github.com/gofrs/flock/flock_windows.go create mode 100644 vendor/github.com/google/go-querystring/LICENSE create mode 100644 vendor/github.com/google/go-querystring/query/encode.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/LICENSE create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/auth.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV2.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV4.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/callback.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_base.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_bucket.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_object.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_other.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_part.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_resume.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/conf.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/const.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/convert.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/error.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/extension.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/http.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/log.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/mime.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_base.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_bucket.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_header.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_object.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_other.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_part.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_response.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/pool.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/progress.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/provider.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_createSignedUrl.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_other.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_signedUrl.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_base.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_bucket.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_object.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_other.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_part.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/transfer.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/type.go create mode 100644 vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/util.go create mode 100644 vendor/github.com/mitchellh/mapstructure/CHANGELOG.md create mode 100644 vendor/github.com/mitchellh/mapstructure/LICENSE create mode 100644 vendor/github.com/mitchellh/mapstructure/README.md create mode 100644 vendor/github.com/mitchellh/mapstructure/decode_hooks.go create mode 100644 vendor/github.com/mitchellh/mapstructure/error.go create mode 100644 vendor/github.com/mitchellh/mapstructure/mapstructure.go create mode 100644 vendor/github.com/mozillazg/go-httpheader/.bumpversion.cfg create mode 100644 vendor/github.com/mozillazg/go-httpheader/.gitignore create mode 100644 vendor/github.com/mozillazg/go-httpheader/CHANGELOG.md create mode 100644 vendor/github.com/mozillazg/go-httpheader/LICENSE create mode 100644 vendor/github.com/mozillazg/go-httpheader/Makefile create mode 100644 vendor/github.com/mozillazg/go-httpheader/README.md create mode 100644 vendor/github.com/mozillazg/go-httpheader/decode.go create mode 100644 vendor/github.com/mozillazg/go-httpheader/encode.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/LICENSE.txt create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/NOTICE.txt create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/certificate_retriever.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/configuration.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/dispatcher_modifier.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client_oke_workload_identity.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_delegation_token_provider.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_key_provider.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/jwt.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_delegation_token_provider.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_key_provider.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_token_path_provider.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v1.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v3.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/auth/utils.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/circuit_breaker.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/client.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/common.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/configuration.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/errors.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/eventual_consistency.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/helpers.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/http.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/http_signer.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/log.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/oci_http_transport_wrapper.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/regions.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/regions.json create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/retry.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/sseReader.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/tls_config_provider.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/transport_template_provider.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/utils/opc_request_id.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/common/version.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/abort_multipart_upload_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/access_target_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/archival_state.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/cancel_work_request_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/checksum_algorithm.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_part_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_bucket_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_lifecycle_policy_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_preauthenticated_request_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_private_endpoint_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_replication_policy_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_retention_rule_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/duration.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/fqdns.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_bucket_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_metadata_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_lifecycle_policy_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_preauthenticated_request_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_private_endpoint_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_replication_policy_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_retention_rule_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_work_request_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_bucket_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_object_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_buckets_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_upload_parts_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_uploads_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_object_versions_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_preauthenticated_requests_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_private_endpoints_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_policies_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_sources_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_retention_rules_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_errors_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_logs_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_requests_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/make_bucket_writable_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload_part_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/namespace_metadata.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_policy.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_rule.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_name_filter.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_collection.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/objectstorage_client.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/pattern_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/prefix_fqdns.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_bucket_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_source.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_collection.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/sse_customer_key_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/storage_tier.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader_req_resp.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/multipart_manifest.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/mutipart_uploader.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader_req_resp.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager_req_resp.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_details.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/upload_part_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_error.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_log_entry.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource_metadata_key.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_summary.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/.bumpversion.cfg create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/.travis.yml create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/LICENSE create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/Makefile create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/README.md create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/batch.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_accelerate.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_logging.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_tagging.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_version.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/doc.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/error.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/object.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/object_acl.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/object_select.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/progress.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/service.go create mode 100644 vendor/github.com/thanos-io/objstore/client/factory.go create mode 100644 vendor/github.com/thanos-io/objstore/clientutil/parse.go create mode 100644 vendor/github.com/thanos-io/objstore/providers/bos/bos.go create mode 100644 vendor/github.com/thanos-io/objstore/providers/cos/cos.go create mode 100644 vendor/github.com/thanos-io/objstore/providers/obs/obs.go create mode 100644 vendor/github.com/thanos-io/objstore/providers/oci/helper.go create mode 100644 vendor/github.com/thanos-io/objstore/providers/oci/oci.go create mode 100644 vendor/github.com/thanos-io/objstore/providers/oss/oss.go create mode 100644 vendor/github.com/thanos-io/thanos/pkg/logging/journald.go create mode 100644 vendor/github.com/thanos-io/thanos/pkg/query/fanout/tracker.go create mode 100644 vendor/github.com/youmark/pkcs8/.gitignore create mode 100644 vendor/github.com/youmark/pkcs8/LICENSE create mode 100644 vendor/github.com/youmark/pkcs8/README create mode 100644 vendor/github.com/youmark/pkcs8/README.md create mode 100644 vendor/github.com/youmark/pkcs8/cipher.go create mode 100644 vendor/github.com/youmark/pkcs8/cipher_3des.go create mode 100644 vendor/github.com/youmark/pkcs8/cipher_aes.go create mode 100644 vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go create mode 100644 vendor/github.com/youmark/pkcs8/kdf_scrypt.go create mode 100644 vendor/github.com/youmark/pkcs8/pkcs8.go create mode 100644 vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go create mode 100644 vendor/golang.org/x/crypto/scrypt/scrypt.go diff --git a/go.mod b/go.mod index 0d07982232b..2497c6d905b 100644 --- a/go.mod +++ b/go.mod @@ -50,8 +50,8 @@ require ( github.com/spf13/afero v1.15.0 github.com/stretchr/testify v1.11.1 github.com/thanos-io/objstore v0.0.0-20250804093838-71d60dfee488 - github.com/thanos-io/promql-engine v0.0.0-20260429105430-454f16264be9 - github.com/thanos-io/thanos v0.41.0 + github.com/thanos-io/promql-engine v0.0.0-20260513095632-c5f6038078e3 + github.com/thanos-io/thanos v0.42.0 github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/weaveworks/common v0.0.0-20230728070032-dd9e68f319d5 go.etcd.io/etcd/api/v3 v3.5.17 @@ -116,8 +116,9 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect - github.com/VictoriaMetrics/easyproto v0.1.4 // indirect + github.com/VictoriaMetrics/easyproto v1.1.3 // indirect github.com/alecthomas/kingpin/v2 v2.4.0 // indirect + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible // indirect github.com/andybalholm/brotli v1.1.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.19.25 // indirect @@ -134,11 +135,13 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.7 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.43.4 // indirect github.com/aws/smithy-go v1.27.1 // indirect + github.com/baidubce/bce-sdk-go v0.9.230 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/caio/go-tdigest v3.1.0+incompatible // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/clbanning/mxj v1.8.4 // indirect github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect github.com/coder/quartz v0.3.1 // indirect github.com/coreos/go-semver v0.3.0 // indirect @@ -180,10 +183,12 @@ require ( github.com/go-openapi/validate v0.25.2 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/gofrs/flock v0.13.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/btree v1.1.3 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20251213031049-b05bdaca462f // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect @@ -199,6 +204,7 @@ require ( github.com/hashicorp/go-version v1.9.0 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/serf v0.10.1 // indirect + github.com/huaweicloud/huaweicloud-sdk-go-obs v3.25.4+incompatible // indirect github.com/jessevdk/go-flags v1.6.1 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect @@ -222,15 +228,18 @@ require ( github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/mozillazg/go-httpheader v0.4.0 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/ncw/swift v1.0.53 // indirect github.com/oklog/run v1.2.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.142.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.142.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.142.0 // indirect + github.com/oracle/oci-go-sdk/v65 v65.93.1 // indirect github.com/parquet-go/bitpack v1.0.0 // indirect github.com/parquet-go/jsonlite v1.0.0 // indirect github.com/philhofer/fwd v1.2.0 // indirect @@ -253,6 +262,7 @@ require ( github.com/soheilhy/cmux v0.1.5 // indirect github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/stretchr/objx v0.5.2 // indirect + github.com/tencentyun/cos-go-sdk-v5 v0.7.66 // indirect github.com/tinylib/msgp v1.6.1 // indirect github.com/twmb/franz-go v1.21.2 // indirect github.com/twmb/franz-go/pkg/kmsg v1.13.1 // indirect @@ -262,6 +272,7 @@ require ( github.com/vimeo/galaxycache v1.3.1 // indirect github.com/weaveworks/promrus v1.2.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect github.com/zeebo/xxh3 v1.1.0 // indirect go.opencensus.io v0.24.0 // indirect @@ -304,7 +315,7 @@ require ( google.golang.org/api v0.257.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324 // indirect gopkg.in/ini.v1 v1.67.2 // indirect gopkg.in/telebot.v3 v3.3.8 // indirect k8s.io/apimachinery v0.34.3 // indirect diff --git a/go.sum b/go.sum index 4e235810228..6bf2223791f 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,9 @@ github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4 github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/VictoriaMetrics/easyproto v0.1.4 h1:r8cNvo8o6sR4QShBXQd1bKw/VVLSQma/V2KhTBPf+Sc= -github.com/VictoriaMetrics/easyproto v0.1.4/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo3/GThPs2KH23mv710= +github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= +github.com/VictoriaMetrics/easyproto v1.1.3 h1:gRSA3ZQs7n4+5I+SniDWD59jde1jVq4JmgQ9HUUyvk4= +github.com/VictoriaMetrics/easyproto v1.1.3/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo3/GThPs2KH23mv710= github.com/VictoriaMetrics/fastcache v1.13.3 h1:rBabE0iIxcqKEMCwUmwHZ9dgEqXerg8FRbRDUvC7OVc= github.com/VictoriaMetrics/fastcache v1.13.3/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZP/GkPY= @@ -441,6 +442,7 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -451,6 +453,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= @@ -515,6 +518,7 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -546,6 +550,7 @@ github.com/google/pprof v0.0.0-20251213031049-b05bdaca462f/go.mod h1:67FPmZWbr+K github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -789,6 +794,7 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mozillazg/go-httpheader v0.4.0 h1:aBn6aRXtFzyDLZ4VIRLsZbbJloagQfMnCiYgOq6hK4w= github.com/mozillazg/go-httpheader v0.4.0/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -944,6 +950,7 @@ github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -982,16 +989,18 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= github.com/tencentyun/cos-go-sdk-v5 v0.7.66 h1:O4O6EsozBoDjxWbltr3iULgkI7WPj/BFNlYTXDuE64E= github.com/tencentyun/cos-go-sdk-v5 v0.7.66/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0= github.com/thanos-community/galaxycache v0.0.0-20211122094458-3a32041a1f1e h1:f1Zsv7OAU9iQhZwigp50Yl38W10g/vd5NC8Rdk1Jzng= github.com/thanos-community/galaxycache v0.0.0-20211122094458-3a32041a1f1e/go.mod h1:jXcofnrSln/cLI6/dhlBxPQZEEQHVPCcFaH75M+nSzM= github.com/thanos-io/objstore v0.0.0-20250804093838-71d60dfee488 h1:khBsQLLRoF1KzXgTlwFZa6mC32bwYUUAu/AeP49V7UM= github.com/thanos-io/objstore v0.0.0-20250804093838-71d60dfee488/go.mod h1:uDHLkMKOGDAnlN75EAz8VrRzob1+VbgYSuUleatWuF0= -github.com/thanos-io/promql-engine v0.0.0-20260429105430-454f16264be9 h1:1lLMuRO2RR068rcJ1Fwl86stfd8N1o01Oa/3MTEqVuc= -github.com/thanos-io/promql-engine v0.0.0-20260429105430-454f16264be9/go.mod h1:uzn40oZHPXvfdP498h+MiRL2fN7RF519gNaV3LyhChc= -github.com/thanos-io/thanos v0.41.0 h1:GDPGynjHBa8ORAX7DfluBFjHbMeY1BzjLTGdviFvo7Q= -github.com/thanos-io/thanos v0.41.0/go.mod h1:ppdHafpAT8WAbcwgLiNU4jNtNe17Ct3xX9dXq+h6g2k= +github.com/thanos-io/promql-engine v0.0.0-20260513095632-c5f6038078e3 h1:vO9SBpSzzp7jlDaWqJ34Y7zumD5OrPTcCZcWgDgzC6M= +github.com/thanos-io/promql-engine v0.0.0-20260513095632-c5f6038078e3/go.mod h1:uzn40oZHPXvfdP498h+MiRL2fN7RF519gNaV3LyhChc= +github.com/thanos-io/thanos v0.42.0 h1:9d+cAEq/lCuhQY6VK3FzxFmXhE/1Qy0Gv45xSYn1EAM= +github.com/thanos-io/thanos v0.42.0/go.mod h1:9BZsUdHl3x8L/zTrc9+kCEupUHglPi6ldBZvHLj1q6o= github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY= github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tjhop/slog-gokit v0.2.0 h1:tUNkuukDjpswQ2abhsugEobRRxN1aHEW8h4rvwdHMqU= @@ -1028,6 +1037,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= @@ -1172,8 +1182,11 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1213,6 +1226,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1263,6 +1278,10 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1299,6 +1318,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1382,12 +1403,21 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1399,6 +1429,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1462,6 +1495,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1604,8 +1639,8 @@ google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuO google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324 h1:9HZDLIdYBJXAnaFOr9WHrKVycfpY+75s9HGadC0305A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= diff --git a/vendor/github.com/VictoriaMetrics/easyproto/reader.go b/vendor/github.com/VictoriaMetrics/easyproto/reader.go index c525c1f17af..ea77038f58c 100644 --- a/vendor/github.com/VictoriaMetrics/easyproto/reader.go +++ b/vendor/github.com/VictoriaMetrics/easyproto/reader.go @@ -155,6 +155,21 @@ const ( wireTypeI32 = wireType(5) ) +func (wt wireType) String() string { + switch wt { + case wireTypeVarint: + return "varint" + case wireTypeI64: + return "i64" + case wireTypeLen: + return "len" + case wireTypeI32: + return "i32" + default: + return fmt.Sprintf("unknown (%d)", int(wt)) + } +} + // Int32 returns int32 value for fc. // // False is returned if fc doesn't contain int32 value. @@ -231,6 +246,16 @@ func (fc *FieldContext) Bool() (bool, bool) { return getBool(fc.intValue) } +// Enum returns enum value for fc. +// +// False is returned if fc doesn't contain enum value. +func (fc *FieldContext) Enum() (int32, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + return getInt32(fc.intValue) +} + // Fixed64 returns fixed64 value for fc. // // False is returned if fc doesn't contain fixed64 value. @@ -688,6 +713,360 @@ func (fc *FieldContext) UnpackFloats(dst []float32) ([]float32, bool) { return dst, true } +func (fc *FieldContext) getField(src []byte, fieldNum uint32, neededWireType wireType) (bool, error) { + for len(src) > 0 { + var err error + src, err = fc.NextField(src) + if err != nil { + return false, fmt.Errorf("cannot read the next field: %w", err) + } + if fc.FieldNum != fieldNum { + continue + } + if fc.wireType != neededWireType { + return false, fmt.Errorf("fieldNum=%d contains unexpected wireType; got %s; want %s", fieldNum, fc.wireType, neededWireType) + } + return true, nil + } + return false, nil +} + +// GetInt32 returns the int32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetInt32(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n, ok = getInt32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to int32", fieldNum, fc.intValue) + } + return n, true, nil +} + +// GetInt64 returns the int64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetInt64(src []byte, fieldNum uint32) (n int64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return int64(fc.intValue), true, nil +} + +// GetUint32 returns the uint32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetUint32(src []byte, fieldNum uint32) (n uint32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n, ok = getUint32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to uint32", fieldNum, fc.intValue) + } + return n, true, nil +} + +// GetUint64 returns the int64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetUint64(src []byte, fieldNum uint32) (n uint64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return fc.intValue, true, nil +} + +// GetSint32 returns sint32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSint32(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + u32, ok := getUint32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to uint32", fieldNum, fc.intValue) + } + n = decodeZigZagInt32(u32) + return n, true, nil +} + +// GetSint64 returns sint64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSint64(src []byte, fieldNum uint32) (n int64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n = decodeZigZagInt64(fc.intValue) + return n, true, nil +} + +// GetBool returns bool value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetBool(src []byte, fieldNum uint32) (b bool, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return false, false, err + } + if !ok { + return false, false, nil + } + b, ok = getBool(fc.intValue) + if !ok { + return false, false, fmt.Errorf("fieldNum=%d contains invalid integer %d, which cannot be converted to bool", fieldNum, fc.intValue) + } + return b, true, nil +} + +// GetEnum returns enum value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetEnum(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n, ok = getInt32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains invalid integer %d, which cannot be converted to enum", fieldNum, fc.intValue) + } + return n, true, nil +} + +// GetFixed64 returns fixed64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetFixed64(src []byte, fieldNum uint32) (n uint64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI64) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return fc.intValue, true, nil +} + +// GetSfixed64 returns sfixed64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSfixed64(src []byte, fieldNum uint32) (n int64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI64) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return int64(fc.intValue), true, nil +} + +// GetDouble returns double value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetDouble(src []byte, fieldNum uint32) (f float64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI64) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + f = math.Float64frombits(fc.intValue) + return f, true, nil +} + +// GetString returns string value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// The returned string is valid until src is changed. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetString(src []byte, fieldNum uint32) (s string, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeLen) + if err != nil { + return "", false, err + } + if !ok { + return "", false, nil + } + return unsafeBytesToString(fc.data), true, nil +} + +// GetBytes returns bytes slice for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// The returned bytes slice is valid until src is changed. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetBytes(src []byte, fieldNum uint32) (b []byte, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeLen) + if err != nil { + return nil, false, err + } + if !ok { + return nil, false, nil + } + return fc.data, true, nil +} + +// GetMessageData returns message data for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// The returned message data is valid until src is changed. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetMessageData(src []byte, fieldNum uint32) (data []byte, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeLen) + if err != nil { + return nil, false, err + } + if !ok { + return nil, false, nil + } + return fc.data, true, nil +} + +// GetFixed32 returns fixed32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetFixed32(src []byte, fieldNum uint32) (n uint32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI32) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n = mustGetUint32(fc.intValue) + return n, true, nil +} + +// GetSfixed32 returns sfixed32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSfixed32(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI32) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n = mustGetInt32(fc.intValue) + return n, true, nil +} + +// GetFloat returns float32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetFloat(src []byte, fieldNum uint32) (f float32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI32) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + u32 := mustGetUint32(fc.intValue) + f = math.Float32frombits(u32) + return f, true, nil +} + func decodeZigZagInt64(u64 uint64) int64 { return int64(u64>>1) ^ (int64(u64<<63) >> 63) } diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/LICENSE b/vendor/github.com/aliyun/aliyun-oss-go-sdk/LICENSE new file mode 100644 index 00000000000..d46e9d128cd --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2015 aliyun.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go new file mode 100644 index 00000000000..2eccf316310 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go @@ -0,0 +1,339 @@ +package oss + +import ( + "bytes" + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "fmt" + "hash" + "io" + "net/http" + "sort" + "strconv" + "strings" + "time" +) + +// headerSorter defines the key-value structure for storing the sorted data in signHeader. +type headerSorter struct { + Keys []string + Vals []string +} + +// getAdditionalHeaderKeys get exist key in http header +func (conn Conn) getAdditionalHeaderKeys(req *http.Request) ([]string, map[string]string) { + var keysList []string + keysMap := make(map[string]string) + srcKeys := make(map[string]string) + + for k := range req.Header { + srcKeys[strings.ToLower(k)] = "" + } + + for _, v := range conn.config.AdditionalHeaders { + if _, ok := srcKeys[strings.ToLower(v)]; ok { + keysMap[strings.ToLower(v)] = "" + } + } + + for k := range keysMap { + keysList = append(keysList, k) + } + sort.Strings(keysList) + return keysList, keysMap +} + +// getAdditionalHeaderKeysV4 get exist key in http header +func (conn Conn) getAdditionalHeaderKeysV4(req *http.Request) ([]string, map[string]string) { + var keysList []string + keysMap := make(map[string]string) + srcKeys := make(map[string]string) + + for k := range req.Header { + srcKeys[strings.ToLower(k)] = "" + } + + for _, v := range conn.config.AdditionalHeaders { + if _, ok := srcKeys[strings.ToLower(v)]; ok { + if !strings.EqualFold(v, HTTPHeaderContentMD5) && !strings.EqualFold(v, HTTPHeaderContentType) { + keysMap[strings.ToLower(v)] = "" + } + } + } + + for k := range keysMap { + keysList = append(keysList, k) + } + sort.Strings(keysList) + return keysList, keysMap +} + +// signHeader signs the header and sets it as the authorization header. +func (conn Conn) signHeader(req *http.Request, canonicalizedResource string, credentials Credentials) { + akIf := credentials + authorizationStr := "" + if conn.config.AuthVersion == AuthV4 { + strDay := "" + strDate := req.Header.Get(HttpHeaderOssDate) + if strDate == "" { + strDate = req.Header.Get(HTTPHeaderDate) + t, _ := time.Parse(http.TimeFormat, strDate) + strDay = t.Format("20060102") + } else { + t, _ := time.Parse(timeFormatV4, strDate) + strDay = t.Format("20060102") + } + signHeaderProduct := conn.config.GetSignProduct() + signHeaderRegion := conn.config.GetSignRegion() + + additionalList, _ := conn.getAdditionalHeaderKeysV4(req) + if len(additionalList) > 0 { + authorizationFmt := "OSS4-HMAC-SHA256 Credential=%v/%v/%v/" + signHeaderProduct + "/aliyun_v4_request,AdditionalHeaders=%v,Signature=%v" + additionnalHeadersStr := strings.Join(additionalList, ";") + authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), strDay, signHeaderRegion, additionnalHeadersStr, conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), nil)) + } else { + authorizationFmt := "OSS4-HMAC-SHA256 Credential=%v/%v/%v/" + signHeaderProduct + "/aliyun_v4_request,Signature=%v" + authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), strDay, signHeaderRegion, conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), nil)) + } + } else if conn.config.AuthVersion == AuthV2 { + additionalList, _ := conn.getAdditionalHeaderKeys(req) + if len(additionalList) > 0 { + authorizationFmt := "OSS2 AccessKeyId:%v,AdditionalHeaders:%v,Signature:%v" + additionnalHeadersStr := strings.Join(additionalList, ";") + authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), additionnalHeadersStr, conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret())) + } else { + authorizationFmt := "OSS2 AccessKeyId:%v,Signature:%v" + authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret())) + } + } else { + // Get the final authorization string + authorizationStr = "OSS " + akIf.GetAccessKeyID() + ":" + conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()) + } + + // Give the parameter "Authorization" value + req.Header.Set(HTTPHeaderAuthorization, authorizationStr) +} + +func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string, keySecret string) string { + // Find out the "x-oss-"'s address in header of the request + ossHeadersMap := make(map[string]string) + additionalList, additionalMap := conn.getAdditionalHeaderKeys(req) + for k, v := range req.Header { + if strings.HasPrefix(strings.ToLower(k), "x-oss-") { + ossHeadersMap[strings.ToLower(k)] = v[0] + } else if conn.config.AuthVersion == AuthV2 { + if _, ok := additionalMap[strings.ToLower(k)]; ok { + ossHeadersMap[strings.ToLower(k)] = v[0] + } + } + } + hs := newHeaderSorter(ossHeadersMap) + + // Sort the ossHeadersMap by the ascending order + hs.Sort() + + // Get the canonicalizedOSSHeaders + canonicalizedOSSHeaders := "" + for i := range hs.Keys { + canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" + } + + // Give other parameters values + // when sign URL, date is expires + date := req.Header.Get(HTTPHeaderDate) + contentType := req.Header.Get(HTTPHeaderContentType) + contentMd5 := req.Header.Get(HTTPHeaderContentMD5) + + // default is v1 signature + signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource + h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret)) + + // v2 signature + if conn.config.AuthVersion == AuthV2 { + signStr = req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + strings.Join(additionalList, ";") + "\n" + canonicalizedResource + h = hmac.New(func() hash.Hash { return sha256.New() }, []byte(keySecret)) + } + + if conn.config.LogLevel >= Debug { + conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, EscapeLFString(signStr)) + } + + io.WriteString(h, signStr) + signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) + + return signedStr +} + +func (conn Conn) getSignedStrV4(req *http.Request, canonicalizedResource string, keySecret string, signingTime *time.Time) string { + // Find out the "x-oss-"'s address in header of the request + ossHeadersMap := make(map[string]string) + additionalList, additionalMap := conn.getAdditionalHeaderKeysV4(req) + for k, v := range req.Header { + lowKey := strings.ToLower(k) + if strings.EqualFold(lowKey, HTTPHeaderContentMD5) || + strings.EqualFold(lowKey, HTTPHeaderContentType) || + strings.HasPrefix(lowKey, "x-oss-") { + ossHeadersMap[lowKey] = strings.Trim(v[0], " ") + } else { + if _, ok := additionalMap[lowKey]; ok { + ossHeadersMap[lowKey] = strings.Trim(v[0], " ") + } + } + } + + // get day,eg 20210914 + //signingTime + signDate := "" + strDay := "" + if signingTime != nil { + signDate = signingTime.Format(timeFormatV4) + strDay = signingTime.Format(shortTimeFormatV4) + } else { + var t time.Time + // Required parameters + if date := req.Header.Get(HTTPHeaderDate); date != "" { + signDate = date + t, _ = time.Parse(http.TimeFormat, date) + } + + if ossDate := req.Header.Get(HttpHeaderOssDate); ossDate != "" { + signDate = ossDate + t, _ = time.Parse(timeFormatV4, ossDate) + } + + strDay = t.Format("20060102") + } + + hs := newHeaderSorter(ossHeadersMap) + + // Sort the ossHeadersMap by the ascending order + hs.Sort() + + // Get the canonicalizedOSSHeaders + canonicalizedOSSHeaders := "" + for i := range hs.Keys { + canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" + } + + signStr := "" + + // v4 signature + hashedPayload := DefaultContentSha256 + if val := req.Header.Get(HttpHeaderOssContentSha256); val != "" { + hashedPayload = val + } + + // subResource + resource := canonicalizedResource + subResource := "" + subPos := strings.LastIndex(canonicalizedResource, "?") + if subPos != -1 { + subResource = canonicalizedResource[subPos+1:] + resource = canonicalizedResource[0:subPos] + } + + // get canonical request + canonicalReuqest := req.Method + "\n" + resource + "\n" + subResource + "\n" + canonicalizedOSSHeaders + "\n" + strings.Join(additionalList, ";") + "\n" + hashedPayload + rh := sha256.New() + io.WriteString(rh, canonicalReuqest) + hashedRequest := hex.EncodeToString(rh.Sum(nil)) + + if conn.config.LogLevel >= Debug { + conn.config.WriteLog(Debug, "[Req:%p]CanonicalRequest:%s\n", req, EscapeLFString(canonicalReuqest)) + } + + // Product & Region + signedStrV4Product := conn.config.GetSignProduct() + signedStrV4Region := conn.config.GetSignRegion() + + signStr = "OSS4-HMAC-SHA256" + "\n" + signDate + "\n" + strDay + "/" + signedStrV4Region + "/" + signedStrV4Product + "/aliyun_v4_request" + "\n" + hashedRequest + if conn.config.LogLevel >= Debug { + conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, EscapeLFString(signStr)) + } + + h1 := hmac.New(func() hash.Hash { return sha256.New() }, []byte("aliyun_v4"+keySecret)) + io.WriteString(h1, strDay) + h1Key := h1.Sum(nil) + + h2 := hmac.New(func() hash.Hash { return sha256.New() }, h1Key) + io.WriteString(h2, signedStrV4Region) + h2Key := h2.Sum(nil) + + h3 := hmac.New(func() hash.Hash { return sha256.New() }, h2Key) + io.WriteString(h3, signedStrV4Product) + h3Key := h3.Sum(nil) + + h4 := hmac.New(func() hash.Hash { return sha256.New() }, h3Key) + io.WriteString(h4, "aliyun_v4_request") + h4Key := h4.Sum(nil) + + h := hmac.New(func() hash.Hash { return sha256.New() }, h4Key) + io.WriteString(h, signStr) + return fmt.Sprintf("%x", h.Sum(nil)) +} + +func (conn Conn) getRtmpSignedStr(bucketName, channelName, playlistName string, expiration int64, keySecret string, params map[string]interface{}) string { + if params[HTTPParamAccessKeyID] == nil { + return "" + } + + canonResource := fmt.Sprintf("/%s/%s", bucketName, channelName) + canonParamsKeys := []string{} + for key := range params { + if key != HTTPParamAccessKeyID && key != HTTPParamSignature && key != HTTPParamExpires && key != HTTPParamSecurityToken { + canonParamsKeys = append(canonParamsKeys, key) + } + } + + sort.Strings(canonParamsKeys) + canonParamsStr := "" + for _, key := range canonParamsKeys { + canonParamsStr = fmt.Sprintf("%s%s:%s\n", canonParamsStr, key, params[key].(string)) + } + + expireStr := strconv.FormatInt(expiration, 10) + signStr := expireStr + "\n" + canonParamsStr + canonResource + + h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret)) + io.WriteString(h, signStr) + signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) + return signedStr +} + +// newHeaderSorter is an additional function for function SignHeader. +func newHeaderSorter(m map[string]string) *headerSorter { + hs := &headerSorter{ + Keys: make([]string, 0, len(m)), + Vals: make([]string, 0, len(m)), + } + + for k, v := range m { + hs.Keys = append(hs.Keys, k) + hs.Vals = append(hs.Vals, v) + } + return hs +} + +// Sort is an additional function for function SignHeader. +func (hs *headerSorter) Sort() { + sort.Sort(hs) +} + +// Len is an additional function for function SignHeader. +func (hs *headerSorter) Len() int { + return len(hs.Vals) +} + +// Less is an additional function for function SignHeader. +func (hs *headerSorter) Less(i, j int) bool { + return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0 +} + +// Swap is an additional function for function SignHeader. +func (hs *headerSorter) Swap(i, j int) { + hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i] + hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i] +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go new file mode 100644 index 00000000000..26dea3bb202 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go @@ -0,0 +1,1321 @@ +package oss + +import ( + "bytes" + "context" + "crypto/md5" + "encoding/base64" + "encoding/xml" + "fmt" + "hash" + "hash/crc64" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "strconv" + "strings" + "time" +) + +// Bucket implements the operations of object. +type Bucket struct { + Client Client + BucketName string +} + +// PutObject creates a new object and it will overwrite the original one if it exists already. +// +// objectKey the object key in UTF-8 encoding. The length must be between 1 and 1023, and cannot start with "/" or "\". +// reader io.Reader instance for reading the data for uploading +// options the options for uploading the object. The valid options here are CacheControl, ContentDisposition, ContentEncoding +// +// Expires, ServerSideEncryption, ObjectACL and Meta. Refer to the link below for more details. +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Option) error { + opts := AddContentType(options, objectKey) + + request := &PutObjectRequest{ + ObjectKey: objectKey, + Reader: reader, + } + resp, err := bucket.DoPutObject(request, opts) + if err != nil { + return err + } + defer resp.Body.Close() + + return err +} + +// PutObjectFromFile creates a new object from the local file. +// +// objectKey object key. +// filePath the local file path to upload. +// options the options for uploading the object. Refer to the parameter options in PutObject for more details. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Option) error { + fd, err := os.Open(filePath) + if err != nil { + return err + } + defer fd.Close() + + opts := AddContentType(options, filePath, objectKey) + + request := &PutObjectRequest{ + ObjectKey: objectKey, + Reader: fd, + } + resp, err := bucket.DoPutObject(request, opts) + if err != nil { + return err + } + defer resp.Body.Close() + + return err +} + +// DoPutObject does the actual upload work. +// +// request the request instance for uploading an object. +// options the options for uploading an object. +// +// Response the response from OSS. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) { + isOptSet, _, _ := IsOptionSet(options, HTTPHeaderContentType) + if !isOptSet { + options = AddContentType(options, request.ObjectKey) + } + + listener := GetProgressListener(options) + + params := map[string]interface{}{} + resp, err := bucket.do("PUT", request.ObjectKey, params, options, request.Reader, listener) + if err != nil { + return nil, err + } + if bucket.GetConfig().IsEnableCRC { + err = CheckCRC(resp, "DoPutObject") + if err != nil { + return resp, err + } + } + err = CheckRespCode(resp.StatusCode, []int{http.StatusOK}) + body, _ := ioutil.ReadAll(resp.Body) + if len(body) > 0 { + if err != nil { + err = tryConvertServiceError(body, resp, err) + } else { + rb, _ := FindOption(options, responseBody, nil) + if rb != nil { + if rbody, ok := rb.(*[]byte); ok { + *rbody = body + } + } + } + } + return resp, err +} + +// GetObject downloads the object. +// +// objectKey the object key. +// options the options for downloading the object. The valid values are: Range, IfModifiedSince, IfUnmodifiedSince, IfMatch, +// +// IfNoneMatch, AcceptEncoding. For more details, please check out: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject +// +// io.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) { + result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options) + if err != nil { + return nil, err + } + + return result.Response, nil +} + +// GetObjectToFile downloads the data to a local file. +// +// objectKey the object key to download. +// filePath the local file to store the object data. +// options the options for downloading the object. Refer to the parameter options in method GetObject for more details. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error { + tempFilePath := filePath + TempFileSuffix + + // Calls the API to actually download the object. Returns the result instance. + result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options) + if err != nil { + return err + } + defer result.Response.Close() + + // If the local file does not exist, create a new one. If it exists, overwrite it. + fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode) + if err != nil { + return err + } + + // Copy the data to the local file path. + _, err = io.Copy(fd, result.Response.Body) + fd.Close() + if err != nil { + return err + } + + // Compares the CRC value + hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange) + encodeOpt, _ := FindOption(options, HTTPHeaderAcceptEncoding, nil) + acceptEncoding := "" + if encodeOpt != nil { + acceptEncoding = encodeOpt.(string) + } + if bucket.GetConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" { + result.Response.ClientCRC = result.ClientCRC.Sum64() + err = CheckCRC(result.Response, "GetObjectToFile") + if err != nil { + os.Remove(tempFilePath) + return err + } + } + + return os.Rename(tempFilePath, filePath) +} + +// DoGetObject is the actual API that gets the object. It's the internal function called by other public APIs. +// +// request the request to download the object. +// options the options for downloading the file. Checks out the parameter options in method GetObject. +// +// GetObjectResult the result instance of getting the object. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) { + params, _ := GetRawParams(options) + resp, err := bucket.do("GET", request.ObjectKey, params, options, nil, nil) + if err != nil { + return nil, err + } + + result := &GetObjectResult{ + Response: resp, + } + + // CRC + var crcCalc hash.Hash64 + hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange) + if bucket.GetConfig().IsEnableCRC && !hasRange { + crcCalc = crc64.New(CrcTable()) + result.ServerCRC = resp.ServerCRC + result.ClientCRC = crcCalc + } + + // Progress + listener := GetProgressListener(options) + + contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64) + resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil) + + return result, nil +} + +// CopyObject copies the object inside the bucket. +// +// srcObjectKey the source object to copy. +// destObjectKey the target object to copy. +// options options for copying an object. You can specify the conditions of copy. The valid conditions are CopySourceIfMatch, +// +// CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective. +// Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires, +// ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details : +// https://www.alibabacloud.com/help/en/object-storage-service/latest/copyobject +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) { + var out CopyObjectResult + + //first find version id + versionIdKey := "versionId" + versionId, _ := FindOption(options, versionIdKey, nil) + if versionId == nil { + options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey))) + } else { + options = DeleteOption(options, versionIdKey) + options = append(options, CopySourceVersion(bucket.BucketName, url.QueryEscape(srcObjectKey), versionId.(string))) + } + + params := map[string]interface{}{} + resp, err := bucket.do("PUT", destObjectKey, params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// CopyObjectTo copies the object to another bucket. +// +// srcObjectKey source object key. The source bucket is Bucket.BucketName . +// destBucketName target bucket name. +// destObjectKey target object name. +// options copy options, check out parameter options in function CopyObject for more details. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey string, options ...Option) (CopyObjectResult, error) { + return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...) +} + +// CopyObjectFrom copies the object to another bucket. +// +// srcBucketName source bucket name. +// srcObjectKey source object name. +// destObjectKey target object name. The target bucket name is Bucket.BucketName. +// options copy options. Check out parameter options in function CopyObject. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) CopyObjectFrom(srcBucketName, srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) { + destBucketName := bucket.BucketName + var out CopyObjectResult + srcBucket, err := bucket.Client.Bucket(srcBucketName) + if err != nil { + return out, err + } + + return srcBucket.copy(srcObjectKey, destBucketName, destObjectKey, options...) +} + +func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, options ...Option) (CopyObjectResult, error) { + var out CopyObjectResult + + //first find version id + versionIdKey := "versionId" + versionId, _ := FindOption(options, versionIdKey, nil) + if versionId == nil { + options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey))) + } else { + options = DeleteOption(options, versionIdKey) + options = append(options, CopySourceVersion(bucket.BucketName, url.QueryEscape(srcObjectKey), versionId.(string))) + } + + headers := make(map[string]string) + err := handleOptions(headers, options) + if err != nil { + return out, err + } + params := map[string]interface{}{} + + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoWithContext(ctx, "PUT", destBucketName, destObjectKey, params, headers, nil, 0, nil) + + // get response header + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + pRespHeader := respHeader.(*http.Header) + if resp != nil { + *pRespHeader = resp.Headers + } + } + + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// AppendObject uploads the data in the way of appending an existing or new object. +// +// AppendObject the parameter appendPosition specifies which postion (in the target object) to append. For the first append (to a non-existing file), +// the appendPosition should be 0. The appendPosition in the subsequent calls will be the current object length. +// For example, the first appendObject's appendPosition is 0 and it uploaded 65536 bytes data, then the second call's position is 65536. +// The response header x-oss-next-append-position after each successful request also specifies the next call's append position (so the caller need not to maintain this information). +// +// objectKey the target object to append to. +// reader io.Reader. The read instance for reading the data to append. +// appendPosition the start position to append. +// destObjectProperties the options for the first appending, such as CacheControl, ContentDisposition, ContentEncoding, +// +// Expires, ServerSideEncryption, ObjectACL. +// +// int64 the next append position, it's valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosition int64, options ...Option) (int64, error) { + request := &AppendObjectRequest{ + ObjectKey: objectKey, + Reader: reader, + Position: appendPosition, + } + + result, err := bucket.DoAppendObject(request, options) + if err != nil { + return appendPosition, err + } + + return result.NextPosition, err +} + +// DoAppendObject is the actual API that does the object append. +// +// request the request object for appending object. +// options the options for appending object. +// +// AppendObjectResult the result object for appending object. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) { + params := map[string]interface{}{} + params["append"] = nil + params["position"] = strconv.FormatInt(request.Position, 10) + headers := make(map[string]string) + + opts := AddContentType(options, request.ObjectKey) + handleOptions(headers, opts) + + var initCRC uint64 + isCRCSet, initCRCOpt, _ := IsOptionSet(options, initCRC64) + if isCRCSet { + initCRC = initCRCOpt.(uint64) + } + + listener := GetProgressListener(options) + + handleOptions(headers, opts) + + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoWithContext(ctx, "POST", bucket.BucketName, request.ObjectKey, params, headers, + request.Reader, initCRC, listener) + + // get response header + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + pRespHeader := respHeader.(*http.Header) + if resp != nil { + *pRespHeader = resp.Headers + } + } + + if err != nil { + return nil, err + } + defer resp.Body.Close() + + nextPosition, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderOssNextAppendPosition), 10, 64) + result := &AppendObjectResult{ + NextPosition: nextPosition, + CRC: resp.ServerCRC, + } + + if bucket.GetConfig().IsEnableCRC && isCRCSet { + err = CheckCRC(resp, "AppendObject") + if err != nil { + return result, err + } + } + + return result, nil +} + +// DeleteObject deletes the object. +// +// objectKey the object key to delete. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error { + params, _ := GetRawParams(options) + resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// DeleteObjects deletes multiple objects. +// +// objectKeys the object keys to delete. +// options the options for deleting objects. +// +// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. +// +// DeleteObjectsResult the result object. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) { + out := DeleteObjectsResult{} + dxml := deleteXML{} + for _, key := range objectKeys { + dxml.Objects = append(dxml.Objects, DeleteObject{Key: key}) + } + isQuiet, _ := FindOption(options, deleteObjectsQuiet, false) + dxml.Quiet = isQuiet.(bool) + xmlData := marshalDeleteObjectToXml(dxml) + body, err := bucket.DeleteMultipleObjectsXml(xmlData, options...) + if err != nil { + return out, err + } + deletedResult := DeleteObjectVersionsResult{} + if !dxml.Quiet { + if err = xmlUnmarshal(strings.NewReader(body), &deletedResult); err == nil { + err = decodeDeleteObjectsResult(&deletedResult) + } + } + // Keep compatibility:need convert to struct DeleteObjectsResult + out.XMLName = deletedResult.XMLName + for _, v := range deletedResult.DeletedObjectsDetail { + out.DeletedObjects = append(out.DeletedObjects, v.Key) + } + return out, err +} + +// DeleteObjectVersions deletes multiple object versions. +// +// objectVersions the object keys and versions to delete. +// options the options for deleting objects. +// +// Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used. +// +// DeleteObjectVersionsResult the result object. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options ...Option) (DeleteObjectVersionsResult, error) { + out := DeleteObjectVersionsResult{} + dxml := deleteXML{} + dxml.Objects = objectVersions + isQuiet, _ := FindOption(options, deleteObjectsQuiet, false) + dxml.Quiet = isQuiet.(bool) + xmlData := marshalDeleteObjectToXml(dxml) + body, err := bucket.DeleteMultipleObjectsXml(xmlData, options...) + if err != nil { + return out, err + } + if !dxml.Quiet { + if err = xmlUnmarshal(strings.NewReader(body), &out); err == nil { + err = decodeDeleteObjectsResult(&out) + } + } + return out, err +} + +// DeleteMultipleObjectsXml deletes multiple object or deletes multiple object versions. +// +// xmlData the object keys and versions to delete as the xml format. +// options the options for deleting objects. +// +// string the result response body. +// error it's nil if no error, otherwise it's an error. +func (bucket Bucket) DeleteMultipleObjectsXml(xmlData string, options ...Option) (string, error) { + buffer := new(bytes.Buffer) + bs := []byte(xmlData) + buffer.Write(bs) + options = append(options, ContentType("application/xml")) + sum := md5.Sum(bs) + b64 := base64.StdEncoding.EncodeToString(sum[:]) + options = append(options, ContentMD5(b64)) + params := map[string]interface{}{} + params["delete"] = nil + params["encoding-type"] = "url" + resp, err := bucket.doInner("POST", "", params, options, buffer, nil) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// IsObjectExist checks if the object exists. +// +// bool flag of object's existence (true:exists; false:non-exist) when error is nil. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, error) { + _, err := bucket.GetObjectMeta(objectKey, options...) + if err == nil { + return true, nil + } + + switch err.(type) { + case ServiceError: + if err.(ServiceError).StatusCode == 404 { + return false, nil + } + } + + return false, err +} + +// ListObjects lists the objects under the current bucket. +// +// options it contains all the filters for listing objects. +// +// It could specify a prefix filter on object keys, the max keys count to return and the object key marker and the delimiter for grouping object names. +// The key marker means the returned objects' key must be greater than it in lexicographic order. +// +// For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21, +// my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns +// my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns +// my-object-3, my-object-31, my-object-32 three objects. If the max keys is 5, then it returns 5 objects. +// The three filters could be used together to achieve filter and paging functionality. +// If the prefix is the folder name, then it could list all files under this folder (including the files under its subfolders). +// But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties. +// For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects. +// But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix. +// +// For common usage scenario, check out sample/list_object.go. +// +// ListObjectsResult the return value after operation succeeds (only valid when error is nil). +func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) { + var out ListObjectsResult + + options = append(options, EncodingType("url")) + params, err := GetRawParams(options) + if err != nil { + return out, err + } + + resp, err := bucket.doInner("GET", "", params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + if err != nil { + return out, err + } + + err = decodeListObjectsResult(&out) + return out, err +} + +// ListObjectsV2 lists the objects under the current bucket. +// Recommend to use ListObjectsV2 to replace ListObjects +// ListObjectsResultV2 the return value after operation succeeds (only valid when error is nil). +func (bucket Bucket) ListObjectsV2(options ...Option) (ListObjectsResultV2, error) { + var out ListObjectsResultV2 + + options = append(options, EncodingType("url")) + options = append(options, ListType(2)) + params, err := GetRawParams(options) + if err != nil { + return out, err + } + + resp, err := bucket.doInner("GET", "", params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + if err != nil { + return out, err + } + + err = decodeListObjectsResultV2(&out) + return out, err +} + +// ListObjectVersions lists objects of all versions under the current bucket. +func (bucket Bucket) ListObjectVersions(options ...Option) (ListObjectVersionsResult, error) { + var out ListObjectVersionsResult + + options = append(options, EncodingType("url")) + params, err := GetRawParams(options) + if err != nil { + return out, err + } + params["versions"] = nil + + resp, err := bucket.doInner("GET", "", params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + if err != nil { + return out, err + } + + err = decodeListObjectVersionsResult(&out) + return out, err +} + +// SetObjectMeta sets the metadata of the Object. +// +// objectKey object +// options options for setting the metadata. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires, +// +// ServerSideEncryption, and custom metadata. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error { + options = append(options, MetadataDirective(MetaReplace)) + _, err := bucket.CopyObject(objectKey, objectKey, options...) + return err +} + +// GetObjectDetailedMeta gets the object's detailed metadata +// +// objectKey object key. +// options the constraints of the object. Only when the object meets the requirements this method will return the metadata. Otherwise returns error. Valid options are IfModifiedSince, IfUnmodifiedSince, +// +// IfMatch, IfNoneMatch. For more details check out https://www.alibabacloud.com/help/en/object-storage-service/latest/headobject +// +// http.Header object meta when error is nil. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) { + params, _ := GetRawParams(options) + resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return resp.Headers, nil +} + +// GetObjectMeta gets object metadata. +// +// GetObjectMeta is more lightweight than GetObjectDetailedMeta as it only returns basic metadata including ETag +// size, LastModified. The size information is in the HTTP header Content-Length. +// +// objectKey object key +// +// http.Header the object's metadata, valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) { + params, _ := GetRawParams(options) + params["objectMeta"] = nil + //resp, err := bucket.do("GET", objectKey, "?objectMeta", "", nil, nil, nil) + resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return resp.Headers, nil +} + +// SetObjectACL updates the object's ACL. +// +// Only the bucket's owner could update object's ACL which priority is higher than bucket's ACL. +// For example, if the bucket ACL is private and object's ACL is public-read-write. +// Then object's ACL is used and it means all users could read or write that object. +// When the object's ACL is not set, then bucket's ACL is used as the object's ACL. +// +// Object read operations include GetObject, HeadObject, CopyObject and UploadPartCopy on the source object; +// Object write operations include PutObject, PostObject, AppendObject, DeleteObject, DeleteMultipleObjects, +// CompleteMultipartUpload and CopyObject on target object. +// +// objectKey the target object key (to set the ACL on) +// objectAcl object ACL. Valid options are PrivateACL, PublicReadACL, PublicReadWriteACL. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options ...Option) error { + options = append(options, ObjectACL(objectACL)) + params, _ := GetRawParams(options) + params["acl"] = nil + resp, err := bucket.do("PUT", objectKey, params, options, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetObjectACL gets object's ACL +// +// objectKey the object to get ACL from. +// +// GetObjectACLResult the result object when error is nil. GetObjectACLResult.Acl is the object ACL. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjectACLResult, error) { + var out GetObjectACLResult + params, _ := GetRawParams(options) + params["acl"] = nil + resp, err := bucket.do("GET", objectKey, params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// PutSymlink creates a symlink (to point to an existing object) +// +// Symlink cannot point to another symlink. +// When creating a symlink, it does not check the existence of the target file, and does not check if the target file is symlink. +// Neither it checks the caller's permission on the target file. All these checks are deferred to the actual GetObject call via this symlink. +// If trying to add an existing file, as long as the caller has the write permission, the existing one will be overwritten. +// If the x-oss-meta- is specified, it will be added as the metadata of the symlink file. +// +// symObjectKey the symlink object's key. +// targetObjectKey the target object key to point to. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error { + options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey))) + params, _ := GetRawParams(options) + params["symlink"] = nil + resp, err := bucket.do("PUT", symObjectKey, params, options, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetSymlink gets the symlink object with the specified key. +// If the symlink object does not exist, returns 404. +// +// objectKey the symlink object's key. +// +// error it's nil if no error, otherwise it's an error object. +// +// When error is nil, the target file key is in the X-Oss-Symlink-Target header of the returned object. +func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Header, error) { + params, _ := GetRawParams(options) + params["symlink"] = nil + resp, err := bucket.do("GET", objectKey, params, options, nil, nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + targetObjectKey := resp.Headers.Get(HTTPHeaderOssSymlinkTarget) + targetObjectKey, err = url.QueryUnescape(targetObjectKey) + if err != nil { + return resp.Headers, err + } + resp.Headers.Set(HTTPHeaderOssSymlinkTarget, targetObjectKey) + return resp.Headers, err +} + +// RestoreObject restores the object from the archive storage. +// +// An archive object is in cold status by default and it cannot be accessed. +// When restore is called on the cold object, it will become available for access after some time. +// If multiple restores are called on the same file when the object is being restored, server side does nothing for additional calls but returns success. +// By default, the restored object is available for access for one day. After that it will be unavailable again. +// But if another RestoreObject are called after the file is restored, then it will extend one day's access time of that object, up to 7 days. +// +// objectKey object key to restore. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) RestoreObject(objectKey string, options ...Option) error { + params, _ := GetRawParams(options) + params["restore"] = nil + resp, err := bucket.do("POST", objectKey, params, options, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted}) +} + +// RestoreObjectDetail support more features than RestoreObject +func (bucket Bucket) RestoreObjectDetail(objectKey string, restoreConfig RestoreConfiguration, options ...Option) error { + if restoreConfig.Tier == "" { + // Expedited, Standard, Bulk + restoreConfig.Tier = string(RestoreStandard) + } + + if restoreConfig.Days == 0 { + restoreConfig.Days = 1 + } + + bs, err := xml.Marshal(restoreConfig) + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + options = append(options, ContentType(contentType)) + + params, _ := GetRawParams(options) + params["restore"] = nil + + resp, err := bucket.do("POST", objectKey, params, options, buffer, nil) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted}) +} + +// RestoreObjectXML support more features than RestoreObject +func (bucket Bucket) RestoreObjectXML(objectKey, configXML string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(configXML)) + + contentType := http.DetectContentType(buffer.Bytes()) + options = append(options, ContentType(contentType)) + + params, _ := GetRawParams(options) + params["restore"] = nil + + resp, err := bucket.do("POST", objectKey, params, options, buffer, nil) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted}) +} + +// SignURL signs the URL. Users could access the object directly with this URL without getting the AK. +// +// objectKey the target object to sign. +// signURLConfig the configuration for the signed URL +// +// string returns the signed URL, when error is nil. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec int64, options ...Option) (string, error) { + err := CheckObjectNameEx(objectKey, isVerifyObjectStrict(bucket.GetConfig())) + if err != nil { + return "", err + } + + if expiredInSec < 0 { + return "", fmt.Errorf("invalid expires: %d, expires must bigger than 0", expiredInSec) + } + expiration := time.Now().Unix() + expiredInSec + + params, err := GetRawParams(options) + if err != nil { + return "", err + } + + headers := make(map[string]string) + err = handleOptions(headers, options) + if err != nil { + return "", err + } + + return bucket.Client.Conn.signURL(method, bucket.BucketName, objectKey, expiration, params, headers) +} + +// PutObjectWithURL uploads an object with the URL. If the object exists, it will be overwritten. +// PutObjectWithURL It will not generate minetype according to the key name. +// +// signedURL signed URL. +// reader io.Reader the read instance for reading the data for the upload. +// options the options for uploading the data. The valid options are CacheControl, ContentDisposition, ContentEncoding, +// +// Expires, ServerSideEncryption, ObjectACL and custom metadata. Check out the following link for details: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putobject +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, options ...Option) error { + resp, err := bucket.DoPutObjectWithURL(signedURL, reader, options) + if err != nil { + return err + } + defer resp.Body.Close() + + return err +} + +// PutObjectFromFileWithURL uploads an object from a local file with the signed URL. +// PutObjectFromFileWithURL It does not generate mimetype according to object key's name or the local file name. +// +// signedURL the signed URL. +// filePath local file path, such as dirfile.txt, for uploading. +// options options for uploading, same as the options in PutObject function. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, options ...Option) error { + fd, err := os.Open(filePath) + if err != nil { + return err + } + defer fd.Close() + + resp, err := bucket.DoPutObjectWithURL(signedURL, fd, options) + if err != nil { + return err + } + defer resp.Body.Close() + + return err +} + +// DoPutObjectWithURL is the actual API that does the upload with URL work(internal for SDK) +// +// signedURL the signed URL. +// reader io.Reader the read instance for getting the data to upload. +// options options for uploading. +// +// Response the response object which contains the HTTP response. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, options []Option) (*Response, error) { + listener := GetProgressListener(options) + + params := map[string]interface{}{} + resp, err := bucket.doURL("PUT", signedURL, params, options, reader, listener) + if err != nil { + return nil, err + } + + if bucket.GetConfig().IsEnableCRC { + err = CheckCRC(resp, "DoPutObjectWithURL") + if err != nil { + return resp, err + } + } + + err = CheckRespCode(resp.StatusCode, []int{http.StatusOK}) + + return resp, err +} + +// GetObjectWithURL downloads the object and returns the reader instance, with the signed URL. +// +// signedURL the signed URL. +// options options for downloading the object. Valid options are IfModifiedSince, IfUnmodifiedSince, IfMatch, +// +// IfNoneMatch, AcceptEncoding. For more information, check out the following link: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/getobject +// +// io.ReadCloser the reader object for getting the data from response. It needs be closed after the usage. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.ReadCloser, error) { + result, err := bucket.DoGetObjectWithURL(signedURL, options) + if err != nil { + return nil, err + } + return result.Response, nil +} + +// GetObjectToFileWithURL downloads the object into a local file with the signed URL. +// +// signedURL the signed URL +// filePath the local file path to download to. +// options the options for downloading object. Check out the parameter options in function GetObject for the reference. +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options ...Option) error { + tempFilePath := filePath + TempFileSuffix + + // Get the object's content + result, err := bucket.DoGetObjectWithURL(signedURL, options) + if err != nil { + return err + } + defer result.Response.Close() + + // If the file does not exist, create one. If exists, then overwrite it. + fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode) + if err != nil { + return err + } + + // Save the data to the file. + _, err = io.Copy(fd, result.Response.Body) + fd.Close() + if err != nil { + return err + } + + // Compare the CRC value. If CRC values do not match, return error. + hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange) + encodeOpt, _ := FindOption(options, HTTPHeaderAcceptEncoding, nil) + acceptEncoding := "" + if encodeOpt != nil { + acceptEncoding = encodeOpt.(string) + } + + if bucket.GetConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" { + result.Response.ClientCRC = result.ClientCRC.Sum64() + err = CheckCRC(result.Response, "GetObjectToFileWithURL") + if err != nil { + os.Remove(tempFilePath) + return err + } + } + + return os.Rename(tempFilePath, filePath) +} + +// DoGetObjectWithURL is the actual API that downloads the file with the signed URL. +// +// signedURL the signed URL. +// options the options for getting object. Check out parameter options in GetObject for the reference. +// +// GetObjectResult the result object when the error is nil. +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) { + params, _ := GetRawParams(options) + resp, err := bucket.doURL("GET", signedURL, params, options, nil, nil) + if err != nil { + return nil, err + } + + result := &GetObjectResult{ + Response: resp, + } + + // CRC + var crcCalc hash.Hash64 + hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange) + if bucket.GetConfig().IsEnableCRC && !hasRange { + crcCalc = crc64.New(CrcTable()) + result.ServerCRC = resp.ServerCRC + result.ClientCRC = crcCalc + } + + // Progress + listener := GetProgressListener(options) + + contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64) + resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil) + + return result, nil +} + +// ProcessObject apply process on the specified image file. +// +// The supported process includes resize, rotate, crop, watermark, format, +// udf, customized style, etc. +// +// objectKey object key to process. +// process process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA" +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) ProcessObject(objectKey string, process string, options ...Option) (ProcessObjectResult, error) { + var out ProcessObjectResult + params, _ := GetRawParams(options) + params["x-oss-process"] = nil + processData := fmt.Sprintf("%v=%v", "x-oss-process", process) + data := strings.NewReader(processData) + resp, err := bucket.do("POST", objectKey, params, nil, data, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = jsonUnmarshal(resp.Body, &out) + return out, err +} + +// AsyncProcessObject apply async process on the specified image file. +// +// The supported process includes resize, rotate, crop, watermark, format, +// udf, customized style, etc. +// +// objectKey object key to process. +// asyncProcess process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA" +// +// error it's nil if no error, otherwise it's an error object. +func (bucket Bucket) AsyncProcessObject(objectKey string, asyncProcess string, options ...Option) (AsyncProcessObjectResult, error) { + var out AsyncProcessObjectResult + params, _ := GetRawParams(options) + params["x-oss-async-process"] = nil + processData := fmt.Sprintf("%v=%v", "x-oss-async-process", asyncProcess) + data := strings.NewReader(processData) + + resp, err := bucket.do("POST", objectKey, params, nil, data, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = jsonUnmarshal(resp.Body, &out) + return out, err +} + +// PutObjectTagging add tagging to object +// +// objectKey object key to add tagging +// tagging tagging to be added +// +// error nil if success, otherwise error +func (bucket Bucket) PutObjectTagging(objectKey string, tagging Tagging, options ...Option) error { + bs, err := xml.Marshal(tagging) + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + params, _ := GetRawParams(options) + params["tagging"] = nil + resp, err := bucket.do("PUT", objectKey, params, options, buffer, nil) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} + +// +// GetObjectTagging get tagging of the object +// +// objectKey object key to get tagging +// +// Tagging +// error nil if success, otherwise error + +func (bucket Bucket) GetObjectTagging(objectKey string, options ...Option) (GetObjectTaggingResult, error) { + var out GetObjectTaggingResult + params, _ := GetRawParams(options) + params["tagging"] = nil + + resp, err := bucket.do("GET", objectKey, params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// DeleteObjectTagging delete object taggging +// +// objectKey object key to delete tagging +// +// error nil if success, otherwise error +func (bucket Bucket) DeleteObjectTagging(objectKey string, options ...Option) error { + params, _ := GetRawParams(options) + params["tagging"] = nil + resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +func (bucket Bucket) OptionsMethod(objectKey string, options ...Option) (http.Header, error) { + var out http.Header + resp, err := bucket.doInner("OPTIONS", objectKey, nil, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + out = resp.Headers + return out, nil +} + +// public +func (bucket Bucket) Do(method, objectName string, params map[string]interface{}, options []Option, + data io.Reader, listener ProgressListener) (*Response, error) { + return bucket.doInner(method, objectName, params, options, data, listener) +} + +// Private +func (bucket Bucket) doInner(method, objectName string, params map[string]interface{}, options []Option, + data io.Reader, listener ProgressListener) (*Response, error) { + headers := make(map[string]string) + err := handleOptions(headers, options) + if err != nil { + return nil, err + } + + err = CheckBucketName(bucket.BucketName) + if len(bucket.BucketName) > 0 && err != nil { + return nil, err + } + + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoWithContext(ctx, method, bucket.BucketName, objectName, + params, headers, data, 0, listener) + + // get response header + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil && resp != nil { + pRespHeader := respHeader.(*http.Header) + if resp != nil { + *pRespHeader = resp.Headers + } + } + + return resp, err +} + +// Private check object name before bucket.do +func (bucket Bucket) do(method, objectName string, params map[string]interface{}, options []Option, + data io.Reader, listener ProgressListener) (*Response, error) { + err := CheckObjectName(objectName) + if err != nil { + return nil, err + } + resp, err := bucket.doInner(method, objectName, params, options, data, listener) + return resp, err +} + +func (bucket Bucket) doURL(method HTTPMethod, signedURL string, params map[string]interface{}, options []Option, + data io.Reader, listener ProgressListener) (*Response, error) { + + headers := make(map[string]string) + err := handleOptions(headers, options) + if err != nil { + return nil, err + } + + ctxArg, _ := FindOption(options, contextArg, nil) + ctx, _ := ctxArg.(context.Context) + + resp, err := bucket.Client.Conn.DoURLWithContext(ctx, method, signedURL, headers, data, 0, listener) + + // get response header + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + pRespHeader := respHeader.(*http.Header) + if resp != nil { + *pRespHeader = resp.Headers + } + } + + return resp, err +} + +func (bucket Bucket) GetConfig() *Config { + return bucket.Client.Config +} + +func AddContentType(options []Option, keys ...string) []Option { + typ := TypeByExtension("") + for _, key := range keys { + typ = TypeByExtension(key) + if typ != "" { + break + } + } + + if typ == "" { + typ = "application/octet-stream" + } + + opts := []Option{ContentType(typ)} + opts = append(opts, options...) + + return opts +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go new file mode 100644 index 00000000000..5910bb3bfbd --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go @@ -0,0 +1,2956 @@ +// Package oss implements functions for access oss service. +// It has two main struct Client and Bucket. +package oss + +import ( + "bytes" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "log" + "net" + "net/http" + "strings" + "time" +) + +// Client SDK's entry point. It's for bucket related options such as create/delete/set bucket (such as set/get ACL/lifecycle/referer/logging/website). +// Object related operations are done by Bucket class. +// Users use oss.New to create Client instance. +// +type ( + // Client OSS client + Client struct { + Config *Config // OSS client configuration + Conn *Conn // Send HTTP request + HTTPClient *http.Client //http.Client to use - if nil will make its own + } + + // ClientOption client option such as UseCname, Timeout, SecurityToken. + ClientOption func(*Client) +) + +// New creates a new client. +// +// endpoint the OSS datacenter endpoint such as http://oss-cn-hangzhou.aliyuncs.com . +// accessKeyId access key Id. +// accessKeySecret access key secret. +// +// Client creates the new client instance, the returned value is valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption) (*Client, error) { + // Configuration + config := getDefaultOssConfig() + config.Endpoint = endpoint + config.AccessKeyID = accessKeyID + config.AccessKeySecret = accessKeySecret + + // URL parse + url := &urlMaker{} + + // HTTP connect + conn := &Conn{config: config, url: url} + + // OSS client + client := &Client{ + Config: config, + Conn: conn, + } + + // Client options parse + for _, option := range options { + option(client) + } + + err := url.InitExt(config.Endpoint, config.IsCname, config.IsUseProxy, config.IsPathStyle) + if err != nil { + return nil, err + } + + if config.AuthVersion != AuthV1 && config.AuthVersion != AuthV2 && config.AuthVersion != AuthV4 { + return nil, fmt.Errorf("Init client Error, invalid Auth version: %v", config.AuthVersion) + } + + // Create HTTP connection + err = conn.init(config, url, client.HTTPClient) + + return client, err +} + +// SetRegion set region for client +// +// region the region, such as cn-hangzhou +func (client *Client) SetRegion(region string) { + client.Config.Region = region +} + +// SetCloudBoxId set CloudBoxId for client +// +// cloudBoxId the id of cloudBox +func (client *Client) SetCloudBoxId(cloudBoxId string) { + client.Config.CloudBoxId = cloudBoxId +} + +// SetProduct set Product type for client +// +// Product product type +func (client *Client) SetProduct(product string) { + client.Config.Product = product +} + +// Bucket gets the bucket instance. +// +// bucketName the bucket name. +// Bucket the bucket object, when error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) Bucket(bucketName string) (*Bucket, error) { + err := CheckBucketName(bucketName) + if err != nil { + return nil, err + } + + return &Bucket{ + client, + bucketName, + }, nil +} + +// CreateBucket creates a bucket. +// +// bucketName the bucket name, it's globably unique and immutable. The bucket name can only consist of lowercase letters, numbers and dash ('-'). +// It must start with lowercase letter or number and the length can only be between 3 and 255. +// options options for creating the bucket, with optional ACL. The ACL could be ACLPrivate, ACLPublicRead, and ACLPublicReadWrite. By default it's ACLPrivate. +// It could also be specified with StorageClass option, which supports StorageStandard, StorageIA(infrequent access), StorageArchive. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) CreateBucket(bucketName string, options ...Option) error { + headers := make(map[string]string) + handleOptions(headers, options) + + buffer := new(bytes.Buffer) + + var cbConfig createBucketConfiguration + cbConfig.StorageClass = StorageStandard + + isStorageSet, valStroage, _ := IsOptionSet(options, storageClass) + isRedundancySet, valRedundancy, _ := IsOptionSet(options, redundancyType) + isObjectHashFuncSet, valHashFunc, _ := IsOptionSet(options, objectHashFunc) + if isStorageSet { + cbConfig.StorageClass = valStroage.(StorageClassType) + } + + if isRedundancySet { + cbConfig.DataRedundancyType = valRedundancy.(DataRedundancyType) + } + + if isObjectHashFuncSet { + cbConfig.ObjectHashFunction = valHashFunc.(ObjecthashFuncType) + } + + bs, err := xml.Marshal(cbConfig) + if err != nil { + return err + } + buffer.Write(bs) + contentType := http.DetectContentType(buffer.Bytes()) + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// create bucket xml +func (client Client) CreateBucketXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// ListBuckets lists buckets of the current account under the given endpoint, with optional filters. +// +// options specifies the filters such as Prefix, Marker and MaxKeys. Prefix is the bucket name's prefix filter. +// And marker makes sure the returned buckets' name are greater than it in lexicographic order. +// Maxkeys limits the max keys to return, and by default it's 100 and up to 1000. +// For the common usage scenario, please check out list_bucket.go in the sample. +// ListBucketsResponse the response object if error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) ListBuckets(options ...Option) (ListBucketsResult, error) { + var out ListBucketsResult + + params, err := GetRawParams(options) + if err != nil { + return out, err + } + + resp, err := client.do("GET", "", params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// ListCloudBoxes lists cloud boxes of the current account under the given endpoint, with optional filters. +// +// options specifies the filters such as Prefix, Marker and MaxKeys. Prefix is the bucket name's prefix filter. +// And marker makes sure the returned buckets' name are greater than it in lexicographic order. +// Maxkeys limits the max keys to return, and by default it's 100 and up to 1000. +// For the common usage scenario, please check out list_bucket.go in the sample. +// ListBucketsResponse the response object if error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) ListCloudBoxes(options ...Option) (ListCloudBoxResult, error) { + var out ListCloudBoxResult + + params, err := GetRawParams(options) + if err != nil { + return out, err + } + + params["cloudboxes"] = nil + + resp, err := client.do("GET", "", params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// IsBucketExist checks if the bucket exists +// +// bucketName the bucket name. +// +// bool true if it exists, and it's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) IsBucketExist(bucketName string) (bool, error) { + listRes, err := client.ListBuckets(Prefix(bucketName), MaxKeys(1)) + if err != nil { + return false, err + } + + if len(listRes.Buckets) == 1 && listRes.Buckets[0].Name == bucketName { + return true, nil + } + return false, nil +} + +// DeleteBucket deletes the bucket. Only empty bucket can be deleted (no object and parts). +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucket(bucketName string, options ...Option) error { + params := map[string]interface{}{} + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// GetBucketLocation gets the bucket location. +// +// Checks out the following link for more information : +// https://www.alibabacloud.com/help/en/object-storage-service/latest/getbucketlocation +// +// bucketName the bucket name +// +// string bucket's datacenter location +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketLocation(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["location"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + var LocationConstraint string + err = xmlUnmarshal(resp.Body, &LocationConstraint) + return LocationConstraint, err +} + +// SetBucketACL sets bucket's ACL. +// +// bucketName the bucket name +// bucketAcl the bucket ACL: ACLPrivate, ACLPublicRead and ACLPublicReadWrite. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketACL(bucketName string, bucketACL ACLType, options ...Option) error { + headers := map[string]string{HTTPHeaderOssACL: string(bucketACL)} + params := map[string]interface{}{} + params["acl"] = nil + resp, err := client.do("PUT", bucketName, params, headers, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketACL gets the bucket ACL. +// +// bucketName the bucket name. +// +// GetBucketAclResponse the result object, and it's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketACL(bucketName string, options ...Option) (GetBucketACLResult, error) { + var out GetBucketACLResult + params := map[string]interface{}{} + params["acl"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// SetBucketLifecycle sets the bucket's lifecycle. +// +// For more information, checks out following link: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketlifecycle +// +// bucketName the bucket name. +// rules the lifecycle rules. There're two kind of rules: absolute time expiration and relative time expiration in days and day/month/year respectively. +// Check out sample/bucket_lifecycle.go for more details. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketLifecycle(bucketName string, rules []LifecycleRule, options ...Option) error { + err := verifyLifecycleRules(rules) + if err != nil { + return err + } + lifecycleCfg := LifecycleConfiguration{Rules: rules} + bs, err := xml.Marshal(lifecycleCfg) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["lifecycle"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// SetBucketLifecycleXml sets the bucket's lifecycle rule from xml config +func (client Client) SetBucketLifecycleXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["lifecycle"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// DeleteBucketLifecycle deletes the bucket's lifecycle. +// +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketLifecycle(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["lifecycle"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// GetBucketLifecycle gets the bucket's lifecycle settings. +// +// bucketName the bucket name. +// +// GetBucketLifecycleResponse the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketLifecycle(bucketName string, options ...Option) (GetBucketLifecycleResult, error) { + var out GetBucketLifecycleResult + params := map[string]interface{}{} + params["lifecycle"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + + // NonVersionTransition is not suggested to use + // to keep compatible + for k, rule := range out.Rules { + if len(rule.NonVersionTransitions) > 0 { + out.Rules[k].NonVersionTransition = &(out.Rules[k].NonVersionTransitions[0]) + } + } + return out, err +} + +func (client Client) GetBucketLifecycleXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["lifecycle"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// SetBucketReferer sets the bucket's referer whitelist and the flag if allowing empty referrer. +// +// To avoid stealing link on OSS data, OSS supports the HTTP referrer header. A whitelist referrer could be set either by API or web console, as well as +// the allowing empty referrer flag. Note that this applies to requests from web browser only. +// For example, for a bucket os-example and its referrer http://www.aliyun.com, all requests from this URL could access the bucket. +// For more information, please check out this link : +// https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketreferer +// +// bucketName the bucket name. +// referrers the referrer white list. A bucket could have a referrer list and each referrer supports one '*' and multiple '?' as wildcards. +// The sample could be found in sample/bucket_referer.go +// allowEmptyReferer the flag of allowing empty referrer. By default it's true. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketReferer(bucketName string, referrers []string, allowEmptyReferer bool, options ...Option) error { + rxml := RefererXML{} + rxml.AllowEmptyReferer = allowEmptyReferer + if referrers == nil { + rxml.RefererList = append(rxml.RefererList, "") + } else { + for _, referrer := range referrers { + rxml.RefererList = append(rxml.RefererList, referrer) + } + } + + bs, err := xml.Marshal(rxml) + if err != nil { + return err + } + + return client.PutBucketRefererXml(bucketName, string(bs), options...) +} + +// SetBucketRefererV2 gets the bucket's referer white list. +// +// setBucketReferer SetBucketReferer bucket referer config in struct format. +// +// GetBucketRefererResponse the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketRefererV2(bucketName string, setBucketReferer RefererXML, options ...Option) error { + bs, err := xml.Marshal(setBucketReferer) + if err != nil { + return err + } + return client.PutBucketRefererXml(bucketName, string(bs), options...) +} + +// PutBucketRefererXml set bucket's style +// bucketName the bucket name. +// xmlData the style in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketRefererXml(bucketName, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["referer"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketReferer gets the bucket's referrer white list. +// bucketName the bucket name. +// GetBucketRefererResult the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketReferer(bucketName string, options ...Option) (GetBucketRefererResult, error) { + var out GetBucketRefererResult + body, err := client.GetBucketRefererXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketRefererXml gets the bucket's referrer white list. +// bucketName the bucket name. +// GetBucketRefererResponse the bucket referer config result in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketRefererXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["referer"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + return string(body), err +} + +// SetBucketLogging sets the bucket logging settings. +// +// OSS could automatically store the access log. Only the bucket owner could enable the logging. +// Once enabled, OSS would save all the access log into hourly log files in a specified bucket. +// For more information, please check out https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketlogging +// +// bucketName bucket name to enable the log. +// targetBucket the target bucket name to store the log files. +// targetPrefix the log files' prefix. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketLogging(bucketName, targetBucket, targetPrefix string, + isEnable bool, options ...Option) error { + var err error + var bs []byte + if isEnable { + lxml := LoggingXML{} + lxml.LoggingEnabled.TargetBucket = targetBucket + lxml.LoggingEnabled.TargetPrefix = targetPrefix + bs, err = xml.Marshal(lxml) + } else { + lxml := loggingXMLEmpty{} + bs, err = xml.Marshal(lxml) + } + + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["logging"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// DeleteBucketLogging deletes the logging configuration to disable the logging on the bucket. +// +// bucketName the bucket name to disable the logging. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketLogging(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["logging"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// GetBucketLogging gets the bucket's logging settings +// +// bucketName the bucket name +// GetBucketLoggingResponse the result object upon successful request. It's only valid when error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketLogging(bucketName string, options ...Option) (GetBucketLoggingResult, error) { + var out GetBucketLoggingResult + params := map[string]interface{}{} + params["logging"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// SetBucketWebsite sets the bucket's static website's index and error page. +// +// OSS supports static web site hosting for the bucket data. When the bucket is enabled with that, you can access the file in the bucket like the way to access a static website. +// For more information, please check out: https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketwebsite +// +// bucketName the bucket name to enable static web site. +// indexDocument index page. +// errorDocument error page. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketWebsite(bucketName, indexDocument, errorDocument string, options ...Option) error { + wxml := WebsiteXML{} + wxml.IndexDocument.Suffix = indexDocument + wxml.ErrorDocument.Key = errorDocument + + bs, err := xml.Marshal(wxml) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["website"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// SetBucketWebsiteDetail sets the bucket's static website's detail +// +// OSS supports static web site hosting for the bucket data. When the bucket is enabled with that, you can access the file in the bucket like the way to access a static website. +// For more information, please check out: https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketwebsite +// +// bucketName the bucket name to enable static web site. +// +// wxml the website's detail +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketWebsiteDetail(bucketName string, wxml WebsiteXML, options ...Option) error { + bs, err := xml.Marshal(wxml) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["website"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// SetBucketWebsiteXml sets the bucket's static website's rule +// +// OSS supports static web site hosting for the bucket data. When the bucket is enabled with that, you can access the file in the bucket like the way to access a static website. +// For more information, please check out: https://www.alibabacloud.com/help/en/object-storage-service/latest/putbucketwebsite +// +// bucketName the bucket name to enable static web site. +// +// wxml the website's detail +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketWebsiteXml(bucketName string, webXml string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(webXml)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["website"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// DeleteBucketWebsite deletes the bucket's static web site settings. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketWebsite(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["website"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// OpenMetaQuery Enables the metadata management feature for a bucket. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) OpenMetaQuery(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["metaQuery"] = nil + params["comp"] = "add" + resp, err := client.do("POST", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetMetaQueryStatus Queries the information about the metadata index library of a bucket. +// +// bucketName the bucket name +// +// GetMetaQueryStatusResult the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetMetaQueryStatus(bucketName string, options ...Option) (GetMetaQueryStatusResult, error) { + var out GetMetaQueryStatusResult + params := map[string]interface{}{} + params["metaQuery"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// DoMetaQuery Queries the objects that meet specified conditions and lists the information about objects based on specified fields and sorting methods. +// +// bucketName the bucket name +// +// metaQuery the option of query +// +// DoMetaQueryResult the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DoMetaQuery(bucketName string, metaQuery MetaQuery, options ...Option) (DoMetaQueryResult, error) { + var out DoMetaQueryResult + bs, err := xml.Marshal(metaQuery) + if err != nil { + return out, err + } + out, err = client.DoMetaQueryXml(bucketName, string(bs), options...) + return out, err +} + +// DoMetaQueryXml Queries the objects that meet specified conditions and lists the information about objects based on specified fields and sorting methods. +// +// bucketName the bucket name +// +// metaQuery the option of query +// +// DoMetaQueryResult the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DoMetaQueryXml(bucketName string, metaQueryXml string, options ...Option) (DoMetaQueryResult, error) { + var out DoMetaQueryResult + buffer := new(bytes.Buffer) + buffer.Write([]byte(metaQueryXml)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["metaQuery"] = nil + params["comp"] = "query" + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// CloseMetaQuery Disables the metadata management feature for a bucket. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) CloseMetaQuery(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["metaQuery"] = nil + params["comp"] = "delete" + resp, err := client.do("POST", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketWebsite gets the bucket's default page (index page) and the error page. +// +// bucketName the bucket name +// +// GetBucketWebsiteResponse the result object upon successful request. It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketWebsite(bucketName string, options ...Option) (GetBucketWebsiteResult, error) { + var out GetBucketWebsiteResult + params := map[string]interface{}{} + params["website"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// GetBucketWebsiteXml gets the bucket's website config xml config. +// +// bucketName the bucket name +// +// string the bucket's xml config, It's only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketWebsiteXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["website"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + + out := string(body) + return out, err +} + +// SetBucketCORS sets the bucket's CORS rules +// +// For more information, please check out https://help.aliyun.com/document_detail/oss/user_guide/security_management/cors.html +// +// bucketName the bucket name +// corsRules the CORS rules to set. The related sample code is in sample/bucket_cors.go. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketCORS(bucketName string, corsRules []CORSRule, options ...Option) error { + corsxml := CORSXML{} + for _, v := range corsRules { + cr := CORSRule{} + cr.AllowedMethod = v.AllowedMethod + cr.AllowedOrigin = v.AllowedOrigin + cr.AllowedHeader = v.AllowedHeader + cr.ExposeHeader = v.ExposeHeader + cr.MaxAgeSeconds = v.MaxAgeSeconds + corsxml.CORSRules = append(corsxml.CORSRules, cr) + } + + bs, err := xml.Marshal(corsxml) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["cors"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// SetBucketCORSV2 sets the bucket's CORS rules +// +// bucketName the bucket name +// putBucketCORS the CORS rules to set. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketCORSV2(bucketName string, putBucketCORS PutBucketCORS, options ...Option) error { + bs, err := xml.Marshal(putBucketCORS) + if err != nil { + return err + } + err = client.SetBucketCORSXml(bucketName, string(bs), options...) + return err +} + +func (client Client) SetBucketCORSXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["cors"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// DeleteBucketCORS deletes the bucket's static website settings. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketCORS(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["cors"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// GetBucketCORS gets the bucket's CORS settings. +// +// bucketName the bucket name. +// GetBucketCORSResult the result object upon successful request. It's only valid when error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketCORS(bucketName string, options ...Option) (GetBucketCORSResult, error) { + var out GetBucketCORSResult + params := map[string]interface{}{} + params["cors"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +func (client Client) GetBucketCORSXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["cors"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// GetBucketInfo gets the bucket information. +// +// bucketName the bucket name. +// GetBucketInfoResult the result object upon successful request. It's only valid when error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketInfo(bucketName string, options ...Option) (GetBucketInfoResult, error) { + var out GetBucketInfoResult + params := map[string]interface{}{} + params["bucketInfo"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + + // convert None to "" + if err == nil { + if out.BucketInfo.SseRule.KMSMasterKeyID == "None" { + out.BucketInfo.SseRule.KMSMasterKeyID = "" + } + + if out.BucketInfo.SseRule.SSEAlgorithm == "None" { + out.BucketInfo.SseRule.SSEAlgorithm = "" + } + + if out.BucketInfo.SseRule.KMSDataEncryption == "None" { + out.BucketInfo.SseRule.KMSDataEncryption = "" + } + } + return out, err +} + +// SetBucketVersioning set bucket versioning:Enabled、Suspended +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) SetBucketVersioning(bucketName string, versioningConfig VersioningConfig, options ...Option) error { + var err error + var bs []byte + bs, err = xml.Marshal(versioningConfig) + + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["versioning"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketVersioning get bucket versioning status:Enabled、Suspended +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketVersioning(bucketName string, options ...Option) (GetBucketVersioningResult, error) { + var out GetBucketVersioningResult + params := map[string]interface{}{} + params["versioning"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// SetBucketEncryption set bucket encryption config +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) SetBucketEncryption(bucketName string, encryptionRule ServerEncryptionRule, options ...Option) error { + var err error + var bs []byte + bs, err = xml.Marshal(encryptionRule) + + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["encryption"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketEncryption get bucket encryption +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketEncryption(bucketName string, options ...Option) (GetBucketEncryptionResult, error) { + var out GetBucketEncryptionResult + params := map[string]interface{}{} + params["encryption"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// DeleteBucketEncryption delete bucket encryption config +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error bucket +func (client Client) DeleteBucketEncryption(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["encryption"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// +// SetBucketTagging add tagging to bucket +// bucketName name of bucket +// tagging tagging to be added +// error nil if success, otherwise error +func (client Client) SetBucketTagging(bucketName string, tagging Tagging, options ...Option) error { + var err error + var bs []byte + bs, err = xml.Marshal(tagging) + + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["tagging"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketTagging get tagging of the bucket +// bucketName name of bucket +// error nil if success, otherwise error +func (client Client) GetBucketTagging(bucketName string, options ...Option) (GetBucketTaggingResult, error) { + var out GetBucketTaggingResult + params := map[string]interface{}{} + params["tagging"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// +// DeleteBucketTagging delete bucket tagging +// bucketName name of bucket +// error nil if success, otherwise error +// +func (client Client) DeleteBucketTagging(bucketName string, options ...Option) error { + key, _ := FindOption(options, "tagging", nil) + params := map[string]interface{}{} + if key == nil { + params["tagging"] = nil + } else { + params["tagging"] = key.(string) + } + + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// GetBucketStat get bucket stat +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketStat(bucketName string, options ...Option) (GetBucketStatResult, error) { + var out GetBucketStatResult + params := map[string]interface{}{} + params["stat"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// GetBucketPolicy API operation for Object Storage Service. +// +// Get the policy from the bucket. +// +// bucketName the bucket name. +// +// string return the bucket's policy, and it's only valid when error is nil. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketPolicy(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["policy"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + + out := string(body) + return out, err +} + +// SetBucketPolicy API operation for Object Storage Service. +// +// Set the policy from the bucket. +// +// bucketName the bucket name. +// +// policy the bucket policy. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketPolicy(bucketName string, policy string, options ...Option) error { + params := map[string]interface{}{} + params["policy"] = nil + + buffer := strings.NewReader(policy) + + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// DeleteBucketPolicy API operation for Object Storage Service. +// +// Deletes the policy from the bucket. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketPolicy(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["policy"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// SetBucketRequestPayment API operation for Object Storage Service. +// +// Set the requestPayment of bucket +// +// bucketName the bucket name. +// +// paymentConfig the payment configuration +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketRequestPayment(bucketName string, paymentConfig RequestPaymentConfiguration, options ...Option) error { + params := map[string]interface{}{} + params["requestPayment"] = nil + + var bs []byte + bs, err := xml.Marshal(paymentConfig) + + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketRequestPayment API operation for Object Storage Service. +// +// Get bucket requestPayment +// +// bucketName the bucket name. +// +// RequestPaymentConfiguration the payment configuration +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketRequestPayment(bucketName string, options ...Option) (RequestPaymentConfiguration, error) { + var out RequestPaymentConfiguration + params := map[string]interface{}{} + params["requestPayment"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// GetUserQoSInfo API operation for Object Storage Service. +// +// Get user qos. +// +// UserQoSConfiguration the User Qos and range Information. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetUserQoSInfo(options ...Option) (UserQoSConfiguration, error) { + var out UserQoSConfiguration + params := map[string]interface{}{} + params["qosInfo"] = nil + + resp, err := client.do("GET", "", params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// SetBucketQoSInfo API operation for Object Storage Service. +// +// Set Bucket Qos information. +// +// bucketName the bucket name. +// +// qosConf the qos configuration. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketQoSInfo(bucketName string, qosConf BucketQoSConfiguration, options ...Option) error { + params := map[string]interface{}{} + params["qosInfo"] = nil + + var bs []byte + bs, err := xml.Marshal(qosConf) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentTpye := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentTpye + + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketQosInfo API operation for Object Storage Service. +// +// Get Bucket Qos information. +// +// bucketName the bucket name. +// +// BucketQoSConfiguration the return qos configuration. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketQosInfo(bucketName string, options ...Option) (BucketQoSConfiguration, error) { + var out BucketQoSConfiguration + params := map[string]interface{}{} + params["qosInfo"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// DeleteBucketQosInfo API operation for Object Storage Service. +// +// Delete Bucket QoS information. +// +// bucketName the bucket name. +// +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketQosInfo(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["qosInfo"] = nil + + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// SetBucketInventory API operation for Object Storage Service +// +// Set the Bucket inventory. +// +// bucketName the bucket name. +// +// inventoryConfig the inventory configuration. +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) SetBucketInventory(bucketName string, inventoryConfig InventoryConfiguration, options ...Option) error { + params := map[string]interface{}{} + params["inventoryId"] = inventoryConfig.Id + params["inventory"] = nil + + var bs []byte + bs, err := xml.Marshal(inventoryConfig) + + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + + if err != nil { + return err + } + + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// SetBucketInventoryXml API operation for Object Storage Service +// +// Set the Bucket inventory +// +// bucketName the bucket name. +// +// xmlBody the inventory configuration. +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) SetBucketInventoryXml(bucketName string, xmlBody string, options ...Option) error { + var inventoryConfig InventoryConfiguration + err := xml.Unmarshal([]byte(xmlBody), &inventoryConfig) + if err != nil { + return err + } + + if inventoryConfig.Id == "" { + return fmt.Errorf("inventory id is empty in xml") + } + + params := map[string]interface{}{} + params["inventoryId"] = inventoryConfig.Id + params["inventory"] = nil + + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketInventory API operation for Object Storage Service +// +// Get the Bucket inventory. +// +// bucketName tht bucket name. +// +// strInventoryId the inventory id. +// +// InventoryConfiguration the inventory configuration. +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) GetBucketInventory(bucketName string, strInventoryId string, options ...Option) (InventoryConfiguration, error) { + var out InventoryConfiguration + params := map[string]interface{}{} + params["inventory"] = nil + params["inventoryId"] = strInventoryId + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// GetBucketInventoryXml API operation for Object Storage Service +// +// Get the Bucket inventory. +// +// bucketName tht bucket name. +// +// strInventoryId the inventory id. +// +// InventoryConfiguration the inventory configuration. +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) GetBucketInventoryXml(bucketName string, strInventoryId string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["inventory"] = nil + params["inventoryId"] = strInventoryId + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// ListBucketInventory API operation for Object Storage Service +// +// List the Bucket inventory. +// +// bucketName tht bucket name. +// +// continuationToken the users token. +// +// ListInventoryConfigurationsResult list all inventory configuration by . +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) ListBucketInventory(bucketName, continuationToken string, options ...Option) (ListInventoryConfigurationsResult, error) { + var out ListInventoryConfigurationsResult + params := map[string]interface{}{} + params["inventory"] = nil + if continuationToken == "" { + params["continuation-token"] = nil + } else { + params["continuation-token"] = continuationToken + } + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// ListBucketInventoryXml API operation for Object Storage Service +// +// List the Bucket inventory. +// +// bucketName tht bucket name. +// +// continuationToken the users token. +// +// ListInventoryConfigurationsResult list all inventory configuration by . +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) ListBucketInventoryXml(bucketName, continuationToken string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["inventory"] = nil + if continuationToken == "" { + params["continuation-token"] = nil + } else { + params["continuation-token"] = continuationToken + } + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// DeleteBucketInventory API operation for Object Storage Service. +// +// Delete Bucket inventory information. +// +// bucketName tht bucket name. +// +// strInventoryId the inventory id. +// +// error it's nil if no error, otherwise it's an error. +// +func (client Client) DeleteBucketInventory(bucketName, strInventoryId string, options ...Option) error { + params := map[string]interface{}{} + params["inventory"] = nil + params["inventoryId"] = strInventoryId + + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// SetBucketAsyncTask API operation for set async fetch task +// +// bucketName tht bucket name. +// +// asynConf configruation +// +// error it's nil if success, otherwise it's an error. +func (client Client) SetBucketAsyncTask(bucketName string, asynConf AsyncFetchTaskConfiguration, options ...Option) (AsyncFetchTaskResult, error) { + var out AsyncFetchTaskResult + params := map[string]interface{}{} + params["asyncFetch"] = nil + + var bs []byte + bs, err := xml.Marshal(asynConf) + + if err != nil { + return out, err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + + if err != nil { + return out, err + } + + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// GetBucketAsyncTask API operation for set async fetch task +// +// bucketName tht bucket name. +// +// taskid returned by SetBucketAsyncTask +// +// error it's nil if success, otherwise it's an error. +func (client Client) GetBucketAsyncTask(bucketName string, taskID string, options ...Option) (AsynFetchTaskInfo, error) { + var out AsynFetchTaskInfo + params := map[string]interface{}{} + params["asyncFetch"] = nil + + headers := make(map[string]string) + headers[HTTPHeaderOssTaskID] = taskID + resp, err := client.do("GET", bucketName, params, headers, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// InitiateBucketWorm creates bucket worm Configuration +// bucketName the bucket name. +// retentionDays the retention period in days +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) InitiateBucketWorm(bucketName string, retentionDays int, options ...Option) (string, error) { + var initiateWormConf InitiateWormConfiguration + initiateWormConf.RetentionPeriodInDays = retentionDays + + var respHeader http.Header + isOptSet, _, _ := IsOptionSet(options, responseHeader) + if !isOptSet { + options = append(options, GetResponseHeader(&respHeader)) + } + + bs, err := xml.Marshal(initiateWormConf) + if err != nil { + return "", err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["worm"] = nil + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + respOpt, _ := FindOption(options, responseHeader, nil) + wormID := "" + err = CheckRespCode(resp.StatusCode, []int{http.StatusOK}) + if err == nil && respOpt != nil { + wormID = (respOpt.(*http.Header)).Get("x-oss-worm-id") + } + return wormID, err +} + +// AbortBucketWorm delete bucket worm Configuration +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) AbortBucketWorm(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["worm"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// CompleteBucketWorm complete bucket worm Configuration +// bucketName the bucket name. +// wormID the worm id +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) CompleteBucketWorm(bucketName string, wormID string, options ...Option) error { + params := map[string]interface{}{} + params["wormId"] = wormID + resp, err := client.do("POST", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// ExtendBucketWorm exetend bucket worm Configuration +// bucketName the bucket name. +// retentionDays the retention period in days +// wormID the worm id +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) ExtendBucketWorm(bucketName string, retentionDays int, wormID string, options ...Option) error { + var extendWormConf ExtendWormConfiguration + extendWormConf.RetentionPeriodInDays = retentionDays + + bs, err := xml.Marshal(extendWormConf) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["wormId"] = wormID + params["wormExtend"] = nil + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketWorm get bucket worm Configuration +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketWorm(bucketName string, options ...Option) (WormConfiguration, error) { + var out WormConfiguration + params := map[string]interface{}{} + params["worm"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// SetBucketTransferAcc set bucket transfer acceleration configuration +// bucketName the bucket name. +// accConf bucket transfer acceleration configuration +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) SetBucketTransferAcc(bucketName string, accConf TransferAccConfiguration, options ...Option) error { + bs, err := xml.Marshal(accConf) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := make(map[string]string) + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["transferAcceleration"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketTransferAcc get bucket transfer acceleration configuration +// bucketName the bucket name. +// accConf bucket transfer acceleration configuration +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketTransferAcc(bucketName string, options ...Option) (TransferAccConfiguration, error) { + var out TransferAccConfiguration + params := map[string]interface{}{} + params["transferAcceleration"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// DeleteBucketTransferAcc delete bucket transfer acceleration configuration +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketTransferAcc(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["transferAcceleration"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// PutBucketReplication put bucket replication configuration +// bucketName the bucket name. +// xmlBody the replication configuration. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) PutBucketReplication(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["replication"] = nil + params["comp"] = "add" + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// PutBucketRTC put bucket replication rtc +// bucketName the bucket name. +// rtc the bucket rtc config. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) PutBucketRTC(bucketName string, rtc PutBucketRTC, options ...Option) error { + bs, err := xml.Marshal(rtc) + if err != nil { + return err + } + err = client.PutBucketRTCXml(bucketName, string(bs), options...) + return err +} + +// PutBucketRTCXml put bucket rtc configuration +// bucketName the bucket name. +// xmlBody the rtc configuration in xml format. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) PutBucketRTCXml(bucketName string, xmlBody string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["rtc"] = nil + resp, err := client.do("PUT", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketReplication get bucket replication configuration +// bucketName the bucket name. +// string the replication configuration. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketReplication(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["replication"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(data), err +} + +// DeleteBucketReplication delete bucket replication configuration +// bucketName the bucket name. +// ruleId the ID of the replication configuration. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) DeleteBucketReplication(bucketName string, ruleId string, options ...Option) error { + replicationxml := ReplicationXML{} + replicationxml.ID = ruleId + + bs, err := xml.Marshal(replicationxml) + if err != nil { + return err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + params := map[string]interface{}{} + params["replication"] = nil + params["comp"] = "delete" + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketReplicationLocation get the locations of the target bucket that can be copied to +// bucketName the bucket name. +// string the locations of the target bucket that can be copied to. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketReplicationLocation(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["replicationLocation"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(data), err +} + +// GetBucketReplicationProgress get the replication progress of bucket +// bucketName the bucket name. +// ruleId the ID of the replication configuration. +// string the replication progress of bucket. +// error it's nil if no error, otherwise it's an error object. +// +func (client Client) GetBucketReplicationProgress(bucketName string, ruleId string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["replicationProgress"] = nil + if ruleId != "" { + params["rule-id"] = ruleId + } + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(data), err +} + +// GetBucketAccessMonitor get bucket's access monitor config +// bucketName the bucket name. +// GetBucketAccessMonitorResult the access monitor configuration result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketAccessMonitor(bucketName string, options ...Option) (GetBucketAccessMonitorResult, error) { + var out GetBucketAccessMonitorResult + body, err := client.GetBucketAccessMonitorXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketAccessMonitorXml get bucket's access monitor config +// bucketName the bucket name. +// string the access monitor configuration result of bucket xml foramt. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketAccessMonitorXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["accessmonitor"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// PutBucketAccessMonitor get bucket's access monitor config +// bucketName the bucket name. +// accessMonitor the access monitor configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketAccessMonitor(bucketName string, accessMonitor PutBucketAccessMonitor, options ...Option) error { + bs, err := xml.Marshal(accessMonitor) + if err != nil { + return err + } + err = client.PutBucketAccessMonitorXml(bucketName, string(bs), options...) + return err +} + +// PutBucketAccessMonitorXml get bucket's access monitor config +// bucketName the bucket name. +// xmlData the access monitor configuration in xml foramt +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketAccessMonitorXml(bucketName string, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["accessmonitor"] = nil + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// ListBucketCname list bucket's binding cname +// bucketName the bucket name. +// string the xml configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) ListBucketCname(bucketName string, options ...Option) (ListBucketCnameResult, error) { + var out ListBucketCnameResult + body, err := client.GetBucketCname(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketCname get bucket's binding cname +// bucketName the bucket name. +// string the xml configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketCname(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["cname"] = nil + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(data), err +} + +// CreateBucketCnameToken create a token for the cname. +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) CreateBucketCnameToken(bucketName string, cname string, options ...Option) (CreateBucketCnameTokenResult, error) { + var out CreateBucketCnameTokenResult + params := map[string]interface{}{} + params["cname"] = nil + params["comp"] = "token" + + rxml := CnameConfigurationXML{} + rxml.Domain = cname + + bs, err := xml.Marshal(rxml) + if err != nil { + return out, err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// GetBucketCnameToken get a token for the cname +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketCnameToken(bucketName string, cname string, options ...Option) (GetBucketCnameTokenResult, error) { + var out GetBucketCnameTokenResult + params := map[string]interface{}{} + params["cname"] = cname + params["comp"] = "token" + + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// PutBucketCnameXml map a custom domain name to a bucket +// bucketName the bucket name. +// xmlBody the cname configuration in xml foramt +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketCnameXml(bucketName string, xmlBody string, options ...Option) error { + params := map[string]interface{}{} + params["cname"] = nil + params["comp"] = "add" + + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlBody)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// PutBucketCname map a custom domain name to a bucket +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketCname(bucketName string, cname string, options ...Option) error { + rxml := CnameConfigurationXML{} + rxml.Domain = cname + bs, err := xml.Marshal(rxml) + if err != nil { + return err + } + return client.PutBucketCnameXml(bucketName, string(bs), options...) +} + +// PutBucketCnameWithCertificate map a custom domain name to a bucket +// bucketName the bucket name. +// PutBucketCname the bucket cname config in struct format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketCnameWithCertificate(bucketName string, putBucketCname PutBucketCname, options ...Option) error { + bs, err := xml.Marshal(putBucketCname) + if err != nil { + return err + } + return client.PutBucketCnameXml(bucketName, string(bs), options...) +} + +// DeleteBucketCname remove the mapping of the custom domain name from a bucket. +// bucketName the bucket name. +// cname a custom domain name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DeleteBucketCname(bucketName string, cname string, options ...Option) error { + params := map[string]interface{}{} + params["cname"] = nil + params["comp"] = "delete" + + rxml := CnameConfigurationXML{} + rxml.Domain = cname + + bs, err := xml.Marshal(rxml) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + + resp, err := client.do("POST", bucketName, params, headers, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// PutBucketResourceGroup set bucket's resource group +// bucketName the bucket name. +// resourceGroup the resource group configuration of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResourceGroup(bucketName string, resourceGroup PutBucketResourceGroup, options ...Option) error { + bs, err := xml.Marshal(resourceGroup) + if err != nil { + return err + } + err = client.PutBucketResourceGroupXml(bucketName, string(bs), options...) + return err +} + +// PutBucketResourceGroupXml set bucket's resource group +// bucketName the bucket name. +// xmlData the resource group in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResourceGroupXml(bucketName string, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["resourceGroup"] = nil + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketResourceGroup get bucket's resource group +// bucketName the bucket name. +// GetBucketResourceGroupResult the resource group configuration result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResourceGroup(bucketName string, options ...Option) (GetBucketResourceGroupResult, error) { + var out GetBucketResourceGroupResult + body, err := client.GetBucketResourceGroupXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketResourceGroupXml get bucket's resource group +// bucketName the bucket name. +// string the resource group result of bucket xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResourceGroupXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["resourceGroup"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// PutBucketStyle set bucket's style +// bucketName the bucket name. +// styleContent the style content. +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketStyle(bucketName, styleName string, styleContent string, options ...Option) error { + bs := fmt.Sprintf("", styleContent) + err := client.PutBucketStyleXml(bucketName, styleName, bs, options...) + return err +} + +// PutBucketStyleXml set bucket's style +// bucketName the bucket name. +// styleName the style name. +// xmlData the style in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketStyleXml(bucketName, styleName, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["style"] = nil + params["styleName"] = styleName + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketStyle get bucket's style +// bucketName the bucket name. +// styleName the bucket style name. +// GetBucketStyleResult the style result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketStyle(bucketName, styleName string, options ...Option) (GetBucketStyleResult, error) { + var out GetBucketStyleResult + body, err := client.GetBucketStyleXml(bucketName, styleName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketStyleXml get bucket's style +// bucketName the bucket name. +// styleName the bucket style name. +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketStyleXml(bucketName, styleName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["style"] = nil + params["styleName"] = styleName + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// ListBucketStyle get bucket's styles +// bucketName the bucket name. +// GetBucketListStyleResult the list style result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) ListBucketStyle(bucketName string, options ...Option) (GetBucketListStyleResult, error) { + var out GetBucketListStyleResult + body, err := client.ListBucketStyleXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// ListBucketStyleXml get bucket's list style +// bucketName the bucket name. +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) ListBucketStyleXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["style"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// DeleteBucketStyle delete bucket's style +// bucketName the bucket name. +// styleName the bucket style name. +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DeleteBucketStyle(bucketName, styleName string, options ...Option) error { + params := map[string]interface{}{} + params["style"] = bucketName + params["styleName"] = styleName + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// PutBucketResponseHeader set bucket response header +// bucketName the bucket name. +// xmlData the resource group in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResponseHeader(bucketName string, responseHeader PutBucketResponseHeader, options ...Option) error { + bs, err := xml.Marshal(responseHeader) + if err != nil { + return err + } + err = client.PutBucketResponseHeaderXml(bucketName, string(bs), options...) + return err +} + +// PutBucketResponseHeaderXml set bucket response header +// bucketName the bucket name. +// xmlData the bucket response header in xml format +// error it's nil if no error, otherwise it's an error object. +func (client Client) PutBucketResponseHeaderXml(bucketName, xmlData string, options ...Option) error { + buffer := new(bytes.Buffer) + buffer.Write([]byte(xmlData)) + contentType := http.DetectContentType(buffer.Bytes()) + headers := map[string]string{} + headers[HTTPHeaderContentType] = contentType + params := map[string]interface{}{} + params["responseHeader"] = nil + resp, err := client.do("PUT", bucketName, params, nil, buffer, options...) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetBucketResponseHeader get bucket's response header. +// bucketName the bucket name. +// GetBucketResponseHeaderResult the response header result of bucket. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResponseHeader(bucketName string, options ...Option) (GetBucketResponseHeaderResult, error) { + var out GetBucketResponseHeaderResult + body, err := client.GetBucketResponseHeaderXml(bucketName, options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// GetBucketResponseHeaderXml get bucket's resource group +// bucketName the bucket name. +// string the response header result of bucket xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) GetBucketResponseHeaderXml(bucketName string, options ...Option) (string, error) { + params := map[string]interface{}{} + params["responseHeader"] = nil + resp, err := client.do("GET", bucketName, params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// DeleteBucketResponseHeader delete response header from a bucket. +// bucketName the bucket name. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DeleteBucketResponseHeader(bucketName string, options ...Option) error { + params := map[string]interface{}{} + params["responseHeader"] = nil + resp, err := client.do("DELETE", bucketName, params, nil, nil, options...) + + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// DescribeRegions get describe regions +// GetDescribeRegionsResult the result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DescribeRegions(options ...Option) (DescribeRegionsResult, error) { + var out DescribeRegionsResult + body, err := client.DescribeRegionsXml(options...) + if err != nil { + return out, err + } + err = xmlUnmarshal(strings.NewReader(body), &out) + return out, err +} + +// DescribeRegionsXml get describe regions +// string the style result of bucket in xml format. +// error it's nil if no error, otherwise it's an error object. +func (client Client) DescribeRegionsXml(options ...Option) (string, error) { + params, err := GetRawParams(options) + if err != nil { + return "", err + } + if params["regions"] == nil { + params["regions"] = nil + } + resp, err := client.do("GET", "", params, nil, nil, options...) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + out := string(body) + return out, err +} + +// LimitUploadSpeed set upload bandwidth limit speed,default is 0,unlimited +// upSpeed KB/s, 0 is unlimited,default is 0 +// error it's nil if success, otherwise failure +func (client Client) LimitUploadSpeed(upSpeed int) error { + if client.Config == nil { + return fmt.Errorf("client config is nil") + } + return client.Config.LimitUploadSpeed(upSpeed) +} + +// LimitDownloadSpeed set download bandwidth limit speed,default is 0,unlimited +// downSpeed KB/s, 0 is unlimited,default is 0 +// error it's nil if success, otherwise failure +func (client Client) LimitDownloadSpeed(downSpeed int) error { + if client.Config == nil { + return fmt.Errorf("client config is nil") + } + return client.Config.LimitDownloadSpeed(downSpeed) +} + +// UseCname sets the flag of using CName. By default it's false. +// +// isUseCname true: the endpoint has the CName, false: the endpoint does not have cname. Default is false. +// +func UseCname(isUseCname bool) ClientOption { + return func(client *Client) { + client.Config.IsCname = isUseCname + } +} + +// ForcePathStyle sets the flag of using Path Style. By default it's false. +// +// isPathStyle true: the endpoint has the Path Style, false: the endpoint does not have Path Style. Default is false. +// +func ForcePathStyle(isPathStyle bool) ClientOption { + return func(client *Client) { + client.Config.IsPathStyle = isPathStyle + } +} + +// Timeout sets the HTTP timeout in seconds. +// +// connectTimeoutSec HTTP timeout in seconds. Default is 10 seconds. 0 means infinite (not recommended) +// readWriteTimeout HTTP read or write's timeout in seconds. Default is 20 seconds. 0 means infinite. +// +func Timeout(connectTimeoutSec, readWriteTimeout int64) ClientOption { + return func(client *Client) { + client.Config.HTTPTimeout.ConnectTimeout = + time.Second * time.Duration(connectTimeoutSec) + client.Config.HTTPTimeout.ReadWriteTimeout = + time.Second * time.Duration(readWriteTimeout) + client.Config.HTTPTimeout.HeaderTimeout = + time.Second * time.Duration(readWriteTimeout) + client.Config.HTTPTimeout.IdleConnTimeout = + time.Second * time.Duration(readWriteTimeout) + client.Config.HTTPTimeout.LongTimeout = + time.Second * time.Duration(readWriteTimeout*10) + } +} + +// MaxConns sets the HTTP max connections for a client. +// +// maxIdleConns controls the maximum number of idle (keep-alive) connections across all hosts. Default is 100. +// maxIdleConnsPerHost controls the maximum idle (keep-alive) connections to keep per-host. Default is 100. +// maxConnsPerHost limits the total number of connections per host. Default is no limit. +// +func MaxConns(maxIdleConns, maxIdleConnsPerHost, maxConnsPerHost int) ClientOption { + return func(client *Client) { + client.Config.HTTPMaxConns.MaxIdleConns = maxIdleConns + client.Config.HTTPMaxConns.MaxIdleConnsPerHost = maxIdleConnsPerHost + client.Config.HTTPMaxConns.MaxConnsPerHost = maxConnsPerHost + } +} + +// SecurityToken sets the temporary user's SecurityToken. +// +// token STS token +// +func SecurityToken(token string) ClientOption { + return func(client *Client) { + client.Config.SecurityToken = strings.TrimSpace(token) + } +} + +// EnableMD5 enables MD5 validation. +// +// isEnableMD5 true: enable MD5 validation; false: disable MD5 validation. +// +func EnableMD5(isEnableMD5 bool) ClientOption { + return func(client *Client) { + client.Config.IsEnableMD5 = isEnableMD5 + } +} + +// MD5ThresholdCalcInMemory sets the memory usage threshold for computing the MD5, default is 16MB. +// +// threshold the memory threshold in bytes. When the uploaded content is more than 16MB, the temp file is used for computing the MD5. +// +func MD5ThresholdCalcInMemory(threshold int64) ClientOption { + return func(client *Client) { + client.Config.MD5Threshold = threshold + } +} + +// EnableCRC enables the CRC checksum. Default is true. +// +// isEnableCRC true: enable CRC checksum; false: disable the CRC checksum. +// +func EnableCRC(isEnableCRC bool) ClientOption { + return func(client *Client) { + client.Config.IsEnableCRC = isEnableCRC + } +} + +// UserAgent specifies UserAgent. The default is aliyun-sdk-go/1.2.0 (windows/-/amd64;go1.5.2). +// +// userAgent the user agent string. +// +func UserAgent(userAgent string) ClientOption { + return func(client *Client) { + client.Config.UserAgent = userAgent + client.Config.UserSetUa = true + } +} + +// Proxy sets the proxy (optional). The default is not using proxy. +// +// proxyHost the proxy host in the format "host:port". For example, proxy.com:80 . +// +func Proxy(proxyHost string) ClientOption { + return func(client *Client) { + client.Config.IsUseProxy = true + client.Config.ProxyHost = proxyHost + } +} + +// AuthProxy sets the proxy information with user name and password. +// +// proxyHost the proxy host in the format "host:port". For example, proxy.com:80 . +// proxyUser the proxy user name. +// proxyPassword the proxy password. +// +func AuthProxy(proxyHost, proxyUser, proxyPassword string) ClientOption { + return func(client *Client) { + client.Config.IsUseProxy = true + client.Config.ProxyHost = proxyHost + client.Config.IsAuthProxy = true + client.Config.ProxyUser = proxyUser + client.Config.ProxyPassword = proxyPassword + } +} + +// +// HTTPClient sets the http.Client in use to the one passed in +// +func HTTPClient(HTTPClient *http.Client) ClientOption { + return func(client *Client) { + client.HTTPClient = HTTPClient + } +} + +// +// SetLogLevel sets the oss sdk log level +// +func SetLogLevel(LogLevel int) ClientOption { + return func(client *Client) { + client.Config.LogLevel = LogLevel + } +} + +// +// SetLogger sets the oss sdk logger +// +func SetLogger(Logger *log.Logger) ClientOption { + return func(client *Client) { + client.Config.Logger = Logger + } +} + +// SetCredentialsProvider sets function for get the user's ak +func SetCredentialsProvider(provider CredentialsProvider) ClientOption { + return func(client *Client) { + client.Config.CredentialsProvider = provider + } +} + +// SetLocalAddr sets function for local addr +func SetLocalAddr(localAddr net.Addr) ClientOption { + return func(client *Client) { + client.Config.LocalAddr = localAddr + } +} + +// AuthVersion sets auth version: v1 or v2 signature which oss_server needed +func AuthVersion(authVersion AuthVersionType) ClientOption { + return func(client *Client) { + client.Config.AuthVersion = authVersion + } +} + +// AdditionalHeaders sets special http headers needed to be signed +func AdditionalHeaders(headers []string) ClientOption { + return func(client *Client) { + client.Config.AdditionalHeaders = headers + } +} + +// RedirectEnabled only effective from go1.7 onward,RedirectEnabled set http redirect enabled or not +func RedirectEnabled(enabled bool) ClientOption { + return func(client *Client) { + client.Config.RedirectEnabled = enabled + } +} + +// InsecureSkipVerify skip verifying tls certificate file +func InsecureSkipVerify(enabled bool) ClientOption { + return func(client *Client) { + client.Config.InsecureSkipVerify = enabled + } +} + +// Region set region +func Region(region string) ClientOption { + return func(client *Client) { + client.Config.Region = region + } +} + +// CloudBoxId set cloudBox id +func CloudBoxId(cloudBoxId string) ClientOption { + return func(client *Client) { + client.Config.CloudBoxId = cloudBoxId + } +} + +// Product set product type +func Product(product string) ClientOption { + return func(client *Client) { + client.Config.Product = product + } +} + +// VerifyObjectStrict sets the flag of verifying object name strictly. +func VerifyObjectStrict(enable bool) ClientOption { + return func(client *Client) { + client.Config.VerifyObjectStrict = enable + } +} + +// Private +func (client Client) do(method, bucketName string, params map[string]interface{}, + headers map[string]string, data io.Reader, options ...Option) (*Response, error) { + err := CheckBucketName(bucketName) + if len(bucketName) > 0 && err != nil { + return nil, err + } + + // option headers + addHeaders := make(map[string]string) + err = handleOptions(addHeaders, options) + if err != nil { + return nil, err + } + + // merge header + if headers == nil { + headers = make(map[string]string) + } + + for k, v := range addHeaders { + if _, ok := headers[k]; !ok { + headers[k] = v + } + } + + resp, err := client.Conn.Do(method, bucketName, "", params, headers, data, 0, nil) + + // get response header + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + pRespHeader := respHeader.(*http.Header) + if resp != nil { + *pRespHeader = resp.Headers + } + } + + return resp, err +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go new file mode 100644 index 00000000000..305fbcf1223 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go @@ -0,0 +1,301 @@ +package oss + +import ( + "bytes" + "fmt" + "log" + "net" + "os" + "time" +) + +// Define the level of the output log +const ( + LogOff = iota + Error + Warn + Info + Debug +) + +// LogTag Tag for each level of log +var LogTag = []string{"[error]", "[warn]", "[info]", "[debug]"} + +// HTTPTimeout defines HTTP timeout. +type HTTPTimeout struct { + ConnectTimeout time.Duration + ReadWriteTimeout time.Duration + HeaderTimeout time.Duration + LongTimeout time.Duration + IdleConnTimeout time.Duration +} + +// HTTPMaxConns defines max idle connections and max idle connections per host +type HTTPMaxConns struct { + MaxIdleConns int + MaxIdleConnsPerHost int + MaxConnsPerHost int +} + +// Credentials is interface for get AccessKeyID,AccessKeySecret,SecurityToken +type Credentials interface { + GetAccessKeyID() string + GetAccessKeySecret() string + GetSecurityToken() string +} + +// CredentialsProvider is interface for get Credential Info +type CredentialsProvider interface { + GetCredentials() Credentials +} + +type CredentialsProviderE interface { + CredentialsProvider + GetCredentialsE() (Credentials, error) +} + +type defaultCredentials struct { + config *Config +} + +func (defCre *defaultCredentials) GetAccessKeyID() string { + return defCre.config.AccessKeyID +} + +func (defCre *defaultCredentials) GetAccessKeySecret() string { + return defCre.config.AccessKeySecret +} + +func (defCre *defaultCredentials) GetSecurityToken() string { + return defCre.config.SecurityToken +} + +type defaultCredentialsProvider struct { + config *Config +} + +func (defBuild *defaultCredentialsProvider) GetCredentials() Credentials { + return &defaultCredentials{config: defBuild.config} +} + +type envCredentials struct { + AccessKeyId string + AccessKeySecret string + SecurityToken string +} + +type EnvironmentVariableCredentialsProvider struct { + cred Credentials +} + +func (credentials *envCredentials) GetAccessKeyID() string { + return credentials.AccessKeyId +} + +func (credentials *envCredentials) GetAccessKeySecret() string { + return credentials.AccessKeySecret +} + +func (credentials *envCredentials) GetSecurityToken() string { + return credentials.SecurityToken +} + +func (defBuild *EnvironmentVariableCredentialsProvider) GetCredentials() Credentials { + var accessID, accessKey, token string + if defBuild.cred == nil { + accessID = os.Getenv("OSS_ACCESS_KEY_ID") + accessKey = os.Getenv("OSS_ACCESS_KEY_SECRET") + token = os.Getenv("OSS_SESSION_TOKEN") + } else { + accessID = defBuild.cred.GetAccessKeyID() + accessKey = defBuild.cred.GetAccessKeySecret() + token = defBuild.cred.GetSecurityToken() + } + + return &envCredentials{ + AccessKeyId: accessID, + AccessKeySecret: accessKey, + SecurityToken: token, + } +} + +func NewEnvironmentVariableCredentialsProvider() (EnvironmentVariableCredentialsProvider, error) { + var provider EnvironmentVariableCredentialsProvider + accessID := os.Getenv("OSS_ACCESS_KEY_ID") + if accessID == "" { + return provider, fmt.Errorf("access key id is empty!") + } + accessKey := os.Getenv("OSS_ACCESS_KEY_SECRET") + if accessKey == "" { + return provider, fmt.Errorf("access key secret is empty!") + } + token := os.Getenv("OSS_SESSION_TOKEN") + envCredential := &envCredentials{ + AccessKeyId: accessID, + AccessKeySecret: accessKey, + SecurityToken: token, + } + return EnvironmentVariableCredentialsProvider{ + cred: envCredential, + }, nil +} + +// Config defines oss configuration +type Config struct { + Endpoint string // OSS endpoint + AccessKeyID string // AccessId + AccessKeySecret string // AccessKey + RetryTimes uint // Retry count by default it's 5. + UserAgent string // SDK name/version/system information + IsDebug bool // Enable debug mode. Default is false. + Timeout uint // Timeout in seconds. By default it's 60. + SecurityToken string // STS Token + IsCname bool // If cname is in the endpoint. + IsPathStyle bool // If Path Style is in the endpoint. + HTTPTimeout HTTPTimeout // HTTP timeout + HTTPMaxConns HTTPMaxConns // Http max connections + IsUseProxy bool // Flag of using proxy. + ProxyHost string // Flag of using proxy host. + IsAuthProxy bool // Flag of needing authentication. + ProxyUser string // Proxy user + ProxyPassword string // Proxy password + IsEnableMD5 bool // Flag of enabling MD5 for upload. + MD5Threshold int64 // Memory footprint threshold for each MD5 computation (16MB is the default), in byte. When the data is more than that, temp file is used. + IsEnableCRC bool // Flag of enabling CRC for upload. + LogLevel int // Log level + Logger *log.Logger // For write log + UploadLimitSpeed int // Upload limit speed:KB/s, 0 is unlimited + UploadLimiter *OssLimiter // Bandwidth limit reader for upload + DownloadLimitSpeed int // Download limit speed:KB/s, 0 is unlimited + DownloadLimiter *OssLimiter // Bandwidth limit reader for download + CredentialsProvider CredentialsProvider // User provides interface to get AccessKeyID, AccessKeySecret, SecurityToken + LocalAddr net.Addr // local client host info + UserSetUa bool // UserAgent is set by user or not + AuthVersion AuthVersionType // v1 or v2, v4 signature,default is v1 + AdditionalHeaders []string // special http headers needed to be sign + RedirectEnabled bool // only effective from go1.7 onward, enable http redirect or not + InsecureSkipVerify bool // for https, Whether to skip verifying the server certificate file + Region string // such as cn-hangzhou + CloudBoxId string // + Product string // oss or oss-cloudbox, default is oss + VerifyObjectStrict bool // a flag of verifying object name strictly. Default is enable. +} + +// LimitUploadSpeed uploadSpeed:KB/s, 0 is unlimited,default is 0 +func (config *Config) LimitUploadSpeed(uploadSpeed int) error { + if uploadSpeed < 0 { + return fmt.Errorf("invalid argument, the value of uploadSpeed is less than 0") + } else if uploadSpeed == 0 { + config.UploadLimitSpeed = 0 + config.UploadLimiter = nil + return nil + } + + var err error + config.UploadLimiter, err = GetOssLimiter(uploadSpeed) + if err == nil { + config.UploadLimitSpeed = uploadSpeed + } + return err +} + +// LimitDownLoadSpeed downloadSpeed:KB/s, 0 is unlimited,default is 0 +func (config *Config) LimitDownloadSpeed(downloadSpeed int) error { + if downloadSpeed < 0 { + return fmt.Errorf("invalid argument, the value of downloadSpeed is less than 0") + } else if downloadSpeed == 0 { + config.DownloadLimitSpeed = 0 + config.DownloadLimiter = nil + return nil + } + + var err error + config.DownloadLimiter, err = GetOssLimiter(downloadSpeed) + if err == nil { + config.DownloadLimitSpeed = downloadSpeed + } + return err +} + +// WriteLog output log function +func (config *Config) WriteLog(LogLevel int, format string, a ...interface{}) { + if config.LogLevel < LogLevel || config.Logger == nil { + return + } + + var logBuffer bytes.Buffer + logBuffer.WriteString(LogTag[LogLevel-1]) + logBuffer.WriteString(fmt.Sprintf(format, a...)) + config.Logger.Printf("%s", logBuffer.String()) +} + +// for get Credentials +func (config *Config) GetCredentials() Credentials { + return config.CredentialsProvider.GetCredentials() +} + +// for get Sign Product +func (config *Config) GetSignProduct() string { + if config.CloudBoxId != "" { + return "oss-cloudbox" + } + return "oss" +} + +// for get Sign Region +func (config *Config) GetSignRegion() string { + if config.CloudBoxId != "" { + return config.CloudBoxId + } + return config.Region +} + +// getDefaultOssConfig gets the default configuration. +func getDefaultOssConfig() *Config { + config := Config{} + + config.Endpoint = "" + config.AccessKeyID = "" + config.AccessKeySecret = "" + config.RetryTimes = 5 + config.IsDebug = false + config.UserAgent = userAgent() + config.Timeout = 60 // Seconds + config.SecurityToken = "" + config.IsCname = false + config.IsPathStyle = false + + config.HTTPTimeout.ConnectTimeout = time.Second * 30 // 30s + config.HTTPTimeout.ReadWriteTimeout = time.Second * 60 // 60s + config.HTTPTimeout.HeaderTimeout = time.Second * 60 // 60s + config.HTTPTimeout.LongTimeout = time.Second * 300 // 300s + config.HTTPTimeout.IdleConnTimeout = time.Second * 50 // 50s + config.HTTPMaxConns.MaxIdleConns = 100 + config.HTTPMaxConns.MaxIdleConnsPerHost = 100 + + config.IsUseProxy = false + config.ProxyHost = "" + config.IsAuthProxy = false + config.ProxyUser = "" + config.ProxyPassword = "" + + config.MD5Threshold = 16 * 1024 * 1024 // 16MB + config.IsEnableMD5 = false + config.IsEnableCRC = true + + config.LogLevel = LogOff + config.Logger = log.New(os.Stdout, "", log.LstdFlags) + + provider := &defaultCredentialsProvider{config: &config} + config.CredentialsProvider = provider + + config.AuthVersion = AuthV1 + config.RedirectEnabled = true + config.InsecureSkipVerify = false + + config.Product = "oss" + + config.VerifyObjectStrict = true + + return &config +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go new file mode 100644 index 00000000000..86e2b6f2f9d --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go @@ -0,0 +1,1021 @@ +package oss + +import ( + "bytes" + "context" + "crypto/md5" + "encoding/base64" + "encoding/json" + "encoding/xml" + "fmt" + "hash" + "io" + "io/ioutil" + "net" + "net/http" + "net/url" + "os" + "sort" + "strconv" + "strings" + "time" +) + +// Conn defines OSS Conn +type Conn struct { + config *Config + url *urlMaker + client *http.Client +} + +var signKeyList = []string{"acl", "uploads", "location", "cors", + "logging", "website", "referer", "lifecycle", + "delete", "append", "tagging", "objectMeta", + "uploadId", "partNumber", "security-token", + "position", "img", "style", "styleName", + "replication", "replicationProgress", + "replicationLocation", "cname", "bucketInfo", + "comp", "qos", "live", "status", "vod", + "startTime", "endTime", "symlink", + "x-oss-process", "response-content-type", "x-oss-traffic-limit", + "response-content-language", "response-expires", + "response-cache-control", "response-content-disposition", + "response-content-encoding", "udf", "udfName", "udfImage", + "udfId", "udfImageDesc", "udfApplication", "comp", + "udfApplicationLog", "restore", "callback", "callback-var", "qosInfo", + "policy", "stat", "encryption", "versions", "versioning", "versionId", "requestPayment", + "x-oss-request-payer", "sequential", + "inventory", "inventoryId", "continuation-token", "asyncFetch", + "worm", "wormId", "wormExtend", "withHashContext", + "x-oss-enable-md5", "x-oss-enable-sha1", "x-oss-enable-sha256", + "x-oss-hash-ctx", "x-oss-md5-ctx", "transferAcceleration", + "regionList", "cloudboxes", "x-oss-ac-source-ip", "x-oss-ac-subnet-mask", "x-oss-ac-vpc-id", "x-oss-ac-forward-allow", + "metaQuery", "resourceGroup", "rtc", "x-oss-async-process", "responseHeader", +} + +const ( + timeFormatV4 = "20060102T150405Z" + shortTimeFormatV4 = "20060102" + signingAlgorithmV4 = "OSS4-HMAC-SHA256" +) + +// init initializes Conn +func (conn *Conn) init(config *Config, urlMaker *urlMaker, client *http.Client) error { + if client == nil { + // New transport + transport := newTransport(conn, config) + + // Proxy + if conn.config.IsUseProxy { + proxyURL, err := url.Parse(config.ProxyHost) + if err != nil { + return err + } + if config.IsAuthProxy { + if config.ProxyPassword != "" { + proxyURL.User = url.UserPassword(config.ProxyUser, config.ProxyPassword) + } else { + proxyURL.User = url.User(config.ProxyUser) + } + } + transport.Proxy = http.ProxyURL(proxyURL) + } + client = &http.Client{Transport: transport} + if !config.RedirectEnabled { + disableHTTPRedirect(client) + } + } + + conn.config = config + conn.url = urlMaker + conn.client = client + + return nil +} + +// Do sends request and returns the response +func (conn Conn) Do(method, bucketName, objectName string, params map[string]interface{}, headers map[string]string, + data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { + return conn.DoWithContext(nil, method, bucketName, objectName, params, headers, data, initCRC, listener) +} + +// DoWithContext sends request and returns the response with context +func (conn Conn) DoWithContext(ctx context.Context, method, bucketName, objectName string, params map[string]interface{}, headers map[string]string, + data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { + urlParams := conn.getURLParams(params) + subResource := conn.getSubResource(params) + uri := conn.url.getURL(bucketName, objectName, urlParams) + + resource := "" + if conn.config.AuthVersion != AuthV4 { + resource = conn.getResource(bucketName, objectName, subResource) + } else { + resource = conn.getResourceV4(bucketName, objectName, subResource) + } + + return conn.doRequest(ctx, method, uri, resource, headers, data, initCRC, listener) +} + +// DoURL sends the request with signed URL and returns the response result. +func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]string, + data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { + return conn.DoURLWithContext(nil, method, signedURL, headers, data, initCRC, listener) +} + +// DoURLWithContext sends the request with signed URL and context and returns the response result. +func (conn Conn) DoURLWithContext(ctx context.Context, method HTTPMethod, signedURL string, headers map[string]string, + data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { + // Get URI from signedURL + uri, err := url.ParseRequestURI(signedURL) + if err != nil { + return nil, err + } + + m := strings.ToUpper(string(method)) + req := &http.Request{ + Method: m, + URL: uri, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(http.Header), + Host: uri.Host, + } + + if ctx != nil { + req = req.WithContext(ctx) + } + tracker := &readerTracker{completedBytes: 0} + fd, crc := conn.handleBody(req, data, initCRC, listener, tracker) + if fd != nil { + defer func() { + fd.Close() + os.Remove(fd.Name()) + }() + } + + if conn.config.IsAuthProxy { + auth := conn.config.ProxyUser + ":" + conn.config.ProxyPassword + basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) + req.Header.Set("Proxy-Authorization", basic) + } + + req.Header.Set(HTTPHeaderHost, req.Host) + req.Header.Set(HTTPHeaderUserAgent, conn.config.UserAgent) + + if headers != nil { + for k, v := range headers { + req.Header.Set(k, v) + } + } + + // Transfer started + event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength, 0) + publishProgress(listener, event) + + if conn.config.LogLevel >= Debug { + conn.LoggerHTTPReq(req) + } + + resp, err := conn.client.Do(req) + if err != nil { + // Transfer failed + conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error()) + event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0) + publishProgress(listener, event) + + return nil, err + } + + if conn.config.LogLevel >= Debug { + //print out http resp + conn.LoggerHTTPResp(req, resp) + } + + // Transfer completed + event = newProgressEvent(TransferCompletedEvent, tracker.completedBytes, req.ContentLength, 0) + publishProgress(listener, event) + + return conn.handleResponse(resp, crc) +} + +func (conn Conn) getURLParams(params map[string]interface{}) string { + // Sort + keys := make([]string, 0, len(params)) + for k := range params { + keys = append(keys, k) + } + sort.Strings(keys) + + // Serialize + var buf bytes.Buffer + for _, k := range keys { + if buf.Len() > 0 { + buf.WriteByte('&') + } + buf.WriteString(url.QueryEscape(k)) + if params[k] != nil && params[k].(string) != "" { + buf.WriteString("=" + strings.Replace(url.QueryEscape(params[k].(string)), "+", "%20", -1)) + } + } + + return buf.String() +} + +func (conn Conn) getSubResource(params map[string]interface{}) string { + // Sort + keys := make([]string, 0, len(params)) + signParams := make(map[string]string) + for k := range params { + if conn.config.AuthVersion == AuthV2 || conn.config.AuthVersion == AuthV4 { + encodedKey := url.QueryEscape(k) + keys = append(keys, encodedKey) + if params[k] != nil && params[k] != "" { + signParams[encodedKey] = strings.Replace(url.QueryEscape(params[k].(string)), "+", "%20", -1) + } + } else if conn.isParamSign(k) { + keys = append(keys, k) + if params[k] != nil { + signParams[k] = params[k].(string) + } + } + } + sort.Strings(keys) + + // Serialize + var buf bytes.Buffer + for _, k := range keys { + if buf.Len() > 0 { + buf.WriteByte('&') + } + buf.WriteString(k) + if _, ok := signParams[k]; ok { + if signParams[k] != "" { + buf.WriteString("=" + signParams[k]) + } + } + } + return buf.String() +} + +func (conn Conn) isParamSign(paramKey string) bool { + for _, k := range signKeyList { + if paramKey == k { + return true + } + } + return false +} + +// getResource gets canonicalized resource +func (conn Conn) getResource(bucketName, objectName, subResource string) string { + if subResource != "" { + subResource = "?" + subResource + } + if bucketName == "" { + if conn.config.AuthVersion == AuthV2 { + return url.QueryEscape("/") + subResource + } + return fmt.Sprintf("/%s%s", bucketName, subResource) + } + if conn.config.AuthVersion == AuthV2 { + return url.QueryEscape("/"+bucketName+"/") + strings.Replace(url.QueryEscape(objectName), "+", "%20", -1) + subResource + } + return fmt.Sprintf("/%s/%s%s", bucketName, objectName, subResource) +} + +// getResource gets canonicalized resource +func (conn Conn) getResourceV4(bucketName, objectName, subResource string) string { + if subResource != "" { + subResource = "?" + subResource + } + + if bucketName == "" { + return fmt.Sprintf("/%s", subResource) + } + + if objectName != "" { + objectName = url.QueryEscape(objectName) + objectName = strings.Replace(objectName, "+", "%20", -1) + objectName = strings.Replace(objectName, "%2F", "/", -1) + return fmt.Sprintf("/%s/%s%s", bucketName, objectName, subResource) + } + return fmt.Sprintf("/%s/%s", bucketName, subResource) +} + +func (conn Conn) doRequest(ctx context.Context, method string, uri *url.URL, canonicalizedResource string, headers map[string]string, + data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) { + method = strings.ToUpper(method) + var req *http.Request + var err error + req = &http.Request{ + Method: method, + URL: uri, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(http.Header), + Host: uri.Host, + } + if ctx != nil { + req = req.WithContext(ctx) + } + tracker := &readerTracker{completedBytes: 0} + fd, crc := conn.handleBody(req, data, initCRC, listener, tracker) + if fd != nil { + defer func() { + fd.Close() + os.Remove(fd.Name()) + }() + } + + if conn.config.IsAuthProxy { + auth := conn.config.ProxyUser + ":" + conn.config.ProxyPassword + basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) + req.Header.Set("Proxy-Authorization", basic) + } + + stNow := time.Now().UTC() + req.Header.Set(HTTPHeaderDate, stNow.Format(http.TimeFormat)) + req.Header.Set(HTTPHeaderHost, req.Host) + req.Header.Set(HTTPHeaderUserAgent, conn.config.UserAgent) + + if conn.config.AuthVersion == AuthV4 { + req.Header.Set(HttpHeaderOssContentSha256, DefaultContentSha256) + } + + var akIf Credentials + if providerE, ok := conn.config.CredentialsProvider.(CredentialsProviderE); ok { + if akIf, err = providerE.GetCredentialsE(); err != nil { + return nil, err + } + } else { + akIf = conn.config.GetCredentials() + } + + if akIf.GetSecurityToken() != "" { + req.Header.Set(HTTPHeaderOssSecurityToken, akIf.GetSecurityToken()) + } + + if headers != nil { + for k, v := range headers { + req.Header.Set(k, v) + } + } + + conn.signHeader(req, canonicalizedResource, akIf) + + // Transfer started + event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength, 0) + publishProgress(listener, event) + + if conn.config.LogLevel >= Debug { + conn.LoggerHTTPReq(req) + } + + resp, err := conn.client.Do(req) + + if err != nil { + conn.config.WriteLog(Debug, "[Resp:%p]http error:%s\n", req, err.Error()) + // Transfer failed + event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength, 0) + publishProgress(listener, event) + return nil, err + } + + if conn.config.LogLevel >= Debug { + //print out http resp + conn.LoggerHTTPResp(req, resp) + } + + // Transfer completed + event = newProgressEvent(TransferCompletedEvent, tracker.completedBytes, req.ContentLength, 0) + publishProgress(listener, event) + + return conn.handleResponse(resp, crc) +} + +func (conn Conn) signURL(method HTTPMethod, bucketName, objectName string, expiration int64, params map[string]interface{}, headers map[string]string) (string, error) { + var akIf Credentials + var err error + if providerE, ok := conn.config.CredentialsProvider.(CredentialsProviderE); ok { + if akIf, err = providerE.GetCredentialsE(); err != nil { + return "", err + } + } else { + akIf = conn.config.GetCredentials() + } + + m := strings.ToUpper(string(method)) + req := &http.Request{ + Method: m, + Header: make(http.Header), + } + + if conn.config.IsAuthProxy { + auth := conn.config.ProxyUser + ":" + conn.config.ProxyPassword + basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) + req.Header.Set("Proxy-Authorization", basic) + } + + if conn.config.AuthVersion == AuthV4 { + if akIf.GetSecurityToken() != "" { + params[HTTPParamOssSecurityToken] = akIf.GetSecurityToken() + } + + if headers != nil { + for k, v := range headers { + req.Header.Set(k, v) + } + } + + now := time.Now().UTC() + expires := expiration - now.Unix() + product := conn.config.GetSignProduct() + region := conn.config.GetSignRegion() + strDay := now.Format(shortTimeFormatV4) + additionalList, _ := conn.getAdditionalHeaderKeys(req) + + params[HTTPParamSignatureVersion] = signingAlgorithmV4 + params[HTTPParamCredential] = fmt.Sprintf("%s/%s/%s/%s/aliyun_v4_request", akIf.GetAccessKeyID(), strDay, region, product) + params[HTTPParamDate] = now.Format(timeFormatV4) + params[HTTPParamExpiresV2] = strconv.FormatInt(expires, 10) + if len(additionalList) > 0 { + params[HTTPParamAdditionalHeadersV2] = strings.Join(additionalList, ";") + } + + subResource := conn.getSubResource(params) + canonicalizedResource := conn.getResourceV4(bucketName, objectName, subResource) + authorizationStr := conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), &now) + params[HTTPParamSignatureV2] = authorizationStr + } else { + if akIf.GetSecurityToken() != "" { + params[HTTPParamSecurityToken] = akIf.GetSecurityToken() + } + + req.Header.Set(HTTPHeaderDate, strconv.FormatInt(expiration, 10)) + + if headers != nil { + for k, v := range headers { + req.Header.Set(k, v) + } + } + + if conn.config.AuthVersion == AuthV2 { + params[HTTPParamSignatureVersion] = "OSS2" + params[HTTPParamExpiresV2] = strconv.FormatInt(expiration, 10) + params[HTTPParamAccessKeyIDV2] = conn.config.AccessKeyID + additionalList, _ := conn.getAdditionalHeaderKeys(req) + if len(additionalList) > 0 { + params[HTTPParamAdditionalHeadersV2] = strings.Join(additionalList, ";") + } + } + + subResource := conn.getSubResource(params) + canonicalizedResource := conn.getResource(bucketName, objectName, subResource) + signedStr := conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()) + + if conn.config.AuthVersion == AuthV1 { + params[HTTPParamExpires] = strconv.FormatInt(expiration, 10) + params[HTTPParamAccessKeyID] = akIf.GetAccessKeyID() + params[HTTPParamSignature] = signedStr + } else if conn.config.AuthVersion == AuthV2 { + params[HTTPParamSignatureV2] = signedStr + } + } + + urlParams := conn.getURLParams(params) + return conn.url.getSignURL(bucketName, objectName, urlParams), nil +} + +func (conn Conn) signRtmpURL(bucketName, channelName, playlistName string, expiration int64) string { + params := map[string]interface{}{} + if playlistName != "" { + params[HTTPParamPlaylistName] = playlistName + } + expireStr := strconv.FormatInt(expiration, 10) + params[HTTPParamExpires] = expireStr + + akIf := conn.config.GetCredentials() + if akIf.GetAccessKeyID() != "" { + params[HTTPParamAccessKeyID] = akIf.GetAccessKeyID() + if akIf.GetSecurityToken() != "" { + params[HTTPParamSecurityToken] = akIf.GetSecurityToken() + } + signedStr := conn.getRtmpSignedStr(bucketName, channelName, playlistName, expiration, akIf.GetAccessKeySecret(), params) + params[HTTPParamSignature] = signedStr + } + + urlParams := conn.getURLParams(params) + return conn.url.getSignRtmpURL(bucketName, channelName, urlParams) +} + +// handleBody handles request body +func (conn Conn) handleBody(req *http.Request, body io.Reader, initCRC uint64, + listener ProgressListener, tracker *readerTracker) (*os.File, hash.Hash64) { + var file *os.File + var crc hash.Hash64 + reader := body + readerLen, err := GetReaderLen(reader) + if err == nil { + req.ContentLength = readerLen + } + req.Header.Set(HTTPHeaderContentLength, strconv.FormatInt(req.ContentLength, 10)) + + // MD5 + if body != nil && conn.config.IsEnableMD5 && req.Header.Get(HTTPHeaderContentMD5) == "" { + md5 := "" + reader, md5, file, _ = calcMD5(body, req.ContentLength, conn.config.MD5Threshold) + req.Header.Set(HTTPHeaderContentMD5, md5) + } + + // CRC + if reader != nil && conn.config.IsEnableCRC { + crc = NewCRC(CrcTable(), initCRC) + reader = TeeReader(reader, crc, req.ContentLength, listener, tracker) + } + + // HTTP body + rc, ok := reader.(io.ReadCloser) + if !ok && reader != nil { + rc = ioutil.NopCloser(reader) + } + + if conn.isUploadLimitReq(req) { + limitReader := &LimitSpeedReader{ + reader: rc, + ossLimiter: conn.config.UploadLimiter, + } + req.Body = limitReader + } else { + req.Body = rc + } + return file, crc +} + +// isUploadLimitReq: judge limit upload speed or not +func (conn Conn) isUploadLimitReq(req *http.Request) bool { + if conn.config.UploadLimitSpeed == 0 || conn.config.UploadLimiter == nil { + return false + } + + if req.Method != "GET" && req.Method != "DELETE" && req.Method != "HEAD" { + if req.ContentLength > 0 { + return true + } + } + return false +} + +func tryGetFileSize(f *os.File) int64 { + fInfo, _ := f.Stat() + return fInfo.Size() +} + +// handleResponse handles response +func (conn Conn) handleResponse(resp *http.Response, crc hash.Hash64) (*Response, error) { + var cliCRC uint64 + var srvCRC uint64 + + statusCode := resp.StatusCode + if statusCode/100 != 2 { + if statusCode >= 400 && statusCode <= 505 { + // 4xx and 5xx indicate that the operation has error occurred + var respBody []byte + var errorXml []byte + respBody, err := readResponseBody(resp) + if err != nil { + return nil, err + } + errorXml = respBody + if len(respBody) == 0 && len(resp.Header.Get(HTTPHeaderOssErr)) > 0 { + errorXml, err = base64.StdEncoding.DecodeString(resp.Header.Get(HTTPHeaderOssErr)) + if err != nil { + errorXml = respBody + } + } + if len(errorXml) == 0 { + err = ServiceError{ + StatusCode: statusCode, + RequestID: resp.Header.Get(HTTPHeaderOssRequestID), + Ec: resp.Header.Get(HTTPHeaderOssEc), + } + } else { + srvErr, errIn := serviceErrFromXML(errorXml, resp.StatusCode, + resp.Header.Get(HTTPHeaderOssRequestID)) + if errIn != nil { // error unmarshal the error response + if len(resp.Header.Get(HTTPHeaderOssEc)) > 0 { + err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s, ec = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID), resp.Header.Get(HTTPHeaderOssEc)) + } else { + err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID)) + } + } else { + err = srvErr + } + } + return &Response{ + StatusCode: resp.StatusCode, + Headers: resp.Header, + Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body + }, err + } else if statusCode >= 300 && statusCode <= 307 { + // OSS use 3xx, but response has no body + err := fmt.Errorf("oss: service returned %d,%s", resp.StatusCode, resp.Status) + return &Response{ + StatusCode: resp.StatusCode, + Headers: resp.Header, + Body: resp.Body, + }, err + } else { + // (0,300) [308,400) [506,) + // Other extended http StatusCode + var respBody []byte + var errorXml []byte + respBody, err := readResponseBody(resp) + if err != nil { + return &Response{StatusCode: resp.StatusCode, Headers: resp.Header, Body: ioutil.NopCloser(bytes.NewReader(respBody))}, err + } + errorXml = respBody + if len(respBody) == 0 && len(resp.Header.Get(HTTPHeaderOssErr)) > 0 { + errorXml, err = base64.StdEncoding.DecodeString(resp.Header.Get(HTTPHeaderOssErr)) + if err != nil { + errorXml = respBody + } + } + if len(errorXml) == 0 { + err = ServiceError{ + StatusCode: statusCode, + RequestID: resp.Header.Get(HTTPHeaderOssRequestID), + Ec: resp.Header.Get(HTTPHeaderOssEc), + } + } else { + srvErr, errIn := serviceErrFromXML(errorXml, resp.StatusCode, + resp.Header.Get(HTTPHeaderOssRequestID)) + if errIn != nil { // error unmarshal the error response + if len(resp.Header.Get(HTTPHeaderOssEc)) > 0 { + err = fmt.Errorf("unknown response body, status = %s, RequestId = %s, ec = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID), resp.Header.Get(HTTPHeaderOssEc)) + } else { + err = fmt.Errorf("unknown response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID)) + } + } else { + err = srvErr + } + } + return &Response{ + StatusCode: resp.StatusCode, + Headers: resp.Header, + Body: ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body + }, err + } + } else { + if conn.config.IsEnableCRC && crc != nil { + cliCRC = crc.Sum64() + } + srvCRC, _ = strconv.ParseUint(resp.Header.Get(HTTPHeaderOssCRC64), 10, 64) + + realBody := resp.Body + if conn.isDownloadLimitResponse(resp) { + limitReader := &LimitSpeedReader{ + reader: realBody, + ossLimiter: conn.config.DownloadLimiter, + } + realBody = limitReader + } + + // 2xx, successful + return &Response{ + StatusCode: resp.StatusCode, + Headers: resp.Header, + Body: realBody, + ClientCRC: cliCRC, + ServerCRC: srvCRC, + }, nil + } +} + +// isUploadLimitReq: judge limit upload speed or not +func (conn Conn) isDownloadLimitResponse(resp *http.Response) bool { + if resp == nil || conn.config.DownloadLimitSpeed == 0 || conn.config.DownloadLimiter == nil { + return false + } + + if strings.EqualFold(resp.Request.Method, "GET") { + return true + } + return false +} + +// LoggerHTTPReq Print the header information of the http request +func (conn Conn) LoggerHTTPReq(req *http.Request) { + var logBuffer bytes.Buffer + logBuffer.WriteString(fmt.Sprintf("[Req:%p]Method:%s\t", req, req.Method)) + logBuffer.WriteString(fmt.Sprintf("Host:%s\t", req.URL.Host)) + logBuffer.WriteString(fmt.Sprintf("Path:%s\t", req.URL.Path)) + logBuffer.WriteString(fmt.Sprintf("Query:%s\t", req.URL.RawQuery)) + logBuffer.WriteString(fmt.Sprintf("Header info:")) + + for k, v := range req.Header { + var valueBuffer bytes.Buffer + for j := 0; j < len(v); j++ { + if j > 0 { + valueBuffer.WriteString(" ") + } + valueBuffer.WriteString(v[j]) + } + logBuffer.WriteString(fmt.Sprintf("\t%s:%s", k, valueBuffer.String())) + } + conn.config.WriteLog(Debug, "%s\n", logBuffer.String()) +} + +// LoggerHTTPResp Print Response to http request +func (conn Conn) LoggerHTTPResp(req *http.Request, resp *http.Response) { + var logBuffer bytes.Buffer + logBuffer.WriteString(fmt.Sprintf("[Resp:%p]StatusCode:%d\t", req, resp.StatusCode)) + logBuffer.WriteString(fmt.Sprintf("Header info:")) + for k, v := range resp.Header { + var valueBuffer bytes.Buffer + for j := 0; j < len(v); j++ { + if j > 0 { + valueBuffer.WriteString(" ") + } + valueBuffer.WriteString(v[j]) + } + logBuffer.WriteString(fmt.Sprintf("\t%s:%s", k, valueBuffer.String())) + } + conn.config.WriteLog(Debug, "%s\n", logBuffer.String()) +} + +func calcMD5(body io.Reader, contentLen, md5Threshold int64) (reader io.Reader, b64 string, tempFile *os.File, err error) { + if contentLen == 0 || contentLen > md5Threshold { + // Huge body, use temporary file + tempFile, err = ioutil.TempFile(os.TempDir(), TempFilePrefix) + if tempFile != nil { + io.Copy(tempFile, body) + tempFile.Seek(0, os.SEEK_SET) + md5 := md5.New() + io.Copy(md5, tempFile) + sum := md5.Sum(nil) + b64 = base64.StdEncoding.EncodeToString(sum[:]) + tempFile.Seek(0, os.SEEK_SET) + reader = tempFile + } + } else { + // Small body, use memory + buf, _ := ioutil.ReadAll(body) + sum := md5.Sum(buf) + b64 = base64.StdEncoding.EncodeToString(sum[:]) + reader = bytes.NewReader(buf) + } + return +} + +func readResponseBody(resp *http.Response) ([]byte, error) { + defer resp.Body.Close() + out, err := ioutil.ReadAll(resp.Body) + if err == io.EOF { + err = nil + } + return out, err +} + +func serviceErrFromXML(body []byte, statusCode int, requestID string) (ServiceError, error) { + var storageErr ServiceError + + if err := xml.Unmarshal(body, &storageErr); err != nil { + return storageErr, err + } + + storageErr.StatusCode = statusCode + storageErr.RequestID = requestID + storageErr.RawMessage = string(body) + return storageErr, nil +} + +func xmlUnmarshal(body io.Reader, v interface{}) error { + data, err := ioutil.ReadAll(body) + if err != nil { + return err + } + return xml.Unmarshal(data, v) +} + +func jsonUnmarshal(body io.Reader, v interface{}) error { + data, err := ioutil.ReadAll(body) + if err != nil { + return err + } + return json.Unmarshal(data, v) +} + +// timeoutConn handles HTTP timeout +type timeoutConn struct { + conn net.Conn + timeout time.Duration + longTimeout time.Duration +} + +func newTimeoutConn(conn net.Conn, timeout time.Duration, longTimeout time.Duration) *timeoutConn { + conn.SetReadDeadline(time.Now().Add(longTimeout)) + return &timeoutConn{ + conn: conn, + timeout: timeout, + longTimeout: longTimeout, + } +} + +func (c *timeoutConn) Read(b []byte) (n int, err error) { + c.SetReadDeadline(time.Now().Add(c.timeout)) + n, err = c.conn.Read(b) + c.SetReadDeadline(time.Now().Add(c.longTimeout)) + return n, err +} + +func (c *timeoutConn) Write(b []byte) (n int, err error) { + c.SetWriteDeadline(time.Now().Add(c.timeout)) + n, err = c.conn.Write(b) + c.SetReadDeadline(time.Now().Add(c.longTimeout)) + return n, err +} + +func (c *timeoutConn) Close() error { + return c.conn.Close() +} + +func (c *timeoutConn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +func (c *timeoutConn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +func (c *timeoutConn) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} + +func (c *timeoutConn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +func (c *timeoutConn) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +} + +// UrlMaker builds URL and resource +const ( + urlTypeCname = 1 + urlTypeIP = 2 + urlTypeAliyun = 3 + urlTypePathStyle = 4 +) + +type urlMaker struct { + Scheme string // HTTP or HTTPS + NetLoc string // Host or IP + Type int // 1 CNAME, 2 IP, 3 ALIYUN + IsProxy bool // Proxy +} + +// Init parses endpoint +func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) error { + return um.InitExt(endpoint, isCname, isProxy, false) +} + +// InitExt parses endpoint +func (um *urlMaker) InitExt(endpoint string, isCname bool, isProxy bool, isPathStyle bool) error { + if strings.HasPrefix(endpoint, "http://") { + um.Scheme = "http" + um.NetLoc = endpoint[len("http://"):] + } else if strings.HasPrefix(endpoint, "https://") { + um.Scheme = "https" + um.NetLoc = endpoint[len("https://"):] + } else { + um.Scheme = "http" + um.NetLoc = endpoint + } + + //use url.Parse() to get real host + strUrl := um.Scheme + "://" + um.NetLoc + url, err := url.Parse(strUrl) + if err != nil { + return err + } + + um.NetLoc = url.Host + host, _, err := net.SplitHostPort(um.NetLoc) + if err != nil { + host = um.NetLoc + if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' { + host = host[1 : len(host)-1] + } + } + + ip := net.ParseIP(host) + if ip != nil { + um.Type = urlTypeIP + } else if isCname { + um.Type = urlTypeCname + } else if isPathStyle { + um.Type = urlTypePathStyle + } else { + um.Type = urlTypeAliyun + } + um.IsProxy = isProxy + + return nil +} + +// getURL gets URL +func (um urlMaker) getURL(bucket, object, params string) *url.URL { + host, path := um.buildURL(bucket, object) + addr := "" + if params == "" { + addr = fmt.Sprintf("%s://%s%s", um.Scheme, host, path) + } else { + addr = fmt.Sprintf("%s://%s%s?%s", um.Scheme, host, path, params) + } + uri, _ := url.ParseRequestURI(addr) + return uri +} + +// getSignURL gets sign URL +func (um urlMaker) getSignURL(bucket, object, params string) string { + host, path := um.buildURL(bucket, object) + return fmt.Sprintf("%s://%s%s?%s", um.Scheme, host, path, params) +} + +// getSignRtmpURL Build Sign Rtmp URL +func (um urlMaker) getSignRtmpURL(bucket, channelName, params string) string { + host, path := um.buildURL(bucket, "live") + + channelName = url.QueryEscape(channelName) + channelName = strings.Replace(channelName, "+", "%20", -1) + + return fmt.Sprintf("rtmp://%s%s/%s?%s", host, path, channelName, params) +} + +// buildURL builds URL +func (um urlMaker) buildURL(bucket, object string) (string, string) { + var host = "" + var path = "" + + object = url.QueryEscape(object) + object = strings.Replace(object, "+", "%20", -1) + + if um.Type == urlTypeCname { + host = um.NetLoc + path = "/" + object + } else if um.Type == urlTypeIP || um.Type == urlTypePathStyle { + if bucket == "" { + host = um.NetLoc + path = "/" + } else { + host = um.NetLoc + path = fmt.Sprintf("/%s/%s", bucket, object) + } + } else { + if bucket == "" { + host = um.NetLoc + path = "/" + } else { + host = bucket + "." + um.NetLoc + path = "/" + object + } + } + + return host, path +} + +// buildURL builds URL +func (um urlMaker) buildURLV4(bucket, object string) (string, string) { + var host = "" + var path = "" + + object = url.QueryEscape(object) + object = strings.Replace(object, "+", "%20", -1) + + // no escape / + object = strings.Replace(object, "%2F", "/", -1) + + if um.Type == urlTypeCname { + host = um.NetLoc + path = "/" + object + } else if um.Type == urlTypeIP || um.Type == urlTypePathStyle { + if bucket == "" { + host = um.NetLoc + path = "/" + } else { + host = um.NetLoc + path = fmt.Sprintf("/%s/%s", bucket, object) + } + } else { + if bucket == "" { + host = um.NetLoc + path = "/" + } else { + host = bucket + "." + um.NetLoc + path = fmt.Sprintf("/%s/%s", bucket, object) + } + } + return host, path +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go new file mode 100644 index 00000000000..400f7cf9512 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go @@ -0,0 +1,273 @@ +package oss + +import "os" + +// ACLType bucket/object ACL +type ACLType string + +const ( + // ACLPrivate definition : private read and write + ACLPrivate ACLType = "private" + + // ACLPublicRead definition : public read and private write + ACLPublicRead ACLType = "public-read" + + // ACLPublicReadWrite definition : public read and public write + ACLPublicReadWrite ACLType = "public-read-write" + + // ACLDefault Object. It's only applicable for object. + ACLDefault ACLType = "default" +) + +// bucket versioning status +type VersioningStatus string + +const ( + // Versioning Status definition: Enabled + VersionEnabled VersioningStatus = "Enabled" + + // Versioning Status definition: Suspended + VersionSuspended VersioningStatus = "Suspended" +) + +// MetadataDirectiveType specifying whether use the metadata of source object when copying object. +type MetadataDirectiveType string + +const ( + // MetaCopy the target object's metadata is copied from the source one + MetaCopy MetadataDirectiveType = "COPY" + + // MetaReplace the target object's metadata is created as part of the copy request (not same as the source one) + MetaReplace MetadataDirectiveType = "REPLACE" +) + +// TaggingDirectiveType specifying whether use the tagging of source object when copying object. +type TaggingDirectiveType string + +const ( + // TaggingCopy the target object's tagging is copied from the source one + TaggingCopy TaggingDirectiveType = "COPY" + + // TaggingReplace the target object's tagging is created as part of the copy request (not same as the source one) + TaggingReplace TaggingDirectiveType = "REPLACE" +) + +// AlgorithmType specifying the server side encryption algorithm name +type AlgorithmType string + +const ( + KMSAlgorithm AlgorithmType = "KMS" + AESAlgorithm AlgorithmType = "AES256" + SM4Algorithm AlgorithmType = "SM4" +) + +// StorageClassType bucket storage type +type StorageClassType string + +const ( + // StorageStandard standard + StorageStandard StorageClassType = "Standard" + + // StorageIA infrequent access + StorageIA StorageClassType = "IA" + + // StorageArchive archive + StorageArchive StorageClassType = "Archive" + + // StorageColdArchive cold archive + StorageColdArchive StorageClassType = "ColdArchive" + + // StorageDeepColdArchive deep cold archive + StorageDeepColdArchive StorageClassType = "DeepColdArchive" +) + +//RedundancyType bucket data Redundancy type +type DataRedundancyType string + +const ( + // RedundancyLRS Local redundancy, default value + RedundancyLRS DataRedundancyType = "LRS" + + // RedundancyZRS Same city redundancy + RedundancyZRS DataRedundancyType = "ZRS" +) + +//ObjecthashFuncType +type ObjecthashFuncType string + +const ( + HashFuncSha1 ObjecthashFuncType = "SHA-1" + HashFuncSha256 ObjecthashFuncType = "SHA-256" +) + +// PayerType the type of request payer +type PayerType string + +const ( + // Requester the requester who send the request + Requester PayerType = "Requester" + + // BucketOwner the requester who send the request + BucketOwner PayerType = "BucketOwner" +) + +//RestoreMode the restore mode for coldArchive object +type RestoreMode string + +const ( + //RestoreExpedited object will be restored in 1 hour + RestoreExpedited RestoreMode = "Expedited" + + //RestoreStandard object will be restored in 2-5 hours + RestoreStandard RestoreMode = "Standard" + + //RestoreBulk object will be restored in 5-10 hours + RestoreBulk RestoreMode = "Bulk" +) + +// HTTPMethod HTTP request method +type HTTPMethod string + +const ( + // HTTPGet HTTP GET + HTTPGet HTTPMethod = "GET" + + // HTTPPut HTTP PUT + HTTPPut HTTPMethod = "PUT" + + // HTTPHead HTTP HEAD + HTTPHead HTTPMethod = "HEAD" + + // HTTPPost HTTP POST + HTTPPost HTTPMethod = "POST" + + // HTTPDelete HTTP DELETE + HTTPDelete HTTPMethod = "DELETE" +) + +// HTTP headers +const ( + HTTPHeaderAcceptEncoding string = "Accept-Encoding" + HTTPHeaderAuthorization = "Authorization" + HTTPHeaderCacheControl = "Cache-Control" + HTTPHeaderContentDisposition = "Content-Disposition" + HTTPHeaderContentEncoding = "Content-Encoding" + HTTPHeaderContentLength = "Content-Length" + HTTPHeaderContentMD5 = "Content-MD5" + HTTPHeaderContentType = "Content-Type" + HTTPHeaderContentLanguage = "Content-Language" + HTTPHeaderDate = "Date" + HTTPHeaderEtag = "ETag" + HTTPHeaderExpires = "Expires" + HTTPHeaderHost = "Host" + HTTPHeaderLastModified = "Last-Modified" + HTTPHeaderRange = "Range" + HTTPHeaderLocation = "Location" + HTTPHeaderOrigin = "Origin" + HTTPHeaderServer = "Server" + HTTPHeaderUserAgent = "User-Agent" + HTTPHeaderIfModifiedSince = "If-Modified-Since" + HTTPHeaderIfUnmodifiedSince = "If-Unmodified-Since" + HTTPHeaderIfMatch = "If-Match" + HTTPHeaderIfNoneMatch = "If-None-Match" + HTTPHeaderACReqMethod = "Access-Control-Request-Method" + HTTPHeaderACReqHeaders = "Access-Control-Request-Headers" + + HTTPHeaderOssACL = "X-Oss-Acl" + HTTPHeaderOssMetaPrefix = "X-Oss-Meta-" + HTTPHeaderOssObjectACL = "X-Oss-Object-Acl" + HTTPHeaderOssSecurityToken = "X-Oss-Security-Token" + HTTPHeaderOssServerSideEncryption = "X-Oss-Server-Side-Encryption" + HTTPHeaderOssServerSideEncryptionKeyID = "X-Oss-Server-Side-Encryption-Key-Id" + HTTPHeaderOssServerSideDataEncryption = "X-Oss-Server-Side-Data-Encryption" + HTTPHeaderSSECAlgorithm = "X-Oss-Server-Side-Encryption-Customer-Algorithm" + HTTPHeaderSSECKey = "X-Oss-Server-Side-Encryption-Customer-Key" + HTTPHeaderSSECKeyMd5 = "X-Oss-Server-Side-Encryption-Customer-Key-MD5" + HTTPHeaderOssCopySource = "X-Oss-Copy-Source" + HTTPHeaderOssCopySourceRange = "X-Oss-Copy-Source-Range" + HTTPHeaderOssCopySourceIfMatch = "X-Oss-Copy-Source-If-Match" + HTTPHeaderOssCopySourceIfNoneMatch = "X-Oss-Copy-Source-If-None-Match" + HTTPHeaderOssCopySourceIfModifiedSince = "X-Oss-Copy-Source-If-Modified-Since" + HTTPHeaderOssCopySourceIfUnmodifiedSince = "X-Oss-Copy-Source-If-Unmodified-Since" + HTTPHeaderOssMetadataDirective = "X-Oss-Metadata-Directive" + HTTPHeaderOssNextAppendPosition = "X-Oss-Next-Append-Position" + HTTPHeaderOssRequestID = "X-Oss-Request-Id" + HTTPHeaderOssCRC64 = "X-Oss-Hash-Crc64ecma" + HTTPHeaderOssSymlinkTarget = "X-Oss-Symlink-Target" + HTTPHeaderOssStorageClass = "X-Oss-Storage-Class" + HTTPHeaderOssCallback = "X-Oss-Callback" + HTTPHeaderOssCallbackVar = "X-Oss-Callback-Var" + HTTPHeaderOssRequester = "X-Oss-Request-Payer" + HTTPHeaderOssTagging = "X-Oss-Tagging" + HTTPHeaderOssTaggingDirective = "X-Oss-Tagging-Directive" + HTTPHeaderOssTrafficLimit = "X-Oss-Traffic-Limit" + HTTPHeaderOssForbidOverWrite = "X-Oss-Forbid-Overwrite" + HTTPHeaderOssRangeBehavior = "X-Oss-Range-Behavior" + HTTPHeaderOssTaskID = "X-Oss-Task-Id" + HTTPHeaderOssHashCtx = "X-Oss-Hash-Ctx" + HTTPHeaderOssMd5Ctx = "X-Oss-Md5-Ctx" + HTTPHeaderAllowSameActionOverLap = "X-Oss-Allow-Same-Action-Overlap" + HttpHeaderOssDate = "X-Oss-Date" + HttpHeaderOssContentSha256 = "X-Oss-Content-Sha256" + HttpHeaderOssNotification = "X-Oss-Notification" + HTTPHeaderOssEc = "X-Oss-Ec" + HTTPHeaderOssErr = "X-Oss-Err" +) + +// HTTP Param +const ( + HTTPParamExpires = "Expires" + HTTPParamAccessKeyID = "OSSAccessKeyId" + HTTPParamSignature = "Signature" + HTTPParamSecurityToken = "security-token" + HTTPParamPlaylistName = "playlistName" + + HTTPParamSignatureVersion = "x-oss-signature-version" + HTTPParamExpiresV2 = "x-oss-expires" + HTTPParamAccessKeyIDV2 = "x-oss-access-key-id" + HTTPParamSignatureV2 = "x-oss-signature" + HTTPParamAdditionalHeadersV2 = "x-oss-additional-headers" + HTTPParamCredential = "x-oss-credential" + HTTPParamDate = "x-oss-date" + HTTPParamOssSecurityToken = "x-oss-security-token" +) + +// Other constants +const ( + MaxPartSize = 5 * 1024 * 1024 * 1024 // Max part size, 5GB + MinPartSize = 100 * 1024 // Min part size, 100KB + + FilePermMode = os.FileMode(0664) // Default file permission + + TempFilePrefix = "oss-go-temp-" // Temp file prefix + TempFileSuffix = ".temp" // Temp file suffix + + CheckpointFileSuffix = ".cp" // Checkpoint file suffix + + NullVersion = "null" + + DefaultContentSha256 = "UNSIGNED-PAYLOAD" // for v4 signature + + Version = "v3.0.2" // Go SDK version +) + +// FrameType +const ( + DataFrameType = 8388609 + ContinuousFrameType = 8388612 + EndFrameType = 8388613 + MetaEndFrameCSVType = 8388614 + MetaEndFrameJSONType = 8388615 +) + +// AuthVersion the version of auth +type AuthVersionType string + +const ( + // AuthV1 v1 + AuthV1 AuthVersionType = "v1" + // AuthV2 v2 + AuthV2 AuthVersionType = "v2" + // AuthV4 v4 + AuthV4 AuthVersionType = "v4" +) diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/crc.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/crc.go new file mode 100644 index 00000000000..c96694f2850 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/crc.go @@ -0,0 +1,123 @@ +package oss + +import ( + "hash" + "hash/crc64" +) + +// digest represents the partial evaluation of a checksum. +type digest struct { + crc uint64 + tab *crc64.Table +} + +// NewCRC creates a new hash.Hash64 computing the CRC64 checksum +// using the polynomial represented by the Table. +func NewCRC(tab *crc64.Table, init uint64) hash.Hash64 { return &digest{init, tab} } + +// Size returns the number of bytes sum will return. +func (d *digest) Size() int { return crc64.Size } + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (d *digest) BlockSize() int { return 1 } + +// Reset resets the hash to its initial state. +func (d *digest) Reset() { d.crc = 0 } + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (d *digest) Write(p []byte) (n int, err error) { + d.crc = crc64.Update(d.crc, d.tab, p) + return len(p), nil +} + +// Sum64 returns CRC64 value. +func (d *digest) Sum64() uint64 { return d.crc } + +// Sum returns hash value. +func (d *digest) Sum(in []byte) []byte { + s := d.Sum64() + return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) +} + +// gf2Dim dimension of GF(2) vectors (length of CRC) +const gf2Dim int = 64 + +func gf2MatrixTimes(mat []uint64, vec uint64) uint64 { + var sum uint64 + for i := 0; vec != 0; i++ { + if vec&1 != 0 { + sum ^= mat[i] + } + + vec >>= 1 + } + return sum +} + +func gf2MatrixSquare(square []uint64, mat []uint64) { + for n := 0; n < gf2Dim; n++ { + square[n] = gf2MatrixTimes(mat, mat[n]) + } +} + +// CRC64Combine combines CRC64 +func CRC64Combine(crc1 uint64, crc2 uint64, len2 uint64) uint64 { + var even [gf2Dim]uint64 // Even-power-of-two zeros operator + var odd [gf2Dim]uint64 // Odd-power-of-two zeros operator + + // Degenerate case + if len2 == 0 { + return crc1 + } + + // Put operator for one zero bit in odd + odd[0] = crc64.ECMA // CRC64 polynomial + var row uint64 = 1 + for n := 1; n < gf2Dim; n++ { + odd[n] = row + row <<= 1 + } + + // Put operator for two zero bits in even + gf2MatrixSquare(even[:], odd[:]) + + // Put operator for four zero bits in odd + gf2MatrixSquare(odd[:], even[:]) + + // Apply len2 zeros to crc1, first square will put the operator for one zero byte, eight zero bits, in even + for { + // Apply zeros operator for this bit of len2 + gf2MatrixSquare(even[:], odd[:]) + + if len2&1 != 0 { + crc1 = gf2MatrixTimes(even[:], crc1) + } + + len2 >>= 1 + + // If no more bits set, then done + if len2 == 0 { + break + } + + // Another iteration of the loop with odd and even swapped + gf2MatrixSquare(odd[:], even[:]) + if len2&1 != 0 { + crc1 = gf2MatrixTimes(odd[:], crc1) + } + len2 >>= 1 + + // If no more bits set, then done + if len2 == 0 { + break + } + } + + // Return combined CRC + crc1 ^= crc2 + return crc1 +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/download.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/download.go new file mode 100644 index 00000000000..90c1b633d9e --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/download.go @@ -0,0 +1,567 @@ +package oss + +import ( + "crypto/md5" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "hash" + "hash/crc64" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strconv" + "time" +) + +// DownloadFile downloads files with multipart download. +// +// objectKey the object key. +// filePath the local file to download from objectKey in OSS. +// partSize the part size in bytes. +// options object's constraints, check out GetObject for the reference. +// +// error it's nil when the call succeeds, otherwise it's an error object. +// +func (bucket Bucket) DownloadFile(objectKey, filePath string, partSize int64, options ...Option) error { + if partSize < 1 { + return errors.New("oss: part size smaller than 1") + } + + uRange, err := GetRangeConfig(options) + if err != nil { + return err + } + + cpConf := getCpConfig(options) + routines := getRoutines(options) + + var strVersionId string + versionId, _ := FindOption(options, "versionId", nil) + if versionId != nil { + strVersionId = versionId.(string) + } + + if cpConf != nil && cpConf.IsEnable { + cpFilePath := getDownloadCpFilePath(cpConf, bucket.BucketName, objectKey, strVersionId, filePath) + if cpFilePath != "" { + return bucket.downloadFileWithCp(objectKey, filePath, partSize, options, cpFilePath, routines, uRange) + } + } + + return bucket.downloadFile(objectKey, filePath, partSize, options, routines, uRange) +} + +func getDownloadCpFilePath(cpConf *cpConfig, srcBucket, srcObject, versionId, destFile string) string { + if cpConf.FilePath == "" && cpConf.DirPath != "" { + src := fmt.Sprintf("oss://%v/%v", srcBucket, srcObject) + absPath, _ := filepath.Abs(destFile) + cpFileName := getCpFileName(src, absPath, versionId) + cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName + } + return cpConf.FilePath +} + +// downloadWorkerArg is download worker's parameters +type downloadWorkerArg struct { + bucket *Bucket + key string + filePath string + options []Option + hook downloadPartHook + enableCRC bool +} + +// downloadPartHook is hook for test +type downloadPartHook func(part downloadPart) error + +var downloadPartHooker downloadPartHook = defaultDownloadPartHook + +func defaultDownloadPartHook(part downloadPart) error { + return nil +} + +// defaultDownloadProgressListener defines default ProgressListener, shields the ProgressListener in options of GetObject. +type defaultDownloadProgressListener struct { +} + +// ProgressChanged no-ops +func (listener *defaultDownloadProgressListener) ProgressChanged(event *ProgressEvent) { +} + +// downloadWorker +func downloadWorker(id int, arg downloadWorkerArg, jobs <-chan downloadPart, results chan<- downloadPart, failed chan<- error, die <-chan bool) { + for part := range jobs { + if err := arg.hook(part); err != nil { + failed <- err + break + } + + // Resolve options + r := Range(part.Start, part.End) + p := Progress(&defaultDownloadProgressListener{}) + + var respHeader http.Header + opts := make([]Option, len(arg.options)+3) + // Append orderly, can not be reversed! + opts = append(opts, arg.options...) + opts = append(opts, r, p, GetResponseHeader(&respHeader)) + + rd, err := arg.bucket.GetObject(arg.key, opts...) + if err != nil { + failed <- err + break + } + defer rd.Close() + + var crcCalc hash.Hash64 + if arg.enableCRC { + crcCalc = crc64.New(CrcTable()) + contentLen := part.End - part.Start + 1 + rd = ioutil.NopCloser(TeeReader(rd, crcCalc, contentLen, nil, nil)) + } + defer rd.Close() + + select { + case <-die: + return + default: + } + + fd, err := os.OpenFile(arg.filePath, os.O_WRONLY, FilePermMode) + if err != nil { + failed <- err + break + } + + _, err = fd.Seek(part.Start-part.Offset, os.SEEK_SET) + if err != nil { + fd.Close() + failed <- err + break + } + + startT := time.Now().UnixNano() / 1000 / 1000 / 1000 + _, err = io.Copy(fd, rd) + endT := time.Now().UnixNano() / 1000 / 1000 / 1000 + if err != nil { + arg.bucket.Client.Config.WriteLog(Debug, "download part error,cost:%d second,part number:%d,request id:%s,error:%s.\n", endT-startT, part.Index, GetRequestId(respHeader), err.Error()) + fd.Close() + failed <- err + break + } + + if arg.enableCRC { + part.CRC64 = crcCalc.Sum64() + } + + fd.Close() + results <- part + } +} + +// downloadScheduler +func downloadScheduler(jobs chan downloadPart, parts []downloadPart) { + for _, part := range parts { + jobs <- part + } + close(jobs) +} + +// downloadPart defines download part +type downloadPart struct { + Index int // Part number, starting from 0 + Start int64 // Start index + End int64 // End index + Offset int64 // Offset + CRC64 uint64 // CRC check value of part +} + +// getDownloadParts gets download parts +func getDownloadParts(objectSize, partSize int64, uRange *UnpackedRange) []downloadPart { + parts := []downloadPart{} + part := downloadPart{} + i := 0 + start, end := AdjustRange(uRange, objectSize) + for offset := start; offset < end; offset += partSize { + part.Index = i + part.Start = offset + part.End = GetPartEnd(offset, end, partSize) + part.Offset = start + part.CRC64 = 0 + parts = append(parts, part) + i++ + } + return parts +} + +// getObjectBytes gets object bytes length +func getObjectBytes(parts []downloadPart) int64 { + var ob int64 + for _, part := range parts { + ob += (part.End - part.Start + 1) + } + return ob +} + +// combineCRCInParts caculates the total CRC of continuous parts +func combineCRCInParts(dps []downloadPart) uint64 { + if dps == nil || len(dps) == 0 { + return 0 + } + + crc := dps[0].CRC64 + for i := 1; i < len(dps); i++ { + crc = CRC64Combine(crc, dps[i].CRC64, (uint64)(dps[i].End-dps[i].Start+1)) + } + + return crc +} + +// downloadFile downloads file concurrently without checkpoint. +func (bucket Bucket) downloadFile(objectKey, filePath string, partSize int64, options []Option, routines int, uRange *UnpackedRange) error { + tempFilePath := filePath + TempFileSuffix + listener := GetProgressListener(options) + + // If the file does not exist, create one. If exists, the download will overwrite it. + fd, err := os.OpenFile(tempFilePath, os.O_WRONLY|os.O_CREATE, FilePermMode) + if err != nil { + return err + } + fd.Close() + + // Get the object detailed meta for object whole size + // must delete header:range to get whole object size + skipOptions := DeleteOption(options, HTTPHeaderRange) + meta, err := bucket.GetObjectDetailedMeta(objectKey, skipOptions...) + if err != nil { + return err + } + + objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 64) + if err != nil { + return err + } + + enableCRC := false + expectedCRC := (uint64)(0) + if bucket.GetConfig().IsEnableCRC && meta.Get(HTTPHeaderOssCRC64) != "" { + if uRange == nil || (!uRange.HasStart && !uRange.HasEnd) { + enableCRC = true + expectedCRC, _ = strconv.ParseUint(meta.Get(HTTPHeaderOssCRC64), 10, 64) + } + } + + // Get the parts of the file + parts := getDownloadParts(objectSize, partSize, uRange) + jobs := make(chan downloadPart, len(parts)) + results := make(chan downloadPart, len(parts)) + failed := make(chan error) + die := make(chan bool) + + var completedBytes int64 + totalBytes := getObjectBytes(parts) + event := newProgressEvent(TransferStartedEvent, 0, totalBytes, 0) + publishProgress(listener, event) + + // Start the download workers + arg := downloadWorkerArg{&bucket, objectKey, tempFilePath, options, downloadPartHooker, enableCRC} + for w := 1; w <= routines; w++ { + go downloadWorker(w, arg, jobs, results, failed, die) + } + + // Download parts concurrently + go downloadScheduler(jobs, parts) + + // Waiting for parts download finished + completed := 0 + for completed < len(parts) { + select { + case part := <-results: + completed++ + downBytes := (part.End - part.Start + 1) + completedBytes += downBytes + parts[part.Index].CRC64 = part.CRC64 + event = newProgressEvent(TransferDataEvent, completedBytes, totalBytes, downBytes) + publishProgress(listener, event) + case err := <-failed: + close(die) + event = newProgressEvent(TransferFailedEvent, completedBytes, totalBytes, 0) + publishProgress(listener, event) + return err + } + + if completed >= len(parts) { + break + } + } + + event = newProgressEvent(TransferCompletedEvent, completedBytes, totalBytes, 0) + publishProgress(listener, event) + + if enableCRC { + actualCRC := combineCRCInParts(parts) + err = CheckDownloadCRC(actualCRC, expectedCRC) + if err != nil { + return err + } + } + + return os.Rename(tempFilePath, filePath) +} + +// ----- Concurrent download with chcekpoint ----- + +const downloadCpMagic = "92611BED-89E2-46B6-89E5-72F273D4B0A3" + +type downloadCheckpoint struct { + Magic string // Magic + MD5 string // Checkpoint content MD5 + FilePath string // Local file + Object string // Key + ObjStat objectStat // Object status + Parts []downloadPart // All download parts + PartStat []bool // Parts' download status + Start int64 // Start point of the file + End int64 // End point of the file + enableCRC bool // Whether has CRC check + CRC uint64 // CRC check value +} + +type objectStat struct { + Size int64 // Object size + LastModified string // Last modified time + Etag string // Etag +} + +// isValid flags of checkpoint data is valid. It returns true when the data is valid and the checkpoint is valid and the object is not updated. +func (cp downloadCheckpoint) isValid(meta http.Header, uRange *UnpackedRange) (bool, error) { + // Compare the CP's Magic and the MD5 + cpb := cp + cpb.MD5 = "" + js, _ := json.Marshal(cpb) + sum := md5.Sum(js) + b64 := base64.StdEncoding.EncodeToString(sum[:]) + + if cp.Magic != downloadCpMagic || b64 != cp.MD5 { + return false, nil + } + + objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 64) + if err != nil { + return false, err + } + + // Compare the object size, last modified time and etag + if cp.ObjStat.Size != objectSize || + cp.ObjStat.LastModified != meta.Get(HTTPHeaderLastModified) || + cp.ObjStat.Etag != meta.Get(HTTPHeaderEtag) { + return false, nil + } + + // Check the download range + if uRange != nil { + start, end := AdjustRange(uRange, objectSize) + if start != cp.Start || end != cp.End { + return false, nil + } + } + + return true, nil +} + +// load checkpoint from local file +func (cp *downloadCheckpoint) load(filePath string) error { + contents, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + + err = json.Unmarshal(contents, cp) + return err +} + +// dump funciton dumps to file +func (cp *downloadCheckpoint) dump(filePath string) error { + bcp := *cp + + // Calculate MD5 + bcp.MD5 = "" + js, err := json.Marshal(bcp) + if err != nil { + return err + } + sum := md5.Sum(js) + b64 := base64.StdEncoding.EncodeToString(sum[:]) + bcp.MD5 = b64 + + // Serialize + js, err = json.Marshal(bcp) + if err != nil { + return err + } + + // Dump + return ioutil.WriteFile(filePath, js, FilePermMode) +} + +// todoParts gets unfinished parts +func (cp downloadCheckpoint) todoParts() []downloadPart { + dps := []downloadPart{} + for i, ps := range cp.PartStat { + if !ps { + dps = append(dps, cp.Parts[i]) + } + } + return dps +} + +// getCompletedBytes gets completed size +func (cp downloadCheckpoint) getCompletedBytes() int64 { + var completedBytes int64 + for i, part := range cp.Parts { + if cp.PartStat[i] { + completedBytes += (part.End - part.Start + 1) + } + } + return completedBytes +} + +// prepare initiates download tasks +func (cp *downloadCheckpoint) prepare(meta http.Header, bucket *Bucket, objectKey, filePath string, partSize int64, uRange *UnpackedRange) error { + // CP + cp.Magic = downloadCpMagic + cp.FilePath = filePath + cp.Object = objectKey + + objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 64) + if err != nil { + return err + } + + cp.ObjStat.Size = objectSize + cp.ObjStat.LastModified = meta.Get(HTTPHeaderLastModified) + cp.ObjStat.Etag = meta.Get(HTTPHeaderEtag) + + if bucket.GetConfig().IsEnableCRC && meta.Get(HTTPHeaderOssCRC64) != "" { + if uRange == nil || (!uRange.HasStart && !uRange.HasEnd) { + cp.enableCRC = true + cp.CRC, _ = strconv.ParseUint(meta.Get(HTTPHeaderOssCRC64), 10, 64) + } + } + + // Parts + cp.Parts = getDownloadParts(objectSize, partSize, uRange) + cp.PartStat = make([]bool, len(cp.Parts)) + for i := range cp.PartStat { + cp.PartStat[i] = false + } + + return nil +} + +func (cp *downloadCheckpoint) complete(cpFilePath, downFilepath string) error { + err := os.Rename(downFilepath, cp.FilePath) + if err != nil { + return err + } + return os.Remove(cpFilePath) +} + +// downloadFileWithCp downloads files with checkpoint. +func (bucket Bucket) downloadFileWithCp(objectKey, filePath string, partSize int64, options []Option, cpFilePath string, routines int, uRange *UnpackedRange) error { + tempFilePath := filePath + TempFileSuffix + listener := GetProgressListener(options) + + // Load checkpoint data. + dcp := downloadCheckpoint{} + err := dcp.load(cpFilePath) + if err != nil { + os.Remove(cpFilePath) + } + + // Get the object detailed meta for object whole size + // must delete header:range to get whole object size + skipOptions := DeleteOption(options, HTTPHeaderRange) + meta, err := bucket.GetObjectDetailedMeta(objectKey, skipOptions...) + if err != nil { + return err + } + + // Load error or data invalid. Re-initialize the download. + valid, err := dcp.isValid(meta, uRange) + if err != nil || !valid { + if err = dcp.prepare(meta, &bucket, objectKey, filePath, partSize, uRange); err != nil { + return err + } + os.Remove(cpFilePath) + } + + // Create the file if not exists. Otherwise the parts download will overwrite it. + fd, err := os.OpenFile(tempFilePath, os.O_WRONLY|os.O_CREATE, FilePermMode) + if err != nil { + return err + } + fd.Close() + + // Unfinished parts + parts := dcp.todoParts() + jobs := make(chan downloadPart, len(parts)) + results := make(chan downloadPart, len(parts)) + failed := make(chan error) + die := make(chan bool) + + completedBytes := dcp.getCompletedBytes() + event := newProgressEvent(TransferStartedEvent, completedBytes, dcp.ObjStat.Size, 0) + publishProgress(listener, event) + + // Start the download workers routine + arg := downloadWorkerArg{&bucket, objectKey, tempFilePath, options, downloadPartHooker, dcp.enableCRC} + for w := 1; w <= routines; w++ { + go downloadWorker(w, arg, jobs, results, failed, die) + } + + // Concurrently downloads parts + go downloadScheduler(jobs, parts) + + // Wait for the parts download finished + completed := 0 + for completed < len(parts) { + select { + case part := <-results: + completed++ + dcp.PartStat[part.Index] = true + dcp.Parts[part.Index].CRC64 = part.CRC64 + dcp.dump(cpFilePath) + downBytes := (part.End - part.Start + 1) + completedBytes += downBytes + event = newProgressEvent(TransferDataEvent, completedBytes, dcp.ObjStat.Size, downBytes) + publishProgress(listener, event) + case err := <-failed: + close(die) + event = newProgressEvent(TransferFailedEvent, completedBytes, dcp.ObjStat.Size, 0) + publishProgress(listener, event) + return err + } + + if completed >= len(parts) { + break + } + } + + event = newProgressEvent(TransferCompletedEvent, completedBytes, dcp.ObjStat.Size, 0) + publishProgress(listener, event) + + if dcp.enableCRC { + actualCRC := combineCRCInParts(dcp.Parts) + err = CheckDownloadCRC(actualCRC, dcp.CRC) + if err != nil { + return err + } + } + + return dcp.complete(cpFilePath, tempFilePath) +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go new file mode 100644 index 00000000000..aaa24f28a9b --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go @@ -0,0 +1,136 @@ +package oss + +import ( + "encoding/xml" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "strings" +) + +// ServiceError contains fields of the error response from Oss Service REST API. +type ServiceError struct { + XMLName xml.Name `xml:"Error"` + Code string `xml:"Code"` // The error code returned from OSS to the caller + Message string `xml:"Message"` // The detail error message from OSS + RequestID string `xml:"RequestId"` // The UUID used to uniquely identify the request + HostID string `xml:"HostId"` // The OSS server cluster's Id + Endpoint string `xml:"Endpoint"` + Ec string `xml:"EC"` + RawMessage string // The raw messages from OSS + StatusCode int // HTTP status code + +} + +// Error implements interface error +func (e ServiceError) Error() string { + errorStr := fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=\"%s\", RequestId=%s", e.StatusCode, e.Code, e.Message, e.RequestID) + if len(e.Endpoint) > 0 { + errorStr = fmt.Sprintf("%s, Endpoint=%s", errorStr, e.Endpoint) + } + if len(e.Ec) > 0 { + errorStr = fmt.Sprintf("%s, Ec=%s", errorStr, e.Ec) + } + return errorStr +} + +// UnexpectedStatusCodeError is returned when a storage service responds with neither an error +// nor with an HTTP status code indicating success. +type UnexpectedStatusCodeError struct { + allowed []int // The expected HTTP stats code returned from OSS + got int // The actual HTTP status code from OSS +} + +// Error implements interface error +func (e UnexpectedStatusCodeError) Error() string { + s := func(i int) string { return fmt.Sprintf("%d %s", i, http.StatusText(i)) } + + got := s(e.got) + expected := []string{} + for _, v := range e.allowed { + expected = append(expected, s(v)) + } + return fmt.Sprintf("oss: status code from service response is %s; was expecting %s", + got, strings.Join(expected, " or ")) +} + +// Got is the actual status code returned by oss. +func (e UnexpectedStatusCodeError) Got() int { + return e.got +} + +// CheckRespCode returns UnexpectedStatusError if the given response code is not +// one of the allowed status codes; otherwise nil. +func CheckRespCode(respCode int, allowed []int) error { + for _, v := range allowed { + if respCode == v { + return nil + } + } + return UnexpectedStatusCodeError{allowed, respCode} +} + +// CheckCallbackResp return error if the given response code is not 200 +func CheckCallbackResp(resp *Response) error { + var err error + contentLengthStr := resp.Headers.Get("Content-Length") + contentLength, _ := strconv.Atoi(contentLengthStr) + var bodyBytes []byte + if contentLength > 0 { + bodyBytes, _ = ioutil.ReadAll(resp.Body) + } + if len(bodyBytes) > 0 { + srvErr, errIn := serviceErrFromXML(bodyBytes, resp.StatusCode, + resp.Headers.Get(HTTPHeaderOssRequestID)) + if errIn != nil { + if len(resp.Headers.Get(HTTPHeaderOssEc)) > 0 { + err = fmt.Errorf("unknown response body, status code = %d, RequestId = %s, ec = %s", resp.StatusCode, resp.Headers.Get(HTTPHeaderOssRequestID), resp.Headers.Get(HTTPHeaderOssEc)) + } else { + err = fmt.Errorf("unknown response body, status code= %d, RequestId = %s", resp.StatusCode, resp.Headers.Get(HTTPHeaderOssRequestID)) + } + } else { + err = srvErr + } + } + return err +} + +func tryConvertServiceError(data []byte, resp *Response, def error) (err error) { + err = def + if len(data) > 0 { + srvErr, errIn := serviceErrFromXML(data, resp.StatusCode, resp.Headers.Get(HTTPHeaderOssRequestID)) + if errIn == nil { + err = srvErr + } + } + return err +} + +// CRCCheckError is returned when crc check is inconsistent between client and server +type CRCCheckError struct { + clientCRC uint64 // Calculated CRC64 in client + serverCRC uint64 // Calculated CRC64 in server + operation string // Upload operations such as PutObject/AppendObject/UploadPart, etc + requestID string // The request id of this operation +} + +// Error implements interface error +func (e CRCCheckError) Error() string { + return fmt.Sprintf("oss: the crc of %s is inconsistent, client %d but server %d; request id is %s", + e.operation, e.clientCRC, e.serverCRC, e.requestID) +} + +func CheckDownloadCRC(clientCRC, serverCRC uint64) error { + if clientCRC == serverCRC { + return nil + } + return CRCCheckError{clientCRC, serverCRC, "DownloadFile", ""} +} + +func CheckCRC(resp *Response, operation string) error { + if resp.Headers.Get(HTTPHeaderOssCRC64) == "" || resp.ClientCRC == resp.ServerCRC { + return nil + } + return CRCCheckError{resp.ClientCRC, resp.ServerCRC, operation, resp.Headers.Get(HTTPHeaderOssRequestID)} +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go new file mode 100644 index 00000000000..2293f99043e --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go @@ -0,0 +1,29 @@ +//go:build !go1.7 +// +build !go1.7 + +// "golang.org/x/time/rate" is depended on golang context package go1.7 onward +// this file is only for build,not supports limit upload speed +package oss + +import ( + "fmt" + "io" +) + +const ( + perTokenBandwidthSize int = 1024 +) + +type OssLimiter struct { +} + +type LimitSpeedReader struct { + io.ReadCloser + reader io.Reader + ossLimiter *OssLimiter +} + +func GetOssLimiter(uploadSpeed int) (ossLimiter *OssLimiter, err error) { + err = fmt.Errorf("rate.Limiter is not supported below version go1.7") + return nil, err +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go new file mode 100644 index 00000000000..ea0826ceca0 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go @@ -0,0 +1,91 @@ +//go:build go1.7 +// +build go1.7 + +package oss + +import ( + "fmt" + "io" + "math" + "time" + + "golang.org/x/time/rate" +) + +const ( + perTokenBandwidthSize int = 1024 +) + +// OssLimiter wrapper rate.Limiter +type OssLimiter struct { + limiter *rate.Limiter +} + +// GetOssLimiter create OssLimiter +// uploadSpeed KB/s +func GetOssLimiter(uploadSpeed int) (ossLimiter *OssLimiter, err error) { + limiter := rate.NewLimiter(rate.Limit(uploadSpeed), uploadSpeed) + + // first consume the initial full token,the limiter will behave more accurately + limiter.AllowN(time.Now(), uploadSpeed) + + return &OssLimiter{ + limiter: limiter, + }, nil +} + +// LimitSpeedReader for limit bandwidth upload +type LimitSpeedReader struct { + io.ReadCloser + reader io.Reader + ossLimiter *OssLimiter +} + +// Read +func (r *LimitSpeedReader) Read(p []byte) (n int, err error) { + n = 0 + err = nil + start := 0 + burst := r.ossLimiter.limiter.Burst() + var end int + var tmpN int + var tc int + for start < len(p) { + if start+burst*perTokenBandwidthSize < len(p) { + end = start + burst*perTokenBandwidthSize + } else { + end = len(p) + } + + tmpN, err = r.reader.Read(p[start:end]) + if tmpN > 0 { + n += tmpN + start = n + } + + if err != nil { + return + } + + tc = int(math.Ceil(float64(tmpN) / float64(perTokenBandwidthSize))) + now := time.Now() + re := r.ossLimiter.limiter.ReserveN(now, tc) + if !re.OK() { + err = fmt.Errorf("LimitSpeedReader.Read() failure,ReserveN error,start:%d,end:%d,burst:%d,perTokenBandwidthSize:%d", + start, end, burst, perTokenBandwidthSize) + return + } + timeDelay := re.Delay() + time.Sleep(timeDelay) + } + return +} + +// Close ... +func (r *LimitSpeedReader) Close() error { + rc, ok := r.reader.(io.ReadCloser) + if ok { + return rc.Close() + } + return nil +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go new file mode 100644 index 00000000000..1fd30fdfd6e --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go @@ -0,0 +1,257 @@ +package oss + +import ( + "bytes" + "encoding/xml" + "fmt" + "io" + "net/http" + "strconv" + "time" +) + +// +// CreateLiveChannel create a live-channel +// +// channelName the name of the channel +// config configuration of the channel +// +// CreateLiveChannelResult the result of create live-channel +// error nil if success, otherwise error +// +func (bucket Bucket) CreateLiveChannel(channelName string, config LiveChannelConfiguration) (CreateLiveChannelResult, error) { + var out CreateLiveChannelResult + + bs, err := xml.Marshal(config) + if err != nil { + return out, err + } + + buffer := new(bytes.Buffer) + buffer.Write(bs) + + params := map[string]interface{}{} + params["live"] = nil + resp, err := bucket.do("PUT", channelName, params, nil, buffer, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// +// PutLiveChannelStatus Set the status of the live-channel: enabled/disabled +// +// channelName the name of the channel +// status enabled/disabled +// +// error nil if success, otherwise error +// +func (bucket Bucket) PutLiveChannelStatus(channelName, status string) error { + params := map[string]interface{}{} + params["live"] = nil + params["status"] = status + + resp, err := bucket.do("PUT", channelName, params, nil, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// PostVodPlaylist create an playlist based on the specified playlist name, startTime and endTime +// +// channelName the name of the channel +// playlistName the name of the playlist, must end with ".m3u8" +// startTime the start time of the playlist +// endTime the endtime of the playlist +// +// error nil if success, otherwise error +// +func (bucket Bucket) PostVodPlaylist(channelName, playlistName string, startTime, endTime time.Time) error { + params := map[string]interface{}{} + params["vod"] = nil + params["startTime"] = strconv.FormatInt(startTime.Unix(), 10) + params["endTime"] = strconv.FormatInt(endTime.Unix(), 10) + + key := fmt.Sprintf("%s/%s", channelName, playlistName) + resp, err := bucket.do("POST", key, params, nil, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusOK}) +} + +// GetVodPlaylist get the playlist based on the specified channelName, startTime and endTime +// +// channelName the name of the channel +// startTime the start time of the playlist +// endTime the endtime of the playlist +// +// io.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil. +// error nil if success, otherwise error +// +func (bucket Bucket) GetVodPlaylist(channelName string, startTime, endTime time.Time) (io.ReadCloser, error) { + params := map[string]interface{}{} + params["vod"] = nil + params["startTime"] = strconv.FormatInt(startTime.Unix(), 10) + params["endTime"] = strconv.FormatInt(endTime.Unix(), 10) + + resp, err := bucket.do("GET", channelName, params, nil, nil, nil) + if err != nil { + return nil, err + } + + return resp.Body, nil +} + +// +// GetLiveChannelStat Get the state of the live-channel +// +// channelName the name of the channel +// +// LiveChannelStat the state of the live-channel +// error nil if success, otherwise error +// +func (bucket Bucket) GetLiveChannelStat(channelName string) (LiveChannelStat, error) { + var out LiveChannelStat + params := map[string]interface{}{} + params["live"] = nil + params["comp"] = "stat" + + resp, err := bucket.do("GET", channelName, params, nil, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// +// GetLiveChannelInfo Get the configuration info of the live-channel +// +// channelName the name of the channel +// +// LiveChannelConfiguration the configuration info of the live-channel +// error nil if success, otherwise error +// +func (bucket Bucket) GetLiveChannelInfo(channelName string) (LiveChannelConfiguration, error) { + var out LiveChannelConfiguration + params := map[string]interface{}{} + params["live"] = nil + + resp, err := bucket.do("GET", channelName, params, nil, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// +// GetLiveChannelHistory Get push records of live-channel +// +// channelName the name of the channel +// +// LiveChannelHistory push records +// error nil if success, otherwise error +// +func (bucket Bucket) GetLiveChannelHistory(channelName string) (LiveChannelHistory, error) { + var out LiveChannelHistory + params := map[string]interface{}{} + params["live"] = nil + params["comp"] = "history" + + resp, err := bucket.do("GET", channelName, params, nil, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// +// ListLiveChannel list the live-channels +// +// options Prefix: filter by the name start with the value of "Prefix" +// MaxKeys: the maximum count returned +// Marker: cursor from which starting list +// +// ListLiveChannelResult live-channel list +// error nil if success, otherwise error +// +func (bucket Bucket) ListLiveChannel(options ...Option) (ListLiveChannelResult, error) { + var out ListLiveChannelResult + + params, err := GetRawParams(options) + if err != nil { + return out, err + } + + params["live"] = nil + + resp, err := bucket.doInner("GET", "", params, nil, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + return out, err +} + +// +// DeleteLiveChannel Delete the live-channel. When a client trying to stream the live-channel, the operation will fail. it will only delete the live-channel itself and the object generated by the live-channel will not be deleted. +// +// channelName the name of the channel +// +// error nil if success, otherwise error +// +func (bucket Bucket) DeleteLiveChannel(channelName string) error { + params := map[string]interface{}{} + params["live"] = nil + + if channelName == "" { + return fmt.Errorf("invalid argument: channel name is empty") + } + + resp, err := bucket.do("DELETE", channelName, params, nil, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// +// SignRtmpURL Generate a RTMP push-stream signature URL for the trusted user to push the RTMP stream to the live-channel. +// +// channelName the name of the channel +// playlistName the name of the playlist, must end with ".m3u8" +// expires expiration (in seconds) +// +// string singed rtmp push stream url +// error nil if success, otherwise error +// +func (bucket Bucket) SignRtmpURL(channelName, playlistName string, expires int64) (string, error) { + if expires <= 0 { + return "", fmt.Errorf("invalid argument: %d, expires must greater than 0", expires) + } + expiration := time.Now().Unix() + expires + + return bucket.Client.Conn.signRtmpURL(bucket.BucketName, channelName, playlistName, expiration), nil +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go new file mode 100644 index 00000000000..96a9ee7aa71 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go @@ -0,0 +1,594 @@ +package oss + +import ( + "mime" + "path" + "strings" +) + +var extToMimeType = map[string]string{ + ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template", + ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", + ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + ".xlam": "application/vnd.ms-excel.addin.macroEnabled.12", + ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12", + ".apk": "application/vnd.android.package-archive", + ".hqx": "application/mac-binhex40", + ".cpt": "application/mac-compactpro", + ".doc": "application/msword", + ".ogg": "application/ogg", + ".pdf": "application/pdf", + ".rtf": "text/rtf", + ".mif": "application/vnd.mif", + ".xls": "application/vnd.ms-excel", + ".ppt": "application/vnd.ms-powerpoint", + ".odc": "application/vnd.oasis.opendocument.chart", + ".odb": "application/vnd.oasis.opendocument.database", + ".odf": "application/vnd.oasis.opendocument.formula", + ".odg": "application/vnd.oasis.opendocument.graphics", + ".otg": "application/vnd.oasis.opendocument.graphics-template", + ".odi": "application/vnd.oasis.opendocument.image", + ".odp": "application/vnd.oasis.opendocument.presentation", + ".otp": "application/vnd.oasis.opendocument.presentation-template", + ".ods": "application/vnd.oasis.opendocument.spreadsheet", + ".ots": "application/vnd.oasis.opendocument.spreadsheet-template", + ".odt": "application/vnd.oasis.opendocument.text", + ".odm": "application/vnd.oasis.opendocument.text-master", + ".ott": "application/vnd.oasis.opendocument.text-template", + ".oth": "application/vnd.oasis.opendocument.text-web", + ".sxw": "application/vnd.sun.xml.writer", + ".stw": "application/vnd.sun.xml.writer.template", + ".sxc": "application/vnd.sun.xml.calc", + ".stc": "application/vnd.sun.xml.calc.template", + ".sxd": "application/vnd.sun.xml.draw", + ".std": "application/vnd.sun.xml.draw.template", + ".sxi": "application/vnd.sun.xml.impress", + ".sti": "application/vnd.sun.xml.impress.template", + ".sxg": "application/vnd.sun.xml.writer.global", + ".sxm": "application/vnd.sun.xml.math", + ".sis": "application/vnd.symbian.install", + ".wbxml": "application/vnd.wap.wbxml", + ".wmlc": "application/vnd.wap.wmlc", + ".wmlsc": "application/vnd.wap.wmlscriptc", + ".bcpio": "application/x-bcpio", + ".torrent": "application/x-bittorrent", + ".bz2": "application/x-bzip2", + ".vcd": "application/x-cdlink", + ".pgn": "application/x-chess-pgn", + ".cpio": "application/x-cpio", + ".csh": "application/x-csh", + ".dvi": "application/x-dvi", + ".spl": "application/x-futuresplash", + ".gtar": "application/x-gtar", + ".hdf": "application/x-hdf", + ".jar": "application/x-java-archive", + ".jnlp": "application/x-java-jnlp-file", + ".js": "application/x-javascript", + ".ksp": "application/x-kspread", + ".chrt": "application/x-kchart", + ".kil": "application/x-killustrator", + ".latex": "application/x-latex", + ".rpm": "application/x-rpm", + ".sh": "application/x-sh", + ".shar": "application/x-shar", + ".swf": "application/x-shockwave-flash", + ".sit": "application/x-stuffit", + ".sv4cpio": "application/x-sv4cpio", + ".sv4crc": "application/x-sv4crc", + ".tar": "application/x-tar", + ".tcl": "application/x-tcl", + ".tex": "application/x-tex", + ".man": "application/x-troff-man", + ".me": "application/x-troff-me", + ".ms": "application/x-troff-ms", + ".ustar": "application/x-ustar", + ".src": "application/x-wais-source", + ".zip": "application/zip", + ".m3u": "audio/x-mpegurl", + ".ra": "audio/x-pn-realaudio", + ".wav": "audio/x-wav", + ".wma": "audio/x-ms-wma", + ".wax": "audio/x-ms-wax", + ".pdb": "chemical/x-pdb", + ".xyz": "chemical/x-xyz", + ".bmp": "image/bmp", + ".gif": "image/gif", + ".ief": "image/ief", + ".png": "image/png", + ".wbmp": "image/vnd.wap.wbmp", + ".ras": "image/x-cmu-raster", + ".pnm": "image/x-portable-anymap", + ".pbm": "image/x-portable-bitmap", + ".pgm": "image/x-portable-graymap", + ".ppm": "image/x-portable-pixmap", + ".rgb": "image/x-rgb", + ".xbm": "image/x-xbitmap", + ".xpm": "image/x-xpixmap", + ".xwd": "image/x-xwindowdump", + ".css": "text/css", + ".rtx": "text/richtext", + ".tsv": "text/tab-separated-values", + ".jad": "text/vnd.sun.j2me.app-descriptor", + ".wml": "text/vnd.wap.wml", + ".wmls": "text/vnd.wap.wmlscript", + ".etx": "text/x-setext", + ".mxu": "video/vnd.mpegurl", + ".flv": "video/x-flv", + ".wm": "video/x-ms-wm", + ".wmv": "video/x-ms-wmv", + ".wmx": "video/x-ms-wmx", + ".wvx": "video/x-ms-wvx", + ".avi": "video/x-msvideo", + ".movie": "video/x-sgi-movie", + ".ice": "x-conference/x-cooltalk", + ".3gp": "video/3gpp", + ".ai": "application/postscript", + ".aif": "audio/x-aiff", + ".aifc": "audio/x-aiff", + ".aiff": "audio/x-aiff", + ".asc": "text/plain", + ".atom": "application/atom+xml", + ".au": "audio/basic", + ".bin": "application/octet-stream", + ".cdf": "application/x-netcdf", + ".cgm": "image/cgm", + ".class": "application/octet-stream", + ".dcr": "application/x-director", + ".dif": "video/x-dv", + ".dir": "application/x-director", + ".djv": "image/vnd.djvu", + ".djvu": "image/vnd.djvu", + ".dll": "application/octet-stream", + ".dmg": "application/octet-stream", + ".dms": "application/octet-stream", + ".dtd": "application/xml-dtd", + ".dv": "video/x-dv", + ".dxr": "application/x-director", + ".eps": "application/postscript", + ".exe": "application/octet-stream", + ".ez": "application/andrew-inset", + ".gram": "application/srgs", + ".grxml": "application/srgs+xml", + ".gz": "application/x-gzip", + ".htm": "text/html", + ".html": "text/html", + ".ico": "image/x-icon", + ".ics": "text/calendar", + ".ifb": "text/calendar", + ".iges": "model/iges", + ".igs": "model/iges", + ".jp2": "image/jp2", + ".jpe": "image/jpeg", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".kar": "audio/midi", + ".lha": "application/octet-stream", + ".lzh": "application/octet-stream", + ".m4a": "audio/mp4a-latm", + ".m4p": "audio/mp4a-latm", + ".m4u": "video/vnd.mpegurl", + ".m4v": "video/x-m4v", + ".mac": "image/x-macpaint", + ".mathml": "application/mathml+xml", + ".mesh": "model/mesh", + ".mid": "audio/midi", + ".midi": "audio/midi", + ".mov": "video/quicktime", + ".mp2": "audio/mpeg", + ".mp3": "audio/mpeg", + ".mp4": "video/mp4", + ".mpe": "video/mpeg", + ".mpeg": "video/mpeg", + ".mpg": "video/mpeg", + ".mpga": "audio/mpeg", + ".msh": "model/mesh", + ".nc": "application/x-netcdf", + ".oda": "application/oda", + ".ogv": "video/ogv", + ".pct": "image/pict", + ".pic": "image/pict", + ".pict": "image/pict", + ".pnt": "image/x-macpaint", + ".pntg": "image/x-macpaint", + ".ps": "application/postscript", + ".qt": "video/quicktime", + ".qti": "image/x-quicktime", + ".qtif": "image/x-quicktime", + ".ram": "audio/x-pn-realaudio", + ".rdf": "application/rdf+xml", + ".rm": "application/vnd.rn-realmedia", + ".roff": "application/x-troff", + ".sgm": "text/sgml", + ".sgml": "text/sgml", + ".silo": "model/mesh", + ".skd": "application/x-koan", + ".skm": "application/x-koan", + ".skp": "application/x-koan", + ".skt": "application/x-koan", + ".smi": "application/smil", + ".smil": "application/smil", + ".snd": "audio/basic", + ".so": "application/octet-stream", + ".svg": "image/svg+xml", + ".t": "application/x-troff", + ".texi": "application/x-texinfo", + ".texinfo": "application/x-texinfo", + ".tif": "image/tiff", + ".tiff": "image/tiff", + ".tr": "application/x-troff", + ".txt": "text/plain", + ".vrml": "model/vrml", + ".vxml": "application/voicexml+xml", + ".webm": "video/webm", + ".wrl": "model/vrml", + ".xht": "application/xhtml+xml", + ".xhtml": "application/xhtml+xml", + ".xml": "application/xml", + ".xsl": "application/xml", + ".xslt": "application/xslt+xml", + ".xul": "application/vnd.mozilla.xul+xml", + ".webp": "image/webp", + ".323": "text/h323", + ".aab": "application/x-authoware-bin", + ".aam": "application/x-authoware-map", + ".aas": "application/x-authoware-seg", + ".acx": "application/internet-property-stream", + ".als": "audio/X-Alpha5", + ".amc": "application/x-mpeg", + ".ani": "application/octet-stream", + ".asd": "application/astound", + ".asf": "video/x-ms-asf", + ".asn": "application/astound", + ".asp": "application/x-asap", + ".asr": "video/x-ms-asf", + ".asx": "video/x-ms-asf", + ".avb": "application/octet-stream", + ".awb": "audio/amr-wb", + ".axs": "application/olescript", + ".bas": "text/plain", + ".bin ": "application/octet-stream", + ".bld": "application/bld", + ".bld2": "application/bld2", + ".bpk": "application/octet-stream", + ".c": "text/plain", + ".cal": "image/x-cals", + ".cat": "application/vnd.ms-pkiseccat", + ".ccn": "application/x-cnc", + ".cco": "application/x-cocoa", + ".cer": "application/x-x509-ca-cert", + ".cgi": "magnus-internal/cgi", + ".chat": "application/x-chat", + ".clp": "application/x-msclip", + ".cmx": "image/x-cmx", + ".co": "application/x-cult3d-object", + ".cod": "image/cis-cod", + ".conf": "text/plain", + ".cpp": "text/plain", + ".crd": "application/x-mscardfile", + ".crl": "application/pkix-crl", + ".crt": "application/x-x509-ca-cert", + ".csm": "chemical/x-csml", + ".csml": "chemical/x-csml", + ".cur": "application/octet-stream", + ".dcm": "x-lml/x-evm", + ".dcx": "image/x-dcx", + ".der": "application/x-x509-ca-cert", + ".dhtml": "text/html", + ".dot": "application/msword", + ".dwf": "drawing/x-dwf", + ".dwg": "application/x-autocad", + ".dxf": "application/x-autocad", + ".ebk": "application/x-expandedbook", + ".emb": "chemical/x-embl-dl-nucleotide", + ".embl": "chemical/x-embl-dl-nucleotide", + ".epub": "application/epub+zip", + ".eri": "image/x-eri", + ".es": "audio/echospeech", + ".esl": "audio/echospeech", + ".etc": "application/x-earthtime", + ".evm": "x-lml/x-evm", + ".evy": "application/envoy", + ".fh4": "image/x-freehand", + ".fh5": "image/x-freehand", + ".fhc": "image/x-freehand", + ".fif": "application/fractals", + ".flr": "x-world/x-vrml", + ".fm": "application/x-maker", + ".fpx": "image/x-fpx", + ".fvi": "video/isivideo", + ".gau": "chemical/x-gaussian-input", + ".gca": "application/x-gca-compressed", + ".gdb": "x-lml/x-gdb", + ".gps": "application/x-gps", + ".h": "text/plain", + ".hdm": "text/x-hdml", + ".hdml": "text/x-hdml", + ".hlp": "application/winhlp", + ".hta": "application/hta", + ".htc": "text/x-component", + ".hts": "text/html", + ".htt": "text/webviewhtml", + ".ifm": "image/gif", + ".ifs": "image/ifs", + ".iii": "application/x-iphone", + ".imy": "audio/melody", + ".ins": "application/x-internet-signup", + ".ips": "application/x-ipscript", + ".ipx": "application/x-ipix", + ".isp": "application/x-internet-signup", + ".it": "audio/x-mod", + ".itz": "audio/x-mod", + ".ivr": "i-world/i-vrml", + ".j2k": "image/j2k", + ".jam": "application/x-jam", + ".java": "text/plain", + ".jfif": "image/pipeg", + ".jpz": "image/jpeg", + ".jwc": "application/jwc", + ".kjx": "application/x-kjx", + ".lak": "x-lml/x-lak", + ".lcc": "application/fastman", + ".lcl": "application/x-digitalloca", + ".lcr": "application/x-digitalloca", + ".lgh": "application/lgh", + ".lml": "x-lml/x-lml", + ".lmlpack": "x-lml/x-lmlpack", + ".log": "text/plain", + ".lsf": "video/x-la-asf", + ".lsx": "video/x-la-asf", + ".m13": "application/x-msmediaview", + ".m14": "application/x-msmediaview", + ".m15": "audio/x-mod", + ".m3url": "audio/x-mpegurl", + ".m4b": "audio/mp4a-latm", + ".ma1": "audio/ma1", + ".ma2": "audio/ma2", + ".ma3": "audio/ma3", + ".ma5": "audio/ma5", + ".map": "magnus-internal/imagemap", + ".mbd": "application/mbedlet", + ".mct": "application/x-mascot", + ".mdb": "application/x-msaccess", + ".mdz": "audio/x-mod", + ".mel": "text/x-vmel", + ".mht": "message/rfc822", + ".mhtml": "message/rfc822", + ".mi": "application/x-mif", + ".mil": "image/x-cals", + ".mio": "audio/x-mio", + ".mmf": "application/x-skt-lbs", + ".mng": "video/x-mng", + ".mny": "application/x-msmoney", + ".moc": "application/x-mocha", + ".mocha": "application/x-mocha", + ".mod": "audio/x-mod", + ".mof": "application/x-yumekara", + ".mol": "chemical/x-mdl-molfile", + ".mop": "chemical/x-mopac-input", + ".mpa": "video/mpeg", + ".mpc": "application/vnd.mpohun.certificate", + ".mpg4": "video/mp4", + ".mpn": "application/vnd.mophun.application", + ".mpp": "application/vnd.ms-project", + ".mps": "application/x-mapserver", + ".mpv2": "video/mpeg", + ".mrl": "text/x-mrml", + ".mrm": "application/x-mrm", + ".msg": "application/vnd.ms-outlook", + ".mts": "application/metastream", + ".mtx": "application/metastream", + ".mtz": "application/metastream", + ".mvb": "application/x-msmediaview", + ".mzv": "application/metastream", + ".nar": "application/zip", + ".nbmp": "image/nbmp", + ".ndb": "x-lml/x-ndb", + ".ndwn": "application/ndwn", + ".nif": "application/x-nif", + ".nmz": "application/x-scream", + ".nokia-op-logo": "image/vnd.nok-oplogo-color", + ".npx": "application/x-netfpx", + ".nsnd": "audio/nsnd", + ".nva": "application/x-neva1", + ".nws": "message/rfc822", + ".oom": "application/x-AtlasMate-Plugin", + ".p10": "application/pkcs10", + ".p12": "application/x-pkcs12", + ".p7b": "application/x-pkcs7-certificates", + ".p7c": "application/x-pkcs7-mime", + ".p7m": "application/x-pkcs7-mime", + ".p7r": "application/x-pkcs7-certreqresp", + ".p7s": "application/x-pkcs7-signature", + ".pac": "audio/x-pac", + ".pae": "audio/x-epac", + ".pan": "application/x-pan", + ".pcx": "image/x-pcx", + ".pda": "image/x-pda", + ".pfr": "application/font-tdpfr", + ".pfx": "application/x-pkcs12", + ".pko": "application/ynd.ms-pkipko", + ".pm": "application/x-perl", + ".pma": "application/x-perfmon", + ".pmc": "application/x-perfmon", + ".pmd": "application/x-pmd", + ".pml": "application/x-perfmon", + ".pmr": "application/x-perfmon", + ".pmw": "application/x-perfmon", + ".pnz": "image/png", + ".pot,": "application/vnd.ms-powerpoint", + ".pps": "application/vnd.ms-powerpoint", + ".pqf": "application/x-cprplayer", + ".pqi": "application/cprplayer", + ".prc": "application/x-prc", + ".prf": "application/pics-rules", + ".prop": "text/plain", + ".proxy": "application/x-ns-proxy-autoconfig", + ".ptlk": "application/listenup", + ".pub": "application/x-mspublisher", + ".pvx": "video/x-pv-pvx", + ".qcp": "audio/vnd.qcelp", + ".r3t": "text/vnd.rn-realtext3d", + ".rar": "application/octet-stream", + ".rc": "text/plain", + ".rf": "image/vnd.rn-realflash", + ".rlf": "application/x-richlink", + ".rmf": "audio/x-rmf", + ".rmi": "audio/mid", + ".rmm": "audio/x-pn-realaudio", + ".rmvb": "audio/x-pn-realaudio", + ".rnx": "application/vnd.rn-realplayer", + ".rp": "image/vnd.rn-realpix", + ".rt": "text/vnd.rn-realtext", + ".rte": "x-lml/x-gps", + ".rtg": "application/metastream", + ".rv": "video/vnd.rn-realvideo", + ".rwc": "application/x-rogerwilco", + ".s3m": "audio/x-mod", + ".s3z": "audio/x-mod", + ".sca": "application/x-supercard", + ".scd": "application/x-msschedule", + ".sct": "text/scriptlet", + ".sdf": "application/e-score", + ".sea": "application/x-stuffit", + ".setpay": "application/set-payment-initiation", + ".setreg": "application/set-registration-initiation", + ".shtml": "text/html", + ".shtm": "text/html", + ".shw": "application/presentations", + ".si6": "image/si6", + ".si7": "image/vnd.stiwap.sis", + ".si9": "image/vnd.lgtwap.sis", + ".slc": "application/x-salsa", + ".smd": "audio/x-smd", + ".smp": "application/studiom", + ".smz": "audio/x-smd", + ".spc": "application/x-pkcs7-certificates", + ".spr": "application/x-sprite", + ".sprite": "application/x-sprite", + ".sdp": "application/sdp", + ".spt": "application/x-spt", + ".sst": "application/vnd.ms-pkicertstore", + ".stk": "application/hyperstudio", + ".stl": "application/vnd.ms-pkistl", + ".stm": "text/html", + ".svf": "image/vnd", + ".svh": "image/svh", + ".svr": "x-world/x-svr", + ".swfl": "application/x-shockwave-flash", + ".tad": "application/octet-stream", + ".talk": "text/x-speech", + ".taz": "application/x-tar", + ".tbp": "application/x-timbuktu", + ".tbt": "application/x-timbuktu", + ".tgz": "application/x-compressed", + ".thm": "application/vnd.eri.thm", + ".tki": "application/x-tkined", + ".tkined": "application/x-tkined", + ".toc": "application/toc", + ".toy": "image/toy", + ".trk": "x-lml/x-gps", + ".trm": "application/x-msterminal", + ".tsi": "audio/tsplayer", + ".tsp": "application/dsptype", + ".ttf": "application/octet-stream", + ".ttz": "application/t-time", + ".uls": "text/iuls", + ".ult": "audio/x-mod", + ".uu": "application/x-uuencode", + ".uue": "application/x-uuencode", + ".vcf": "text/x-vcard", + ".vdo": "video/vdo", + ".vib": "audio/vib", + ".viv": "video/vivo", + ".vivo": "video/vivo", + ".vmd": "application/vocaltec-media-desc", + ".vmf": "application/vocaltec-media-file", + ".vmi": "application/x-dreamcast-vms-info", + ".vms": "application/x-dreamcast-vms", + ".vox": "audio/voxware", + ".vqe": "audio/x-twinvq-plugin", + ".vqf": "audio/x-twinvq", + ".vql": "audio/x-twinvq", + ".vre": "x-world/x-vream", + ".vrt": "x-world/x-vrt", + ".vrw": "x-world/x-vream", + ".vts": "workbook/formulaone", + ".wcm": "application/vnd.ms-works", + ".wdb": "application/vnd.ms-works", + ".web": "application/vnd.xara", + ".wi": "image/wavelet", + ".wis": "application/x-InstallShield", + ".wks": "application/vnd.ms-works", + ".wmd": "application/x-ms-wmd", + ".wmf": "application/x-msmetafile", + ".wmlscript": "text/vnd.wap.wmlscript", + ".wmz": "application/x-ms-wmz", + ".wpng": "image/x-up-wpng", + ".wps": "application/vnd.ms-works", + ".wpt": "x-lml/x-gps", + ".wri": "application/x-mswrite", + ".wrz": "x-world/x-vrml", + ".ws": "text/vnd.wap.wmlscript", + ".wsc": "application/vnd.wap.wmlscriptc", + ".wv": "video/wavelet", + ".wxl": "application/x-wxl", + ".x-gzip": "application/x-gzip", + ".xaf": "x-world/x-vrml", + ".xar": "application/vnd.xara", + ".xdm": "application/x-xdma", + ".xdma": "application/x-xdma", + ".xdw": "application/vnd.fujixerox.docuworks", + ".xhtm": "application/xhtml+xml", + ".xla": "application/vnd.ms-excel", + ".xlc": "application/vnd.ms-excel", + ".xll": "application/x-excel", + ".xlm": "application/vnd.ms-excel", + ".xlt": "application/vnd.ms-excel", + ".xlw": "application/vnd.ms-excel", + ".xm": "audio/x-mod", + ".xmz": "audio/x-mod", + ".xof": "x-world/x-vrml", + ".xpi": "application/x-xpinstall", + ".xsit": "text/xml", + ".yz1": "application/x-yz1", + ".z": "application/x-compress", + ".zac": "application/x-zaurus-zac", + ".json": "application/json", +} + +// TypeByExtension returns the MIME type associated with the file extension ext. +// gets the file's MIME type for HTTP header Content-Type +func TypeByExtension(filePath string) string { + typ := mime.TypeByExtension(path.Ext(filePath)) + if typ == "" { + typ = extToMimeType[strings.ToLower(path.Ext(filePath))] + } else { + if strings.HasPrefix(typ, "text/") && strings.Contains(typ, "charset=") { + typ = removeCharsetInMimeType(typ) + } + } + return typ +} + +// Remove charset from mime type +func removeCharsetInMimeType(typ string) (str string) { + temArr := strings.Split(typ, ";") + var builder strings.Builder + for i, s := range temArr { + tmpStr := strings.Trim(s, " ") + if strings.Contains(tmpStr, "charset=") { + continue + } + if i == 0 { + builder.WriteString(s) + } else { + builder.WriteString("; " + s) + } + } + return builder.String() +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/model.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/model.go new file mode 100644 index 00000000000..b0b4a502715 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/model.go @@ -0,0 +1,69 @@ +package oss + +import ( + "hash" + "io" + "net/http" +) + +// Response defines HTTP response from OSS +type Response struct { + StatusCode int + Headers http.Header + Body io.ReadCloser + ClientCRC uint64 + ServerCRC uint64 +} + +func (r *Response) Read(p []byte) (n int, err error) { + return r.Body.Read(p) +} + +// Close close http reponse body +func (r *Response) Close() error { + return r.Body.Close() +} + +// PutObjectRequest is the request of DoPutObject +type PutObjectRequest struct { + ObjectKey string + Reader io.Reader +} + +// GetObjectRequest is the request of DoGetObject +type GetObjectRequest struct { + ObjectKey string +} + +// GetObjectResult is the result of DoGetObject +type GetObjectResult struct { + Response *Response + ClientCRC hash.Hash64 + ServerCRC uint64 +} + +// AppendObjectRequest is the requtest of DoAppendObject +type AppendObjectRequest struct { + ObjectKey string + Reader io.Reader + Position int64 +} + +// AppendObjectResult is the result of DoAppendObject +type AppendObjectResult struct { + NextPosition int64 + CRC uint64 +} + +// UploadPartRequest is the request of DoUploadPart +type UploadPartRequest struct { + InitResult *InitiateMultipartUploadResult + Reader io.Reader + PartSize int64 + PartNumber int +} + +// UploadPartResult is the result of DoUploadPart +type UploadPartResult struct { + Part UploadPart +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multicopy.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multicopy.go new file mode 100644 index 00000000000..56ed8cadfd0 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multicopy.go @@ -0,0 +1,474 @@ +package oss + +import ( + "crypto/md5" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "os" + "strconv" +) + +// CopyFile is multipart copy object +// +// srcBucketName source bucket name +// srcObjectKey source object name +// destObjectKey target object name in the form of bucketname.objectkey +// partSize the part size in byte. +// options object's contraints. Check out function InitiateMultipartUpload. +// +// error it's nil if the operation succeeds, otherwise it's an error object. +// +func (bucket Bucket) CopyFile(srcBucketName, srcObjectKey, destObjectKey string, partSize int64, options ...Option) error { + destBucketName := bucket.BucketName + if partSize < MinPartSize || partSize > MaxPartSize { + return errors.New("oss: part size invalid range (1024KB, 5GB]") + } + + cpConf := getCpConfig(options) + routines := getRoutines(options) + + var strVersionId string + versionId, _ := FindOption(options, "versionId", nil) + if versionId != nil { + strVersionId = versionId.(string) + } + + if cpConf != nil && cpConf.IsEnable { + cpFilePath := getCopyCpFilePath(cpConf, srcBucketName, srcObjectKey, destBucketName, destObjectKey, strVersionId) + if cpFilePath != "" { + return bucket.copyFileWithCp(srcBucketName, srcObjectKey, destBucketName, destObjectKey, partSize, options, cpFilePath, routines) + } + } + + return bucket.copyFile(srcBucketName, srcObjectKey, destBucketName, destObjectKey, + partSize, options, routines) +} + +func getCopyCpFilePath(cpConf *cpConfig, srcBucket, srcObject, destBucket, destObject, versionId string) string { + if cpConf.FilePath == "" && cpConf.DirPath != "" { + dest := fmt.Sprintf("oss://%v/%v", destBucket, destObject) + src := fmt.Sprintf("oss://%v/%v", srcBucket, srcObject) + cpFileName := getCpFileName(src, dest, versionId) + cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName + } + return cpConf.FilePath +} + +// ----- Concurrently copy without checkpoint --------- + +// copyWorkerArg defines the copy worker arguments +type copyWorkerArg struct { + bucket *Bucket + imur InitiateMultipartUploadResult + srcBucketName string + srcObjectKey string + options []Option + hook copyPartHook +} + +// copyPartHook is the hook for testing purpose +type copyPartHook func(part copyPart) error + +var copyPartHooker copyPartHook = defaultCopyPartHook + +func defaultCopyPartHook(part copyPart) error { + return nil +} + +// copyWorker copies worker +func copyWorker(id int, arg copyWorkerArg, jobs <-chan copyPart, results chan<- UploadPart, failed chan<- error, die <-chan bool) { + for chunk := range jobs { + if err := arg.hook(chunk); err != nil { + failed <- err + break + } + chunkSize := chunk.End - chunk.Start + 1 + part, err := arg.bucket.UploadPartCopy(arg.imur, arg.srcBucketName, arg.srcObjectKey, + chunk.Start, chunkSize, chunk.Number, arg.options...) + if err != nil { + failed <- err + break + } + select { + case <-die: + return + default: + } + results <- part + } +} + +// copyScheduler +func copyScheduler(jobs chan copyPart, parts []copyPart) { + for _, part := range parts { + jobs <- part + } + close(jobs) +} + +// copyPart structure +type copyPart struct { + Number int // Part number (from 1 to 10,000) + Start int64 // The start index in the source file. + End int64 // The end index in the source file +} + +// getCopyParts calculates copy parts +func getCopyParts(objectSize, partSize int64) []copyPart { + parts := []copyPart{} + part := copyPart{} + i := 0 + for offset := int64(0); offset < objectSize; offset += partSize { + part.Number = i + 1 + part.Start = offset + part.End = GetPartEnd(offset, objectSize, partSize) + parts = append(parts, part) + i++ + } + return parts +} + +// getSrcObjectBytes gets the source file size +func getSrcObjectBytes(parts []copyPart) int64 { + var ob int64 + for _, part := range parts { + ob += (part.End - part.Start + 1) + } + return ob +} + +// copyFile is a concurrently copy without checkpoint +func (bucket Bucket) copyFile(srcBucketName, srcObjectKey, destBucketName, destObjectKey string, + partSize int64, options []Option, routines int) error { + descBucket, err := bucket.Client.Bucket(destBucketName) + srcBucket, err := bucket.Client.Bucket(srcBucketName) + listener := GetProgressListener(options) + + // choice valid options + headerOptions := ChoiceHeadObjectOption(options) + partOptions := ChoiceTransferPartOption(options) + completeOptions := ChoiceCompletePartOption(options) + abortOptions := ChoiceAbortPartOption(options) + + meta, err := srcBucket.GetObjectDetailedMeta(srcObjectKey, headerOptions...) + if err != nil { + return err + } + + objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 0) + if err != nil { + return err + } + + // Get copy parts + parts := getCopyParts(objectSize, partSize) + // Initialize the multipart upload + imur, err := descBucket.InitiateMultipartUpload(destObjectKey, options...) + if err != nil { + return err + } + + jobs := make(chan copyPart, len(parts)) + results := make(chan UploadPart, len(parts)) + failed := make(chan error) + die := make(chan bool) + + var completedBytes int64 + totalBytes := getSrcObjectBytes(parts) + event := newProgressEvent(TransferStartedEvent, 0, totalBytes, 0) + publishProgress(listener, event) + + // Start to copy workers + arg := copyWorkerArg{descBucket, imur, srcBucketName, srcObjectKey, partOptions, copyPartHooker} + for w := 1; w <= routines; w++ { + go copyWorker(w, arg, jobs, results, failed, die) + } + + // Start the scheduler + go copyScheduler(jobs, parts) + + // Wait for the parts finished. + completed := 0 + ups := make([]UploadPart, len(parts)) + for completed < len(parts) { + select { + case part := <-results: + completed++ + ups[part.PartNumber-1] = part + copyBytes := (parts[part.PartNumber-1].End - parts[part.PartNumber-1].Start + 1) + completedBytes += copyBytes + event = newProgressEvent(TransferDataEvent, completedBytes, totalBytes, copyBytes) + publishProgress(listener, event) + case err := <-failed: + close(die) + descBucket.AbortMultipartUpload(imur, abortOptions...) + event = newProgressEvent(TransferFailedEvent, completedBytes, totalBytes, 0) + publishProgress(listener, event) + return err + } + + if completed >= len(parts) { + break + } + } + + event = newProgressEvent(TransferCompletedEvent, completedBytes, totalBytes, 0) + publishProgress(listener, event) + + // Complete the multipart upload + _, err = descBucket.CompleteMultipartUpload(imur, ups, completeOptions...) + if err != nil { + bucket.AbortMultipartUpload(imur, abortOptions...) + return err + } + return nil +} + +// ----- Concurrently copy with checkpoint ----- + +const copyCpMagic = "84F1F18C-FF1D-403B-A1D8-9DEB5F65910A" + +type copyCheckpoint struct { + Magic string // Magic + MD5 string // CP content MD5 + SrcBucketName string // Source bucket + SrcObjectKey string // Source object + DestBucketName string // Target bucket + DestObjectKey string // Target object + CopyID string // Copy ID + ObjStat objectStat // Object stat + Parts []copyPart // Copy parts + CopyParts []UploadPart // The uploaded parts + PartStat []bool // The part status +} + +// isValid checks if the data is valid which means CP is valid and object is not updated. +func (cp copyCheckpoint) isValid(meta http.Header) (bool, error) { + // Compare CP's magic number and the MD5. + cpb := cp + cpb.MD5 = "" + js, _ := json.Marshal(cpb) + sum := md5.Sum(js) + b64 := base64.StdEncoding.EncodeToString(sum[:]) + + if cp.Magic != downloadCpMagic || b64 != cp.MD5 { + return false, nil + } + + objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 64) + if err != nil { + return false, err + } + + // Compare the object size and last modified time and etag. + if cp.ObjStat.Size != objectSize || + cp.ObjStat.LastModified != meta.Get(HTTPHeaderLastModified) || + cp.ObjStat.Etag != meta.Get(HTTPHeaderEtag) { + return false, nil + } + + return true, nil +} + +// load loads from the checkpoint file +func (cp *copyCheckpoint) load(filePath string) error { + contents, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + + err = json.Unmarshal(contents, cp) + return err +} + +// update updates the parts status +func (cp *copyCheckpoint) update(part UploadPart) { + cp.CopyParts[part.PartNumber-1] = part + cp.PartStat[part.PartNumber-1] = true +} + +// dump dumps the CP to the file +func (cp *copyCheckpoint) dump(filePath string) error { + bcp := *cp + + // Calculate MD5 + bcp.MD5 = "" + js, err := json.Marshal(bcp) + if err != nil { + return err + } + sum := md5.Sum(js) + b64 := base64.StdEncoding.EncodeToString(sum[:]) + bcp.MD5 = b64 + + // Serialization + js, err = json.Marshal(bcp) + if err != nil { + return err + } + + // Dump + return ioutil.WriteFile(filePath, js, FilePermMode) +} + +// todoParts returns unfinished parts +func (cp copyCheckpoint) todoParts() []copyPart { + dps := []copyPart{} + for i, ps := range cp.PartStat { + if !ps { + dps = append(dps, cp.Parts[i]) + } + } + return dps +} + +// getCompletedBytes returns finished bytes count +func (cp copyCheckpoint) getCompletedBytes() int64 { + var completedBytes int64 + for i, part := range cp.Parts { + if cp.PartStat[i] { + completedBytes += (part.End - part.Start + 1) + } + } + return completedBytes +} + +// prepare initializes the multipart upload +func (cp *copyCheckpoint) prepare(meta http.Header, srcBucket *Bucket, srcObjectKey string, destBucket *Bucket, destObjectKey string, + partSize int64, options []Option) error { + // CP + cp.Magic = copyCpMagic + cp.SrcBucketName = srcBucket.BucketName + cp.SrcObjectKey = srcObjectKey + cp.DestBucketName = destBucket.BucketName + cp.DestObjectKey = destObjectKey + + objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 64) + if err != nil { + return err + } + + cp.ObjStat.Size = objectSize + cp.ObjStat.LastModified = meta.Get(HTTPHeaderLastModified) + cp.ObjStat.Etag = meta.Get(HTTPHeaderEtag) + + // Parts + cp.Parts = getCopyParts(objectSize, partSize) + cp.PartStat = make([]bool, len(cp.Parts)) + for i := range cp.PartStat { + cp.PartStat[i] = false + } + cp.CopyParts = make([]UploadPart, len(cp.Parts)) + + // Init copy + imur, err := destBucket.InitiateMultipartUpload(destObjectKey, options...) + if err != nil { + return err + } + cp.CopyID = imur.UploadID + + return nil +} + +func (cp *copyCheckpoint) complete(bucket *Bucket, parts []UploadPart, cpFilePath string, options []Option) error { + imur := InitiateMultipartUploadResult{Bucket: cp.DestBucketName, + Key: cp.DestObjectKey, UploadID: cp.CopyID} + _, err := bucket.CompleteMultipartUpload(imur, parts, options...) + if err != nil { + return err + } + os.Remove(cpFilePath) + return err +} + +// copyFileWithCp is concurrently copy with checkpoint +func (bucket Bucket) copyFileWithCp(srcBucketName, srcObjectKey, destBucketName, destObjectKey string, + partSize int64, options []Option, cpFilePath string, routines int) error { + descBucket, err := bucket.Client.Bucket(destBucketName) + srcBucket, err := bucket.Client.Bucket(srcBucketName) + listener := GetProgressListener(options) + + // Load CP data + ccp := copyCheckpoint{} + err = ccp.load(cpFilePath) + if err != nil { + os.Remove(cpFilePath) + } + + // choice valid options + headerOptions := ChoiceHeadObjectOption(options) + partOptions := ChoiceTransferPartOption(options) + completeOptions := ChoiceCompletePartOption(options) + + meta, err := srcBucket.GetObjectDetailedMeta(srcObjectKey, headerOptions...) + if err != nil { + return err + } + + // Load error or the CP data is invalid---reinitialize + valid, err := ccp.isValid(meta) + if err != nil || !valid { + if err = ccp.prepare(meta, srcBucket, srcObjectKey, descBucket, destObjectKey, partSize, options); err != nil { + return err + } + os.Remove(cpFilePath) + } + + // Unfinished parts + parts := ccp.todoParts() + imur := InitiateMultipartUploadResult{ + Bucket: destBucketName, + Key: destObjectKey, + UploadID: ccp.CopyID} + + jobs := make(chan copyPart, len(parts)) + results := make(chan UploadPart, len(parts)) + failed := make(chan error) + die := make(chan bool) + + completedBytes := ccp.getCompletedBytes() + event := newProgressEvent(TransferStartedEvent, completedBytes, ccp.ObjStat.Size, 0) + publishProgress(listener, event) + + // Start the worker coroutines + arg := copyWorkerArg{descBucket, imur, srcBucketName, srcObjectKey, partOptions, copyPartHooker} + for w := 1; w <= routines; w++ { + go copyWorker(w, arg, jobs, results, failed, die) + } + + // Start the scheduler + go copyScheduler(jobs, parts) + + // Wait for the parts completed. + completed := 0 + for completed < len(parts) { + select { + case part := <-results: + completed++ + ccp.update(part) + ccp.dump(cpFilePath) + copyBytes := (parts[part.PartNumber-1].End - parts[part.PartNumber-1].Start + 1) + completedBytes += copyBytes + event = newProgressEvent(TransferDataEvent, completedBytes, ccp.ObjStat.Size, copyBytes) + publishProgress(listener, event) + case err := <-failed: + close(die) + event = newProgressEvent(TransferFailedEvent, completedBytes, ccp.ObjStat.Size, 0) + publishProgress(listener, event) + return err + } + + if completed >= len(parts) { + break + } + } + + event = newProgressEvent(TransferCompletedEvent, completedBytes, ccp.ObjStat.Size, 0) + publishProgress(listener, event) + + return ccp.complete(descBucket, ccp.CopyParts, cpFilePath, completeOptions) +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go new file mode 100644 index 00000000000..aea7fafb6ea --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go @@ -0,0 +1,320 @@ +package oss + +import ( + "bytes" + "encoding/xml" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "sort" + "strconv" +) + +// InitiateMultipartUpload initializes multipart upload +// +// objectKey object name +// options the object constricts for upload. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires, +// +// ServerSideEncryption, Meta, check out the following link: +// https://www.alibabacloud.com/help/en/object-storage-service/latest/initiatemultipartupload +// +// InitiateMultipartUploadResult the return value of the InitiateMultipartUpload, which is used for calls later on such as UploadPartFromFile,UploadPartCopy. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) InitiateMultipartUpload(objectKey string, options ...Option) (InitiateMultipartUploadResult, error) { + var imur InitiateMultipartUploadResult + opts := AddContentType(options, objectKey) + params, _ := GetRawParams(options) + paramKeys := []string{"sequential", "withHashContext", "x-oss-enable-md5", "x-oss-enable-sha1", "x-oss-enable-sha256"} + ConvertEmptyValueToNil(params, paramKeys) + params["uploads"] = nil + + resp, err := bucket.do("POST", objectKey, params, opts, nil, nil) + if err != nil { + return imur, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &imur) + return imur, err +} + +// UploadPart uploads parts +// +// After initializing a Multipart Upload, the upload Id and object key could be used for uploading the parts. +// Each part has its part number (ranges from 1 to 10,000). And for each upload Id, the part number identifies the position of the part in the whole file. +// And thus with the same part number and upload Id, another part upload will overwrite the data. +// Except the last one, minimal part size is 100KB. There's no limit on the last part size. +// +// imur the returned value of InitiateMultipartUpload. +// reader io.Reader the reader for the part's data. +// size the part size. +// partNumber the part number (ranges from 1 to 10,000). Invalid part number will lead to InvalidArgument error. +// +// UploadPart the return value of the upload part. It consists of PartNumber and ETag. It's valid when error is nil. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) UploadPart(imur InitiateMultipartUploadResult, reader io.Reader, + partSize int64, partNumber int, options ...Option) (UploadPart, error) { + request := &UploadPartRequest{ + InitResult: &imur, + Reader: reader, + PartSize: partSize, + PartNumber: partNumber, + } + + result, err := bucket.DoUploadPart(request, options) + + return result.Part, err +} + +// UploadPartFromFile uploads part from the file. +// +// imur the return value of a successful InitiateMultipartUpload. +// filePath the local file path to upload. +// startPosition the start position in the local file. +// partSize the part size. +// partNumber the part number (from 1 to 10,000) +// +// UploadPart the return value consists of PartNumber and ETag. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) UploadPartFromFile(imur InitiateMultipartUploadResult, filePath string, + startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) { + var part = UploadPart{} + fd, err := os.Open(filePath) + if err != nil { + return part, err + } + defer fd.Close() + fd.Seek(startPosition, os.SEEK_SET) + + request := &UploadPartRequest{ + InitResult: &imur, + Reader: fd, + PartSize: partSize, + PartNumber: partNumber, + } + + result, err := bucket.DoUploadPart(request, options) + + return result.Part, err +} + +// DoUploadPart does the actual part upload. +// +// request part upload request +// +// UploadPartResult the result of uploading part. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) DoUploadPart(request *UploadPartRequest, options []Option) (*UploadPartResult, error) { + listener := GetProgressListener(options) + options = append(options, ContentLength(request.PartSize)) + params := map[string]interface{}{} + params["partNumber"] = strconv.Itoa(request.PartNumber) + params["uploadId"] = request.InitResult.UploadID + resp, err := bucket.do("PUT", request.InitResult.Key, params, options, + &io.LimitedReader{R: request.Reader, N: request.PartSize}, listener) + if err != nil { + return &UploadPartResult{}, err + } + defer resp.Body.Close() + + part := UploadPart{ + ETag: resp.Headers.Get(HTTPHeaderEtag), + PartNumber: request.PartNumber, + } + + if bucket.GetConfig().IsEnableCRC { + err = CheckCRC(resp, "DoUploadPart") + if err != nil { + return &UploadPartResult{part}, err + } + } + + return &UploadPartResult{part}, nil +} + +// UploadPartCopy uploads part copy +// +// imur the return value of InitiateMultipartUpload +// copySrc source Object name +// startPosition the part's start index in the source file +// partSize the part size +// partNumber the part number, ranges from 1 to 10,000. If it exceeds the range OSS returns InvalidArgument error. +// options the constraints of source object for the copy. The copy happens only when these contraints are met. Otherwise it returns error. +// +// CopySourceIfNoneMatch, CopySourceIfModifiedSince CopySourceIfUnmodifiedSince, check out the following link for the detail +// https://www.alibabacloud.com/help/en/object-storage-service/latest/uploadpartcopy +// +// UploadPart the return value consists of PartNumber and ETag. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) UploadPartCopy(imur InitiateMultipartUploadResult, srcBucketName, srcObjectKey string, + startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) { + var out UploadPartCopyResult + var part UploadPart + var opts []Option + + //first find version id + versionIdKey := "versionId" + versionId, _ := FindOption(options, versionIdKey, nil) + if versionId == nil { + opts = []Option{CopySource(srcBucketName, url.QueryEscape(srcObjectKey)), + CopySourceRange(startPosition, partSize)} + } else { + opts = []Option{CopySourceVersion(srcBucketName, url.QueryEscape(srcObjectKey), versionId.(string)), + CopySourceRange(startPosition, partSize)} + options = DeleteOption(options, versionIdKey) + } + + opts = append(opts, options...) + + params := map[string]interface{}{} + params["partNumber"] = strconv.Itoa(partNumber) + params["uploadId"] = imur.UploadID + resp, err := bucket.do("PUT", imur.Key, params, opts, nil, nil) + if err != nil { + return part, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + if err != nil { + return part, err + } + part.ETag = out.ETag + part.PartNumber = partNumber + + return part, nil +} + +// CompleteMultipartUpload completes the multipart upload. +// +// imur the return value of InitiateMultipartUpload. +// parts the array of return value of UploadPart/UploadPartFromFile/UploadPartCopy. +// +// CompleteMultipartUploadResponse the return value when the call succeeds. Only valid when the error is nil. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult, + parts []UploadPart, options ...Option) (CompleteMultipartUploadResult, error) { + var out CompleteMultipartUploadResult + + sort.Sort(UploadParts(parts)) + cxml := completeMultipartUploadXML{} + cxml.Part = parts + bs, err := xml.Marshal(cxml) + if err != nil { + return out, err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + params := map[string]interface{}{} + params["uploadId"] = imur.UploadID + resp, err := bucket.do("POST", imur.Key, params, options, buffer, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return out, err + } + err = CheckRespCode(resp.StatusCode, []int{http.StatusOK}) + if len(body) > 0 { + if err != nil { + err = tryConvertServiceError(body, resp, err) + } else { + callback, _ := FindOption(options, HTTPHeaderOssCallback, nil) + if callback == nil { + err = xml.Unmarshal(body, &out) + } else { + rb, _ := FindOption(options, responseBody, nil) + if rb != nil { + if rbody, ok := rb.(*[]byte); ok { + *rbody = body + } + } + } + } + } + return out, err +} + +// AbortMultipartUpload aborts the multipart upload. +// +// imur the return value of InitiateMultipartUpload. +// +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) AbortMultipartUpload(imur InitiateMultipartUploadResult, options ...Option) error { + params := map[string]interface{}{} + params["uploadId"] = imur.UploadID + resp, err := bucket.do("DELETE", imur.Key, params, options, nil, nil) + if err != nil { + return err + } + defer resp.Body.Close() + return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent}) +} + +// ListUploadedParts lists the uploaded parts. +// +// imur the return value of InitiateMultipartUpload. +// +// ListUploadedPartsResponse the return value if it succeeds, only valid when error is nil. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) ListUploadedParts(imur InitiateMultipartUploadResult, options ...Option) (ListUploadedPartsResult, error) { + var out ListUploadedPartsResult + options = append(options, EncodingType("url")) + + params := map[string]interface{}{} + params, err := GetRawParams(options) + if err != nil { + return out, err + } + + params["uploadId"] = imur.UploadID + resp, err := bucket.do("GET", imur.Key, params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + if err != nil { + return out, err + } + err = decodeListUploadedPartsResult(&out) + return out, err +} + +// ListMultipartUploads lists all ongoing multipart upload tasks +// +// options listObject's filter. Prefix specifies the returned object's prefix; KeyMarker specifies the returned object's start point in lexicographic order; +// +// MaxKeys specifies the max entries to return; Delimiter is the character for grouping object keys. +// +// ListMultipartUploadResponse the return value if it succeeds, only valid when error is nil. +// error it's nil if the operation succeeds, otherwise it's an error object. +func (bucket Bucket) ListMultipartUploads(options ...Option) (ListMultipartUploadResult, error) { + var out ListMultipartUploadResult + + options = append(options, EncodingType("url")) + params, err := GetRawParams(options) + if err != nil { + return out, err + } + params["uploads"] = nil + + resp, err := bucket.doInner("GET", "", params, options, nil, nil) + if err != nil { + return out, err + } + defer resp.Body.Close() + + err = xmlUnmarshal(resp.Body, &out) + if err != nil { + return out, err + } + err = decodeListMultipartUploadResult(&out) + return out, err +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go new file mode 100644 index 00000000000..7e517ddbed3 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go @@ -0,0 +1,735 @@ +package oss + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + +type optionType string + +const ( + optionParam optionType = "HTTPParameter" // URL parameter + optionHTTP optionType = "HTTPHeader" // HTTP header + optionContext optionType = "HTTPContext" // context + optionArg optionType = "FuncArgument" // Function argument + +) + +const ( + deleteObjectsQuiet = "delete-objects-quiet" + routineNum = "x-routine-num" + checkpointConfig = "x-cp-config" + initCRC64 = "init-crc64" + progressListener = "x-progress-listener" + storageClass = "storage-class" + responseHeader = "x-response-header" + redundancyType = "redundancy-type" + objectHashFunc = "object-hash-func" + responseBody = "x-response-body" + contextArg = "x-context-arg" +) + +type ( + optionValue struct { + Value interface{} + Type optionType + } + + // Option HTTP option + Option func(map[string]optionValue) error +) + +// ACL is an option to set X-Oss-Acl header +func ACL(acl ACLType) Option { + return setHeader(HTTPHeaderOssACL, string(acl)) +} + +// ContentType is an option to set Content-Type header +func ContentType(value string) Option { + return setHeader(HTTPHeaderContentType, value) +} + +// ContentLength is an option to set Content-Length header +func ContentLength(length int64) Option { + return setHeader(HTTPHeaderContentLength, strconv.FormatInt(length, 10)) +} + +// CacheControl is an option to set Cache-Control header +func CacheControl(value string) Option { + return setHeader(HTTPHeaderCacheControl, value) +} + +// ContentDisposition is an option to set Content-Disposition header +func ContentDisposition(value string) Option { + return setHeader(HTTPHeaderContentDisposition, value) +} + +// ContentEncoding is an option to set Content-Encoding header +func ContentEncoding(value string) Option { + return setHeader(HTTPHeaderContentEncoding, value) +} + +// ContentLanguage is an option to set Content-Language header +func ContentLanguage(value string) Option { + return setHeader(HTTPHeaderContentLanguage, value) +} + +// ContentMD5 is an option to set Content-MD5 header +func ContentMD5(value string) Option { + return setHeader(HTTPHeaderContentMD5, value) +} + +// Expires is an option to set Expires header +func Expires(t time.Time) Option { + return setHeader(HTTPHeaderExpires, t.Format(http.TimeFormat)) +} + +// Meta is an option to set Meta header +func Meta(key, value string) Option { + return setHeader(HTTPHeaderOssMetaPrefix+key, value) +} + +// Range is an option to set Range header, [start, end] +func Range(start, end int64) Option { + return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%d-%d", start, end)) +} + +// NormalizedRange is an option to set Range header, such as 1024-2048 or 1024- or -2048 +func NormalizedRange(nr string) Option { + return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%s", strings.TrimSpace(nr))) +} + +// AcceptEncoding is an option to set Accept-Encoding header +func AcceptEncoding(value string) Option { + return setHeader(HTTPHeaderAcceptEncoding, value) +} + +// IfModifiedSince is an option to set If-Modified-Since header +func IfModifiedSince(t time.Time) Option { + return setHeader(HTTPHeaderIfModifiedSince, t.Format(http.TimeFormat)) +} + +// IfUnmodifiedSince is an option to set If-Unmodified-Since header +func IfUnmodifiedSince(t time.Time) Option { + return setHeader(HTTPHeaderIfUnmodifiedSince, t.Format(http.TimeFormat)) +} + +// IfMatch is an option to set If-Match header +func IfMatch(value string) Option { + return setHeader(HTTPHeaderIfMatch, value) +} + +// IfNoneMatch is an option to set IfNoneMatch header +func IfNoneMatch(value string) Option { + return setHeader(HTTPHeaderIfNoneMatch, value) +} + +// CopySource is an option to set X-Oss-Copy-Source header +func CopySource(sourceBucket, sourceObject string) Option { + return setHeader(HTTPHeaderOssCopySource, "/"+sourceBucket+"/"+sourceObject) +} + +// CopySourceVersion is an option to set X-Oss-Copy-Source header,include versionId +func CopySourceVersion(sourceBucket, sourceObject string, versionId string) Option { + return setHeader(HTTPHeaderOssCopySource, "/"+sourceBucket+"/"+sourceObject+"?"+"versionId="+versionId) +} + +// CopySourceRange is an option to set X-Oss-Copy-Source header +func CopySourceRange(startPosition, partSize int64) Option { + val := "bytes=" + strconv.FormatInt(startPosition, 10) + "-" + + strconv.FormatInt((startPosition+partSize-1), 10) + return setHeader(HTTPHeaderOssCopySourceRange, val) +} + +// CopySourceIfMatch is an option to set X-Oss-Copy-Source-If-Match header +func CopySourceIfMatch(value string) Option { + return setHeader(HTTPHeaderOssCopySourceIfMatch, value) +} + +// CopySourceIfNoneMatch is an option to set X-Oss-Copy-Source-If-None-Match header +func CopySourceIfNoneMatch(value string) Option { + return setHeader(HTTPHeaderOssCopySourceIfNoneMatch, value) +} + +// CopySourceIfModifiedSince is an option to set X-Oss-CopySource-If-Modified-Since header +func CopySourceIfModifiedSince(t time.Time) Option { + return setHeader(HTTPHeaderOssCopySourceIfModifiedSince, t.Format(http.TimeFormat)) +} + +// CopySourceIfUnmodifiedSince is an option to set X-Oss-Copy-Source-If-Unmodified-Since header +func CopySourceIfUnmodifiedSince(t time.Time) Option { + return setHeader(HTTPHeaderOssCopySourceIfUnmodifiedSince, t.Format(http.TimeFormat)) +} + +// MetadataDirective is an option to set X-Oss-Metadata-Directive header +func MetadataDirective(directive MetadataDirectiveType) Option { + return setHeader(HTTPHeaderOssMetadataDirective, string(directive)) +} + +// ServerSideEncryption is an option to set X-Oss-Server-Side-Encryption header +func ServerSideEncryption(value string) Option { + return setHeader(HTTPHeaderOssServerSideEncryption, value) +} + +// ServerSideEncryptionKeyID is an option to set X-Oss-Server-Side-Encryption-Key-Id header +func ServerSideEncryptionKeyID(value string) Option { + return setHeader(HTTPHeaderOssServerSideEncryptionKeyID, value) +} + +// ServerSideDataEncryption is an option to set X-Oss-Server-Side-Data-Encryption header +func ServerSideDataEncryption(value string) Option { + return setHeader(HTTPHeaderOssServerSideDataEncryption, value) +} + +// SSECAlgorithm is an option to set X-Oss-Server-Side-Encryption-Customer-Algorithm header +func SSECAlgorithm(value string) Option { + return setHeader(HTTPHeaderSSECAlgorithm, value) +} + +// SSECKey is an option to set X-Oss-Server-Side-Encryption-Customer-Key header +func SSECKey(value string) Option { + return setHeader(HTTPHeaderSSECKey, value) +} + +// SSECKeyMd5 is an option to set X-Oss-Server-Side-Encryption-Customer-Key-Md5 header +func SSECKeyMd5(value string) Option { + return setHeader(HTTPHeaderSSECKeyMd5, value) +} + +// ObjectACL is an option to set X-Oss-Object-Acl header +func ObjectACL(acl ACLType) Option { + return setHeader(HTTPHeaderOssObjectACL, string(acl)) +} + +// symlinkTarget is an option to set X-Oss-Symlink-Target +func symlinkTarget(targetObjectKey string) Option { + return setHeader(HTTPHeaderOssSymlinkTarget, targetObjectKey) +} + +// Origin is an option to set Origin header +func Origin(value string) Option { + return setHeader(HTTPHeaderOrigin, value) +} + +// ObjectStorageClass is an option to set the storage class of object +func ObjectStorageClass(storageClass StorageClassType) Option { + return setHeader(HTTPHeaderOssStorageClass, string(storageClass)) +} + +// Callback is an option to set callback values +func Callback(callback string) Option { + return setHeader(HTTPHeaderOssCallback, callback) +} + +// CallbackVar is an option to set callback user defined values +func CallbackVar(callbackVar string) Option { + return setHeader(HTTPHeaderOssCallbackVar, callbackVar) +} + +// RequestPayer is an option to set payer who pay for the request +func RequestPayer(payerType PayerType) Option { + return setHeader(HTTPHeaderOssRequester, strings.ToLower(string(payerType))) +} + +// RequestPayerParam is an option to set payer who pay for the request +func RequestPayerParam(payerType PayerType) Option { + return addParam(strings.ToLower(HTTPHeaderOssRequester), strings.ToLower(string(payerType))) +} + +// SetTagging is an option to set object tagging +func SetTagging(tagging Tagging) Option { + if len(tagging.Tags) == 0 { + return nil + } + + taggingValue := "" + for index, tag := range tagging.Tags { + if index != 0 { + taggingValue += "&" + } + taggingValue += url.QueryEscape(tag.Key) + "=" + url.QueryEscape(tag.Value) + } + return setHeader(HTTPHeaderOssTagging, taggingValue) +} + +// TaggingDirective is an option to set X-Oss-Metadata-Directive header +func TaggingDirective(directive TaggingDirectiveType) Option { + return setHeader(HTTPHeaderOssTaggingDirective, string(directive)) +} + +// ACReqMethod is an option to set Access-Control-Request-Method header +func ACReqMethod(value string) Option { + return setHeader(HTTPHeaderACReqMethod, value) +} + +// ACReqHeaders is an option to set Access-Control-Request-Headers header +func ACReqHeaders(value string) Option { + return setHeader(HTTPHeaderACReqHeaders, value) +} + +// TrafficLimitHeader is an option to set X-Oss-Traffic-Limit +func TrafficLimitHeader(value int64) Option { + return setHeader(HTTPHeaderOssTrafficLimit, strconv.FormatInt(value, 10)) +} + +// UserAgentHeader is an option to set HTTPHeaderUserAgent +func UserAgentHeader(ua string) Option { + return setHeader(HTTPHeaderUserAgent, ua) +} + +// ForbidOverWrite is an option to set X-Oss-Forbid-Overwrite +func ForbidOverWrite(forbidWrite bool) Option { + if forbidWrite { + return setHeader(HTTPHeaderOssForbidOverWrite, "true") + } else { + return setHeader(HTTPHeaderOssForbidOverWrite, "false") + } +} + +// RangeBehavior is an option to set Range value, such as "standard" +func RangeBehavior(value string) Option { + return setHeader(HTTPHeaderOssRangeBehavior, value) +} + +func PartHashCtxHeader(value string) Option { + return setHeader(HTTPHeaderOssHashCtx, value) +} + +func PartMd5CtxHeader(value string) Option { + return setHeader(HTTPHeaderOssMd5Ctx, value) +} + +func PartHashCtxParam(value string) Option { + return addParam("x-oss-hash-ctx", value) +} + +func PartMd5CtxParam(value string) Option { + return addParam("x-oss-md5-ctx", value) +} + +// Delimiter is an option to set delimiler parameter +func Delimiter(value string) Option { + return addParam("delimiter", value) +} + +// Marker is an option to set marker parameter +func Marker(value string) Option { + return addParam("marker", value) +} + +// MaxKeys is an option to set maxkeys parameter +func MaxKeys(value int) Option { + return addParam("max-keys", strconv.Itoa(value)) +} + +// Prefix is an option to set prefix parameter +func Prefix(value string) Option { + return addParam("prefix", value) +} + +// EncodingType is an option to set encoding-type parameter +func EncodingType(value string) Option { + return addParam("encoding-type", value) +} + +// MaxUploads is an option to set max-uploads parameter +func MaxUploads(value int) Option { + return addParam("max-uploads", strconv.Itoa(value)) +} + +// KeyMarker is an option to set key-marker parameter +func KeyMarker(value string) Option { + return addParam("key-marker", value) +} + +// VersionIdMarker is an option to set version-id-marker parameter +func VersionIdMarker(value string) Option { + return addParam("version-id-marker", value) +} + +// VersionId is an option to set versionId parameter +func VersionId(value string) Option { + return addParam("versionId", value) +} + +// TagKey is an option to set tag key parameter +func TagKey(value string) Option { + return addParam("tag-key", value) +} + +// TagValue is an option to set tag value parameter +func TagValue(value string) Option { + return addParam("tag-value", value) +} + +// UploadIDMarker is an option to set upload-id-marker parameter +func UploadIDMarker(value string) Option { + return addParam("upload-id-marker", value) +} + +// MaxParts is an option to set max-parts parameter +func MaxParts(value int) Option { + return addParam("max-parts", strconv.Itoa(value)) +} + +// PartNumberMarker is an option to set part-number-marker parameter +func PartNumberMarker(value int) Option { + return addParam("part-number-marker", strconv.Itoa(value)) +} + +// Sequential is an option to set sequential parameter for InitiateMultipartUpload +func Sequential() Option { + return addParam("sequential", "") +} + +// WithHashContext is an option to set withHashContext parameter for InitiateMultipartUpload +func WithHashContext() Option { + return addParam("withHashContext", "") +} + +// EnableMd5 is an option to set x-oss-enable-md5 parameter for InitiateMultipartUpload +func EnableMd5() Option { + return addParam("x-oss-enable-md5", "") +} + +// EnableSha1 is an option to set x-oss-enable-sha1 parameter for InitiateMultipartUpload +func EnableSha1() Option { + return addParam("x-oss-enable-sha1", "") +} + +// EnableSha256 is an option to set x-oss-enable-sha256 parameter for InitiateMultipartUpload +func EnableSha256() Option { + return addParam("x-oss-enable-sha256", "") +} + +// ListType is an option to set List-type parameter for ListObjectsV2 +func ListType(value int) Option { + return addParam("list-type", strconv.Itoa(value)) +} + +// StartAfter is an option to set start-after parameter for ListObjectsV2 +func StartAfter(value string) Option { + return addParam("start-after", value) +} + +// ContinuationToken is an option to set Continuation-token parameter for ListObjectsV2 +func ContinuationToken(value string) Option { + if value == "" { + return addParam("continuation-token", nil) + } + return addParam("continuation-token", value) +} + +// FetchOwner is an option to set Fetch-owner parameter for ListObjectsV2 +func FetchOwner(value bool) Option { + if value { + return addParam("fetch-owner", "true") + } + return addParam("fetch-owner", "false") +} + +// DeleteObjectsQuiet false:DeleteObjects in verbose mode; true:DeleteObjects in quite mode. Default is false. +func DeleteObjectsQuiet(isQuiet bool) Option { + return addArg(deleteObjectsQuiet, isQuiet) +} + +// StorageClass bucket storage class +func StorageClass(value StorageClassType) Option { + return addArg(storageClass, value) +} + +// RedundancyType bucket data redundancy type +func RedundancyType(value DataRedundancyType) Option { + return addArg(redundancyType, value) +} + +// RedundancyType bucket data redundancy type +func ObjectHashFunc(value ObjecthashFuncType) Option { + return addArg(objectHashFunc, value) +} + +// WithContext returns an option that sets the context for requests. +func WithContext(ctx context.Context) Option { + return addArg(contextArg, ctx) +} + +// Checkpoint configuration +type cpConfig struct { + IsEnable bool + FilePath string + DirPath string +} + +// Checkpoint sets the isEnable flag and checkpoint file path for DownloadFile/UploadFile. +func Checkpoint(isEnable bool, filePath string) Option { + return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, FilePath: filePath}) +} + +// CheckpointDir sets the isEnable flag and checkpoint dir path for DownloadFile/UploadFile. +func CheckpointDir(isEnable bool, dirPath string) Option { + return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, DirPath: dirPath}) +} + +// Routines DownloadFile/UploadFile routine count +func Routines(n int) Option { + return addArg(routineNum, n) +} + +// InitCRC Init AppendObject CRC +func InitCRC(initCRC uint64) Option { + return addArg(initCRC64, initCRC) +} + +// Progress set progress listener +func Progress(listener ProgressListener) Option { + return addArg(progressListener, listener) +} + +// GetResponseHeader for get response http header +func GetResponseHeader(respHeader *http.Header) Option { + return addArg(responseHeader, respHeader) +} + +// CallbackResult for get response of call back +func CallbackResult(body *[]byte) Option { + return addArg(responseBody, body) +} + +// ResponseContentType is an option to set response-content-type param +func ResponseContentType(value string) Option { + return addParam("response-content-type", value) +} + +// ResponseContentLanguage is an option to set response-content-language param +func ResponseContentLanguage(value string) Option { + return addParam("response-content-language", value) +} + +// ResponseExpires is an option to set response-expires param +func ResponseExpires(value string) Option { + return addParam("response-expires", value) +} + +// ResponseCacheControl is an option to set response-cache-control param +func ResponseCacheControl(value string) Option { + return addParam("response-cache-control", value) +} + +// ResponseContentDisposition is an option to set response-content-disposition param +func ResponseContentDisposition(value string) Option { + return addParam("response-content-disposition", value) +} + +// ResponseContentEncoding is an option to set response-content-encoding param +func ResponseContentEncoding(value string) Option { + return addParam("response-content-encoding", value) +} + +// Process is an option to set x-oss-process param +func Process(value string) Option { + return addParam("x-oss-process", value) +} + +// TrafficLimitParam is a option to set x-oss-traffic-limit +func TrafficLimitParam(value int64) Option { + return addParam("x-oss-traffic-limit", strconv.FormatInt(value, 10)) +} + +// SetHeader Allow users to set personalized http headers +func SetHeader(key string, value interface{}) Option { + return setHeader(key, value) +} + +// AddParam Allow users to set personalized http params +func AddParam(key string, value interface{}) Option { + return addParam(key, value) +} + +func setHeader(key string, value interface{}) Option { + return func(params map[string]optionValue) error { + if value == nil { + return nil + } + params[key] = optionValue{value, optionHTTP} + return nil + } +} + +func addParam(key string, value interface{}) Option { + return func(params map[string]optionValue) error { + if value == nil { + return nil + } + params[key] = optionValue{value, optionParam} + return nil + } +} + +func addArg(key string, value interface{}) Option { + return func(params map[string]optionValue) error { + if value == nil { + return nil + } + params[key] = optionValue{value, optionArg} + return nil + } +} + +func handleOptions(headers map[string]string, options []Option) error { + params := map[string]optionValue{} + for _, option := range options { + if option != nil { + if err := option(params); err != nil { + return err + } + } + } + + for k, v := range params { + if v.Type == optionHTTP { + headers[k] = v.Value.(string) + } + } + return nil +} + +func GetRawParams(options []Option) (map[string]interface{}, error) { + // Option + params := map[string]optionValue{} + for _, option := range options { + if option != nil { + if err := option(params); err != nil { + return nil, err + } + } + } + + paramsm := map[string]interface{}{} + // Serialize + for k, v := range params { + if v.Type == optionParam { + vs := params[k] + paramsm[k] = vs.Value.(string) + } + } + + return paramsm, nil +} + +func FindOption(options []Option, param string, defaultVal interface{}) (interface{}, error) { + params := map[string]optionValue{} + for _, option := range options { + if option != nil { + if err := option(params); err != nil { + return nil, err + } + } + } + + if val, ok := params[param]; ok { + return val.Value, nil + } + return defaultVal, nil +} + +func IsOptionSet(options []Option, option string) (bool, interface{}, error) { + params := map[string]optionValue{} + for _, option := range options { + if option != nil { + if err := option(params); err != nil { + return false, nil, err + } + } + } + + if val, ok := params[option]; ok { + return true, val.Value, nil + } + return false, nil, nil +} + +func DeleteOption(options []Option, strKey string) []Option { + var outOption []Option + params := map[string]optionValue{} + for _, option := range options { + if option != nil { + option(params) + _, exist := params[strKey] + if !exist { + outOption = append(outOption, option) + } else { + delete(params, strKey) + } + } + } + return outOption +} + +func GetRequestId(header http.Header) string { + return header.Get("x-oss-request-id") +} + +func GetVersionId(header http.Header) string { + return header.Get("x-oss-version-id") +} + +func GetCopySrcVersionId(header http.Header) string { + return header.Get("x-oss-copy-source-version-id") +} + +func GetDeleteMark(header http.Header) bool { + value := header.Get("x-oss-delete-marker") + if strings.ToUpper(value) == "TRUE" { + return true + } + return false +} + +func GetQosDelayTime(header http.Header) string { + return header.Get("x-oss-qos-delay-time") +} + +// ForbidOverWrite is an option to set X-Oss-Forbid-Overwrite +func AllowSameActionOverLap(enabled bool) Option { + if enabled { + return setHeader(HTTPHeaderAllowSameActionOverLap, "true") + } else { + return setHeader(HTTPHeaderAllowSameActionOverLap, "false") + } +} + +func GetCallbackBody(options []Option, resp *Response, callbackSet bool) error { + var err error + + // get response body + if callbackSet { + err = setBody(options, resp) + } else { + callback, _ := FindOption(options, HTTPHeaderOssCallback, nil) + if callback != nil { + err = setBody(options, resp) + } + } + return err +} + +func setBody(options []Option, resp *Response) error { + respBody, _ := FindOption(options, responseBody, nil) + if respBody != nil && resp != nil { + pRespBody := respBody.(*[]byte) + pBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + if pBody != nil { + *pRespBody = pBody + } + } + return nil +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go new file mode 100644 index 00000000000..1b6535ba5ed --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go @@ -0,0 +1,116 @@ +package oss + +import ( + "io" +) + +// ProgressEventType defines transfer progress event type +type ProgressEventType int + +const ( + // TransferStartedEvent transfer started, set TotalBytes + TransferStartedEvent ProgressEventType = 1 + iota + // TransferDataEvent transfer data, set ConsumedBytes and TotalBytes + TransferDataEvent + // TransferCompletedEvent transfer completed + TransferCompletedEvent + // TransferFailedEvent transfer encounters an error + TransferFailedEvent +) + +// ProgressEvent defines progress event +type ProgressEvent struct { + ConsumedBytes int64 + TotalBytes int64 + RwBytes int64 + EventType ProgressEventType +} + +// ProgressListener listens progress change +type ProgressListener interface { + ProgressChanged(event *ProgressEvent) +} + +// -------------------- Private -------------------- + +func newProgressEvent(eventType ProgressEventType, consumed, total int64, rwBytes int64) *ProgressEvent { + return &ProgressEvent{ + ConsumedBytes: consumed, + TotalBytes: total, + RwBytes: rwBytes, + EventType: eventType} +} + +// publishProgress +func publishProgress(listener ProgressListener, event *ProgressEvent) { + if listener != nil && event != nil { + listener.ProgressChanged(event) + } +} + +type readerTracker struct { + completedBytes int64 +} + +type teeReader struct { + reader io.Reader + writer io.Writer + listener ProgressListener + consumedBytes int64 + totalBytes int64 + tracker *readerTracker +} + +// TeeReader returns a Reader that writes to w what it reads from r. +// All reads from r performed through it are matched with +// corresponding writes to w. There is no internal buffering - +// the write must complete before the read completes. +// Any error encountered while writing is reported as a read error. +func TeeReader(reader io.Reader, writer io.Writer, totalBytes int64, listener ProgressListener, tracker *readerTracker) io.ReadCloser { + return &teeReader{ + reader: reader, + writer: writer, + listener: listener, + consumedBytes: 0, + totalBytes: totalBytes, + tracker: tracker, + } +} + +func (t *teeReader) Read(p []byte) (n int, err error) { + n, err = t.reader.Read(p) + + // Read encountered error + if err != nil && err != io.EOF { + event := newProgressEvent(TransferFailedEvent, t.consumedBytes, t.totalBytes, 0) + publishProgress(t.listener, event) + } + + if n > 0 { + t.consumedBytes += int64(n) + // CRC + if t.writer != nil { + if n, err := t.writer.Write(p[:n]); err != nil { + return n, err + } + } + // Progress + if t.listener != nil { + event := newProgressEvent(TransferDataEvent, t.consumedBytes, t.totalBytes, int64(n)) + publishProgress(t.listener, event) + } + // Track + if t.tracker != nil { + t.tracker.completedBytes = t.consumedBytes + } + } + + return +} + +func (t *teeReader) Close() error { + if rc, ok := t.reader.(io.ReadCloser); ok { + return rc.Close() + } + return nil +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go new file mode 100644 index 00000000000..ea17d5bd5ce --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_6.go @@ -0,0 +1,12 @@ +//go:build !go1.7 +// +build !go1.7 + +package oss + +import "net/http" + +// http.ErrUseLastResponse only is defined go1.7 onward + +func disableHTTPRedirect(client *http.Client) { + +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go new file mode 100644 index 00000000000..5d1442dd184 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/redirect_1_7.go @@ -0,0 +1,13 @@ +//go:build go1.7 +// +build go1.7 + +package oss + +import "net/http" + +// http.ErrUseLastResponse only is defined go1.7 onward +func disableHTTPRedirect(client *http.Client) { + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object.go new file mode 100644 index 00000000000..2e0da4637f1 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object.go @@ -0,0 +1,197 @@ +package oss + +import ( + "bytes" + "encoding/xml" + "hash/crc32" + "io" + "io/ioutil" + "net/http" + "os" + "strings" +) + +// CreateSelectCsvObjectMeta is Creating csv object meta +// +// key the object key. +// csvMeta the csv file meta +// options the options for create csv Meta of the object. +// +// MetaEndFrameCSV the csv file meta info +// error it's nil if no error, otherwise it's an error object. +// +func (bucket Bucket) CreateSelectCsvObjectMeta(key string, csvMeta CsvMetaRequest, options ...Option) (MetaEndFrameCSV, error) { + var endFrame MetaEndFrameCSV + params := map[string]interface{}{} + params["x-oss-process"] = "csv/meta" + + csvMeta.encodeBase64() + bs, err := xml.Marshal(csvMeta) + if err != nil { + return endFrame, err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + resp, err := bucket.DoPostSelectObject(key, params, buffer, options...) + if err != nil { + return endFrame, err + } + defer resp.Body.Close() + + _, err = ioutil.ReadAll(resp) + + return resp.Frame.MetaEndFrameCSV, err +} + +// CreateSelectJsonObjectMeta is Creating json object meta +// +// key the object key. +// csvMeta the json file meta +// options the options for create json Meta of the object. +// +// MetaEndFrameJSON the json file meta info +// error it's nil if no error, otherwise it's an error object. +// +func (bucket Bucket) CreateSelectJsonObjectMeta(key string, jsonMeta JsonMetaRequest, options ...Option) (MetaEndFrameJSON, error) { + var endFrame MetaEndFrameJSON + params := map[string]interface{}{} + params["x-oss-process"] = "json/meta" + + bs, err := xml.Marshal(jsonMeta) + if err != nil { + return endFrame, err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + + resp, err := bucket.DoPostSelectObject(key, params, buffer, options...) + if err != nil { + return endFrame, err + } + defer resp.Body.Close() + + _, err = ioutil.ReadAll(resp) + + return resp.Frame.MetaEndFrameJSON, err +} + +// SelectObject is the select object api, approve csv and json file. +// +// key the object key. +// selectReq the request data for select object +// options the options for select file of the object. +// +// o.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil. +// error it's nil if no error, otherwise it's an error object. +// +func (bucket Bucket) SelectObject(key string, selectReq SelectRequest, options ...Option) (io.ReadCloser, error) { + params := map[string]interface{}{} + if selectReq.InputSerializationSelect.JsonBodyInput.JsonIsEmpty() { + params["x-oss-process"] = "csv/select" // default select csv file + } else { + params["x-oss-process"] = "json/select" + } + selectReq.encodeBase64() + bs, err := xml.Marshal(selectReq) + if err != nil { + return nil, err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + resp, err := bucket.DoPostSelectObject(key, params, buffer, options...) + if err != nil { + return nil, err + } + if selectReq.OutputSerializationSelect.EnablePayloadCrc != nil && *selectReq.OutputSerializationSelect.EnablePayloadCrc == true { + resp.Frame.EnablePayloadCrc = true + } + resp.Frame.OutputRawData = strings.ToUpper(resp.Headers.Get("x-oss-select-output-raw")) == "TRUE" + + return resp, err +} + +// DoPostSelectObject is the SelectObject/CreateMeta api, approve csv and json file. +// +// key the object key. +// params the resource of oss approve csv/meta, json/meta, csv/select, json/select. +// buf the request data trans to buffer. +// options the options for select file of the object. +// +// SelectObjectResponse the response of select object. +// error it's nil if no error, otherwise it's an error object. +// +func (bucket Bucket) DoPostSelectObject(key string, params map[string]interface{}, buf *bytes.Buffer, options ...Option) (*SelectObjectResponse, error) { + resp, err := bucket.do("POST", key, params, options, buf, nil) + if err != nil { + return nil, err + } + + result := &SelectObjectResponse{ + Body: resp.Body, + StatusCode: resp.StatusCode, + Frame: SelectObjectResult{}, + } + result.Headers = resp.Headers + // result.Frame = SelectObjectResult{} + result.ReadTimeOut = bucket.GetConfig().Timeout + + // Progress + listener := GetProgressListener(options) + + // CRC32 + crcCalc := crc32.NewIEEE() + result.WriterForCheckCrc32 = crcCalc + result.Body = TeeReader(resp.Body, nil, 0, listener, nil) + + err = CheckRespCode(resp.StatusCode, []int{http.StatusPartialContent, http.StatusOK}) + + return result, err +} + +// SelectObjectIntoFile is the selectObject to file api +// +// key the object key. +// fileName saving file's name to localstation. +// selectReq the request data for select object +// options the options for select file of the object. +// +// error it's nil if no error, otherwise it's an error object. +// +func (bucket Bucket) SelectObjectIntoFile(key, fileName string, selectReq SelectRequest, options ...Option) error { + tempFilePath := fileName + TempFileSuffix + + params := map[string]interface{}{} + if selectReq.InputSerializationSelect.JsonBodyInput.JsonIsEmpty() { + params["x-oss-process"] = "csv/select" // default select csv file + } else { + params["x-oss-process"] = "json/select" + } + selectReq.encodeBase64() + bs, err := xml.Marshal(selectReq) + if err != nil { + return err + } + buffer := new(bytes.Buffer) + buffer.Write(bs) + resp, err := bucket.DoPostSelectObject(key, params, buffer, options...) + if err != nil { + return err + } + defer resp.Close() + + // If the local file does not exist, create a new one. If it exists, overwrite it. + fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode) + if err != nil { + return err + } + + // Copy the data to the local file path. + _, err = io.Copy(fd, resp) + fd.Close() + if err != nil { + return err + } + + return os.Rename(tempFilePath, fileName) +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go new file mode 100644 index 00000000000..75a454555d1 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/select_object_type.go @@ -0,0 +1,365 @@ +package oss + +import ( + "bytes" + "encoding/binary" + "fmt" + "hash" + "hash/crc32" + "io" + "net/http" + "time" +) + +// The adapter class for Select object's response. +// The response consists of frames. Each frame has the following format: + +// Type | Payload Length | Header Checksum | Payload | Payload Checksum + +// |<4-->| <--4 bytes------><---4 bytes-------><-n/a-----><--4 bytes---------> +// And we have three kind of frames. +// Data Frame: +// Type:8388609 +// Payload: Offset | Data +// <-8 bytes> + +// Continuous Frame +// Type:8388612 +// Payload: Offset (8-bytes) + +// End Frame +// Type:8388613 +// Payload: Offset | total scanned bytes | http status code | error message +// <-- 8bytes--><-----8 bytes--------><---4 bytes-------><---variabe---> + +// SelectObjectResponse defines HTTP response from OSS SelectObject +type SelectObjectResponse struct { + StatusCode int + Headers http.Header + Body io.ReadCloser + Frame SelectObjectResult + ReadTimeOut uint + ClientCRC32 uint32 + ServerCRC32 uint32 + WriterForCheckCrc32 hash.Hash32 + Finish bool +} + +func (sr *SelectObjectResponse) Read(p []byte) (n int, err error) { + n, err = sr.readFrames(p) + return +} + +// Close http reponse body +func (sr *SelectObjectResponse) Close() error { + return sr.Body.Close() +} + +// PostSelectResult is the request of SelectObject +type PostSelectResult struct { + Response *SelectObjectResponse +} + +// readFrames is read Frame +func (sr *SelectObjectResponse) readFrames(p []byte) (int, error) { + var nn int + var err error + var checkValid bool + if sr.Frame.OutputRawData == true { + nn, err = sr.Body.Read(p) + return nn, err + } + + if sr.Finish { + return 0, io.EOF + } + + for { + // if this Frame is Readed, then not reading Header + if sr.Frame.OpenLine != true { + err = sr.analysisHeader() + if err != nil { + return nn, err + } + } + + if sr.Frame.FrameType == DataFrameType { + n, err := sr.analysisData(p[nn:]) + if err != nil { + return nn, err + } + nn += n + + // if this Frame is readed all data, then empty the Frame to read it with next frame + if sr.Frame.ConsumedBytesLength == sr.Frame.PayloadLength-8 { + checkValid, err = sr.checkPayloadSum() + if err != nil || !checkValid { + return nn, fmt.Errorf("%s", err.Error()) + } + sr.emptyFrame() + } + + if nn == len(p) { + return nn, nil + } + } else if sr.Frame.FrameType == ContinuousFrameType { + checkValid, err = sr.checkPayloadSum() + if err != nil || !checkValid { + return nn, fmt.Errorf("%s", err.Error()) + } + sr.Frame.OpenLine = false + } else if sr.Frame.FrameType == EndFrameType { + err = sr.analysisEndFrame() + if err != nil { + return nn, err + } + checkValid, err = sr.checkPayloadSum() + if checkValid { + sr.Finish = true + } + return nn, err + } else if sr.Frame.FrameType == MetaEndFrameCSVType { + err = sr.analysisMetaEndFrameCSV() + if err != nil { + return nn, err + } + checkValid, err = sr.checkPayloadSum() + if checkValid { + sr.Finish = true + } + return nn, err + } else if sr.Frame.FrameType == MetaEndFrameJSONType { + err = sr.analysisMetaEndFrameJSON() + if err != nil { + return nn, err + } + checkValid, err = sr.checkPayloadSum() + if checkValid { + sr.Finish = true + } + return nn, err + } + } + return nn, nil +} + +type chanReadIO struct { + readLen int + err error +} + +func (sr *SelectObjectResponse) readLen(p []byte, timeOut time.Duration) (int, error) { + r := sr.Body + ch := make(chan chanReadIO, 1) + defer close(ch) + go func(p []byte) { + var needReadLength int + readChan := chanReadIO{} + needReadLength = len(p) + for { + n, err := r.Read(p[readChan.readLen:needReadLength]) + readChan.readLen += n + if err != nil { + readChan.err = err + ch <- readChan + return + } + + if readChan.readLen == needReadLength { + break + } + } + ch <- readChan + }(p) + + select { + case <-time.After(time.Second * timeOut): + return 0, fmt.Errorf("requestId: %s, readLen timeout, timeout is %d(second),need read:%d", sr.Headers.Get(HTTPHeaderOssRequestID), timeOut, len(p)) + case result := <-ch: + return result.readLen, result.err + } +} + +// analysisHeader is reading selectObject response body's header +func (sr *SelectObjectResponse) analysisHeader() error { + headFrameByte := make([]byte, 20) + _, err := sr.readLen(headFrameByte, time.Duration(sr.ReadTimeOut)) + if err != nil { + return fmt.Errorf("requestId: %s, Read response frame header failure,err:%s", sr.Headers.Get(HTTPHeaderOssRequestID), err.Error()) + } + + frameTypeByte := headFrameByte[0:4] + sr.Frame.Version = frameTypeByte[0] + frameTypeByte[0] = 0 + bytesToInt(frameTypeByte, &sr.Frame.FrameType) + + if sr.Frame.FrameType != DataFrameType && sr.Frame.FrameType != ContinuousFrameType && + sr.Frame.FrameType != EndFrameType && sr.Frame.FrameType != MetaEndFrameCSVType && sr.Frame.FrameType != MetaEndFrameJSONType { + return fmt.Errorf("requestId: %s, Unexpected frame type: %d", sr.Headers.Get(HTTPHeaderOssRequestID), sr.Frame.FrameType) + } + + payloadLengthByte := headFrameByte[4:8] + bytesToInt(payloadLengthByte, &sr.Frame.PayloadLength) + headCheckSumByte := headFrameByte[8:12] + bytesToInt(headCheckSumByte, &sr.Frame.HeaderCheckSum) + byteOffset := headFrameByte[12:20] + bytesToInt(byteOffset, &sr.Frame.Offset) + sr.Frame.OpenLine = true + + err = sr.writerCheckCrc32(byteOffset) + return err +} + +// analysisData is reading the DataFrameType data of selectObject response body +func (sr *SelectObjectResponse) analysisData(p []byte) (int, error) { + var needReadLength int32 + lenP := int32(len(p)) + restByteLength := sr.Frame.PayloadLength - 8 - sr.Frame.ConsumedBytesLength + if lenP <= restByteLength { + needReadLength = lenP + } else { + needReadLength = restByteLength + } + n, err := sr.readLen(p[:needReadLength], time.Duration(sr.ReadTimeOut)) + if err != nil { + return n, fmt.Errorf("read frame data error,%s", err.Error()) + } + sr.Frame.ConsumedBytesLength += int32(n) + err = sr.writerCheckCrc32(p[:n]) + return n, err +} + +// analysisEndFrame is reading the EndFrameType data of selectObject response body +func (sr *SelectObjectResponse) analysisEndFrame() error { + var eF EndFrame + payLoadBytes := make([]byte, sr.Frame.PayloadLength-8) + _, err := sr.readLen(payLoadBytes, time.Duration(sr.ReadTimeOut)) + if err != nil { + return fmt.Errorf("read end frame error:%s", err.Error()) + } + bytesToInt(payLoadBytes[0:8], &eF.TotalScanned) + bytesToInt(payLoadBytes[8:12], &eF.HTTPStatusCode) + errMsgLength := sr.Frame.PayloadLength - 20 + eF.ErrorMsg = string(payLoadBytes[12 : errMsgLength+12]) + sr.Frame.EndFrame.TotalScanned = eF.TotalScanned + sr.Frame.EndFrame.HTTPStatusCode = eF.HTTPStatusCode + sr.Frame.EndFrame.ErrorMsg = eF.ErrorMsg + err = sr.writerCheckCrc32(payLoadBytes) + return err +} + +// analysisMetaEndFrameCSV is reading the MetaEndFrameCSVType data of selectObject response body +func (sr *SelectObjectResponse) analysisMetaEndFrameCSV() error { + var mCF MetaEndFrameCSV + payLoadBytes := make([]byte, sr.Frame.PayloadLength-8) + _, err := sr.readLen(payLoadBytes, time.Duration(sr.ReadTimeOut)) + if err != nil { + return fmt.Errorf("read meta end csv frame error:%s", err.Error()) + } + + bytesToInt(payLoadBytes[0:8], &mCF.TotalScanned) + bytesToInt(payLoadBytes[8:12], &mCF.Status) + bytesToInt(payLoadBytes[12:16], &mCF.SplitsCount) + bytesToInt(payLoadBytes[16:24], &mCF.RowsCount) + bytesToInt(payLoadBytes[24:28], &mCF.ColumnsCount) + errMsgLength := sr.Frame.PayloadLength - 36 + mCF.ErrorMsg = string(payLoadBytes[28 : errMsgLength+28]) + sr.Frame.MetaEndFrameCSV.ErrorMsg = mCF.ErrorMsg + sr.Frame.MetaEndFrameCSV.TotalScanned = mCF.TotalScanned + sr.Frame.MetaEndFrameCSV.Status = mCF.Status + sr.Frame.MetaEndFrameCSV.SplitsCount = mCF.SplitsCount + sr.Frame.MetaEndFrameCSV.RowsCount = mCF.RowsCount + sr.Frame.MetaEndFrameCSV.ColumnsCount = mCF.ColumnsCount + err = sr.writerCheckCrc32(payLoadBytes) + return err +} + +// analysisMetaEndFrameJSON is reading the MetaEndFrameJSONType data of selectObject response body +func (sr *SelectObjectResponse) analysisMetaEndFrameJSON() error { + var mJF MetaEndFrameJSON + payLoadBytes := make([]byte, sr.Frame.PayloadLength-8) + _, err := sr.readLen(payLoadBytes, time.Duration(sr.ReadTimeOut)) + if err != nil { + return fmt.Errorf("read meta end json frame error:%s", err.Error()) + } + + bytesToInt(payLoadBytes[0:8], &mJF.TotalScanned) + bytesToInt(payLoadBytes[8:12], &mJF.Status) + bytesToInt(payLoadBytes[12:16], &mJF.SplitsCount) + bytesToInt(payLoadBytes[16:24], &mJF.RowsCount) + errMsgLength := sr.Frame.PayloadLength - 32 + mJF.ErrorMsg = string(payLoadBytes[24 : errMsgLength+24]) + sr.Frame.MetaEndFrameJSON.ErrorMsg = mJF.ErrorMsg + sr.Frame.MetaEndFrameJSON.TotalScanned = mJF.TotalScanned + sr.Frame.MetaEndFrameJSON.Status = mJF.Status + sr.Frame.MetaEndFrameJSON.SplitsCount = mJF.SplitsCount + sr.Frame.MetaEndFrameJSON.RowsCount = mJF.RowsCount + + err = sr.writerCheckCrc32(payLoadBytes) + return err +} + +func (sr *SelectObjectResponse) checkPayloadSum() (bool, error) { + payLoadChecksumByte := make([]byte, 4) + n, err := sr.readLen(payLoadChecksumByte, time.Duration(sr.ReadTimeOut)) + if n == 4 { + bytesToInt(payLoadChecksumByte, &sr.Frame.PayloadChecksum) + sr.ServerCRC32 = sr.Frame.PayloadChecksum + sr.ClientCRC32 = sr.WriterForCheckCrc32.Sum32() + if sr.Frame.EnablePayloadCrc == true && sr.ServerCRC32 != 0 && sr.ServerCRC32 != sr.ClientCRC32 { + return false, fmt.Errorf("RequestId: %s, Unexpected frame type: %d, client %d but server %d", + sr.Headers.Get(HTTPHeaderOssRequestID), sr.Frame.FrameType, sr.ClientCRC32, sr.ServerCRC32) + } + return true, err + } + return false, fmt.Errorf("RequestId:%s, read checksum error:%s", sr.Headers.Get(HTTPHeaderOssRequestID), err.Error()) +} + +func (sr *SelectObjectResponse) writerCheckCrc32(p []byte) (err error) { + err = nil + if sr.Frame.EnablePayloadCrc == true { + _, err = sr.WriterForCheckCrc32.Write(p) + } + return err +} + +// emptyFrame is emptying SelectObjectResponse Frame information +func (sr *SelectObjectResponse) emptyFrame() { + crcCalc := crc32.NewIEEE() + sr.WriterForCheckCrc32 = crcCalc + sr.Finish = false + + sr.Frame.ConsumedBytesLength = 0 + sr.Frame.OpenLine = false + sr.Frame.Version = byte(0) + sr.Frame.FrameType = 0 + sr.Frame.PayloadLength = 0 + sr.Frame.HeaderCheckSum = 0 + sr.Frame.Offset = 0 + sr.Frame.Data = "" + + sr.Frame.EndFrame.TotalScanned = 0 + sr.Frame.EndFrame.HTTPStatusCode = 0 + sr.Frame.EndFrame.ErrorMsg = "" + + sr.Frame.MetaEndFrameCSV.TotalScanned = 0 + sr.Frame.MetaEndFrameCSV.Status = 0 + sr.Frame.MetaEndFrameCSV.SplitsCount = 0 + sr.Frame.MetaEndFrameCSV.RowsCount = 0 + sr.Frame.MetaEndFrameCSV.ColumnsCount = 0 + sr.Frame.MetaEndFrameCSV.ErrorMsg = "" + + sr.Frame.MetaEndFrameJSON.TotalScanned = 0 + sr.Frame.MetaEndFrameJSON.Status = 0 + sr.Frame.MetaEndFrameJSON.SplitsCount = 0 + sr.Frame.MetaEndFrameJSON.RowsCount = 0 + sr.Frame.MetaEndFrameJSON.ErrorMsg = "" + + sr.Frame.PayloadChecksum = 0 +} + +// bytesToInt byte's array trans to int +func bytesToInt(b []byte, ret interface{}) { + binBuf := bytes.NewBuffer(b) + binary.Read(binBuf, binary.BigEndian, ret) +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go new file mode 100644 index 00000000000..08a83a00178 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go @@ -0,0 +1,42 @@ +//go:build !go1.7 +// +build !go1.7 + +package oss + +import ( + "crypto/tls" + "net" + "net/http" + "time" +) + +func newTransport(conn *Conn, config *Config) *http.Transport { + httpTimeOut := conn.config.HTTPTimeout + httpMaxConns := conn.config.HTTPMaxConns + // New Transport + transport := &http.Transport{ + Dial: func(netw, addr string) (net.Conn, error) { + d := net.Dialer{ + Timeout: httpTimeOut.ConnectTimeout, + KeepAlive: 30 * time.Second, + } + if config.LocalAddr != nil { + d.LocalAddr = config.LocalAddr + } + conn, err := d.Dial(netw, addr) + if err != nil { + return nil, err + } + return newTimeoutConn(conn, httpTimeOut.ReadWriteTimeout, httpTimeOut.LongTimeout), nil + }, + MaxIdleConnsPerHost: httpMaxConns.MaxIdleConnsPerHost, + ResponseHeaderTimeout: httpTimeOut.HeaderTimeout, + } + + if config.InsecureSkipVerify { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, + } + } + return transport +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go new file mode 100644 index 00000000000..1acb84154d7 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go @@ -0,0 +1,45 @@ +//go:build go1.7 +// +build go1.7 + +package oss + +import ( + "crypto/tls" + "net" + "net/http" + "time" +) + +func newTransport(conn *Conn, config *Config) *http.Transport { + httpTimeOut := conn.config.HTTPTimeout + httpMaxConns := conn.config.HTTPMaxConns + // New Transport + transport := &http.Transport{ + Dial: func(netw, addr string) (net.Conn, error) { + d := net.Dialer{ + Timeout: httpTimeOut.ConnectTimeout, + KeepAlive: 30 * time.Second, + } + if config.LocalAddr != nil { + d.LocalAddr = config.LocalAddr + } + conn, err := d.Dial(netw, addr) + if err != nil { + return nil, err + } + return newTimeoutConn(conn, httpTimeOut.ReadWriteTimeout, httpTimeOut.LongTimeout), nil + }, + MaxIdleConns: httpMaxConns.MaxIdleConns, + MaxIdleConnsPerHost: httpMaxConns.MaxIdleConnsPerHost, + MaxConnsPerHost: httpMaxConns.MaxConnsPerHost, + IdleConnTimeout: httpTimeOut.IdleConnTimeout, + ResponseHeaderTimeout: httpTimeOut.HeaderTimeout, + } + + if config.InsecureSkipVerify { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, + } + } + return transport +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go new file mode 100644 index 00000000000..a704e3ceff8 --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go @@ -0,0 +1,1695 @@ +package oss + +import ( + "encoding/base64" + "encoding/xml" + "fmt" + "net/url" + "strconv" + "strings" + "time" +) + +// ListBucketsResult defines the result object from ListBuckets request +type ListBucketsResult struct { + XMLName xml.Name `xml:"ListAllMyBucketsResult"` + Prefix string `xml:"Prefix"` // The prefix in this query + Marker string `xml:"Marker"` // The marker filter + MaxKeys int `xml:"MaxKeys"` // The max entry count to return. This information is returned when IsTruncated is true. + IsTruncated bool `xml:"IsTruncated"` // Flag true means there's remaining buckets to return. + NextMarker string `xml:"NextMarker"` // The marker filter for the next list call + Owner Owner `xml:"Owner"` // The owner information + Buckets []BucketProperties `xml:"Buckets>Bucket"` // The bucket list +} + +// BucketProperties defines bucket properties +type BucketProperties struct { + XMLName xml.Name `xml:"Bucket"` + Name string `xml:"Name"` // Bucket name + Location string `xml:"Location"` // Bucket datacenter + CreationDate time.Time `xml:"CreationDate"` // Bucket create time + StorageClass string `xml:"StorageClass"` // Bucket storage class + Region string `xml:"Region"` // Bucket region +} + +// ListCloudBoxResult defines the result object from ListBuckets request +type ListCloudBoxResult struct { + XMLName xml.Name `xml:"ListCloudBoxResult"` + Prefix string `xml:"Prefix"` // The prefix in this query + Marker string `xml:"Marker"` // The marker filter + MaxKeys int `xml:"MaxKeys"` // The max entry count to return. This information is returned when IsTruncated is true. + IsTruncated bool `xml:"IsTruncated"` // Flag true means there's remaining cloudboxes to return. + NextMarker string `xml:"NextMarker"` // The marker filter for the next list call + Owner string `xml:"Owner>DisplayName"` // The owner information + CloudBoxes []CloudBoxProperties `xml:"CloudBoxes>CloudBox"` // The cloudbox list +} + +// CloudBoxProperties defines cloudbox properties +type CloudBoxProperties struct { + XMLName xml.Name `xml:"CloudBox"` + ID string `xml:"ID"` + Name string `xml:"Name"` + Region string `xml:"Region"` + ControlEndpoint string `xml:"ControlEndpoint"` + DataEndpoint string `xml:"DataEndpoint"` +} + +// GetBucketACLResult defines GetBucketACL request's result +type GetBucketACLResult struct { + XMLName xml.Name `xml:"AccessControlPolicy"` + ACL string `xml:"AccessControlList>Grant"` // Bucket ACL + Owner Owner `xml:"Owner"` // Bucket owner +} + +// LifecycleConfiguration is the Bucket Lifecycle configuration +type LifecycleConfiguration struct { + XMLName xml.Name `xml:"LifecycleConfiguration"` + Rules []LifecycleRule `xml:"Rule"` +} + +// LifecycleRule defines Lifecycle rules +type LifecycleRule struct { + XMLName xml.Name `xml:"Rule"` + ID string `xml:"ID,omitempty"` // The rule ID + Prefix string `xml:"Prefix"` // The object key prefix + Status string `xml:"Status"` // The rule status (enabled or not) + Tags []Tag `xml:"Tag,omitempty"` // the tags property + Expiration *LifecycleExpiration `xml:"Expiration,omitempty"` // The expiration property + Transitions []LifecycleTransition `xml:"Transition,omitempty"` // The transition property + AbortMultipartUpload *LifecycleAbortMultipartUpload `xml:"AbortMultipartUpload,omitempty"` // The AbortMultipartUpload property + NonVersionExpiration *LifecycleVersionExpiration `xml:"NoncurrentVersionExpiration,omitempty"` + // Deprecated: Use NonVersionTransitions instead. + NonVersionTransition *LifecycleVersionTransition `xml:"-"` // NonVersionTransition is not suggested to use + NonVersionTransitions []LifecycleVersionTransition `xml:"NoncurrentVersionTransition,omitempty"` + Filter *LifecycleFilter `xml:Filter,omitempty` //condition parameter container of this exclusion rule +} + +// LifecycleExpiration defines the rule's expiration property +type LifecycleExpiration struct { + XMLName xml.Name `xml:"Expiration"` + Days int `xml:"Days,omitempty"` // Relative expiration time: The expiration time in days after the last modified time + Date string `xml:"Date,omitempty"` // Absolute expiration time: The expiration time in date, not recommended + CreatedBeforeDate string `xml:"CreatedBeforeDate,omitempty"` // objects created before the date will be expired + ExpiredObjectDeleteMarker *bool `xml:"ExpiredObjectDeleteMarker,omitempty"` // Specifies whether the expired delete tag is automatically deleted +} + +// LifecycleTransition defines the rule's transition propery +type LifecycleTransition struct { + XMLName xml.Name `xml:"Transition"` + Days int `xml:"Days,omitempty"` // Relative transition time: The transition time in days after the last modified time + CreatedBeforeDate string `xml:"CreatedBeforeDate,omitempty"` // objects created before the date will be expired + StorageClass StorageClassType `xml:"StorageClass,omitempty"` // Specifies the target storage type + IsAccessTime *bool `xml:"IsAccessTime,omitempty"` // access time + ReturnToStdWhenVisit *bool `xml:"ReturnToStdWhenVisit,omitempty"` // Return To Std When Visit + AllowSmallFile *bool `xml:AllowSmallFile,omitempty` +} + +// LifecycleAbortMultipartUpload defines the rule's abort multipart upload propery +type LifecycleAbortMultipartUpload struct { + XMLName xml.Name `xml:"AbortMultipartUpload"` + Days int `xml:"Days,omitempty"` // Relative expiration time: The expiration time in days after the last modified time + CreatedBeforeDate string `xml:"CreatedBeforeDate,omitempty"` // objects created before the date will be expired +} + +// LifecycleVersionExpiration defines the rule's NoncurrentVersionExpiration propery +type LifecycleVersionExpiration struct { + XMLName xml.Name `xml:"NoncurrentVersionExpiration"` + NoncurrentDays int `xml:"NoncurrentDays,omitempty"` // How many days after the Object becomes a non-current version +} + +// LifecycleVersionTransition defines the rule's NoncurrentVersionTransition propery +type LifecycleVersionTransition struct { + XMLName xml.Name `xml:"NoncurrentVersionTransition"` + NoncurrentDays int `xml:"NoncurrentDays,omitempty"` // How many days after the Object becomes a non-current version + StorageClass StorageClassType `xml:"StorageClass,omitempty"` + IsAccessTime *bool `xml:"IsAccessTime,omitempty"` // access time + ReturnToStdWhenVisit *bool `xml:"ReturnToStdWhenVisit,omitempty"` // Return To Std When Visit + AllowSmallFile *bool `xml:AllowSmallFile,omitempty` +} + +// LifecycleFilter defines the rule's Filter propery +type LifecycleFilter struct { + XMLName xml.Name `xml:"Filter"` + Not []LifecycleFilterNot `xml:"Not,omitempty"` + ObjectSizeGreaterThan *int64 `xml:"ObjectSizeGreaterThan,omitempty"` + ObjectSizeLessThan *int64 `xml:"ObjectSizeLessThan,omitempty"` +} + +// LifecycleFilterNot defines the rule's Filter Not propery +type LifecycleFilterNot struct { + XMLName xml.Name `xml:"Not"` + Prefix string `xml:"Prefix"` //Object prefix applicable to this exclusion rule + Tag *Tag `xml:"Tag,omitempty"` //the tags applicable to this exclusion rule +} + +const iso8601DateFormat = "2006-01-02T15:04:05.000Z" +const iso8601DateFormatSecond = "2006-01-02T15:04:05Z" + +// BuildLifecycleRuleByDays builds a lifecycle rule objects will expiration in days after the last modified time +func BuildLifecycleRuleByDays(id, prefix string, status bool, days int) LifecycleRule { + var statusStr = "Enabled" + if !status { + statusStr = "Disabled" + } + return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr, + Expiration: &LifecycleExpiration{Days: days}} +} + +// BuildLifecycleRuleByDate builds a lifecycle rule objects will expiration in specified date +func BuildLifecycleRuleByDate(id, prefix string, status bool, year, month, day int) LifecycleRule { + var statusStr = "Enabled" + if !status { + statusStr = "Disabled" + } + date := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC).Format(iso8601DateFormat) + return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr, + Expiration: &LifecycleExpiration{Date: date}} +} + +// ValidateLifecycleRule Determine if a lifecycle rule is valid, if it is invalid, it will return an error. +func verifyLifecycleRules(rules []LifecycleRule) error { + if len(rules) == 0 { + return fmt.Errorf("invalid rules, the length of rules is zero") + } + for k, rule := range rules { + if rule.Status != "Enabled" && rule.Status != "Disabled" { + return fmt.Errorf("invalid rule, the value of status must be Enabled or Disabled") + } + + abortMPU := rule.AbortMultipartUpload + if abortMPU != nil { + if (abortMPU.Days != 0 && abortMPU.CreatedBeforeDate != "") || (abortMPU.Days == 0 && abortMPU.CreatedBeforeDate == "") { + return fmt.Errorf("invalid abort multipart upload lifecycle, must be set one of CreatedBeforeDate and Days") + } + } + + transitions := rule.Transitions + if len(transitions) > 0 { + for _, transition := range transitions { + if (transition.Days != 0 && transition.CreatedBeforeDate != "") || (transition.Days == 0 && transition.CreatedBeforeDate == "") { + return fmt.Errorf("invalid transition lifecycle, must be set one of CreatedBeforeDate and Days") + } + } + } + + // NonVersionTransition is not suggested to use + // to keep compatible + if rule.NonVersionTransition != nil && len(rule.NonVersionTransitions) > 0 { + return fmt.Errorf("NonVersionTransition and NonVersionTransitions cannot both have values") + } else if rule.NonVersionTransition != nil { + rules[k].NonVersionTransitions = append(rules[k].NonVersionTransitions, *rule.NonVersionTransition) + } + } + + return nil +} + +// GetBucketLifecycleResult defines GetBucketLifecycle's result object +type GetBucketLifecycleResult LifecycleConfiguration + +// RefererXML defines Referer configuration +type RefererXML struct { + XMLName xml.Name `xml:"RefererConfiguration"` + AllowEmptyReferer bool `xml:"AllowEmptyReferer"` // Allow empty referrer + AllowTruncateQueryString *bool `xml:"AllowTruncateQueryString,omitempty"` + RefererList []string `xml:"RefererList>Referer"` // Referer whitelist + RefererBlacklist *RefererBlacklist `xml:"RefererBlacklist,omitempty"` // Referer blacklist +} + +// GetBucketRefererResult defines result object for GetBucketReferer request +type GetBucketRefererResult RefererXML + +type RefererBlacklist struct { + Referer []string `xml:"Referer,omitempty"` +} + +// LoggingXML defines logging configuration +type LoggingXML struct { + XMLName xml.Name `xml:"BucketLoggingStatus"` + LoggingEnabled LoggingEnabled `xml:"LoggingEnabled"` // The logging configuration information +} + +type loggingXMLEmpty struct { + XMLName xml.Name `xml:"BucketLoggingStatus"` +} + +// LoggingEnabled defines the logging configuration information +type LoggingEnabled struct { + XMLName xml.Name `xml:"LoggingEnabled"` + TargetBucket string `xml:"TargetBucket"` // The bucket name for storing the log files + TargetPrefix string `xml:"TargetPrefix"` // The log file prefix +} + +// GetBucketLoggingResult defines the result from GetBucketLogging request +type GetBucketLoggingResult LoggingXML + +// WebsiteXML defines Website configuration +type WebsiteXML struct { + XMLName xml.Name `xml:"WebsiteConfiguration"` + IndexDocument IndexDocument `xml:"IndexDocument,omitempty"` // The index page + ErrorDocument ErrorDocument `xml:"ErrorDocument,omitempty"` // The error page + RoutingRules []RoutingRule `xml:"RoutingRules>RoutingRule,omitempty"` // The routing Rule list +} + +// IndexDocument defines the index page info +type IndexDocument struct { + XMLName xml.Name `xml:"IndexDocument"` + Suffix string `xml:"Suffix"` // The file name for the index page +} + +// ErrorDocument defines the 404 error page info +type ErrorDocument struct { + XMLName xml.Name `xml:"ErrorDocument"` + Key string `xml:"Key"` // 404 error file name +} + +// RoutingRule defines the routing rules +type RoutingRule struct { + XMLName xml.Name `xml:"RoutingRule"` + RuleNumber int `xml:"RuleNumber,omitempty"` // The routing number + Condition Condition `xml:"Condition,omitempty"` // The routing condition + Redirect Redirect `xml:"Redirect,omitempty"` // The routing redirect + +} + +// Condition defines codition in the RoutingRule +type Condition struct { + XMLName xml.Name `xml:"Condition"` + KeyPrefixEquals string `xml:"KeyPrefixEquals,omitempty"` // Matching objcet prefix + HTTPErrorCodeReturnedEquals int `xml:"HttpErrorCodeReturnedEquals,omitempty"` // The rule is for Accessing to the specified object + IncludeHeader []IncludeHeader `xml:"IncludeHeader"` // The rule is for request which include header +} + +// IncludeHeader defines includeHeader in the RoutingRule's Condition +type IncludeHeader struct { + XMLName xml.Name `xml:"IncludeHeader"` + Key string `xml:"Key,omitempty"` // The Include header key + Equals string `xml:"Equals,omitempty"` // The Include header value +} + +// Redirect defines redirect in the RoutingRule +type Redirect struct { + XMLName xml.Name `xml:"Redirect"` + RedirectType string `xml:"RedirectType,omitempty"` // The redirect type, it have Mirror,External,Internal,AliCDN + PassQueryString *bool `xml:"PassQueryString"` // Whether to send the specified request's parameters, true or false + MirrorURL string `xml:"MirrorURL,omitempty"` // Mirror of the website address back to the source. + MirrorPassQueryString *bool `xml:"MirrorPassQueryString"` // To Mirror of the website Whether to send the specified request's parameters, true or false + MirrorFollowRedirect *bool `xml:"MirrorFollowRedirect"` // Redirect the location, if the mirror return 3XX + MirrorCheckMd5 *bool `xml:"MirrorCheckMd5"` // Check the mirror is MD5. + MirrorHeaders MirrorHeaders `xml:"MirrorHeaders,omitempty"` // Mirror headers + Protocol string `xml:"Protocol,omitempty"` // The redirect Protocol + HostName string `xml:"HostName,omitempty"` // The redirect HostName + ReplaceKeyPrefixWith string `xml:"ReplaceKeyPrefixWith,omitempty"` // object name'Prefix replace the value + HttpRedirectCode int `xml:"HttpRedirectCode,omitempty"` // THe redirect http code + ReplaceKeyWith string `xml:"ReplaceKeyWith,omitempty"` // object name replace the value +} + +// MirrorHeaders defines MirrorHeaders in the Redirect +type MirrorHeaders struct { + XMLName xml.Name `xml:"MirrorHeaders"` + PassAll *bool `xml:"PassAll"` // Penetrating all of headers to source website. + Pass []string `xml:"Pass"` // Penetrating some of headers to source website. + Remove []string `xml:"Remove"` // Prohibit passthrough some of headers to source website + Set []MirrorHeaderSet `xml:"Set"` // Setting some of headers send to source website +} + +// MirrorHeaderSet defines Set for Redirect's MirrorHeaders +type MirrorHeaderSet struct { + XMLName xml.Name `xml:"Set"` + Key string `xml:"Key,omitempty"` // The mirror header key + Value string `xml:"Value,omitempty"` // The mirror header value +} + +// GetBucketWebsiteResult defines the result from GetBucketWebsite request. +type GetBucketWebsiteResult WebsiteXML + +// CORSXML defines CORS configuration +type CORSXML struct { + XMLName xml.Name `xml:"CORSConfiguration"` + CORSRules []CORSRule `xml:"CORSRule"` // CORS rules + ResponseVary *bool `xml:"ResponseVary,omitempty"` // return Vary or not +} + +// CORSRule defines CORS rules +type CORSRule struct { + XMLName xml.Name `xml:"CORSRule"` + AllowedOrigin []string `xml:"AllowedOrigin"` // Allowed origins. By default it's wildcard '*' + AllowedMethod []string `xml:"AllowedMethod"` // Allowed methods + AllowedHeader []string `xml:"AllowedHeader"` // Allowed headers + ExposeHeader []string `xml:"ExposeHeader"` // Allowed response headers + MaxAgeSeconds int `xml:"MaxAgeSeconds"` // Max cache ages in seconds +} + +// GetBucketCORSResult defines the result from GetBucketCORS request. +type GetBucketCORSResult CORSXML + +// PutBucketCORS defines the PutBucketCORS config xml. +type PutBucketCORS CORSXML + +// GetBucketInfoResult defines the result from GetBucketInfo request. +type GetBucketInfoResult struct { + XMLName xml.Name `xml:"BucketInfo"` + BucketInfo BucketInfo `xml:"Bucket"` +} + +// BucketInfo defines Bucket information +type BucketInfo struct { + XMLName xml.Name `xml:"Bucket"` + Name string `xml:"Name"` // Bucket name + AccessMonitor string `xml:"AccessMonitor"` // Bucket Access Monitor + Location string `xml:"Location"` // Bucket datacenter + CreationDate time.Time `xml:"CreationDate"` // Bucket creation time + ExtranetEndpoint string `xml:"ExtranetEndpoint"` // Bucket external endpoint + IntranetEndpoint string `xml:"IntranetEndpoint"` // Bucket internal endpoint + ACL string `xml:"AccessControlList>Grant"` // Bucket ACL + RedundancyType string `xml:"DataRedundancyType"` // Bucket DataRedundancyType + Owner Owner `xml:"Owner"` // Bucket owner + StorageClass string `xml:"StorageClass"` // Bucket storage class + SseRule SSERule `xml:"ServerSideEncryptionRule"` // Bucket ServerSideEncryptionRule + Versioning string `xml:"Versioning"` // Bucket Versioning + TransferAcceleration string `xml:"TransferAcceleration"` // bucket TransferAcceleration + CrossRegionReplication string `xml:"CrossRegionReplication"` // bucket CrossRegionReplication +} + +type SSERule struct { + XMLName xml.Name `xml:"ServerSideEncryptionRule"` // Bucket ServerSideEncryptionRule + KMSMasterKeyID string `xml:"KMSMasterKeyID,omitempty"` // Bucket KMSMasterKeyID + SSEAlgorithm string `xml:"SSEAlgorithm,omitempty"` // Bucket SSEAlgorithm + KMSDataEncryption string `xml:"KMSDataEncryption,omitempty"` //Bucket KMSDataEncryption +} + +// ListObjectsResult defines the result from ListObjects request +type ListObjectsResult struct { + XMLName xml.Name `xml:"ListBucketResult"` + Prefix string `xml:"Prefix"` // The object prefix + Marker string `xml:"Marker"` // The marker filter. + MaxKeys int `xml:"MaxKeys"` // Max keys to return + Delimiter string `xml:"Delimiter"` // The delimiter for grouping objects' name + IsTruncated bool `xml:"IsTruncated"` // Flag indicates if all results are returned (when it's false) + NextMarker string `xml:"NextMarker"` // The start point of the next query + Objects []ObjectProperties `xml:"Contents"` // Object list + CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` // You can think of commonprefixes as "folders" whose names end with the delimiter +} + +// ObjectProperties defines Objecct properties +type ObjectProperties struct { + XMLName xml.Name `xml:"Contents"` + Key string `xml:"Key"` // Object key + Type string `xml:"Type"` // Object type + Size int64 `xml:"Size"` // Object size + ETag string `xml:"ETag"` // Object ETag + Owner Owner `xml:"Owner"` // Object owner information + LastModified time.Time `xml:"LastModified"` // Object last modified time + StorageClass string `xml:"StorageClass"` // Object storage class (Standard, IA, Archive) + RestoreInfo string `xml:"RestoreInfo,omitempty"` // Object restoreInfo +} + +// ListObjectsResultV2 defines the result from ListObjectsV2 request +type ListObjectsResultV2 struct { + XMLName xml.Name `xml:"ListBucketResult"` + Prefix string `xml:"Prefix"` // The object prefix + StartAfter string `xml:"StartAfter"` // the input StartAfter + ContinuationToken string `xml:"ContinuationToken"` // the input ContinuationToken + MaxKeys int `xml:"MaxKeys"` // Max keys to return + Delimiter string `xml:"Delimiter"` // The delimiter for grouping objects' name + IsTruncated bool `xml:"IsTruncated"` // Flag indicates if all results are returned (when it's false) + NextContinuationToken string `xml:"NextContinuationToken"` // The start point of the next NextContinuationToken + Objects []ObjectProperties `xml:"Contents"` // Object list + CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` // You can think of commonprefixes as "folders" whose names end with the delimiter +} + +// ListObjectVersionsResult defines the result from ListObjectVersions request +type ListObjectVersionsResult struct { + XMLName xml.Name `xml:"ListVersionsResult"` + Name string `xml:"Name"` // The Bucket Name + Owner Owner `xml:"Owner"` // The owner of bucket + Prefix string `xml:"Prefix"` // The object prefix + KeyMarker string `xml:"KeyMarker"` // The start marker filter. + VersionIdMarker string `xml:"VersionIdMarker"` // The start VersionIdMarker filter. + MaxKeys int `xml:"MaxKeys"` // Max keys to return + Delimiter string `xml:"Delimiter"` // The delimiter for grouping objects' name + IsTruncated bool `xml:"IsTruncated"` // Flag indicates if all results are returned (when it's false) + NextKeyMarker string `xml:"NextKeyMarker"` // The start point of the next query + NextVersionIdMarker string `xml:"NextVersionIdMarker"` // The start point of the next query + CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` // You can think of commonprefixes as "folders" whose names end with the delimiter + ObjectDeleteMarkers []ObjectDeleteMarkerProperties `xml:"DeleteMarker"` // DeleteMarker list + ObjectVersions []ObjectVersionProperties `xml:"Version"` // version list +} + +type ObjectDeleteMarkerProperties struct { + XMLName xml.Name `xml:"DeleteMarker"` + Key string `xml:"Key"` // The Object Key + VersionId string `xml:"VersionId"` // The Object VersionId + IsLatest bool `xml:"IsLatest"` // is current version or not + LastModified time.Time `xml:"LastModified"` // Object last modified time + Owner Owner `xml:"Owner"` // bucket owner element +} + +type ObjectVersionProperties struct { + XMLName xml.Name `xml:"Version"` + Key string `xml:"Key"` // The Object Key + VersionId string `xml:"VersionId"` // The Object VersionId + IsLatest bool `xml:"IsLatest"` // is latest version or not + LastModified time.Time `xml:"LastModified"` // Object last modified time + Type string `xml:"Type"` // Object type + Size int64 `xml:"Size"` // Object size + ETag string `xml:"ETag"` // Object ETag + StorageClass string `xml:"StorageClass"` // Object storage class (Standard, IA, Archive) + Owner Owner `xml:"Owner"` // bucket owner element + RestoreInfo string `xml:"RestoreInfo,omitempty"` // Object restoreInfo +} + +// Owner defines Bucket/Object's owner +type Owner struct { + XMLName xml.Name `xml:"Owner"` + ID string `xml:"ID"` // Owner ID + DisplayName string `xml:"DisplayName"` // Owner's display name +} + +// CopyObjectResult defines result object of CopyObject +type CopyObjectResult struct { + XMLName xml.Name `xml:"CopyObjectResult"` + LastModified time.Time `xml:"LastModified"` // New object's last modified time. + ETag string `xml:"ETag"` // New object's ETag +} + +// GetObjectACLResult defines result of GetObjectACL request +type GetObjectACLResult GetBucketACLResult + +type deleteXML struct { + XMLName xml.Name `xml:"Delete"` + Objects []DeleteObject `xml:"Object"` // Objects to delete + Quiet bool `xml:"Quiet"` // Flag of quiet mode. +} + +// DeleteObject defines the struct for deleting object +type DeleteObject struct { + XMLName xml.Name `xml:"Object"` + Key string `xml:"Key"` // Object name + VersionId string `xml:"VersionId,omitempty"` // Object VersionId +} + +// DeleteObjectsResult defines result of DeleteObjects request +type DeleteObjectsResult struct { + XMLName xml.Name + DeletedObjects []string // Deleted object key list +} + +// DeleteObjectVersionsResult defines result of DeleteObjects request +type DeleteObjectVersionsResult struct { + XMLName xml.Name `xml:"DeleteResult"` + DeletedObjectsDetail []DeletedKeyInfo `xml:"Deleted"` // Deleted object detail info +} + +// DeletedKeyInfo defines object delete info +type DeletedKeyInfo struct { + XMLName xml.Name `xml:"Deleted"` + Key string `xml:"Key"` // Object key + VersionId string `xml:"VersionId"` // VersionId + DeleteMarker bool `xml:"DeleteMarker"` // Object DeleteMarker + DeleteMarkerVersionId string `xml:"DeleteMarkerVersionId"` // Object DeleteMarkerVersionId +} + +// InitiateMultipartUploadResult defines result of InitiateMultipartUpload request +type InitiateMultipartUploadResult struct { + XMLName xml.Name `xml:"InitiateMultipartUploadResult"` + Bucket string `xml:"Bucket"` // Bucket name + Key string `xml:"Key"` // Object name to upload + UploadID string `xml:"UploadId"` // Generated UploadId +} + +// UploadPart defines the upload/copy part +type UploadPart struct { + XMLName xml.Name `xml:"Part"` + PartNumber int `xml:"PartNumber"` // Part number + ETag string `xml:"ETag"` // ETag value of the part's data +} + +type UploadParts []UploadPart + +func (slice UploadParts) Len() int { + return len(slice) +} + +func (slice UploadParts) Less(i, j int) bool { + return slice[i].PartNumber < slice[j].PartNumber +} + +func (slice UploadParts) Swap(i, j int) { + slice[i], slice[j] = slice[j], slice[i] +} + +// UploadPartCopyResult defines result object of multipart copy request. +type UploadPartCopyResult struct { + XMLName xml.Name `xml:"CopyPartResult"` + LastModified time.Time `xml:"LastModified"` // Last modified time + ETag string `xml:"ETag"` // ETag +} + +type completeMultipartUploadXML struct { + XMLName xml.Name `xml:"CompleteMultipartUpload"` + Part []UploadPart `xml:"Part"` +} + +// CompleteMultipartUploadResult defines result object of CompleteMultipartUploadRequest +type CompleteMultipartUploadResult struct { + XMLName xml.Name `xml:"CompleteMultipartUploadResult"` + Location string `xml:"Location"` // Object URL + Bucket string `xml:"Bucket"` // Bucket name + ETag string `xml:"ETag"` // Object ETag + Key string `xml:"Key"` // Object name +} + +// ListUploadedPartsResult defines result object of ListUploadedParts +type ListUploadedPartsResult struct { + XMLName xml.Name `xml:"ListPartsResult"` + Bucket string `xml:"Bucket"` // Bucket name + Key string `xml:"Key"` // Object name + UploadID string `xml:"UploadId"` // Upload ID + NextPartNumberMarker string `xml:"NextPartNumberMarker"` // Next part number + MaxParts int `xml:"MaxParts"` // Max parts count + IsTruncated bool `xml:"IsTruncated"` // Flag indicates all entries returned.false: all entries returned. + UploadedParts []UploadedPart `xml:"Part"` // Uploaded parts +} + +// UploadedPart defines uploaded part +type UploadedPart struct { + XMLName xml.Name `xml:"Part"` + PartNumber int `xml:"PartNumber"` // Part number + LastModified time.Time `xml:"LastModified"` // Last modified time + ETag string `xml:"ETag"` // ETag cache + Size int `xml:"Size"` // Part size +} + +// ListMultipartUploadResult defines result object of ListMultipartUpload +type ListMultipartUploadResult struct { + XMLName xml.Name `xml:"ListMultipartUploadsResult"` + Bucket string `xml:"Bucket"` // Bucket name + Delimiter string `xml:"Delimiter"` // Delimiter for grouping object. + Prefix string `xml:"Prefix"` // Object prefix + KeyMarker string `xml:"KeyMarker"` // Object key marker + UploadIDMarker string `xml:"UploadIdMarker"` // UploadId marker + NextKeyMarker string `xml:"NextKeyMarker"` // Next key marker, if not all entries returned. + NextUploadIDMarker string `xml:"NextUploadIdMarker"` // Next uploadId marker, if not all entries returned. + MaxUploads int `xml:"MaxUploads"` // Max uploads to return + IsTruncated bool `xml:"IsTruncated"` // Flag indicates all entries are returned. + Uploads []UncompletedUpload `xml:"Upload"` // Ongoing uploads (not completed, not aborted) + CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` // Common prefixes list. +} + +// UncompletedUpload structure wraps an uncompleted upload task +type UncompletedUpload struct { + XMLName xml.Name `xml:"Upload"` + Key string `xml:"Key"` // Object name + UploadID string `xml:"UploadId"` // The UploadId + Initiated time.Time `xml:"Initiated"` // Initialization time in the format such as 2012-02-23T04:18:23.000Z +} + +// ProcessObjectResult defines result object of ProcessObject +type ProcessObjectResult struct { + Bucket string `json:"bucket"` + FileSize int `json:"fileSize"` + Object string `json:"object"` + Status string `json:"status"` +} + +// AsyncProcessObjectResult defines result object of AsyncProcessObject +type AsyncProcessObjectResult struct { + EventId string `json:"EventId"` + RequestId string `json:"RequestId"` + TaskId string `json:"TaskId"` +} + +// decodeDeleteObjectsResult decodes deleting objects result in URL encoding +func decodeDeleteObjectsResult(result *DeleteObjectVersionsResult) error { + var err error + for i := 0; i < len(result.DeletedObjectsDetail); i++ { + result.DeletedObjectsDetail[i].Key, err = url.QueryUnescape(result.DeletedObjectsDetail[i].Key) + if err != nil { + return err + } + } + return nil +} + +// decodeListObjectsResult decodes list objects result in URL encoding +func decodeListObjectsResult(result *ListObjectsResult) error { + var err error + result.Prefix, err = url.QueryUnescape(result.Prefix) + if err != nil { + return err + } + result.Marker, err = url.QueryUnescape(result.Marker) + if err != nil { + return err + } + result.Delimiter, err = url.QueryUnescape(result.Delimiter) + if err != nil { + return err + } + result.NextMarker, err = url.QueryUnescape(result.NextMarker) + if err != nil { + return err + } + for i := 0; i < len(result.Objects); i++ { + result.Objects[i].Key, err = url.QueryUnescape(result.Objects[i].Key) + if err != nil { + return err + } + } + for i := 0; i < len(result.CommonPrefixes); i++ { + result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i]) + if err != nil { + return err + } + } + return nil +} + +// decodeListObjectsResult decodes list objects result in URL encoding +func decodeListObjectsResultV2(result *ListObjectsResultV2) error { + var err error + result.Prefix, err = url.QueryUnescape(result.Prefix) + if err != nil { + return err + } + result.StartAfter, err = url.QueryUnescape(result.StartAfter) + if err != nil { + return err + } + result.Delimiter, err = url.QueryUnescape(result.Delimiter) + if err != nil { + return err + } + result.NextContinuationToken, err = url.QueryUnescape(result.NextContinuationToken) + if err != nil { + return err + } + for i := 0; i < len(result.Objects); i++ { + result.Objects[i].Key, err = url.QueryUnescape(result.Objects[i].Key) + if err != nil { + return err + } + } + for i := 0; i < len(result.CommonPrefixes); i++ { + result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i]) + if err != nil { + return err + } + } + return nil +} + +// decodeListObjectVersionsResult decodes list version objects result in URL encoding +func decodeListObjectVersionsResult(result *ListObjectVersionsResult) error { + var err error + + // decode:Delimiter + result.Delimiter, err = url.QueryUnescape(result.Delimiter) + if err != nil { + return err + } + + // decode Prefix + result.Prefix, err = url.QueryUnescape(result.Prefix) + if err != nil { + return err + } + + // decode KeyMarker + result.KeyMarker, err = url.QueryUnescape(result.KeyMarker) + if err != nil { + return err + } + + // decode VersionIdMarker + result.VersionIdMarker, err = url.QueryUnescape(result.VersionIdMarker) + if err != nil { + return err + } + + // decode NextKeyMarker + result.NextKeyMarker, err = url.QueryUnescape(result.NextKeyMarker) + if err != nil { + return err + } + + // decode NextVersionIdMarker + result.NextVersionIdMarker, err = url.QueryUnescape(result.NextVersionIdMarker) + if err != nil { + return err + } + + // decode CommonPrefixes + for i := 0; i < len(result.CommonPrefixes); i++ { + result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i]) + if err != nil { + return err + } + } + + // decode deleteMarker + for i := 0; i < len(result.ObjectDeleteMarkers); i++ { + result.ObjectDeleteMarkers[i].Key, err = url.QueryUnescape(result.ObjectDeleteMarkers[i].Key) + if err != nil { + return err + } + } + + // decode ObjectVersions + for i := 0; i < len(result.ObjectVersions); i++ { + result.ObjectVersions[i].Key, err = url.QueryUnescape(result.ObjectVersions[i].Key) + if err != nil { + return err + } + } + + return nil +} + +// decodeListUploadedPartsResult decodes +func decodeListUploadedPartsResult(result *ListUploadedPartsResult) error { + var err error + result.Key, err = url.QueryUnescape(result.Key) + if err != nil { + return err + } + return nil +} + +// decodeListMultipartUploadResult decodes list multipart upload result in URL encoding +func decodeListMultipartUploadResult(result *ListMultipartUploadResult) error { + var err error + result.Prefix, err = url.QueryUnescape(result.Prefix) + if err != nil { + return err + } + result.Delimiter, err = url.QueryUnescape(result.Delimiter) + if err != nil { + return err + } + result.KeyMarker, err = url.QueryUnescape(result.KeyMarker) + if err != nil { + return err + } + result.NextKeyMarker, err = url.QueryUnescape(result.NextKeyMarker) + if err != nil { + return err + } + for i := 0; i < len(result.Uploads); i++ { + result.Uploads[i].Key, err = url.QueryUnescape(result.Uploads[i].Key) + if err != nil { + return err + } + } + for i := 0; i < len(result.CommonPrefixes); i++ { + result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i]) + if err != nil { + return err + } + } + return nil +} + +// marshalDeleteObjectToXml deleteXML struct to xml +func marshalDeleteObjectToXml(dxml deleteXML) string { + var builder strings.Builder + builder.WriteString("") + builder.WriteString("") + builder.WriteString(strconv.FormatBool(dxml.Quiet)) + builder.WriteString("") + if len(dxml.Objects) > 0 { + for _, object := range dxml.Objects { + builder.WriteString("") + if object.Key != "" { + builder.WriteString("") + builder.WriteString(EscapeXml(object.Key)) + builder.WriteString("") + } + if object.VersionId != "" { + builder.WriteString("") + builder.WriteString(object.VersionId) + builder.WriteString("") + } + builder.WriteString("") + } + } + builder.WriteString("") + return builder.String() +} + +// createBucketConfiguration defines the configuration for creating a bucket. +type createBucketConfiguration struct { + XMLName xml.Name `xml:"CreateBucketConfiguration"` + StorageClass StorageClassType `xml:"StorageClass,omitempty"` + DataRedundancyType DataRedundancyType `xml:"DataRedundancyType,omitempty"` + ObjectHashFunction ObjecthashFuncType `xml:"ObjectHashFunction,omitempty"` +} + +// LiveChannelConfiguration defines the configuration for live-channel +type LiveChannelConfiguration struct { + XMLName xml.Name `xml:"LiveChannelConfiguration"` + Description string `xml:"Description,omitempty"` //Description of live-channel, up to 128 bytes + Status string `xml:"Status,omitempty"` //Specify the status of livechannel + Target LiveChannelTarget `xml:"Target"` //target configuration of live-channel + // use point instead of struct to avoid omit empty snapshot + Snapshot *LiveChannelSnapshot `xml:"Snapshot,omitempty"` //snapshot configuration of live-channel +} + +// LiveChannelTarget target configuration of live-channel +type LiveChannelTarget struct { + XMLName xml.Name `xml:"Target"` + Type string `xml:"Type"` //the type of object, only supports HLS + FragDuration int `xml:"FragDuration,omitempty"` //the length of each ts object (in seconds), in the range [1,100] + FragCount int `xml:"FragCount,omitempty"` //the number of ts objects in the m3u8 object, in the range of [1,100] + PlaylistName string `xml:"PlaylistName,omitempty"` //the name of m3u8 object, which must end with ".m3u8" and the length range is [6,128] +} + +// LiveChannelSnapshot snapshot configuration of live-channel +type LiveChannelSnapshot struct { + XMLName xml.Name `xml:"Snapshot"` + RoleName string `xml:"RoleName,omitempty"` //The role of snapshot operations, it sholud has write permission of DestBucket and the permission to send messages to the NotifyTopic. + DestBucket string `xml:"DestBucket,omitempty"` //Bucket the snapshots will be written to. should be the same owner as the source bucket. + NotifyTopic string `xml:"NotifyTopic,omitempty"` //Topics of MNS for notifying users of high frequency screenshot operation results + Interval int `xml:"Interval,omitempty"` //interval of snapshots, threre is no snapshot if no I-frame during the interval time +} + +// CreateLiveChannelResult the result of crete live-channel +type CreateLiveChannelResult struct { + XMLName xml.Name `xml:"CreateLiveChannelResult"` + PublishUrls []string `xml:"PublishUrls>Url"` //push urls list + PlayUrls []string `xml:"PlayUrls>Url"` //play urls list +} + +// LiveChannelStat the result of get live-channel state +type LiveChannelStat struct { + XMLName xml.Name `xml:"LiveChannelStat"` + Status string `xml:"Status"` //Current push status of live-channel: Disabled,Live,Idle + ConnectedTime time.Time `xml:"ConnectedTime"` //The time when the client starts pushing, format: ISO8601 + RemoteAddr string `xml:"RemoteAddr"` //The ip address of the client + Video LiveChannelVideo `xml:"Video"` //Video stream information + Audio LiveChannelAudio `xml:"Audio"` //Audio stream information +} + +// LiveChannelVideo video stream information +type LiveChannelVideo struct { + XMLName xml.Name `xml:"Video"` + Width int `xml:"Width"` //Width (unit: pixels) + Height int `xml:"Height"` //Height (unit: pixels) + FrameRate int `xml:"FrameRate"` //FramRate + Bandwidth int `xml:"Bandwidth"` //Bandwidth (unit: B/s) +} + +// LiveChannelAudio audio stream information +type LiveChannelAudio struct { + XMLName xml.Name `xml:"Audio"` + SampleRate int `xml:"SampleRate"` //SampleRate + Bandwidth int `xml:"Bandwidth"` //Bandwidth (unit: B/s) + Codec string `xml:"Codec"` //Encoding forma +} + +// LiveChannelHistory the result of GetLiveChannelHistory, at most return up to lastest 10 push records +type LiveChannelHistory struct { + XMLName xml.Name `xml:"LiveChannelHistory"` + Record []LiveRecord `xml:"LiveRecord"` //push records list +} + +// LiveRecord push recode +type LiveRecord struct { + XMLName xml.Name `xml:"LiveRecord"` + StartTime time.Time `xml:"StartTime"` //StartTime, format: ISO8601 + EndTime time.Time `xml:"EndTime"` //EndTime, format: ISO8601 + RemoteAddr string `xml:"RemoteAddr"` //The ip address of remote client +} + +// ListLiveChannelResult the result of ListLiveChannel +type ListLiveChannelResult struct { + XMLName xml.Name `xml:"ListLiveChannelResult"` + Prefix string `xml:"Prefix"` //Filter by the name start with the value of "Prefix" + Marker string `xml:"Marker"` //cursor from which starting list + MaxKeys int `xml:"MaxKeys"` //The maximum count returned. the default value is 100. it cannot be greater than 1000. + IsTruncated bool `xml:"IsTruncated"` //Indicates whether all results have been returned, "true" indicates partial results returned while "false" indicates all results have been returned + NextMarker string `xml:"NextMarker"` //NextMarker indicate the Marker value of the next request + LiveChannel []LiveChannelInfo `xml:"LiveChannel"` //The infomation of live-channel +} + +// LiveChannelInfo the infomation of live-channel +type LiveChannelInfo struct { + XMLName xml.Name `xml:"LiveChannel"` + Name string `xml:"Name"` //The name of live-channel + Description string `xml:"Description"` //Description of live-channel + Status string `xml:"Status"` //Status: disabled or enabled + LastModified time.Time `xml:"LastModified"` //Last modification time, format: ISO8601 + PublishUrls []string `xml:"PublishUrls>Url"` //push urls list + PlayUrls []string `xml:"PlayUrls>Url"` //play urls list +} + +// Tag a tag for the object +type Tag struct { + XMLName xml.Name `xml:"Tag"` + Key string `xml:"Key"` + Value string `xml:"Value"` +} + +// Tagging tag set for the object +type Tagging struct { + XMLName xml.Name `xml:"Tagging"` + Tags []Tag `xml:"TagSet>Tag,omitempty"` +} + +// GetObjectTaggingResult for GetObjectTagging return value +type GetObjectTaggingResult Tagging + +// VersioningConfig for the bucket +type VersioningConfig struct { + XMLName xml.Name `xml:"VersioningConfiguration"` + Status string `xml:"Status"` +} + +type GetBucketVersioningResult VersioningConfig + +// ServerEncryptionRule Server Encryption rule for the bucket +type ServerEncryptionRule struct { + XMLName xml.Name `xml:"ServerSideEncryptionRule"` + SSEDefault SSEDefaultRule `xml:"ApplyServerSideEncryptionByDefault"` +} + +// SSEDefaultRule Server Encryption deafult rule for the bucket +type SSEDefaultRule struct { + XMLName xml.Name `xml:"ApplyServerSideEncryptionByDefault"` + SSEAlgorithm string `xml:"SSEAlgorithm,omitempty"` + KMSMasterKeyID string `xml:"KMSMasterKeyID,omitempty"` + KMSDataEncryption string `xml:"KMSDataEncryption,,omitempty"` +} + +type GetBucketEncryptionResult ServerEncryptionRule +type GetBucketTaggingResult Tagging + +type BucketStat struct { + XMLName xml.Name `xml:"BucketStat"` + Storage int64 `xml:"Storage"` + ObjectCount int64 `xml:"ObjectCount"` + MultipartUploadCount int64 `xml:"MultipartUploadCount"` + LiveChannelCount int64 `xml:"LiveChannelCount"` + LastModifiedTime int64 `xml:"LastModifiedTime"` + StandardStorage int64 `xml:"StandardStorage"` + StandardObjectCount int64 `xml:"StandardObjectCount"` + InfrequentAccessStorage int64 `xml:"InfrequentAccessStorage"` + InfrequentAccessRealStorage int64 `xml:"InfrequentAccessRealStorage"` + InfrequentAccessObjectCount int64 `xml:"InfrequentAccessObjectCount"` + ArchiveStorage int64 `xml:"ArchiveStorage"` + ArchiveRealStorage int64 `xml:"ArchiveRealStorage"` + ArchiveObjectCount int64 `xml:"ArchiveObjectCount"` + ColdArchiveStorage int64 `xml:"ColdArchiveStorage"` + ColdArchiveRealStorage int64 `xml:"ColdArchiveRealStorage"` + ColdArchiveObjectCount int64 `xml:"ColdArchiveObjectCount"` +} +type GetBucketStatResult BucketStat + +// RequestPaymentConfiguration define the request payment configuration +type RequestPaymentConfiguration struct { + XMLName xml.Name `xml:"RequestPaymentConfiguration"` + Payer string `xml:"Payer,omitempty"` +} + +// BucketQoSConfiguration define QoS configuration +type BucketQoSConfiguration struct { + XMLName xml.Name `xml:"QoSConfiguration"` + TotalUploadBandwidth *int `xml:"TotalUploadBandwidth"` // Total upload bandwidth + IntranetUploadBandwidth *int `xml:"IntranetUploadBandwidth"` // Intranet upload bandwidth + ExtranetUploadBandwidth *int `xml:"ExtranetUploadBandwidth"` // Extranet upload bandwidth + TotalDownloadBandwidth *int `xml:"TotalDownloadBandwidth"` // Total download bandwidth + IntranetDownloadBandwidth *int `xml:"IntranetDownloadBandwidth"` // Intranet download bandwidth + ExtranetDownloadBandwidth *int `xml:"ExtranetDownloadBandwidth"` // Extranet download bandwidth + TotalQPS *int `xml:"TotalQps"` // Total Qps + IntranetQPS *int `xml:"IntranetQps"` // Intranet Qps + ExtranetQPS *int `xml:"ExtranetQps"` // Extranet Qps +} + +// UserQoSConfiguration define QoS and Range configuration +type UserQoSConfiguration struct { + XMLName xml.Name `xml:"QoSConfiguration"` + Region string `xml:"Region,omitempty"` // Effective area of Qos configuration + BucketQoSConfiguration +} + +////////////////////////////////////////////////////////////// +/////////////////// Select OBject //////////////////////////// +////////////////////////////////////////////////////////////// + +type CsvMetaRequest struct { + XMLName xml.Name `xml:"CsvMetaRequest"` + InputSerialization InputSerialization `xml:"InputSerialization"` + OverwriteIfExists *bool `xml:"OverwriteIfExists,omitempty"` +} + +// encodeBase64 encode base64 of the CreateSelectObjectMeta api request params +func (meta *CsvMetaRequest) encodeBase64() { + meta.InputSerialization.CSV.RecordDelimiter = + base64.StdEncoding.EncodeToString([]byte(meta.InputSerialization.CSV.RecordDelimiter)) + meta.InputSerialization.CSV.FieldDelimiter = + base64.StdEncoding.EncodeToString([]byte(meta.InputSerialization.CSV.FieldDelimiter)) + meta.InputSerialization.CSV.QuoteCharacter = + base64.StdEncoding.EncodeToString([]byte(meta.InputSerialization.CSV.QuoteCharacter)) +} + +type JsonMetaRequest struct { + XMLName xml.Name `xml:"JsonMetaRequest"` + InputSerialization InputSerialization `xml:"InputSerialization"` + OverwriteIfExists *bool `xml:"OverwriteIfExists,omitempty"` +} + +type InputSerialization struct { + XMLName xml.Name `xml:"InputSerialization"` + CSV CSV `xml:CSV,omitempty` + JSON JSON `xml:JSON,omitempty` + CompressionType string `xml:"CompressionType,omitempty"` +} +type CSV struct { + XMLName xml.Name `xml:"CSV"` + RecordDelimiter string `xml:"RecordDelimiter,omitempty"` + FieldDelimiter string `xml:"FieldDelimiter,omitempty"` + QuoteCharacter string `xml:"QuoteCharacter,omitempty"` +} + +type JSON struct { + XMLName xml.Name `xml:"JSON"` + JSONType string `xml:"Type,omitempty"` +} + +// SelectRequest is for the SelectObject request params of json file +type SelectRequest struct { + XMLName xml.Name `xml:"SelectRequest"` + Expression string `xml:"Expression"` + InputSerializationSelect InputSerializationSelect `xml:"InputSerialization"` + OutputSerializationSelect OutputSerializationSelect `xml:"OutputSerialization"` + SelectOptions SelectOptions `xml:"Options,omitempty"` +} +type InputSerializationSelect struct { + XMLName xml.Name `xml:"InputSerialization"` + CsvBodyInput CSVSelectInput `xml:CSV,omitempty` + JsonBodyInput JSONSelectInput `xml:JSON,omitempty` + CompressionType string `xml:"CompressionType,omitempty"` +} +type CSVSelectInput struct { + XMLName xml.Name `xml:"CSV"` + FileHeaderInfo string `xml:"FileHeaderInfo,omitempty"` + RecordDelimiter string `xml:"RecordDelimiter,omitempty"` + FieldDelimiter string `xml:"FieldDelimiter,omitempty"` + QuoteCharacter string `xml:"QuoteCharacter,omitempty"` + CommentCharacter string `xml:"CommentCharacter,omitempty"` + Range string `xml:"Range,omitempty"` + SplitRange string +} +type JSONSelectInput struct { + XMLName xml.Name `xml:"JSON"` + JSONType string `xml:"Type,omitempty"` + Range string `xml:"Range,omitempty"` + ParseJSONNumberAsString *bool `xml:"ParseJsonNumberAsString"` + SplitRange string +} + +func (jsonInput *JSONSelectInput) JsonIsEmpty() bool { + if jsonInput.JSONType != "" { + return false + } + return true +} + +type OutputSerializationSelect struct { + XMLName xml.Name `xml:"OutputSerialization"` + CsvBodyOutput CSVSelectOutput `xml:CSV,omitempty` + JsonBodyOutput JSONSelectOutput `xml:JSON,omitempty` + OutputRawData *bool `xml:"OutputRawData,omitempty"` + KeepAllColumns *bool `xml:"KeepAllColumns,omitempty"` + EnablePayloadCrc *bool `xml:"EnablePayloadCrc,omitempty"` + OutputHeader *bool `xml:"OutputHeader,omitempty"` +} +type CSVSelectOutput struct { + XMLName xml.Name `xml:"CSV"` + RecordDelimiter string `xml:"RecordDelimiter,omitempty"` + FieldDelimiter string `xml:"FieldDelimiter,omitempty"` +} +type JSONSelectOutput struct { + XMLName xml.Name `xml:"JSON"` + RecordDelimiter string `xml:"RecordDelimiter,omitempty"` +} + +func (selectReq *SelectRequest) encodeBase64() { + if selectReq.InputSerializationSelect.JsonBodyInput.JsonIsEmpty() { + selectReq.csvEncodeBase64() + } else { + selectReq.jsonEncodeBase64() + } +} + +// csvEncodeBase64 encode base64 of the SelectObject api request params +func (selectReq *SelectRequest) csvEncodeBase64() { + selectReq.Expression = base64.StdEncoding.EncodeToString([]byte(selectReq.Expression)) + selectReq.InputSerializationSelect.CsvBodyInput.RecordDelimiter = + base64.StdEncoding.EncodeToString([]byte(selectReq.InputSerializationSelect.CsvBodyInput.RecordDelimiter)) + selectReq.InputSerializationSelect.CsvBodyInput.FieldDelimiter = + base64.StdEncoding.EncodeToString([]byte(selectReq.InputSerializationSelect.CsvBodyInput.FieldDelimiter)) + selectReq.InputSerializationSelect.CsvBodyInput.QuoteCharacter = + base64.StdEncoding.EncodeToString([]byte(selectReq.InputSerializationSelect.CsvBodyInput.QuoteCharacter)) + selectReq.InputSerializationSelect.CsvBodyInput.CommentCharacter = + base64.StdEncoding.EncodeToString([]byte(selectReq.InputSerializationSelect.CsvBodyInput.CommentCharacter)) + selectReq.OutputSerializationSelect.CsvBodyOutput.FieldDelimiter = + base64.StdEncoding.EncodeToString([]byte(selectReq.OutputSerializationSelect.CsvBodyOutput.FieldDelimiter)) + selectReq.OutputSerializationSelect.CsvBodyOutput.RecordDelimiter = + base64.StdEncoding.EncodeToString([]byte(selectReq.OutputSerializationSelect.CsvBodyOutput.RecordDelimiter)) + + // handle Range + if selectReq.InputSerializationSelect.CsvBodyInput.Range != "" { + selectReq.InputSerializationSelect.CsvBodyInput.Range = "line-range=" + selectReq.InputSerializationSelect.CsvBodyInput.Range + } + + if selectReq.InputSerializationSelect.CsvBodyInput.SplitRange != "" { + selectReq.InputSerializationSelect.CsvBodyInput.Range = "split-range=" + selectReq.InputSerializationSelect.CsvBodyInput.SplitRange + } +} + +// jsonEncodeBase64 encode base64 of the SelectObject api request params +func (selectReq *SelectRequest) jsonEncodeBase64() { + selectReq.Expression = base64.StdEncoding.EncodeToString([]byte(selectReq.Expression)) + selectReq.OutputSerializationSelect.JsonBodyOutput.RecordDelimiter = + base64.StdEncoding.EncodeToString([]byte(selectReq.OutputSerializationSelect.JsonBodyOutput.RecordDelimiter)) + + // handle Range + if selectReq.InputSerializationSelect.JsonBodyInput.Range != "" { + selectReq.InputSerializationSelect.JsonBodyInput.Range = "line-range=" + selectReq.InputSerializationSelect.JsonBodyInput.Range + } + + if selectReq.InputSerializationSelect.JsonBodyInput.SplitRange != "" { + selectReq.InputSerializationSelect.JsonBodyInput.Range = "split-range=" + selectReq.InputSerializationSelect.JsonBodyInput.SplitRange + } +} + +// SelectOptions is a element in the SelectObject api request's params +type SelectOptions struct { + XMLName xml.Name `xml:"Options"` + SkipPartialDataRecord *bool `xml:"SkipPartialDataRecord,omitempty"` + MaxSkippedRecordsAllowed string `xml:"MaxSkippedRecordsAllowed,omitempty"` +} + +// SelectObjectResult is the SelectObject api's return +type SelectObjectResult struct { + Version byte + FrameType int32 + PayloadLength int32 + HeaderCheckSum uint32 + Offset uint64 + Data string // DataFrame + EndFrame EndFrame // EndFrame + MetaEndFrameCSV MetaEndFrameCSV // MetaEndFrameCSV + MetaEndFrameJSON MetaEndFrameJSON // MetaEndFrameJSON + PayloadChecksum uint32 + ReadFlagInfo +} + +// ReadFlagInfo if reading the frame data, recode the reading status +type ReadFlagInfo struct { + OpenLine bool + ConsumedBytesLength int32 + EnablePayloadCrc bool + OutputRawData bool +} + +// EndFrame is EndFrameType of SelectObject api +type EndFrame struct { + TotalScanned int64 + HTTPStatusCode int32 + ErrorMsg string +} + +// MetaEndFrameCSV is MetaEndFrameCSVType of CreateSelectObjectMeta +type MetaEndFrameCSV struct { + TotalScanned int64 + Status int32 + SplitsCount int32 + RowsCount int64 + ColumnsCount int32 + ErrorMsg string +} + +// MetaEndFrameJSON is MetaEndFrameJSON of CreateSelectObjectMeta +type MetaEndFrameJSON struct { + TotalScanned int64 + Status int32 + SplitsCount int32 + RowsCount int64 + ErrorMsg string +} + +// InventoryConfiguration is Inventory config +type InventoryConfiguration struct { + XMLName xml.Name `xml:"InventoryConfiguration"` + Id string `xml:"Id,omitempty"` + IsEnabled *bool `xml:"IsEnabled,omitempty"` + Prefix string `xml:"Filter>Prefix,omitempty"` + OSSBucketDestination OSSBucketDestination `xml:"Destination>OSSBucketDestination,omitempty"` + Frequency string `xml:"Schedule>Frequency,omitempty"` + IncludedObjectVersions string `xml:"IncludedObjectVersions,omitempty"` + OptionalFields OptionalFields `xml:OptionalFields,omitempty` +} + +type OptionalFields struct { + XMLName xml.Name `xml:"OptionalFields,omitempty` + Field []string `xml:"Field,omitempty` +} + +type OSSBucketDestination struct { + XMLName xml.Name `xml:"OSSBucketDestination"` + Format string `xml:"Format,omitempty"` + AccountId string `xml:"AccountId,omitempty"` + RoleArn string `xml:"RoleArn,omitempty"` + Bucket string `xml:"Bucket,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + Encryption *InvEncryption `xml:"Encryption,omitempty"` +} + +type InvEncryption struct { + XMLName xml.Name `xml:"Encryption"` + SseOss *InvSseOss `xml:"SSE-OSS"` + SseKms *InvSseKms `xml:"SSE-KMS"` +} + +type InvSseOss struct { + XMLName xml.Name `xml:"SSE-OSS"` +} + +type InvSseKms struct { + XMLName xml.Name `xml:"SSE-KMS"` + KmsId string `xml:"KeyId,omitempty"` +} + +type ListInventoryConfigurationsResult struct { + XMLName xml.Name `xml:"ListInventoryConfigurationsResult"` + InventoryConfiguration []InventoryConfiguration `xml:"InventoryConfiguration,omitempty` + IsTruncated *bool `xml:"IsTruncated,omitempty"` + NextContinuationToken string `xml:"NextContinuationToken,omitempty"` +} + +// RestoreConfiguration for RestoreObject +type RestoreConfiguration struct { + XMLName xml.Name `xml:"RestoreRequest"` + Days int32 `xml:"Days,omitempty"` + Tier string `xml:"JobParameters>Tier,omitempty"` +} + +// AsyncFetchTaskConfiguration for SetBucketAsyncFetchTask +type AsyncFetchTaskConfiguration struct { + XMLName xml.Name `xml:"AsyncFetchTaskConfiguration"` + Url string `xml:"Url,omitempty"` + Object string `xml:"Object,omitempty"` + Host string `xml:"Host,omitempty"` + ContentMD5 string `xml:"ContentMD5,omitempty"` + Callback string `xml:"Callback,omitempty"` + StorageClass string `xml:"StorageClass,omitempty"` + IgnoreSameKey bool `xml:"IgnoreSameKey"` +} + +// AsyncFetchTaskResult for SetBucketAsyncFetchTask result +type AsyncFetchTaskResult struct { + XMLName xml.Name `xml:"AsyncFetchTaskResult"` + TaskId string `xml:"TaskId,omitempty"` +} + +// AsynFetchTaskInfo for GetBucketAsyncFetchTask result +type AsynFetchTaskInfo struct { + XMLName xml.Name `xml:"AsyncFetchTaskInfo"` + TaskId string `xml:"TaskId,omitempty"` + State string `xml:"State,omitempty"` + ErrorMsg string `xml:"ErrorMsg,omitempty"` + TaskInfo AsyncTaskInfo `xml:"TaskInfo,omitempty"` +} + +// AsyncTaskInfo for async task information +type AsyncTaskInfo struct { + XMLName xml.Name `xml:"TaskInfo"` + Url string `xml:"Url,omitempty"` + Object string `xml:"Object,omitempty"` + Host string `xml:"Host,omitempty"` + ContentMD5 string `xml:"ContentMD5,omitempty"` + Callback string `xml:"Callback,omitempty"` + StorageClass string `xml:"StorageClass,omitempty"` + IgnoreSameKey bool `xml:"IgnoreSameKey"` +} + +// InitiateWormConfiguration define InitiateBucketWorm configuration +type InitiateWormConfiguration struct { + XMLName xml.Name `xml:"InitiateWormConfiguration"` + RetentionPeriodInDays int `xml:"RetentionPeriodInDays"` // specify retention days +} + +// ExtendWormConfiguration define ExtendWormConfiguration configuration +type ExtendWormConfiguration struct { + XMLName xml.Name `xml:"ExtendWormConfiguration"` + RetentionPeriodInDays int `xml:"RetentionPeriodInDays"` // specify retention days +} + +// WormConfiguration define WormConfiguration +type WormConfiguration struct { + XMLName xml.Name `xml:"WormConfiguration"` + WormId string `xml:"WormId,omitempty"` + State string `xml:"State,omitempty"` + RetentionPeriodInDays int `xml:"RetentionPeriodInDays"` // specify retention days + CreationDate string `xml:"CreationDate,omitempty"` +} + +// TransferAccConfiguration define transfer acceleration configuration +type TransferAccConfiguration struct { + XMLName xml.Name `xml:"TransferAccelerationConfiguration"` + Enabled bool `xml:"Enabled"` +} + +// ReplicationXML defines simple replication xml, and ReplicationXML is used for "DeleteBucketReplication" in client.go +type ReplicationXML struct { + XMLName xml.Name `xml:"ReplicationRules"` + ID string `xml:"ID,omitempty"` +} + +// PutBucketReplication define the bucket replication config +type PutBucketReplication BucketReplicationXml + +// GetBucketReplicationResult define get bucket's replication config +type GetBucketReplicationResult BucketReplicationXml + +// GetBucketReplicationLocationResult define get bucket's replication location +type GetBucketReplicationLocationResult BucketReplicationLocationXml + +// GetBucketReplicationProgressResult define get bucket's replication progress +type GetBucketReplicationProgressResult BucketReplicationProgressXml + +// PutBucketRTC define the bucket rtc config +type PutBucketRTC BucketRTCXml + +// BucketReplicationXml define the xml of bucket replication config +type BucketReplicationXml struct { + XMLName xml.Name `xml:"ReplicationConfiguration"` + Rule []ReplicationRule `xml:"Rule,omitempty"` +} + +// BucketReplicationProgressXml define the xml of bucket replication config +type BucketReplicationProgressXml struct { + XMLName xml.Name `xml:"ReplicationProgress"` + Rule []ReplicationRule `xml:"Rule,omitempty"` +} + +// BucketRTCXml define the xml of bucket rtc config +type BucketRTCXml struct { + XMLName xml.Name `xml:"ReplicationRule"` + RTC *string `xml:"RTC>Status,omitempty"` + ID string `xml:"ID,omitempty"` +} + +// ReplicationRule define the xml of bucket replication config rule +type ReplicationRule struct { + ID string `xml:"ID,omitempty"` + RTC *string `xml:"RTC>Status,omitempty"` + PrefixSet *ReplicationRulePrefix `xml:"PrefixSet,omitempty"` + Action string `xml:"Action,omitempty"` + Destination *ReplicationRuleDestination `xml:"Destination,omitempty"` + HistoricalObjectReplication string `xml:"HistoricalObjectReplication,omitempty"` + Status string `xml:"Status,omitempty"` + SyncRole string `xml:"SyncRole,omitempty"` + SourceSelectionCriteria *string `xml:"SourceSelectionCriteria>SseKmsEncryptedObjects>Status,omitempty"` + EncryptionConfiguration *string `xml:"EncryptionConfiguration>ReplicaKmsKeyID,omitempty"` + Progress *ReplicationRuleProgress `xml:"Progress,omitempty"` + HistoricalObject string `xml:"HistoricalObject,omitempty"` +} + +type ReplicationRulePrefix struct { + Prefix []*string `xml:"Prefix,omitempty"` +} + +type ReplicationRuleDestination struct { + Bucket string `xml:"Bucket,omitempty"` + Location string `xml:"Location,omitempty"` + TransferType string `xml:"TransferType,omitempty"` +} + +// BucketReplicationLocationXml define the xml of bucket replication location info +type BucketReplicationLocationXml struct { + XMLName xml.Name `xml:"ReplicationLocation"` + Location []string `xml:"Location,omitempty"` + LocationTransferType []ReplicationLocationTransferType `xml:"LocationTransferTypeConstraint>LocationTransferType,omitempty"` + RTCLocation []string `xml:"LocationRTCConstraint>Location,omitempty"` +} + +type ReplicationLocation struct { + Location string `xml:"Location,omitempty"` +} + +type ReplicationLocationTransferType struct { + Location string `xml:"Location,omitempty"` + TransferTypes string `xml:"TransferTypes>Type,omitempty"` +} + +type ReplicationRuleProgress struct { + HistoricalObject string `xml:"HistoricalObject,omitempty"` + NewObject string `xml:"NewObject,omitempty"` +} + +// CnameConfigurationXML define cname configuration +type CnameConfigurationXML struct { + XMLName xml.Name `xml:"BucketCnameConfiguration"` + Domain string `xml:"Cname>Domain"` +} + +type PutBucketCname PutBucketCnameXml + +// PutBucketCnameXml define cname configuration +type PutBucketCnameXml struct { + XMLName xml.Name `xml:"BucketCnameConfiguration"` + Cname string `xml:"Cname>Domain"` + CertificateConfiguration *CertificateConfiguration `xml:"Cname>CertificateConfiguration"` +} + +type CertificateConfiguration struct { + CertId string `xml:"CertId,omitempty"` + Certificate string `xml:"Certificate,omitempty"` + PrivateKey string `xml:"PrivateKey,omitempty"` + PreviousCertId string `xml:"PreviousCertId,omitempty"` + Force bool `xml:"Force,omitempty"` + DeleteCertificate bool `xml:"DeleteCertificate,omitempty"` +} + +// CnameTokenXML define cname token information +type CnameTokenXML struct { + XMLName xml.Name `xml:"CnameToken"` + Bucket string `xml:"Bucket,omitempty"` + Cname string `xml:"Cname,omitempty"` + Token string `xml:"Token,omitempty"` + ExpireTime string `xml:"ExpireTime,omitempty"` +} + +// CreateBucketCnameTokenResult defines result object for CreateBucketCnameToken request +type CreateBucketCnameTokenResult CnameTokenXML + +// GetBucketCnameTokenResult defines result object for GetBucketCnameToken request +type GetBucketCnameTokenResult CnameTokenXML + +// GetMetaQueryStatusResult defines result for GetMetaQueryStatus result +type GetMetaQueryStatusResult GetMetaQueryStatusResultXml + +// GetMetaQueryStatusResultXml define get meta query status information +type GetMetaQueryStatusResultXml struct { + XMLName xml.Name `xml:"MetaQueryStatus"` + State string `xml:"State"` + Phase string `xml:"Phase"` + CreateTime string `xml:"CreateTime"` + UpdateTime string `xml:"UpdateTime"` +} + +// MetaQuery defines meta query struct +type MetaQuery struct { + XMLName xml.Name `xml:"MetaQuery"` + NextToken string `xml:"NextToken,omitempty"` + MaxResults int64 `xml:"MaxResults,omitempty"` + Query string `xml:"Query"` + Sort string `xml:"Sort,omitempty"` + Order string `xml:"Order,omitempty"` + Aggregations []MetaQueryAggregationRequest `xml:"Aggregations>Aggregation,omitempty"` +} + +// MetaQueryAggregationRequest defines meta query aggregation request +type MetaQueryAggregationRequest struct { + XMLName xml.Name `xml:"Aggregation"` + Field string `xml:"Field,omitempty"` + Operation string `xml:"Operation,omitempty"` +} + +// MetaQueryAggregationResponse defines meta query aggregation response +type MetaQueryAggregationResponse struct { + XMLName xml.Name `xml:"Aggregation"` + Field string `xml:"Field,omitempty"` + Operation string `xml:"Operation,omitempty"` + Value float64 `xml:"Value,omitempty"` + Groups []MetaQueryGroup `xml:"Groups>Group,omitempty"` +} + +// DoMetaQueryResult defines result for DoMetaQuery result +type DoMetaQueryResult DoMetaQueryResultXml + +// DoMetaQueryResultXml defines do meta query information +type DoMetaQueryResultXml struct { + XMLName xml.Name `xml:"MetaQuery"` + NextToken string `xml:"NextToken,omitempty"` // next token + Files []MetaQueryFile `xml:"Files>File,omitempty"` // file + Aggregations []MetaQueryAggregationResponse `xml:"Aggregations>Aggregation,omitempty"'` // Aggregation +} + +// MetaQueryFile defines do meta query result file information +type MetaQueryFile struct { + XMLName xml.Name `xml:"File"` + Filename string `xml:"Filename"` //file name + Size int64 `xml:"Size"` // file size + FileModifiedTime string `xml:"FileModifiedTime"` // file Modified Time + OssObjectType string `xml:"OSSObjectType"` // Oss Object Type + OssStorageClass string `xml:"OSSStorageClass"` // Oss Storage Class + ObjectACL string `xml:"ObjectACL"` // Object Acl + ETag string `xml:"ETag"` // ETag + OssCRC64 string `xml:"OSSCRC64"` // Oss CRC64 + OssTaggingCount int64 `xml:"OSSTaggingCount,omitempty"` // Oss Tagging Count + OssTagging []MetaQueryTagging `xml:"OSSTagging>Tagging,omitempty"` // Tagging + OssUserMeta []MetaQueryUserMeta `xml:"OSSUserMeta>UserMeta,omitempty"` // UserMeta + ServerSideEncryption string `xml:"ServerSideEncryption,omitempty"` //Server Side Encryption + ServerSideEncryptionCustomerAlgorithm string `xml:"ServerSideEncryptionCustomerAlgorithm,omitempty"` // Server Side Encryption Customer Algorithm +} + +// MetaQueryTagging defines do meta query result tagging information +type MetaQueryTagging struct { + XMLName xml.Name `xml:"Tagging"` + Key string `xml:"Key"` + Value string `xml:"Value"` +} + +// MetaQueryUserMeta defines do meta query result user meta information +type MetaQueryUserMeta struct { + XMLName xml.Name `xml:"UserMeta"` + Key string `xml:"Key"` + Value string `xml:"Value"` +} + +// MetaQueryGroup defines do meta query result group information +type MetaQueryGroup struct { + XMLName xml.Name `xml:"Group"` + Value string `xml:"Value"` + Count int64 `xml:"Count"` +} + +// GetBucketAccessMonitorResult define config for get bucket access monitor +type GetBucketAccessMonitorResult BucketAccessMonitorXml + +// PutBucketAccessMonitor define the xml of bucket access monitor config +type PutBucketAccessMonitor BucketAccessMonitorXml + +// BucketAccessMonitorXml define get bucket access monitor information +type BucketAccessMonitorXml struct { + XMLName xml.Name `xml:"AccessMonitorConfiguration"` + Status string `xml:"Status"` // access monitor status +} + +// ListBucketCnameResult define the cname list of the bucket +type ListBucketCnameResult BucketCnameXml + +// BucketCnameXml define get the bucket cname information +type BucketCnameXml struct { + XMLName xml.Name `xml:"ListCnameResult"` + Bucket string `xml:"Bucket"` + Owner string `xml:"Owner"` + Cname []Cname `xml:"Cname"` +} + +// Cname define the cname information +type Cname struct { + Domain string `xml:"Domain"` + LastModified string `xml:"LastModified"` + Status string `xml:"Status"` + Certificate Certificate `xml:"Certificate"` +} + +// Certificate define Details of domain name certificate +type Certificate struct { + Type string `xml:"Type"` + CertId string `xml:"CertId"` + Status string `xml:"Status"` + CreationDate string `xml:"CreationDate"` + Fingerprint string `xml:"Fingerprint"` + ValidStartDate string `xml:"ValidStartDate"` + ValidEndDate string `xml:"ValidEndDate"` +} + +// GetBucketResourceGroupResult define resource group for the bucket +type GetBucketResourceGroupResult BucketResourceGroupXml + +// PutBucketResourceGroup define the xml of bucket's resource group config +type PutBucketResourceGroup BucketResourceGroupXml + +// BucketResourceGroupXml define the information of the bucket's resource group +type BucketResourceGroupXml struct { + XMLName xml.Name `xml:"BucketResourceGroupConfiguration"` + ResourceGroupId string `xml:"ResourceGroupId"` // resource groupId +} + +// GetBucketStyleResult define style for the bucket +type GetBucketStyleResult BucketStyleXml + +// GetBucketListStyleResult define the list style for the bucket +type GetBucketListStyleResult BucketListStyleXml + +// BucketListStyleXml define the list style of the bucket +type BucketListStyleXml struct { + XMLName xml.Name `xml:"StyleList"` + Style []BucketStyleXml `xml:"Style,omitempty"` // style +} + +// BucketStyleXml define the information of the bucket's style +type BucketStyleXml struct { + XMLName xml.Name `xml:"Style"` + Name string `xml:"Name,omitempty"` // style name + Content string `xml:"Content"` // style content + CreateTime string `xml:"CreateTime,omitempty"` // style create time + LastModifyTime string `xml:"LastModifyTime,omitempty"` // style last modify time +} + +// DescribeRegionsResult define get the describe regions result +type DescribeRegionsResult RegionInfoList + +type RegionInfo struct { + Region string `xml:"Region"` + InternetEndpoint string `xml:"InternetEndpoint"` + InternalEndpoint string `xml:"InternalEndpoint"` + AccelerateEndpoint string `xml:"AccelerateEndpoint"` +} + +type RegionInfoList struct { + XMLName xml.Name `xml:"RegionInfoList"` + Regions []RegionInfo `xml:"RegionInfo"` +} + +//PutBucketResponseHeader define the xml of bucket's response header config +type PutBucketResponseHeader ResponseHeaderXml + +//GetBucketResponseHeaderResult define the xml of bucket's response header result +type GetBucketResponseHeaderResult ResponseHeaderXml + +type ResponseHeaderXml struct { + XMLName xml.Name `xml:"ResponseHeaderConfiguration"` + Rule []ResponseHeaderRule `xml:Rule,omitempty"` // rule +} + +type ResponseHeaderRule struct { + Name string `xml:"Name"` // rule name + Filters ResponseHeaderRuleFilters `xml:"Filters,omitempty"` // rule filters Operation + HideHeaders ResponseHeaderRuleHeaders `xml:"HideHeaders,omitempty"` // rule hide header +} + +type ResponseHeaderRuleFilters struct { + Operation []string `xml:"Operation,omitempty"` +} + +type ResponseHeaderRuleHeaders struct { + Header []string `xml:"Header,omitempty"` +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go new file mode 100644 index 00000000000..becc6433dcf --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go @@ -0,0 +1,578 @@ +package oss + +import ( + "bytes" + "crypto/md5" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "time" +) + +// UploadFile is multipart file upload. +// +// objectKey the object name. +// filePath the local file path to upload. +// partSize the part size in byte. +// options the options for uploading object. +// +// error it's nil if the operation succeeds, otherwise it's an error object. +// +func (bucket Bucket) UploadFile(objectKey, filePath string, partSize int64, options ...Option) error { + if partSize < MinPartSize || partSize > MaxPartSize { + return errors.New("oss: part size invalid range (100KB, 5GB]") + } + + cpConf := getCpConfig(options) + routines := getRoutines(options) + + if cpConf != nil && cpConf.IsEnable { + cpFilePath := getUploadCpFilePath(cpConf, filePath, bucket.BucketName, objectKey) + if cpFilePath != "" { + return bucket.uploadFileWithCp(objectKey, filePath, partSize, options, cpFilePath, routines) + } + } + + return bucket.uploadFile(objectKey, filePath, partSize, options, routines) +} + +func getUploadCpFilePath(cpConf *cpConfig, srcFile, destBucket, destObject string) string { + if cpConf.FilePath == "" && cpConf.DirPath != "" { + dest := fmt.Sprintf("oss://%v/%v", destBucket, destObject) + absPath, _ := filepath.Abs(srcFile) + cpFileName := getCpFileName(absPath, dest, "") + cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName + } + return cpConf.FilePath +} + +// ----- concurrent upload without checkpoint ----- + +// getCpConfig gets checkpoint configuration +func getCpConfig(options []Option) *cpConfig { + cpcOpt, err := FindOption(options, checkpointConfig, nil) + if err != nil || cpcOpt == nil { + return nil + } + + return cpcOpt.(*cpConfig) +} + +// getCpFileName return the name of the checkpoint file +func getCpFileName(src, dest, versionId string) string { + md5Ctx := md5.New() + md5Ctx.Write([]byte(src)) + srcCheckSum := hex.EncodeToString(md5Ctx.Sum(nil)) + + md5Ctx.Reset() + md5Ctx.Write([]byte(dest)) + destCheckSum := hex.EncodeToString(md5Ctx.Sum(nil)) + + if versionId == "" { + return fmt.Sprintf("%v-%v.cp", srcCheckSum, destCheckSum) + } + + md5Ctx.Reset() + md5Ctx.Write([]byte(versionId)) + versionCheckSum := hex.EncodeToString(md5Ctx.Sum(nil)) + return fmt.Sprintf("%v-%v-%v.cp", srcCheckSum, destCheckSum, versionCheckSum) +} + +// getRoutines gets the routine count. by default it's 1. +func getRoutines(options []Option) int { + rtnOpt, err := FindOption(options, routineNum, nil) + if err != nil || rtnOpt == nil { + return 1 + } + + rs := rtnOpt.(int) + if rs < 1 { + rs = 1 + } else if rs > 100 { + rs = 100 + } + + return rs +} + +// getPayer return the payer of the request +func getPayer(options []Option) string { + payerOpt, err := FindOption(options, HTTPHeaderOssRequester, nil) + if err != nil || payerOpt == nil { + return "" + } + return payerOpt.(string) +} + +// GetProgressListener gets the progress callback +func GetProgressListener(options []Option) ProgressListener { + isSet, listener, _ := IsOptionSet(options, progressListener) + if !isSet { + return nil + } + return listener.(ProgressListener) +} + +// uploadPartHook is for testing usage +type uploadPartHook func(id int, chunk FileChunk) error + +var uploadPartHooker uploadPartHook = defaultUploadPart + +func defaultUploadPart(id int, chunk FileChunk) error { + return nil +} + +// workerArg defines worker argument structure +type workerArg struct { + bucket *Bucket + filePath string + imur InitiateMultipartUploadResult + options []Option + hook uploadPartHook +} + +// worker is the worker coroutine function +type defaultUploadProgressListener struct { +} + +// ProgressChanged no-ops +func (listener *defaultUploadProgressListener) ProgressChanged(event *ProgressEvent) { +} + +func worker(id int, arg workerArg, jobs <-chan FileChunk, results chan<- UploadPart, failed chan<- error, die <-chan bool) { + for chunk := range jobs { + if err := arg.hook(id, chunk); err != nil { + failed <- err + break + } + var respHeader http.Header + p := Progress(&defaultUploadProgressListener{}) + opts := make([]Option, len(arg.options)+2) + opts = append(opts, arg.options...) + + // use defaultUploadProgressListener + opts = append(opts, p, GetResponseHeader(&respHeader)) + + startT := time.Now().UnixNano() / 1000 / 1000 / 1000 + part, err := arg.bucket.UploadPartFromFile(arg.imur, arg.filePath, chunk.Offset, chunk.Size, chunk.Number, opts...) + endT := time.Now().UnixNano() / 1000 / 1000 / 1000 + if err != nil { + arg.bucket.Client.Config.WriteLog(Debug, "upload part error,cost:%d second,part number:%d,request id:%s,error:%s\n", endT-startT, chunk.Number, GetRequestId(respHeader), err.Error()) + failed <- err + break + } + select { + case <-die: + return + default: + } + results <- part + } +} + +// scheduler function +func scheduler(jobs chan FileChunk, chunks []FileChunk) { + for _, chunk := range chunks { + jobs <- chunk + } + close(jobs) +} + +func getTotalBytes(chunks []FileChunk) int64 { + var tb int64 + for _, chunk := range chunks { + tb += chunk.Size + } + return tb +} + +// uploadFile is a concurrent upload, without checkpoint +func (bucket Bucket) uploadFile(objectKey, filePath string, partSize int64, options []Option, routines int) error { + listener := GetProgressListener(options) + + chunks, err := SplitFileByPartSize(filePath, partSize) + if err != nil { + return err + } + + partOptions := ChoiceTransferPartOption(options) + completeOptions := ChoiceCompletePartOption(options) + abortOptions := ChoiceAbortPartOption(options) + + // Initialize the multipart upload + imur, err := bucket.InitiateMultipartUpload(objectKey, options...) + if err != nil { + return err + } + + jobs := make(chan FileChunk, len(chunks)) + results := make(chan UploadPart, len(chunks)) + failed := make(chan error) + die := make(chan bool) + + var completedBytes int64 + totalBytes := getTotalBytes(chunks) + event := newProgressEvent(TransferStartedEvent, 0, totalBytes, 0) + publishProgress(listener, event) + + // Start the worker coroutine + arg := workerArg{&bucket, filePath, imur, partOptions, uploadPartHooker} + for w := 1; w <= routines; w++ { + go worker(w, arg, jobs, results, failed, die) + } + + // Schedule the jobs + go scheduler(jobs, chunks) + + // Waiting for the upload finished + completed := 0 + parts := make([]UploadPart, len(chunks)) + for completed < len(chunks) { + select { + case part := <-results: + completed++ + parts[part.PartNumber-1] = part + completedBytes += chunks[part.PartNumber-1].Size + + // why RwBytes in ProgressEvent is 0 ? + // because read or write event has been notified in teeReader.Read() + event = newProgressEvent(TransferDataEvent, completedBytes, totalBytes, chunks[part.PartNumber-1].Size) + publishProgress(listener, event) + case err := <-failed: + close(die) + event = newProgressEvent(TransferFailedEvent, completedBytes, totalBytes, 0) + publishProgress(listener, event) + bucket.AbortMultipartUpload(imur, abortOptions...) + return err + } + + if completed >= len(chunks) { + break + } + } + + event = newProgressEvent(TransferCompletedEvent, completedBytes, totalBytes, 0) + publishProgress(listener, event) + + // Complete the multpart upload + _, err = bucket.CompleteMultipartUpload(imur, parts, completeOptions...) + if err != nil { + bucket.AbortMultipartUpload(imur, abortOptions...) + return err + } + return nil +} + +// ----- concurrent upload with checkpoint ----- +const uploadCpMagic = "FE8BB4EA-B593-4FAC-AD7A-2459A36E2E62" + +type uploadCheckpoint struct { + Magic string // Magic + MD5 string // Checkpoint file content's MD5 + FilePath string // Local file path + FileStat cpStat // File state + ObjectKey string // Key + UploadID string // Upload ID + Parts []cpPart // All parts of the local file + CallbackVal string + CallbackBody *[]byte +} + +type cpStat struct { + Size int64 // File size + LastModified time.Time // File's last modified time + MD5 string // Local file's MD5 +} + +type cpPart struct { + Chunk FileChunk // File chunk + Part UploadPart // Uploaded part + IsCompleted bool // Upload complete flag +} + +// isValid checks if the uploaded data is valid---it's valid when the file is not updated and the checkpoint data is valid. +func (cp uploadCheckpoint) isValid(filePath string,options []Option) (bool, error) { + + callbackVal, _ := FindOption(options, HTTPHeaderOssCallback, "") + if callbackVal != "" && cp.CallbackVal != callbackVal { + return false, nil + } + callbackBody, _ := FindOption(options, responseBody, nil) + if callbackBody != nil{ + body, _ := json.Marshal(callbackBody) + if bytes.Equal(*cp.CallbackBody, body) { + return false, nil + } + } + // Compare the CP's magic number and MD5. + cpb := cp + cpb.MD5 = "" + js, _ := json.Marshal(cpb) + sum := md5.Sum(js) + b64 := base64.StdEncoding.EncodeToString(sum[:]) + + if cp.Magic != uploadCpMagic || b64 != cp.MD5 { + return false, nil + } + + // Make sure if the local file is updated. + fd, err := os.Open(filePath) + if err != nil { + return false, err + } + defer fd.Close() + + st, err := fd.Stat() + if err != nil { + return false, err + } + + md, err := calcFileMD5(filePath) + if err != nil { + return false, err + } + + // Compare the file size, file's last modified time and file's MD5 + if cp.FileStat.Size != st.Size() || + !cp.FileStat.LastModified.Equal(st.ModTime()) || + cp.FileStat.MD5 != md { + return false, nil + } + + return true, nil +} + +// load loads from the file +func (cp *uploadCheckpoint) load(filePath string) error { + contents, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + + err = json.Unmarshal(contents, cp) + return err +} + +// dump dumps to the local file +func (cp *uploadCheckpoint) dump(filePath string) error { + bcp := *cp + + // Calculate MD5 + bcp.MD5 = "" + js, err := json.Marshal(bcp) + if err != nil { + return err + } + sum := md5.Sum(js) + b64 := base64.StdEncoding.EncodeToString(sum[:]) + bcp.MD5 = b64 + + // Serialization + js, err = json.Marshal(bcp) + if err != nil { + return err + } + + // Dump + return ioutil.WriteFile(filePath, js, FilePermMode) +} + +// updatePart updates the part status +func (cp *uploadCheckpoint) updatePart(part UploadPart) { + cp.Parts[part.PartNumber-1].Part = part + cp.Parts[part.PartNumber-1].IsCompleted = true +} + +// todoParts returns unfinished parts +func (cp *uploadCheckpoint) todoParts() []FileChunk { + fcs := []FileChunk{} + for _, part := range cp.Parts { + if !part.IsCompleted { + fcs = append(fcs, part.Chunk) + } + } + return fcs +} + +// allParts returns all parts +func (cp *uploadCheckpoint) allParts() []UploadPart { + ps := []UploadPart{} + for _, part := range cp.Parts { + ps = append(ps, part.Part) + } + return ps +} + +// getCompletedBytes returns completed bytes count +func (cp *uploadCheckpoint) getCompletedBytes() int64 { + var completedBytes int64 + for _, part := range cp.Parts { + if part.IsCompleted { + completedBytes += part.Chunk.Size + } + } + return completedBytes +} + +// calcFileMD5 calculates the MD5 for the specified local file +func calcFileMD5(filePath string) (string, error) { + return "", nil +} + +// prepare initializes the multipart upload +func prepare(cp *uploadCheckpoint, objectKey, filePath string, partSize int64, bucket *Bucket, options []Option) error { + // CP + cp.Magic = uploadCpMagic + cp.FilePath = filePath + cp.ObjectKey = objectKey + + // Local file + fd, err := os.Open(filePath) + if err != nil { + return err + } + defer fd.Close() + + st, err := fd.Stat() + if err != nil { + return err + } + cp.FileStat.Size = st.Size() + cp.FileStat.LastModified = st.ModTime() + callbackVal, _ := FindOption(options, HTTPHeaderOssCallback, "") + cp.CallbackVal = callbackVal.(string) + callbackBody, _ := FindOption(options, responseBody, nil) + if callbackBody != nil { + body, _ := json.Marshal(callbackBody) + cp.CallbackBody = &body + } + md, err := calcFileMD5(filePath) + if err != nil { + return err + } + cp.FileStat.MD5 = md + + // Chunks + parts, err := SplitFileByPartSize(filePath, partSize) + if err != nil { + return err + } + + cp.Parts = make([]cpPart, len(parts)) + for i, part := range parts { + cp.Parts[i].Chunk = part + cp.Parts[i].IsCompleted = false + } + + // Init load + imur, err := bucket.InitiateMultipartUpload(objectKey, options...) + if err != nil { + return err + } + cp.UploadID = imur.UploadID + + return nil +} + +// complete completes the multipart upload and deletes the local CP files +func complete(cp *uploadCheckpoint, bucket *Bucket, parts []UploadPart, cpFilePath string, options []Option) error { + imur := InitiateMultipartUploadResult{Bucket: bucket.BucketName, + Key: cp.ObjectKey, UploadID: cp.UploadID} + + _, err := bucket.CompleteMultipartUpload(imur, parts, options...) + if err != nil { + if e, ok := err.(ServiceError);ok && (e.StatusCode == 203 || e.StatusCode == 404) { + os.Remove(cpFilePath) + } + return err + } + os.Remove(cpFilePath) + return err +} + +// uploadFileWithCp handles concurrent upload with checkpoint +func (bucket Bucket) uploadFileWithCp(objectKey, filePath string, partSize int64, options []Option, cpFilePath string, routines int) error { + listener := GetProgressListener(options) + + partOptions := ChoiceTransferPartOption(options) + completeOptions := ChoiceCompletePartOption(options) + + // Load CP data + ucp := uploadCheckpoint{} + err := ucp.load(cpFilePath) + if err != nil { + os.Remove(cpFilePath) + } + + // Load error or the CP data is invalid. + valid, err := ucp.isValid(filePath,options) + if err != nil || !valid { + if err = prepare(&ucp, objectKey, filePath, partSize, &bucket, options); err != nil { + return err + } + os.Remove(cpFilePath) + } + + chunks := ucp.todoParts() + imur := InitiateMultipartUploadResult{ + Bucket: bucket.BucketName, + Key: objectKey, + UploadID: ucp.UploadID} + + jobs := make(chan FileChunk, len(chunks)) + results := make(chan UploadPart, len(chunks)) + failed := make(chan error) + die := make(chan bool) + + completedBytes := ucp.getCompletedBytes() + + // why RwBytes in ProgressEvent is 0 ? + // because read or write event has been notified in teeReader.Read() + event := newProgressEvent(TransferStartedEvent, completedBytes, ucp.FileStat.Size, 0) + publishProgress(listener, event) + + // Start the workers + arg := workerArg{&bucket, filePath, imur, partOptions, uploadPartHooker} + for w := 1; w <= routines; w++ { + go worker(w, arg, jobs, results, failed, die) + } + + // Schedule jobs + go scheduler(jobs, chunks) + + // Waiting for the job finished + completed := 0 + for completed < len(chunks) { + select { + case part := <-results: + completed++ + ucp.updatePart(part) + ucp.dump(cpFilePath) + completedBytes += ucp.Parts[part.PartNumber-1].Chunk.Size + event = newProgressEvent(TransferDataEvent, completedBytes, ucp.FileStat.Size, ucp.Parts[part.PartNumber-1].Chunk.Size) + publishProgress(listener, event) + case err := <-failed: + close(die) + event = newProgressEvent(TransferFailedEvent, completedBytes, ucp.FileStat.Size, 0) + publishProgress(listener, event) + return err + } + + if completed >= len(chunks) { + break + } + } + + event = newProgressEvent(TransferCompletedEvent, completedBytes, ucp.FileStat.Size, 0) + publishProgress(listener, event) + + // Complete the multipart upload + err = complete(&ucp, &bucket, ucp.allParts(), cpFilePath, completeOptions) + return err +} diff --git a/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go new file mode 100644 index 00000000000..8f3f035003a --- /dev/null +++ b/vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go @@ -0,0 +1,674 @@ +package oss + +import ( + "bytes" + "errors" + "fmt" + "hash/crc32" + "hash/crc64" + "io" + "net/http" + "os" + "runtime" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +var sys_name string +var sys_release string +var sys_machine string + +var ( + escQuot = []byte(""") // shorter than """ + escApos = []byte("'") // shorter than "'" + escAmp = []byte("&") + escLT = []byte("<") + escGT = []byte(">") + escTab = []byte(" ") + escNL = []byte(" ") + escCR = []byte(" ") + escFFFD = []byte("\uFFFD") // Unicode replacement character +) + +func init() { + sys_name = runtime.GOOS + sys_release = "-" + sys_machine = runtime.GOARCH +} + +// userAgent gets user agent +// It has the SDK version information, OS information and GO version +func userAgent() string { + sys := getSysInfo() + return fmt.Sprintf("aliyun-sdk-go/%s (%s/%s/%s;%s)", Version, sys.name, + sys.release, sys.machine, runtime.Version()) +} + +type sysInfo struct { + name string // OS name such as windows/Linux + release string // OS version 2.6.32-220.23.2.ali1089.el5.x86_64 etc + machine string // CPU type amd64/x86_64 +} + +// getSysInfo gets system info +// gets the OS information and CPU type +func getSysInfo() sysInfo { + return sysInfo{name: sys_name, release: sys_release, machine: sys_machine} +} + +// GetRangeConfig gets the download range from the options. +func GetRangeConfig(options []Option) (*UnpackedRange, error) { + rangeOpt, err := FindOption(options, HTTPHeaderRange, nil) + if err != nil || rangeOpt == nil { + return nil, err + } + return ParseRange(rangeOpt.(string)) +} + +// UnpackedRange +type UnpackedRange struct { + HasStart bool // Flag indicates if the start point is specified + HasEnd bool // Flag indicates if the end point is specified + Start int64 // Start point + End int64 // End point +} + +// InvalidRangeError returns invalid range error +func InvalidRangeError(r string) error { + return fmt.Errorf("InvalidRange %s", r) +} + +func GetRangeString(unpackRange UnpackedRange) string { + var strRange string + if unpackRange.HasStart && unpackRange.HasEnd { + strRange = fmt.Sprintf("%d-%d", unpackRange.Start, unpackRange.End) + } else if unpackRange.HasStart { + strRange = fmt.Sprintf("%d-", unpackRange.Start) + } else if unpackRange.HasEnd { + strRange = fmt.Sprintf("-%d", unpackRange.End) + } + return strRange +} + +// ParseRange parse various styles of range such as bytes=M-N +func ParseRange(normalizedRange string) (*UnpackedRange, error) { + var err error + hasStart := false + hasEnd := false + var start int64 + var end int64 + + // Bytes==M-N or ranges=M-N + nrSlice := strings.Split(normalizedRange, "=") + if len(nrSlice) != 2 || nrSlice[0] != "bytes" { + return nil, InvalidRangeError(normalizedRange) + } + + // Bytes=M-N,X-Y + rSlice := strings.Split(nrSlice[1], ",") + rStr := rSlice[0] + + if strings.HasSuffix(rStr, "-") { // M- + startStr := rStr[:len(rStr)-1] + start, err = strconv.ParseInt(startStr, 10, 64) + if err != nil { + return nil, InvalidRangeError(normalizedRange) + } + hasStart = true + } else if strings.HasPrefix(rStr, "-") { // -N + len := rStr[1:] + end, err = strconv.ParseInt(len, 10, 64) + if err != nil { + return nil, InvalidRangeError(normalizedRange) + } + if end == 0 { // -0 + return nil, InvalidRangeError(normalizedRange) + } + hasEnd = true + } else { // M-N + valSlice := strings.Split(rStr, "-") + if len(valSlice) != 2 { + return nil, InvalidRangeError(normalizedRange) + } + start, err = strconv.ParseInt(valSlice[0], 10, 64) + if err != nil { + return nil, InvalidRangeError(normalizedRange) + } + hasStart = true + end, err = strconv.ParseInt(valSlice[1], 10, 64) + if err != nil { + return nil, InvalidRangeError(normalizedRange) + } + hasEnd = true + } + + return &UnpackedRange{hasStart, hasEnd, start, end}, nil +} + +// AdjustRange returns adjusted range, adjust the range according to the length of the file +func AdjustRange(ur *UnpackedRange, size int64) (start, end int64) { + if ur == nil { + return 0, size + } + + if ur.HasStart && ur.HasEnd { + start = ur.Start + end = ur.End + 1 + if ur.Start < 0 || ur.Start >= size || ur.End > size || ur.Start > ur.End { + start = 0 + end = size + } + } else if ur.HasStart { + start = ur.Start + end = size + if ur.Start < 0 || ur.Start >= size { + start = 0 + } + } else if ur.HasEnd { + start = size - ur.End + end = size + if ur.End < 0 || ur.End > size { + start = 0 + end = size + } + } + return +} + +// GetNowSec returns Unix time, the number of seconds elapsed since January 1, 1970 UTC. +// gets the current time in Unix time, in seconds. +func GetNowSec() int64 { + return time.Now().Unix() +} + +// GetNowNanoSec returns t as a Unix time, the number of nanoseconds elapsed +// since January 1, 1970 UTC. The result is undefined if the Unix time +// in nanoseconds cannot be represented by an int64. Note that this +// means the result of calling UnixNano on the zero Time is undefined. +// gets the current time in Unix time, in nanoseconds. +func GetNowNanoSec() int64 { + return time.Now().UnixNano() +} + +// GetNowGMT gets the current time in GMT format. +func GetNowGMT() string { + return time.Now().UTC().Format(http.TimeFormat) +} + +// FileChunk is the file chunk definition +type FileChunk struct { + Number int // Chunk number + Offset int64 // Chunk offset + Size int64 // Chunk size. +} + +// SplitFileByPartNum splits big file into parts by the num of parts. +// Split the file with specified parts count, returns the split result when error is nil. +func SplitFileByPartNum(fileName string, chunkNum int) ([]FileChunk, error) { + if chunkNum <= 0 || chunkNum > 10000 { + return nil, errors.New("chunkNum invalid") + } + + file, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer file.Close() + + stat, err := file.Stat() + if err != nil { + return nil, err + } + + if int64(chunkNum) > stat.Size() { + return nil, errors.New("oss: chunkNum invalid") + } + + var chunks []FileChunk + var chunk = FileChunk{} + var chunkN = (int64)(chunkNum) + for i := int64(0); i < chunkN; i++ { + chunk.Number = int(i + 1) + chunk.Offset = i * (stat.Size() / chunkN) + if i == chunkN-1 { + chunk.Size = stat.Size()/chunkN + stat.Size()%chunkN + } else { + chunk.Size = stat.Size() / chunkN + } + chunks = append(chunks, chunk) + } + + return chunks, nil +} + +// SplitFileByPartSize splits big file into parts by the size of parts. +// Splits the file by the part size. Returns the FileChunk when error is nil. +func SplitFileByPartSize(fileName string, chunkSize int64) ([]FileChunk, error) { + if chunkSize <= 0 { + return nil, errors.New("chunkSize invalid") + } + + file, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer file.Close() + + stat, err := file.Stat() + if err != nil { + return nil, err + } + var chunkN = stat.Size() / chunkSize + if chunkN >= 10000 { + return nil, errors.New("Too many parts, please increase part size") + } + + var chunks []FileChunk + var chunk = FileChunk{} + for i := int64(0); i < chunkN; i++ { + chunk.Number = int(i + 1) + chunk.Offset = i * chunkSize + chunk.Size = chunkSize + chunks = append(chunks, chunk) + } + + if stat.Size()%chunkSize > 0 { + chunk.Number = len(chunks) + 1 + chunk.Offset = int64(len(chunks)) * chunkSize + chunk.Size = stat.Size() % chunkSize + chunks = append(chunks, chunk) + } + + return chunks, nil +} + +// GetPartEnd calculates the end position +func GetPartEnd(begin int64, total int64, per int64) int64 { + if begin+per > total { + return total - 1 + } + return begin + per - 1 +} + +// CrcTable returns the table constructed from the specified polynomial +var CrcTable = func() *crc64.Table { + return crc64.MakeTable(crc64.ECMA) +} + +// CrcTable returns the table constructed from the specified polynomial +var crc32Table = func() *crc32.Table { + return crc32.MakeTable(crc32.IEEE) +} + +// choiceTransferPartOption choices valid option supported by Uploadpart or DownloadPart +func ChoiceTransferPartOption(options []Option) []Option { + var outOption []Option + + listener, _ := FindOption(options, progressListener, nil) + if listener != nil { + outOption = append(outOption, Progress(listener.(ProgressListener))) + } + + payer, _ := FindOption(options, HTTPHeaderOssRequester, nil) + if payer != nil { + outOption = append(outOption, RequestPayer(PayerType(payer.(string)))) + } + + versionId, _ := FindOption(options, "versionId", nil) + if versionId != nil { + outOption = append(outOption, VersionId(versionId.(string))) + } + + trafficLimit, _ := FindOption(options, HTTPHeaderOssTrafficLimit, nil) + if trafficLimit != nil { + speed, _ := strconv.ParseInt(trafficLimit.(string), 10, 64) + outOption = append(outOption, TrafficLimitHeader(speed)) + } + + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header))) + } + + return outOption +} + +// ChoiceCompletePartOption choices valid option supported by CompleteMulitiPart +func ChoiceCompletePartOption(options []Option) []Option { + var outOption []Option + + listener, _ := FindOption(options, progressListener, nil) + if listener != nil { + outOption = append(outOption, Progress(listener.(ProgressListener))) + } + + payer, _ := FindOption(options, HTTPHeaderOssRequester, nil) + if payer != nil { + outOption = append(outOption, RequestPayer(PayerType(payer.(string)))) + } + + acl, _ := FindOption(options, HTTPHeaderOssObjectACL, nil) + if acl != nil { + outOption = append(outOption, ObjectACL(ACLType(acl.(string)))) + } + + callback, _ := FindOption(options, HTTPHeaderOssCallback, nil) + if callback != nil { + outOption = append(outOption, Callback(callback.(string))) + } + + callbackVar, _ := FindOption(options, HTTPHeaderOssCallbackVar, nil) + if callbackVar != nil { + outOption = append(outOption, CallbackVar(callbackVar.(string))) + } + + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header))) + } + + forbidOverWrite, _ := FindOption(options, HTTPHeaderOssForbidOverWrite, nil) + if forbidOverWrite != nil { + if forbidOverWrite.(string) == "true" { + outOption = append(outOption, ForbidOverWrite(true)) + } else { + outOption = append(outOption, ForbidOverWrite(false)) + } + } + + notification, _ := FindOption(options, HttpHeaderOssNotification, nil) + if notification != nil { + outOption = append(outOption, SetHeader(HttpHeaderOssNotification, notification)) + } + + return outOption +} + +// ChoiceAbortPartOption choices valid option supported by AbortMultipartUpload +func ChoiceAbortPartOption(options []Option) []Option { + var outOption []Option + payer, _ := FindOption(options, HTTPHeaderOssRequester, nil) + if payer != nil { + outOption = append(outOption, RequestPayer(PayerType(payer.(string)))) + } + + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header))) + } + + return outOption +} + +// ChoiceHeadObjectOption choices valid option supported by HeadObject +func ChoiceHeadObjectOption(options []Option) []Option { + var outOption []Option + + // not select HTTPHeaderRange to get whole object length + payer, _ := FindOption(options, HTTPHeaderOssRequester, nil) + if payer != nil { + outOption = append(outOption, RequestPayer(PayerType(payer.(string)))) + } + + versionId, _ := FindOption(options, "versionId", nil) + if versionId != nil { + outOption = append(outOption, VersionId(versionId.(string))) + } + + respHeader, _ := FindOption(options, responseHeader, nil) + if respHeader != nil { + outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header))) + } + + return outOption +} + +func CheckBucketName(bucketName string) error { + nameLen := len(bucketName) + if nameLen < 3 || nameLen > 63 { + return fmt.Errorf("bucket name %s len is between [3-63],now is %d", bucketName, nameLen) + } + + for _, v := range bucketName { + if !(('a' <= v && v <= 'z') || ('0' <= v && v <= '9') || v == '-') { + return fmt.Errorf("bucket name %s can only include lowercase letters, numbers, and -", bucketName) + } + } + if bucketName[0] == '-' || bucketName[nameLen-1] == '-' { + return fmt.Errorf("bucket name %s must start and end with a lowercase letter or number", bucketName) + } + return nil +} + +func CheckObjectName(objectName string) error { + if len(objectName) == 0 { + return fmt.Errorf("object name is empty") + } + return nil +} + +func CheckObjectNameEx(objectName string, strict bool) error { + if err := CheckObjectName(objectName); err != nil { + return err + } + + if strict && strings.HasPrefix(objectName, "?") { + return fmt.Errorf("object name is invalid, can't start with '?'") + } + + return nil +} + +/* + func GetReaderLen(reader io.Reader) (int64, error) { + var contentLength int64 + var err error + switch v := reader.(type) { + case *bytes.Buffer: + contentLength = int64(v.Len()) + case *bytes.Reader: + contentLength = int64(v.Len()) + case *strings.Reader: + contentLength = int64(v.Len()) + case *os.File: + fInfo, fError := v.Stat() + if fError != nil { + err = fmt.Errorf("can't get reader content length,%s", fError.Error()) + } else { + contentLength = fInfo.Size() + } + case *io.LimitedReader: + contentLength = int64(v.N) + case *LimitedReadCloser: + contentLength = int64(v.N) + default: + err = fmt.Errorf("can't get reader content length,unkown reader type") + } + return contentLength, err + } +*/ + +func GetReaderLen(reader io.Reader) (int64, error) { + var contentLength int64 + var err error + switch v := reader.(type) { + case *io.LimitedReader: + contentLength = int64(v.N) + case *LimitedReadCloser: + contentLength = int64(v.N) + default: + // Len + type lenner interface { + Len() int + } + if lr, ok := reader.(lenner); ok { + return int64(lr.Len()), nil + } + // seeker len + if s, ok := reader.(io.Seeker); ok { + curOffset, err := s.Seek(0, io.SeekCurrent) + if err != nil { + return 0, err + } + endOffset, err := s.Seek(0, io.SeekEnd) + if err != nil { + return 0, err + } + _, err = s.Seek(curOffset, io.SeekStart) + if err != nil { + return 0, err + } + n := endOffset - curOffset + if n >= 0 { + return n, nil + } + } + // + err = fmt.Errorf("can't get reader content length,unkown reader type") + } + return contentLength, err +} + +func LimitReadCloser(r io.Reader, n int64) io.Reader { + var lc LimitedReadCloser + lc.R = r + lc.N = n + return &lc +} + +// LimitedRC support Close() +type LimitedReadCloser struct { + io.LimitedReader +} + +func (lc *LimitedReadCloser) Close() error { + if closer, ok := lc.R.(io.ReadCloser); ok { + return closer.Close() + } + return nil +} + +type DiscardReadCloser struct { + RC io.ReadCloser + Discard int +} + +func (drc *DiscardReadCloser) Read(b []byte) (int, error) { + n, err := drc.RC.Read(b) + if drc.Discard == 0 || n <= 0 { + return n, err + } + + if n <= drc.Discard { + drc.Discard -= n + return 0, err + } + + realLen := n - drc.Discard + copy(b[0:realLen], b[drc.Discard:n]) + drc.Discard = 0 + return realLen, err +} + +func (drc *DiscardReadCloser) Close() error { + closer, ok := drc.RC.(io.ReadCloser) + if ok { + return closer.Close() + } + return nil +} + +func ConvertEmptyValueToNil(params map[string]interface{}, keys []string) { + for _, key := range keys { + value, ok := params[key] + if ok && value == "" { + // convert "" to nil + params[key] = nil + } + } +} + +func EscapeLFString(str string) string { + var log bytes.Buffer + for i := 0; i < len(str); i++ { + if str[i] != '\n' { + log.WriteByte(str[i]) + } else { + log.WriteString("\\n") + } + } + return log.String() +} + +// EscapeString writes to p the properly escaped XML equivalent +// of the plain text data s. +func EscapeXml(s string) string { + var p strings.Builder + var esc []byte + hextable := "0123456789ABCDEF" + escPattern := []byte("�") + last := 0 + for i := 0; i < len(s); { + r, width := utf8.DecodeRuneInString(s[i:]) + i += width + switch r { + case '"': + esc = escQuot + case '\'': + esc = escApos + case '&': + esc = escAmp + case '<': + esc = escLT + case '>': + esc = escGT + case '\t': + esc = escTab + case '\n': + esc = escNL + case '\r': + esc = escCR + default: + if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) { + if r >= 0x00 && r < 0x20 { + escPattern[3] = hextable[r>>4] + escPattern[4] = hextable[r&0x0f] + esc = escPattern + } else { + esc = escFFFD + } + break + } + continue + } + p.WriteString(s[last : i-width]) + p.Write(esc) + last = i + } + p.WriteString(s[last:]) + return p.String() +} + +// Decide whether the given rune is in the XML Character Range, per +// the Char production of https://www.xml.com/axml/testaxml.htm, +// Section 2.2 Characters. +func isInCharacterRange(r rune) (inrange bool) { + return r == 0x09 || + r == 0x0A || + r == 0x0D || + r >= 0x20 && r <= 0xD7FF || + r >= 0xE000 && r <= 0xFFFD || + r >= 0x10000 && r <= 0x10FFFF +} + +func isVerifyObjectStrict(config *Config) bool { + if config != nil { + if config.AuthVersion == AuthV2 || config.AuthVersion == AuthV4 { + return false + } + return config.VerifyObjectStrict + } + return true +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/LICENSE b/vendor/github.com/baidubce/bce-sdk-go/LICENSE new file mode 100644 index 00000000000..f433b1a53f5 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/vendor/github.com/baidubce/bce-sdk-go/auth/credentials.go b/vendor/github.com/baidubce/bce-sdk-go/auth/credentials.go new file mode 100644 index 00000000000..fb1e415fd5c --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/auth/credentials.go @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// credentials.go - the credentials data structure definition + +// Package auth implements the authorization functionality for BCE. +// It use the BCE access key ID and secret access key with the specific sign algorithm to generate +// the authorization string. It also supports the temporary authorization by the STS token. +package auth + +import "errors" + +// BceCredentials define the data structure for authorization +type BceCredentials struct { + AccessKeyId string // access key id to the service + SecretAccessKey string // secret access key to the service + SessionToken string // session token generate by the STS service +} + +func (b *BceCredentials) String() string { + str := "ak: " + b.AccessKeyId + ", sk: " + b.SecretAccessKey + if len(b.SessionToken) != 0 { + return str + ", sessionToken: " + b.SessionToken + } + return str +} + +func NewBceCredentials(ak, sk string) (*BceCredentials, error) { + if len(ak) == 0 { + return nil, errors.New("accessKeyId should not be empty") + } + if len(sk) == 0 { + return nil, errors.New("secretKey should not be empty") + } + + return &BceCredentials{ak, sk, ""}, nil +} + +func NewSessionBceCredentials(ak, sk, token string) (*BceCredentials, error) { + if len(token) == 0 { + return nil, errors.New("sessionToken should not be empty") + } + + result, err := NewBceCredentials(ak, sk) + if err != nil { + return nil, err + } + result.SessionToken = token + + return result, nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/auth/signer.go b/vendor/github.com/baidubce/bce-sdk-go/auth/signer.go new file mode 100644 index 00000000000..c5c01d1a5b1 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/auth/signer.go @@ -0,0 +1,184 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// signer.go - implement the specific sign algorithm of BCE V1 protocol + +package auth + +import ( + "fmt" + "sort" + "strings" + + "github.com/baidubce/bce-sdk-go/http" + "github.com/baidubce/bce-sdk-go/util" + "github.com/baidubce/bce-sdk-go/util/log" +) + +var ( + BCE_AUTH_VERSION = "bce-auth-v1" + SIGN_JOINER = "\n" + SIGN_HEADER_JOINER = ";" + DEFAULT_EXPIRE_SECONDS = 1800 + DEFAULT_HEADERS_TO_SIGN = map[string]struct{}{ + strings.ToLower(http.HOST): {}, + strings.ToLower(http.CONTENT_LENGTH): {}, + strings.ToLower(http.CONTENT_TYPE): {}, + strings.ToLower(http.CONTENT_MD5): {}, + } +) + +// Signer abstracts the entity that implements the `Sign` method +type Signer interface { + // Sign the given Request with the Credentials and SignOptions + Sign(*http.Request, *BceCredentials, *SignOptions) +} + +// SignOptions defines the data structure used by Signer +type SignOptions struct { + HeadersToSign map[string]struct{} + Timestamp int64 + ExpireSeconds int +} + +func (opt *SignOptions) String() string { + return fmt.Sprintf(`SignOptions [ + HeadersToSign=%s; + Timestamp=%d; + ExpireSeconds=%d + ]`, opt.HeadersToSign, opt.Timestamp, opt.ExpireSeconds) +} + +// BceV1Signer implements the v1 sign algorithm +type BceV1Signer struct{} + +// Sign - generate the authorization string from the BceCredentials and SignOptions +// +// PARAMS: +// - req: *http.Request for this sign +// - cred: *BceCredentials to access the serice +// - opt: *SignOptions for this sign algorithm +func (b *BceV1Signer) Sign(req *http.Request, cred *BceCredentials, opt *SignOptions) { + if req == nil { + log.Fatal("request should not be null for sign") + return + } + if cred == nil { + log.Fatal("credentials should not be null for sign") + return + } + + // Prepare parameters + accessKeyId := cred.AccessKeyId + secretAccessKey := cred.SecretAccessKey + signDate := util.FormatISO8601Date(util.NowUTCSeconds()) + // Modify the sign time if it is not the default value but specified by client + if opt.Timestamp != 0 { + signDate = util.FormatISO8601Date(opt.Timestamp) + } + + // Set security token if using session credentials and session token not in param + if len(cred.SessionToken) != 0 && req.Param(http.BCE_SECURITY_TOKEN) == "" { + req.SetHeader(http.BCE_SECURITY_TOKEN, cred.SessionToken) + } + + // Prepare the canonical request components + signKeyInfo := fmt.Sprintf("%s/%s/%s/%d", + BCE_AUTH_VERSION, + accessKeyId, + signDate, + opt.ExpireSeconds) + signKey := util.HmacSha256Hex(secretAccessKey, signKeyInfo) + canonicalUri := getCanonicalURIPath(req.Uri()) + canonicalQueryString := getCanonicalQueryString(req.Params()) + canonicalHeaders, signedHeadersArr := getCanonicalHeaders(req.Headers(), opt.HeadersToSign) + + // Generate signed headers string + signedHeaders := "" + if len(signedHeadersArr) > 0 { + sort.Strings(signedHeadersArr) + signedHeaders = strings.Join(signedHeadersArr, SIGN_HEADER_JOINER) + } + + // Generate signature + canonicalParts := []string{req.Method(), canonicalUri, canonicalQueryString, canonicalHeaders} + canonicalReq := strings.Join(canonicalParts, SIGN_JOINER) + log.Debug("CanonicalRequest data:\n" + canonicalReq) + signature := util.HmacSha256Hex(signKey, canonicalReq) + + // Generate auth string and add to the reqeust header + authStr := signKeyInfo + "/" + signedHeaders + "/" + signature + log.Info("Authorization=" + authStr) + + req.SetHeader(http.AUTHORIZATION, authStr) +} + +func getCanonicalURIPath(path string) string { + if len(path) == 0 { + return "/" + } + canonical_path := path + if strings.HasPrefix(path, "/") { + canonical_path = path[1:] + } + canonical_path = util.UriEncode(canonical_path, false) + return "/" + canonical_path +} + +func getCanonicalQueryString(params map[string]string) string { + if len(params) == 0 { + return "" + } + + result := make([]string, 0, len(params)) + for k, v := range params { + if strings.ToLower(k) == strings.ToLower(http.AUTHORIZATION) { + continue + } + item := "" + if len(v) == 0 { + item = fmt.Sprintf("%s=", util.UriEncode(k, true)) + } else { + item = fmt.Sprintf("%s=%s", util.UriEncode(k, true), util.UriEncode(v, true)) + } + result = append(result, item) + } + sort.Strings(result) + return strings.Join(result, "&") +} + +func getCanonicalHeaders(headers map[string]string, + headersToSign map[string]struct{}) (string, []string) { + canonicalHeaders := make([]string, 0, len(headers)) + signHeaders := make([]string, 0, len(headersToSign)) + for k, v := range headers { + headKey := strings.ToLower(k) + if headKey == strings.ToLower(http.AUTHORIZATION) { + continue + } + _, headExists := headersToSign[headKey] + if headExists || + (strings.HasPrefix(headKey, http.BCE_PREFIX) && + (headKey != http.BCE_REQUEST_ID)) { + + headVal := strings.TrimSpace(v) + encoded := util.UriEncode(headKey, true) + ":" + util.UriEncode(headVal, true) + canonicalHeaders = append(canonicalHeaders, encoded) + signHeaders = append(signHeaders, headKey) + } + } + sort.Strings(canonicalHeaders) + sort.Strings(signHeaders) + return strings.Join(canonicalHeaders, SIGN_JOINER), signHeaders +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/bce/builder.go b/vendor/github.com/baidubce/bce-sdk-go/bce/builder.go new file mode 100644 index 00000000000..1b25504cb4e --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/bce/builder.go @@ -0,0 +1,189 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// builder.go - defines the RequestBuilder structure for BCE servies + +package bce + +import ( + "encoding/json" + "fmt" +) + +// RequestBuilder holds config data for bce request. +// Some of fields are required and the others are optional. +// The builder pattern can simplify the execution of requests. +type RequestBuilder struct { + client Client + + url string // required + method string // required + queryParams map[string]string // optional + headers map[string]string // optional + body interface{} // optional + result interface{} // optional +} + +// create RequestBuilder with the client. +func NewRequestBuilder(client Client) *RequestBuilder { + return &RequestBuilder{ + client: client, + } +} + +func (b *RequestBuilder) WithURL(url string) *RequestBuilder { + b.url = url + return b +} + +func (b *RequestBuilder) WithMethod(method string) *RequestBuilder { + b.method = method + return b +} + +// set query param with the key/value directly. +func (b *RequestBuilder) WithQueryParam(key, value string) *RequestBuilder { + if b.queryParams == nil { + b.queryParams = make(map[string]string) + } + b.queryParams[key] = value + return b +} + +// set query param with the key/value only when the value is not blank. +func (b *RequestBuilder) WithQueryParamFilter(key, value string) *RequestBuilder { + if len(value) == 0 { + return b + } + return b.WithQueryParam(key, value) +} + +func (b *RequestBuilder) WithQueryParams(params map[string]string) *RequestBuilder { + if b.queryParams == nil { + b.queryParams = params + } else { + for key, value := range params { + b.queryParams[key] = value + } + } + return b +} + +func (b *RequestBuilder) WithHeader(key, value string) *RequestBuilder { + if b.headers == nil { + b.headers = make(map[string]string) + } + b.headers[key] = value + return b +} + +func (b *RequestBuilder) WithHeaders(headers map[string]string) *RequestBuilder { + if b.headers == nil { + b.headers = headers + } else { + for key, value := range headers { + b.headers[key] = value + } + } + return b +} + +func (b *RequestBuilder) WithBody(body interface{}) *RequestBuilder { + b.body = body + return b +} + +func (b *RequestBuilder) WithResult(result interface{}) *RequestBuilder { + b.result = result + return b +} + +// Do will send request to bce and get result with the builder's parameters. +func (b *RequestBuilder) Do() error { + if err := b.validate(); err != nil { + return err + } + + // build BceRequest + req, err := b.buildBceRequest() + if err != nil { + return err + } + + // get result from BceResponse + if err := b.buildBceResponse(req); err != nil { + return err + } + + return nil +} + +// Validate if the required fields are providered. +func (b *RequestBuilder) validate() error { + if len(b.url) == 0 { + return fmt.Errorf("The url can't be null.") + } + if len(b.method) == 0 { + return fmt.Errorf("The method can't be null.") + } + if b.client == nil { + return fmt.Errorf("The client can't be null.") + } + return nil +} + +func (b *RequestBuilder) buildBceRequest() (*BceRequest, error) { + // Build the request + req := &BceRequest{} + req.SetUri(b.url) + req.SetMethod(b.method) + + if b.headers != nil { + req.SetHeaders(b.headers) + } + if b.queryParams != nil { + req.SetParams(b.queryParams) + } + if b.body != nil { + bodyBytes, err := json.Marshal(b.body) + if err != nil { + return nil, err + } + body, err := NewBodyFromBytes(bodyBytes) + if err != nil { + return nil, err + } + req.SetBody(body) + } + + return req, nil +} + +func (b *RequestBuilder) buildBceResponse(req *BceRequest) error { + // Send request and get response + resp := &BceResponse{} + if err := b.client.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer resp.Body().Close() + + if b.result == nil { + return nil + } + + return resp.ParseJsonBody(b.result) +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/bce/client.go b/vendor/github.com/baidubce/bce-sdk-go/bce/client.go new file mode 100644 index 00000000000..d8ea23dbe5f --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/bce/client.go @@ -0,0 +1,279 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// client.go - definiton the BceClientConfiguration and BceClient structure + +// Package bce implements the infrastructure to access BCE services. +// +// - BceClient: +// It is the general client of BCE to access all services. It builds http request to access the +// services based on the given client configuration. +// +// - BceClientConfiguration: +// The client configuration data structure which contains endpoint, region, credentials, retry +// policy, sign options and so on. It supports most of the default value and user can also +// access or change the default with its public fields' name. +// +// - Error types: +// The error types when making request or receiving response to the BCE services contains two +// types: the BceClientError when making request to BCE services and the BceServiceError when +// recieving response from them. +// +// - BceRequest: +// The request instance stands for an request to access the BCE services. +// +// - BceResponse: +// The response instance stands for an response from the BCE services. +package bce + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "time" + + "github.com/baidubce/bce-sdk-go/auth" + "github.com/baidubce/bce-sdk-go/http" + "github.com/baidubce/bce-sdk-go/util" + "github.com/baidubce/bce-sdk-go/util/log" +) + +// Client is the general interface which can perform sending request. Different service +// will define its own client in case of specific extension. +type Client interface { + SendRequest(*BceRequest, *BceResponse) error + SendRequestFromBytes(*BceRequest, *BceResponse, []byte) error + GetBceClientConfig() *BceClientConfiguration +} + +// BceClient defines the general client to access the BCE services. +type BceClient struct { + Config *BceClientConfiguration + Signer auth.Signer // the sign algorithm +} + +// BuildHttpRequest - the helper method for the client to build http request +// +// PARAMS: +// - request: the input request object to be built +func (c *BceClient) buildHttpRequest(request *BceRequest) { + // Construct the http request instance for the special fields + request.BuildHttpRequest() + + // Set the client specific configurations + if request.Endpoint() == "" { + request.SetEndpoint(c.Config.Endpoint) + } + if request.Protocol() == "" { + request.SetProtocol(DEFAULT_PROTOCOL) + } + if len(c.Config.ProxyUrl) != 0 { + request.SetProxyUrl(c.Config.ProxyUrl) + } + request.SetTimeout(c.Config.ConnectionTimeoutInMillis / 1000) + + // Set the BCE request headers + request.SetHeader(http.HOST, request.Host()) + request.SetHeader(http.USER_AGENT, c.Config.UserAgent) + request.SetHeader(http.BCE_DATE, util.FormatISO8601Date(util.NowUTCSeconds())) + + //set default content-type if null + if request.Header(http.CONTENT_TYPE) == "" { + request.SetHeader(http.CONTENT_TYPE, DEFAULT_CONTENT_TYPE) + } + + // Generate the auth string if needed + if c.Config.Credentials != nil { + c.Signer.Sign(&request.Request, c.Config.Credentials, c.Config.SignOption) + } +} + +// SendRequest - the client performs sending the http request with retry policy and receive the +// response from the BCE services. +// +// PARAMS: +// - req: the request object to be sent to the BCE service +// - resp: the response object to receive the content from BCE service +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func (c *BceClient) SendRequest(req *BceRequest, resp *BceResponse) error { + // Return client error if it is not nil + if req.ClientError() != nil { + return req.ClientError() + } + + // Build the http request and prepare to send + c.buildHttpRequest(req) + log.Infof("send http request: %v", req) + + // Send request with the given retry policy + retries := 0 + if req.Body() != nil { + defer req.Body().Close() // Manually close the ReadCloser body for retry + } + for { + // The request body should be temporarily saved if retry to send the http request + var retryBuf bytes.Buffer + var teeReader io.Reader + if c.Config.Retry.ShouldRetry(nil, 0) && req.Body() != nil { + teeReader = io.TeeReader(req.Body(), &retryBuf) + req.Request.SetBody(ioutil.NopCloser(teeReader)) + } + httpResp, err := http.Execute(&req.Request) + + if err != nil { + if c.Config.Retry.ShouldRetry(err, retries) { + delay_in_mills := c.Config.Retry.GetDelayBeforeNextRetryInMillis(err, retries) + time.Sleep(delay_in_mills) + } else { + return &BceClientError{ + fmt.Sprintf("execute http request failed! Retried %d times, error: %v", + retries, err)} + } + retries++ + log.Warnf("send request failed: %v, retry for %d time(s)", err, retries) + if req.Body() != nil { + ioutil.ReadAll(teeReader) + req.Request.SetBody(ioutil.NopCloser(&retryBuf)) + } + continue + } + resp.SetHttpResponse(httpResp) + resp.ParseResponse() + + log.Infof("receive http response: status: %s, debugId: %s, requestId: %s, elapsed: %v", + resp.StatusText(), resp.DebugId(), resp.RequestId(), resp.ElapsedTime()) + + if resp.ElapsedTime().Milliseconds() > DEFAULT_WARN_LOG_TIMEOUT_IN_MILLS { + log.Warnf("request time more than 5 second, debugId: %s, requestId: %s, elapsed: %v", + resp.DebugId(), resp.RequestId(), resp.ElapsedTime()) + } + for k, v := range resp.Headers() { + log.Debugf("%s=%s", k, v) + } + if resp.IsFail() { + err := resp.ServiceError() + if c.Config.Retry.ShouldRetry(err, retries) { + delay_in_mills := c.Config.Retry.GetDelayBeforeNextRetryInMillis(err, retries) + time.Sleep(delay_in_mills) + } else { + return err + } + retries++ + log.Warnf("send request failed, retry for %d time(s)", retries) + if req.Body() != nil { + ioutil.ReadAll(teeReader) + req.Request.SetBody(ioutil.NopCloser(&retryBuf)) + } + continue + } + return nil + } +} + +// SendRequestFromBytes - the client performs sending the http request with retry policy and receive the +// response from the BCE services. +// +// PARAMS: +// - req: the request object to be sent to the BCE service +// - resp: the response object to receive the content from BCE service +// - content: the content of body +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func (c *BceClient) SendRequestFromBytes(req *BceRequest, resp *BceResponse, content []byte) error { + // Return client error if it is not nil + if req.ClientError() != nil { + return req.ClientError() + } + // Build the http request and prepare to send + c.buildHttpRequest(req) + log.Infof("send http request: %v", req) + // Send request with the given retry policy + retries := 0 + for { + // The request body should be temporarily saved if retry to send the http request + buf := bytes.NewBuffer(content) + req.Request.SetBody(ioutil.NopCloser(buf)) + defer req.Request.Body().Close() // Manually close the ReadCloser body for retry + httpResp, err := http.Execute(&req.Request) + if err != nil { + if c.Config.Retry.ShouldRetry(err, retries) { + delay_in_mills := c.Config.Retry.GetDelayBeforeNextRetryInMillis(err, retries) + time.Sleep(delay_in_mills) + } else { + return &BceClientError{ + fmt.Sprintf("execute http request failed! Retried %d times, error: %v", + retries, err)} + } + retries++ + log.Warnf("send request failed: %v, retry for %d time(s)", err, retries) + continue + } + resp.SetHttpResponse(httpResp) + resp.ParseResponse() + log.Infof("receive http response: status: %s, debugId: %s, requestId: %s, elapsed: %v", + resp.StatusText(), resp.DebugId(), resp.RequestId(), resp.ElapsedTime()) + for k, v := range resp.Headers() { + log.Debugf("%s=%s", k, v) + } + if resp.IsFail() { + err := resp.ServiceError() + if c.Config.Retry.ShouldRetry(err, retries) { + delay_in_mills := c.Config.Retry.GetDelayBeforeNextRetryInMillis(err, retries) + time.Sleep(delay_in_mills) + } else { + return err + } + retries++ + log.Warnf("send request failed, retry for %d time(s)", retries) + continue + } + return nil + } +} + +func (c *BceClient) GetBceClientConfig() *BceClientConfiguration { + return c.Config +} + +func NewBceClient(conf *BceClientConfiguration, sign auth.Signer) *BceClient { + clientConfig := http.ClientConfig{RedirectDisabled: conf.RedirectDisabled} + http.InitClient(clientConfig) + return &BceClient{conf, sign} +} + +func NewBceClientWithAkSk(ak, sk, endPoint string) (*BceClient, error) { + credentials, err := auth.NewBceCredentials(ak, sk) + if err != nil { + return nil, err + } + defaultSignOptions := &auth.SignOptions{ + HeadersToSign: auth.DEFAULT_HEADERS_TO_SIGN, + ExpireSeconds: auth.DEFAULT_EXPIRE_SECONDS} + defaultConf := &BceClientConfiguration{ + Endpoint: endPoint, + Region: DEFAULT_REGION, + UserAgent: DEFAULT_USER_AGENT, + Credentials: credentials, + SignOption: defaultSignOptions, + Retry: DEFAULT_RETRY_POLICY, + ConnectionTimeoutInMillis: DEFAULT_CONNECTION_TIMEOUT_IN_MILLIS, + RedirectDisabled: false} + v1Signer := &auth.BceV1Signer{} + + return NewBceClient(defaultConf, v1Signer), nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/bce/config.go b/vendor/github.com/baidubce/bce-sdk-go/bce/config.go new file mode 100644 index 00000000000..c9e57cd8303 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/bce/config.go @@ -0,0 +1,82 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// config.go - define the client configuration for BCE + +package bce + +import ( + "fmt" + "reflect" + "runtime" + + "github.com/baidubce/bce-sdk-go/auth" +) + +// Constants and default values for the package bce +const ( + SDK_VERSION = "0.9.230" + URI_PREFIX = "/" // now support uri without prefix "v1" so just set root path + DEFAULT_DOMAIN = "baidubce.com" + DEFAULT_PROTOCOL = "http" + HTTPS_PROTOCAL = "https" + DEFAULT_REGION = "bj" + DEFAULT_CONTENT_TYPE = "application/json;charset=utf-8" + DEFAULT_CONNECTION_TIMEOUT_IN_MILLIS = 1200 * 1000 + DEFAULT_WARN_LOG_TIMEOUT_IN_MILLS = 5 * 1000 +) + +var ( + DEFAULT_USER_AGENT string + DEFAULT_RETRY_POLICY = NewBackOffRetryPolicy(3, 20000, 300) +) + +func init() { + DEFAULT_USER_AGENT = "bce-sdk-go" + DEFAULT_USER_AGENT += "/" + SDK_VERSION + DEFAULT_USER_AGENT += "/" + runtime.Version() + DEFAULT_USER_AGENT += "/" + runtime.GOOS + DEFAULT_USER_AGENT += "/" + runtime.GOARCH +} + +// BceClientConfiguration defines the config components structure. +type BceClientConfiguration struct { + Endpoint string + ProxyUrl string + Region string + UserAgent string + Credentials *auth.BceCredentials + SignOption *auth.SignOptions + Retry RetryPolicy + ConnectionTimeoutInMillis int + // CnameEnabled should be true when use custom domain as endpoint to visit bos resource + CnameEnabled bool + BackupEndpoint string + RedirectDisabled bool +} + +func (c *BceClientConfiguration) String() string { + return fmt.Sprintf(`BceClientConfiguration [ + Endpoint=%s; + ProxyUrl=%s; + Region=%s; + UserAgent=%s; + Credentials=%v; + SignOption=%v; + RetryPolicy=%v; + ConnectionTimeoutInMillis=%v; + RedirectDisabled=%v + ]`, c.Endpoint, c.ProxyUrl, c.Region, c.UserAgent, c.Credentials, + c.SignOption, reflect.TypeOf(c.Retry).Name(), c.ConnectionTimeoutInMillis, c.RedirectDisabled) +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/bce/error.go b/vendor/github.com/baidubce/bce-sdk-go/bce/error.go new file mode 100644 index 00000000000..e6256512981 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/bce/error.go @@ -0,0 +1,64 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// error.go - define the error types for BCE + +package bce + +const ( + EACCESS_DENIED = "AccessDenied" + EINAPPROPRIATE_JSON = "InappropriateJSON" + EINTERNAL_ERROR = "InternalError" + EINVALID_ACCESS_KEY_ID = "InvalidAccessKeyId" + EINVALID_HTTP_AUTH_HEADER = "InvalidHTTPAuthHeader" + EINVALID_HTTP_REQUEST = "InvalidHTTPRequest" + EINVALID_URI = "InvalidURI" + EMALFORMED_JSON = "MalformedJSON" + EINVALID_VERSION = "InvalidVersion" + EOPT_IN_REQUIRED = "OptInRequired" + EPRECONDITION_FAILED = "PreconditionFailed" + EREQUEST_EXPIRED = "RequestExpired" + ESIGNATURE_DOES_NOT_MATCH = "SignatureDoesNotMatch" +) + +// BceError abstracts the error for BCE +type BceError interface { + error +} + +// BceClientError defines the error struct for the client when making request +type BceClientError struct{ Message string } + +func (b *BceClientError) Error() string { return b.Message } + +func NewBceClientError(msg string) *BceClientError { return &BceClientError{msg} } + +// BceServiceError defines the error struct for the BCE service when receiving response +type BceServiceError struct { + Code string + Message string + RequestId string + StatusCode int +} + +func (b *BceServiceError) Error() string { + ret := "[Code: " + b.Code + ret += "; Message: " + b.Message + ret += "; RequestId: " + b.RequestId + "]" + return ret +} + +func NewBceServiceError(code, msg, reqId string, status int) *BceServiceError { + return &BceServiceError{code, msg, reqId, status} +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/bce/request.go b/vendor/github.com/baidubce/bce-sdk-go/bce/request.go new file mode 100644 index 00000000000..49eecc2ffa5 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/bce/request.go @@ -0,0 +1,224 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// request.go - defines the BCE servies request + +package bce + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + + "github.com/baidubce/bce-sdk-go/http" + "github.com/baidubce/bce-sdk-go/util" +) + +// Body defines the data structure used in BCE request. +// Every BCE request that sets the body field must set its content-length and content-md5 headers +// to ensure the correctness of the body content forcely, and users can also set the content-sha256 +// header to strengthen the correctness with the "SetHeader" method. +type Body struct { + stream io.ReadCloser + size int64 + contentMD5 string +} + +func (b *Body) Stream() io.ReadCloser { return b.stream } + +func (b *Body) SetStream(stream io.ReadCloser) { b.stream = stream } + +func (b *Body) Size() int64 { return b.size } + +func (b *Body) ContentMD5() string { return b.contentMD5 } + +// NewBodyFromBytes - build a Body object from the byte stream to be used in the http request, it +// calculates the content-md5 of the byte stream and store the size as well as the stream. +// +// PARAMS: +// - stream: byte stream +// +// RETURNS: +// - *Body: the return Body object +// - error: error if any specific error occurs +func NewBodyFromBytes(stream []byte) (*Body, error) { + buf := bytes.NewBuffer(stream) + size := int64(buf.Len()) + contentMD5, err := util.CalculateContentMD5(buf, size) + if err != nil { + return nil, err + } + buf = bytes.NewBuffer(stream) + return &Body{ioutil.NopCloser(buf), size, contentMD5}, nil +} + +// NewBodyFromString - build a Body object from the string to be used in the http request, it +// calculates the content-md5 of the byte stream and store the size as well as the stream. +// +// PARAMS: +// - str: the input string +// +// RETURNS: +// - *Body: the return Body object +// - error: error if any specific error occurs +func NewBodyFromString(str string) (*Body, error) { + buf := bytes.NewBufferString(str) + size := int64(len(str)) + contentMD5, err := util.CalculateContentMD5(buf, size) + if err != nil { + return nil, err + } + buf = bytes.NewBufferString(str) + return &Body{ioutil.NopCloser(buf), size, contentMD5}, nil +} + +// NewBodyFromFile - build a Body object from the given file name to be used in the http request, +// it calculates the content-md5 of the byte stream and store the size as well as the stream. +// +// PARAMS: +// - fname: the given file name +// +// RETURNS: +// - *Body: the return Body object +// - error: error if any specific error occurs +func NewBodyFromFile(fname string) (*Body, error) { + file, err := os.Open(fname) + if err != nil { + return nil, err + } + fileInfo, infoErr := file.Stat() + if infoErr != nil { + return nil, infoErr + } + contentMD5, md5Err := util.CalculateContentMD5(file, fileInfo.Size()) + if md5Err != nil { + return nil, md5Err + } + if _, err = file.Seek(0, 0); err != nil { + return nil, err + } + return &Body{file, fileInfo.Size(), contentMD5}, nil +} + +// NewBodyFromSectionFile - build a Body object from the given file pointer with offset and size. +// It calculates the content-md5 of the given content and store the size as well as the stream. +// +// PARAMS: +// - file: the input file pointer +// - off: offset of current section body +// - size: current section body size +// +// RETURNS: +// - *Body: the return Body object +// - error: error if any specific error occurs +func NewBodyFromSectionFile(file *os.File, off, size int64) (*Body, error) { + if _, err := file.Seek(off, 0); err != nil { + return nil, err + } + contentMD5, md5Err := util.CalculateContentMD5(file, size) + if md5Err != nil { + return nil, md5Err + } + if _, err := file.Seek(0, 0); err != nil { + return nil, err + } + section := io.NewSectionReader(file, off, size) + return &Body{ioutil.NopCloser(section), size, contentMD5}, nil +} + +// NewBodyFromSizedReader - build a Body object from the given reader with size. +// It calculates the content-md5 of the given content and store the size as well as the stream. +// +// PARAMS: +// - r: the input reader +// - size: the size to be read, -1 is read all +// +// RETURNS: +// - *Body: the return Body object +// - error: error if any specific error occurs +func NewBodyFromSizedReader(r io.Reader, size int64) (*Body, error) { + var buffer bytes.Buffer + var rlen int64 + var err error + if size >= 0 { + rlen, err = io.CopyN(&buffer, r, size) + } else { + rlen, err = io.Copy(&buffer, r) + } + if err != nil { + return nil, err + } + if rlen != int64(buffer.Len()) { // must be equal + return nil, NewBceClientError("unexpected reader") + } + if size >= 0 { + if rlen < size { + return nil, NewBceClientError("size is great than reader actual size") + } + } + contentMD5, err := util.CalculateContentMD5(bytes.NewBuffer(buffer.Bytes()), rlen) + if err != nil { + return nil, err + } + body := &Body{ + stream: ioutil.NopCloser(&buffer), + size: rlen, + contentMD5: contentMD5, + } + return body, nil +} + +// BceRequest defines the request structure for accessing BCE services +type BceRequest struct { + http.Request + requestId string + clientError *BceClientError +} + +func (b *BceRequest) RequestId() string { return b.requestId } + +func (b *BceRequest) SetRequestId(val string) { b.requestId = val } + +func (b *BceRequest) ClientError() *BceClientError { return b.clientError } + +func (b *BceRequest) SetClientError(err *BceClientError) { b.clientError = err } + +func (b *BceRequest) SetBody(body *Body) { // override SetBody derived from http.Request + b.Request.SetBody(body.Stream()) + b.SetLength(body.Size()) // set field of "net/http.Request.ContentLength" + if body.Size() > 0 { + b.SetHeader(http.CONTENT_MD5, body.ContentMD5()) + b.SetHeader(http.CONTENT_LENGTH, fmt.Sprintf("%d", body.Size())) + } +} + +func (b *BceRequest) BuildHttpRequest() { + // Only need to build the specific `requestId` field for BCE, other fields are same as the + // `http.Request` as well as its methods. + if len(b.requestId) == 0 { + // Construct the request ID with UUID + b.requestId = util.NewRequestId() + } + b.SetHeader(http.BCE_REQUEST_ID, b.requestId) +} + +func (b *BceRequest) String() string { + requestIdStr := "requestId=" + b.requestId + if b.clientError != nil { + return requestIdStr + ", client error: " + b.ClientError().Error() + } + return requestIdStr + "\n" + b.Request.String() +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/bce/response.go b/vendor/github.com/baidubce/bce-sdk-go/bce/response.go new file mode 100644 index 00000000000..94f2ae4b8c0 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/bce/response.go @@ -0,0 +1,128 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// response.go - defines the common BCE services response + +package bce + +import ( + "bytes" + "encoding/json" + "io" + "io/ioutil" + "strings" + "time" + + "github.com/baidubce/bce-sdk-go/http" +) + +// BceResponse defines the response structure for receiving BCE services response. +type BceResponse struct { + statusCode int + statusText string + requestId string + debugId string + response *http.Response + serviceError *BceServiceError +} + +func (r *BceResponse) IsFail() bool { + return r.response.StatusCode() >= 400 +} + +func (r *BceResponse) StatusCode() int { + return r.statusCode +} + +func (r *BceResponse) StatusText() string { + return r.statusText +} + +func (r *BceResponse) RequestId() string { + return r.requestId +} + +func (r *BceResponse) DebugId() string { + return r.debugId +} + +func (r *BceResponse) Header(key string) string { + return r.response.GetHeader(key) +} + +func (r *BceResponse) Headers() map[string]string { + return r.response.GetHeaders() +} + +func (r *BceResponse) Body() io.ReadCloser { + return r.response.Body() +} + +func (r *BceResponse) SetHttpResponse(response *http.Response) { + r.response = response +} + +func (r *BceResponse) ElapsedTime() time.Duration { + return r.response.ElapsedTime() +} + +func (r *BceResponse) ServiceError() *BceServiceError { + return r.serviceError +} + +func (r *BceResponse) ParseResponse() { + r.statusCode = r.response.StatusCode() + r.statusText = r.response.StatusText() + r.requestId = r.response.GetHeader(http.BCE_REQUEST_ID) + r.debugId = r.response.GetHeader(http.BCE_DEBUG_ID) + if r.IsFail() { + r.serviceError = NewBceServiceError("", r.statusText, r.requestId, r.statusCode) + + // First try to read the error `Code' and `Message' from body + rawBody, _ := ioutil.ReadAll(r.Body()) + defer r.Body().Close() + if len(rawBody) != 0 { + jsonDecoder := json.NewDecoder(bytes.NewBuffer(rawBody)) + if err := jsonDecoder.Decode(r.serviceError); err != nil { + r.serviceError = NewBceServiceError( + EMALFORMED_JSON, + "Service json error message decode failed", + r.requestId, + r.statusCode) + } + return + } + + // Then guess the `Message' from by the return status code + switch r.statusCode { + case 400: + r.serviceError.Code = EINVALID_HTTP_REQUEST + case 403: + r.serviceError.Code = EACCESS_DENIED + case 412: + r.serviceError.Code = EPRECONDITION_FAILED + case 500: + r.serviceError.Code = EINTERNAL_ERROR + default: + words := strings.Split(r.statusText, " ") + r.serviceError.Code = strings.Join(words[1:], "") + } + } +} + +func (r *BceResponse) ParseJsonBody(result interface{}) error { + defer r.Body().Close() + jsonDecoder := json.NewDecoder(r.Body()) + return jsonDecoder.Decode(result) +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/bce/retry.go b/vendor/github.com/baidubce/bce-sdk-go/bce/retry.go new file mode 100644 index 00000000000..3e05e740e73 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/bce/retry.go @@ -0,0 +1,124 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// retry.go - define the retry policy when making requests to BCE services + +package bce + +import ( + "net" + "net/http" + "strings" + "time" + + "github.com/baidubce/bce-sdk-go/util/log" +) + +// RetryPolicy defines the two methods to retry for sending request. +type RetryPolicy interface { + ShouldRetry(BceError, int) bool + GetDelayBeforeNextRetryInMillis(BceError, int) time.Duration +} + +// NoRetryPolicy just does not retry. +type NoRetryPolicy struct{} + +func (_ *NoRetryPolicy) ShouldRetry(err BceError, attempts int) bool { + return false +} + +func (_ *NoRetryPolicy) GetDelayBeforeNextRetryInMillis( + err BceError, attempts int) time.Duration { + return 0 * time.Millisecond +} + +func NewNoRetryPolicy() *NoRetryPolicy { + return &NoRetryPolicy{} +} + +// BackOffRetryPolicy implements a policy that retries with exponential back-off strategy. +// This policy will keep retrying until the maximum number of retries is reached. The delay time +// will be a fixed interval for the first time then 2 * interval for the second, 4 * internal for +// the third, and so on. +// In general, the delay time will be 2^number_of_retries_attempted*interval. When a maximum of +// delay time is specified, the delay time will never exceed this limit. +type BackOffRetryPolicy struct { + maxErrorRetry int + maxDelayInMillis int64 + baseIntervalInMillis int64 +} + +func (b *BackOffRetryPolicy) ShouldRetry(err BceError, attempts int) bool { + // Do not retry any more when retry the max times + if attempts >= b.maxErrorRetry { + return false + } + + if err == nil { + return true + } + + // Always retry on IO error + if _, ok := err.(net.Error); ok { + // context canceled should not retry + if strings.Contains(err.Error(), "context deadline exceeded") || + strings.Contains(err.Error(), "context canceled") { + return false + } + return true + } + + // Only retry on a service error + if realErr, ok := err.(*BceServiceError); ok { + switch realErr.StatusCode { + case http.StatusInternalServerError: + log.Warn("retry for internal server error(500)") + return true + case http.StatusBadGateway: + log.Warn("retry for bad gateway(502)") + return true + case http.StatusServiceUnavailable: + log.Warn("retry for service unavailable(503)") + return true + case http.StatusBadRequest: + if realErr.Code != "Http400" { + return false + } + log.Warn("retry for bad request(400)") + return true + } + + if realErr.Code == EREQUEST_EXPIRED { + log.Warn("retry for request expired") + return true + } + } + return false +} + +func (b *BackOffRetryPolicy) GetDelayBeforeNextRetryInMillis( + err BceError, attempts int) time.Duration { + if attempts < 0 { + return 0 * time.Millisecond + } + delayInMillis := (1 << uint64(attempts)) * b.baseIntervalInMillis + if delayInMillis > b.maxDelayInMillis { + return time.Duration(b.maxDelayInMillis) * time.Millisecond + } + return time.Duration(delayInMillis) * time.Millisecond +} + +func NewBackOffRetryPolicy(maxRetry int, maxDelay, base int64) *BackOffRetryPolicy { + return &BackOffRetryPolicy{maxRetry, maxDelay, base} +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/http/client.go b/vendor/github.com/baidubce/bce-sdk-go/http/client.go new file mode 100644 index 00000000000..76b5501004e --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/http/client.go @@ -0,0 +1,198 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// client.go - define the execute function to send http request and get response + +// Package http defines the structure of request and response which used to access the BCE services +// as well as the http constant headers and and methods. And finally implement the `Execute` funct- +// ion to do the work. +package http + +import ( + "net" + "net/http" + "net/url" + "sync" + "time" +) + +const ( + defaultMaxIdleConnsPerHost = 500 + defaultResponseHeaderTimeout = 60 * time.Second + defaultDialTimeout = 30 * time.Second + defaultSmallInterval = 600 * time.Second + defaultLargeInterval = 1200 * time.Second +) + +// The httpClient is the global variable to send the request and get response +// for reuse and the Client provided by the Go standard library is thread safe. +var ( + httpClient *http.Client + transport *http.Transport +) + +type timeoutConn struct { + conn net.Conn + smallInterval time.Duration + largeInterval time.Duration +} + +func (c *timeoutConn) Read(b []byte) (n int, err error) { + c.SetReadDeadline(time.Now().Add(c.smallInterval)) + n, err = c.conn.Read(b) + c.SetReadDeadline(time.Now().Add(c.largeInterval)) + return n, err +} +func (c *timeoutConn) Write(b []byte) (n int, err error) { + c.SetWriteDeadline(time.Now().Add(c.smallInterval)) + n, err = c.conn.Write(b) + c.SetWriteDeadline(time.Now().Add(c.largeInterval)) + return n, err +} +func (c *timeoutConn) Close() error { return c.conn.Close() } +func (c *timeoutConn) LocalAddr() net.Addr { return c.conn.LocalAddr() } +func (c *timeoutConn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() } +func (c *timeoutConn) SetDeadline(t time.Time) error { return c.conn.SetDeadline(t) } +func (c *timeoutConn) SetReadDeadline(t time.Time) error { return c.conn.SetReadDeadline(t) } +func (c *timeoutConn) SetWriteDeadline(t time.Time) error { return c.conn.SetWriteDeadline(t) } + +type ClientConfig struct { + RedirectDisabled bool +} + +var customizeInit sync.Once + +func InitClient(config ClientConfig) { + customizeInit.Do(func() { + httpClient = &http.Client{} + transport = &http.Transport{ + MaxIdleConnsPerHost: defaultMaxIdleConnsPerHost, + ResponseHeaderTimeout: defaultResponseHeaderTimeout, + Dial: func(network, address string) (net.Conn, error) { + conn, err := net.DialTimeout(network, address, defaultDialTimeout) + if err != nil { + return nil, err + } + tc := &timeoutConn{conn, defaultSmallInterval, defaultLargeInterval} + tc.SetReadDeadline(time.Now().Add(defaultLargeInterval)) + return tc, nil + }, + } + httpClient.Transport = transport + if config.RedirectDisabled { + httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + } + }) +} + +// Execute - do the http requset and get the response +// +// PARAMS: +// - request: the http request instance to be sent +// +// RETURNS: +// - response: the http response returned from the server +// - error: nil if ok otherwise the specific error +func Execute(request *Request) (*Response, error) { + // Build the request object for the current requesting + httpRequest := &http.Request{ + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + } + + if request.Context() != nil { + httpRequest = httpRequest.WithContext(request.Context()) + } + + // Set the connection timeout for current request + httpClient.Timeout = time.Duration(request.Timeout()) * time.Second + + // Set the request method + httpRequest.Method = request.Method() + + // Set the request url + internalUrl := &url.URL{ + Scheme: request.Protocol(), + Host: request.Host(), + Path: request.Uri(), + RawQuery: request.QueryString()} + httpRequest.URL = internalUrl + + // Set the request headers + internalHeader := make(http.Header) + for k, v := range request.Headers() { + val := make([]string, 0, 1) + val = append(val, v) + internalHeader[k] = val + } + httpRequest.Header = internalHeader + + if request.Body() != nil { + if request.Length() > 0 { + httpRequest.ContentLength = request.Length() + httpRequest.Body = request.Body() + } else if request.Length() < 0 { + // if set body and ContentLength <= 0, will be chunked + httpRequest.Body = request.Body() + } // else {} body == nil and ContentLength == 0 + } + + // Set the proxy setting if needed + if len(request.ProxyUrl()) != 0 { + transport.Proxy = func(_ *http.Request) (*url.URL, error) { + return url.Parse(request.ProxyUrl()) + } + } + + // Perform the http request and get response + // It needs to explicitly close the keep-alive connections when error occurs for the request + // that may continue sending request's data subsequently. + start := time.Now() + + httpResponse, err := httpClient.Do(httpRequest) + + end := time.Now() + if err != nil { + transport.CloseIdleConnections() + return nil, err + } + if httpResponse.StatusCode >= 400 && + (httpRequest.Method == PUT || httpRequest.Method == POST) { + transport.CloseIdleConnections() + } + response := &Response{httpResponse, end.Sub(start)} + return response, nil +} +func SetResponseHeaderTimeout(t int) { + transport = &http.Transport{ + MaxIdleConnsPerHost: defaultMaxIdleConnsPerHost, + ResponseHeaderTimeout: time.Duration(t) * time.Second, + Dial: func(network, address string) (net.Conn, error) { + conn, err := net.DialTimeout(network, address, defaultDialTimeout) + if err != nil { + return nil, err + } + tc := &timeoutConn{conn, defaultSmallInterval, defaultLargeInterval} + err = tc.SetReadDeadline(time.Now().Add(defaultLargeInterval)) + if err != nil { + return nil, err + } + return tc, nil + }, + } + httpClient.Transport = transport +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/http/constants.go b/vendor/github.com/baidubce/bce-sdk-go/http/constants.go new file mode 100644 index 00000000000..27ae864f321 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/http/constants.go @@ -0,0 +1,93 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// constants.go - defines constants of the BCE http package including headers and methods + +package http + +// Constants of the supported HTTP methods for BCE +const ( + GET = "GET" + PUT = "PUT" + POST = "POST" + DELETE = "DELETE" + HEAD = "HEAD" + OPTIONS = "OPTIONS" + PATCH = "PATCH" +) + +// Constants of the HTTP headers for BCE +const ( + // Standard HTTP Headers + AUTHORIZATION = "Authorization" + CACHE_CONTROL = "Cache-Control" + CONTENT_DISPOSITION = "Content-Disposition" + CONTENT_ENCODING = "Content-Encoding" + CONTENT_LANGUAGE = "Content-Language" + CONTENT_LENGTH = "Content-Length" + CONTENT_MD5 = "Content-Md5" + CONTENT_RANGE = "Content-Range" + CONTENT_TYPE = "Content-Type" + DATE = "Date" + ETAG = "Etag" + EXPIRES = "Expires" + HOST = "Host" + LAST_MODIFIED = "Last-Modified" + LOCATION = "Location" + RANGE = "Range" + SERVER = "Server" + TRANSFER_ENCODING = "Transfer-Encoding" + USER_AGENT = "User-Agent" + + // BCE Common HTTP Headers + BCE_PREFIX = "x-bce-" + BCE_ACL = "x-bce-acl" + BCE_GRANT_READ = "x-bce-grant-read" + BCE_GRANT_FULL_CONTROL = "x-bce-grant-full-control" + BCE_CONTENT_SHA256 = "x-bce-content-sha256" + BCE_CONTENT_CRC32 = "x-bce-content-crc32" + BCE_CONTENT_CRC32C = "x-bce-content-crc32c" + BCE_CONTENT_CRC32C_FLAG = "x-bce-content-crc32c-flag" + BCE_REQUEST_ID = "x-bce-request-id" + BCE_USER_METADATA_PREFIX = "x-bce-meta-" + BCE_SECURITY_TOKEN = "x-bce-security-token" + BCE_DATE = "x-bce-date" + BCE_TAG = "x-bce-tag-list" + + // BOS HTTP Headers + BCE_COPY_METADATA_DIRECTIVE = "x-bce-metadata-directive" + BCE_COPY_TAGGING_DIRECTIVE = "x-bce-tagging-directive" + BCE_COPY_SOURCE = "x-bce-copy-source" + BCE_COPY_SOURCE_IF_MATCH = "x-bce-copy-source-if-match" + BCE_COPY_SOURCE_IF_MODIFIED_SINCE = "x-bce-copy-source-if-modified-since" + BCE_COPY_SOURCE_IF_NONE_MATCH = "x-bce-copy-source-if-none-match" + BCE_COPY_SOURCE_IF_UNMODIFIED_SINCE = "x-bce-copy-source-if-unmodified-since" + BCE_COPY_SOURCE_RANGE = "x-bce-copy-source-range" + BCE_DEBUG_ID = "x-bce-debug-id" + BCE_OBJECT_TYPE = "x-bce-object-type" + BCE_NEXT_APPEND_OFFSET = "x-bce-next-append-offset" + BCE_STORAGE_CLASS = "x-bce-storage-class" + BCE_PROCESS = "x-bce-process" + BCE_RESTORE_TIER = "x-bce-restore-tier" + BCE_RESTORE_DAYS = "x-bce-restore-days" + BCE_RESTORE = "x-bce-restore" + BCE_FORBID_OVERWRITE = "x-bce-forbid-overwrite" + BCE_SYMLINK_TARGET = "x-bce-symlink-target" + BCE_SYMLINK_BUCKET = "x-bce-symlink-bucket" + BCE_TRAFFIC_LIMIT = "x-bce-traffic-limit" + BCE_BUCKET_TYPE = "x-bce-bucket-type" + BCE_OBJECT_TAGGING = "x-bce-tagging" + BCE_FETCH_CALLBACK_ADDRESS = "x-bce-callback-address" + BCE_VERSION_ID = "x-bce-version-id" +) diff --git a/vendor/github.com/baidubce/bce-sdk-go/http/request.go b/vendor/github.com/baidubce/bce-sdk-go/http/request.go new file mode 100644 index 00000000000..21b5eb0517a --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/http/request.go @@ -0,0 +1,237 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// request.go - the custom HTTP request for BCE + +package http + +import ( + "context" + "fmt" + "io" + "strconv" + "strings" + + "github.com/baidubce/bce-sdk-go/util" +) + +// Reauest stands for the general http request structure to make request to the BCE services. +type Request struct { + protocol string + host string + port int + method string + uri string + proxyUrl string + timeout int + headers map[string]string + params map[string]string + + // Optional body and length fields to set the body stream and content length + body io.ReadCloser + length int64 + ctx context.Context +} + +func (r *Request) Context() context.Context { + return r.ctx +} + +func (r *Request) SetContext(ctx context.Context) { + if ctx != nil { + r.ctx = ctx + } +} + +func (r *Request) Protocol() string { + return r.protocol +} + +func (r *Request) SetProtocol(protocol string) { + r.protocol = protocol +} + +func (r *Request) Endpoint() string { + if r.host == "" { + return "" + } + return r.protocol + "://" + r.host +} + +func (r *Request) SetEndpoint(endpoint string) { + pos := strings.Index(endpoint, "://") + rest := endpoint + if pos != -1 { + r.protocol = endpoint[0:pos] + rest = endpoint[pos+3:] + } else { + r.protocol = "http" + } + + r.SetHost(rest) +} + +func (r *Request) Host() string { + return r.host +} + +func (r *Request) SetHost(host string) { + r.host = host + pos := strings.Index(host, ":") + if pos != -1 { + p, e := strconv.Atoi(host[pos+1:]) + if e == nil { + r.port = p + } + } + + if r.port == 0 { + if r.protocol == "http" { + r.port = 80 + } else if r.protocol == "https" { + r.port = 443 + } + } +} + +func (r *Request) Port() int { + return r.port +} + +func (r *Request) SetPort(port int) { + // Port can be set by the endpoint or host, this method is rarely used. + r.port = port +} + +func (r *Request) Headers() map[string]string { + return r.headers +} + +func (r *Request) SetHeaders(headers map[string]string) { + r.headers = headers +} + +func (r *Request) Header(key string) string { + if v, ok := r.headers[key]; ok { + return v + } + return "" +} + +func (r *Request) SetHeader(key, value string) { + if r.headers == nil { + r.headers = make(map[string]string) + } + r.headers[key] = value +} + +func (r *Request) Params() map[string]string { + return r.params +} + +func (r *Request) SetParams(params map[string]string) { + r.params = params +} + +func (r *Request) Param(key string) string { + if v, ok := r.params[key]; ok { + return v + } + return "" +} + +func (r *Request) SetParam(key, value string) { + if r.params == nil { + r.params = make(map[string]string) + } + r.params[key] = value +} + +func (r *Request) QueryString() string { + buf := make([]string, 0, len(r.params)) + for k, v := range r.params { + if len(v) == 0 { + buf = append(buf, util.UriEncode(k, true)) + } else { + buf = append(buf, util.UriEncode(k, true)+"="+util.UriEncode(v, true)) + } + } + return strings.Join(buf, "&") +} + +func (r *Request) Method() string { + return r.method +} + +func (r *Request) SetMethod(method string) { + r.method = method +} + +func (r *Request) Uri() string { + return r.uri +} + +func (r *Request) SetUri(uri string) { + r.uri = uri +} + +func (r *Request) ProxyUrl() string { + return r.proxyUrl +} + +func (r *Request) SetProxyUrl(url string) { + r.proxyUrl = url +} + +func (r *Request) Timeout() int { + return r.timeout +} + +func (r *Request) SetTimeout(timeout int) { + r.timeout = timeout +} + +func (r *Request) Body() io.ReadCloser { + return r.body +} + +func (r *Request) SetBody(stream io.ReadCloser) { + r.body = stream +} + +func (r *Request) Length() int64 { + return r.length +} + +func (r *Request) SetLength(l int64) { + r.length = l +} + +func (r *Request) GenerateUrl(addPort bool) string { + if addPort { + return fmt.Sprintf("%s://%s:%d%s?%s", + r.protocol, r.host, r.port, r.uri, r.QueryString()) + } else { + return fmt.Sprintf("%s://%s%s?%s", r.protocol, r.host, r.uri, r.QueryString()) + } +} + +func (r *Request) String() string { + header := make([]string, 0, len(r.headers)) + for k, v := range r.headers { + header = append(header, "\t"+k+"="+v) + } + return fmt.Sprintf("\t%s %s\n%v", + r.method, r.GenerateUrl(false), strings.Join(header, "\n")) +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/http/response.go b/vendor/github.com/baidubce/bce-sdk-go/http/response.go new file mode 100644 index 00000000000..98632fc9fd0 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/http/response.go @@ -0,0 +1,74 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// response.go - the custom HTTP response for BCE + +package http + +import ( + "io" + "net/http" + "time" +) + +// Response defines the general http response structure for accessing the BCE services. +type Response struct { + httpResponse *http.Response // the standard libaray http.Response object + elapsedTime time.Duration // elapsed time just from sending request to receiving response +} + +func (r *Response) StatusText() string { + return r.httpResponse.Status +} + +func (r *Response) StatusCode() int { + return r.httpResponse.StatusCode +} + +func (r *Response) Protocol() string { + return r.httpResponse.Proto +} + +func (r *Response) HttpResponse() *http.Response { + return r.httpResponse +} + +func (r *Response) SetHttpResponse(response *http.Response) { + r.httpResponse = response +} + +func (r *Response) ElapsedTime() time.Duration { + return r.elapsedTime +} + +func (r *Response) GetHeader(name string) string { + return r.httpResponse.Header.Get(name) +} + +func (r *Response) GetHeaders() map[string]string { + header := r.httpResponse.Header + ret := make(map[string]string, len(header)) + for k, v := range header { + ret[k] = v[0] + } + return ret +} + +func (r *Response) ContentLength() int64 { + return r.httpResponse.ContentLength +} + +func (r *Response) Body() io.ReadCloser { + return r.httpResponse.Body +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/bucket.go b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/bucket.go new file mode 100644 index 00000000000..486025b958f --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/bucket.go @@ -0,0 +1,1387 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// bucket.go - the bucket APIs definition supported by the BOS service + +// Package api defines all APIs supported by the BOS service of BCE. +package api + +import ( + "encoding/json" + "fmt" + "strconv" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +// ListBuckets - list all buckets of the account +// +// PARAMS: +// - cli: the client agent which can perform sending request +// RETURNS: +// - *ListBucketsResult: the result bucket list structure +// - error: nil if ok otherwise the specific error +func ListBuckets(cli bce.Client, ctx *BosContext) (*ListBucketsResult, error) { + req := &bce.BceRequest{} + req.SetMethod(http.GET) + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListBucketsResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// ListObjects - list all objects of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - args: the optional arguments to list objects +// RETURNS: +// - *ListObjectsResult: the result object list structure +// - error: nil if ok otherwise the specific error +func ListObjects(cli bce.Client, bucket string, + args *ListObjectsArgs, ctx *BosContext) (*ListObjectsResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + ctx.Bucket = bucket + // Optional arguments settings + if args != nil { + if len(args.Delimiter) != 0 { + req.SetParam("delimiter", args.Delimiter) + } + if len(args.Marker) != 0 { + req.SetParam("marker", args.Marker) + } + if args.MaxKeys != 0 { + req.SetParam("maxKeys", strconv.Itoa(args.MaxKeys)) + } + if len(args.Prefix) != 0 { + req.SetParam("prefix", args.Prefix) + } + } + if args == nil || args.MaxKeys == 0 { + req.SetParam("maxKeys", "1000") + } + + // Send the request and get result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListObjectsResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return result, nil +} + +func ListObjectsVersions(cli bce.Client, bucket string, + args *ListObjectsArgs, ctx *BosContext) (*ListObjectsResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("versions", "") + ctx.Bucket = bucket + // Optional arguments settings + if args != nil { + if len(args.Delimiter) != 0 { + req.SetParam("delimiter", args.Delimiter) + } + if len(args.Marker) != 0 { + req.SetParam("marker", args.Marker) + } + if args.MaxKeys != 0 { + req.SetParam("maxKeys", strconv.Itoa(args.MaxKeys)) + } + if len(args.Prefix) != 0 { + req.SetParam("prefix", args.Prefix) + } + if len(args.VersionIdMarker) != 0 { + req.SetParam("versionIdMarker", args.VersionIdMarker) + } + } + if args == nil || args.MaxKeys == 0 { + req.SetParam("maxKeys", "1000") + } + + // Send the request and get result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListObjectsResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return result, nil +} + +// HeadBucket - test the given bucket existed and access authority +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if exists and have authority otherwise the specific error +func HeadBucket(cli bce.Client, bucket string, ctx *BosContext) (error, *bce.BceResponse) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.HEAD) + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err, resp + } + if resp.IsFail() { + return resp.ServiceError(), resp + } + defer func() { resp.Body().Close() }() + return nil, resp +} + +// PutBucket - create a new bucket with the given name +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the new bucket name +// RETURNS: +// - string: the location of the new bucket if create success +// - error: nil if create success otherwise the specific error +func PutBucket(cli bce.Client, bucket string, args *PutBucketArgs, ctx *BosContext) (string, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + ctx.Bucket = bucket + if args != nil { + if len(args.TagList) != 0 { + req.SetHeader(http.BCE_TAG, args.TagList) + } + jsonBytes, jsonErr := json.Marshal(args) + if jsonErr != nil { + return "", jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return "", err + } + req.SetBody(body) + } + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return resp.Header(http.LOCATION), nil +} + +// DeleteBucket - delete an empty bucket by given name +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name to be deleted +// RETURNS: +// - error: nil if delete success otherwise the specific error +func DeleteBucket(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketLocation - get the location of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - string: the location of the bucket +// - error: nil if delete success otherwise the specific error +func GetBucketLocation(cli bce.Client, bucket string, ctx *BosContext) (string, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("location", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + result := &LocationType{} + if err := resp.ParseJsonBody(result); err != nil { + return "", err + } + defer func() { resp.Body().Close() }() + return result.LocationConstraint, nil +} + +// PutBucketAcl - set the acl of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - cannedAcl: support private, public-read, public-read-write +// - aclBody: the acl file body +// RETURNS: +// - error: nil if delete success otherwise the specific error +func PutBucketAcl(cli bce.Client, bucket, cannedAcl string, aclBody *bce.Body, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("acl", "") + ctx.Bucket = bucket + // The acl setting + if len(cannedAcl) != 0 && aclBody != nil { + return bce.NewBceClientError("BOS does not support cannedAcl and acl file at the same time") + } + if validCannedAcl(cannedAcl) { + req.SetHeader(http.BCE_ACL, cannedAcl) + } + if aclBody != nil { + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + req.SetBody(aclBody) + } + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketAcl - get the acl of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - *GetBucketAclResult: the result of the bucket acl +// - error: nil if success otherwise the specific error +func GetBucketAcl(cli bce.Client, bucket string, ctx *BosContext) (*GetBucketAclResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("acl", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketAclResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return result, nil +} + +// PutBucketLogging - set the logging prefix of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - logging: the logging prefix json string body +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketLogging(cli bce.Client, bucket string, logging *bce.Body, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("logging", "") + req.SetBody(logging) + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketLogging - get the logging config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - *GetBucketLoggingResult: the logging setting of the bucket +// - error: nil if success otherwise the specific error +func GetBucketLogging(cli bce.Client, bucket string, ctx *BosContext) (*GetBucketLoggingResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("logging", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketLoggingResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// DeleteBucketLogging - delete the logging setting of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteBucketLogging(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("logging", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PutBucketLifecycle - set the lifecycle rule of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - lifecycle: the lifecycle rule json string body +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketLifecycle(cli bce.Client, bucket string, lifecycle *bce.Body, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("lifecycle", "") + req.SetBody(lifecycle) + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketLifecycle - get the lifecycle rule of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - *GetBucketLifecycleResult: the lifecycle rule of the bucket +// - error: nil if success otherwise the specific error +func GetBucketLifecycle(cli bce.Client, bucket string, ctx *BosContext) (*GetBucketLifecycleResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("lifecycle", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketLifecycleResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// DeleteBucketLifecycle - delete the lifecycle rule of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteBucketLifecycle(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("lifecycle", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PutBucketStorageclass - set the storage class of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - storageClass: the storage class string +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketStorageclass(cli bce.Client, bucket, storageClass string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("storageClass", "") + ctx.Bucket = bucket + obj := &StorageClassType{storageClass} + jsonBytes, jsonErr := json.Marshal(obj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + req.SetBody(body) + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketStorageclass - get the storage class of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - string: the storage class of the bucket +// - error: nil if success otherwise the specific error +func GetBucketStorageclass(cli bce.Client, bucket string, ctx *BosContext) (string, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("storageClass", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + result := &StorageClassType{} + if err := resp.ParseJsonBody(result); err != nil { + return "", err + } + return result.StorageClass, nil +} + +// PutBucketReplication - set the bucket replication of different region +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - replicationConf: the replication config body stream +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketReplication(cli bce.Client, bucket string, replicationConf *bce.Body, replicationRuleId string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("replication", "") + ctx.Bucket = bucket + if len(replicationRuleId) > 0 { + req.SetParam("id", replicationRuleId) + } + + if replicationConf != nil { + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + req.SetBody(replicationConf) + } + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketReplication - get the bucket replication config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// RETURNS: +// - *GetBucketReplicationResult: the result of the bucket replication config +// - error: nil if success otherwise the specific error +func GetBucketReplication(cli bce.Client, bucket string, replicationRuleId string, ctx *BosContext) (*GetBucketReplicationResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("replication", "") + ctx.Bucket = bucket + if len(replicationRuleId) > 0 { + req.SetParam("id", replicationRuleId) + } + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketReplicationResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// ListBucketReplication - list all replication config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if success otherwise the specific error +func ListBucketReplication(cli bce.Client, bucket string, ctx *BosContext) (*ListBucketReplicationResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("replication", "") + req.SetParam("list", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListBucketReplicationResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// DeleteBucketReplication - delete the bucket replication config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteBucketReplication(cli bce.Client, bucket string, replicationRuleId string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("replication", "") + ctx.Bucket = bucket + if len(replicationRuleId) > 0 { + req.SetParam("id", replicationRuleId) + } + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketReplicationProgress - get the bucket replication process of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// RETURNS: +// - *GetBucketReplicationProgressResult: the result of the bucket replication process +// - error: nil if success otherwise the specific error +func GetBucketReplicationProgress(cli bce.Client, bucket string, replicationRuleId string, ctx *BosContext) ( + *GetBucketReplicationProgressResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("replicationProgress", "") + ctx.Bucket = bucket + if len(replicationRuleId) > 0 { + req.SetParam("id", replicationRuleId) + } + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketReplicationProgressResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// PutBucketEncryption - set the bucket encrpytion config +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - algorithm: the encryption algorithm +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketEncryption(cli bce.Client, bucket, algorithm string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("encryption", "") + ctx.Bucket = bucket + obj := &BucketEncryptionType{algorithm} + jsonBytes, jsonErr := json.Marshal(obj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + req.SetBody(body) + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketEncryption - get the encryption config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - algorithm: the bucket encryption algorithm +// - error: nil if success otherwise the specific error +func GetBucketEncryption(cli bce.Client, bucket string, ctx *BosContext) (string, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("encryption", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + result := &BucketEncryptionType{} + if err := resp.ParseJsonBody(result); err != nil { + return "", err + } + return result.EncryptionAlgorithm, nil +} + +// DeleteBucketEncryption - delete the encryption config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteBucketEncryption(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("encryption", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PutBucketStaticWebsite - set the bucket static website config +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - confBody: the static website config body stream +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketStaticWebsite(cli bce.Client, bucket string, confBody *bce.Body, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("website", "") + ctx.Bucket = bucket + if confBody != nil { + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + req.SetBody(confBody) + } + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketStaticWebsite - get the static website config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - result: the bucket static website config result object +// - error: nil if success otherwise the specific error +func GetBucketStaticWebsite(cli bce.Client, bucket string, ctx *BosContext) ( + *GetBucketStaticWebsiteResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("website", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketStaticWebsiteResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// DeleteBucketStaticWebsite - delete the static website config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteBucketStaticWebsite(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("website", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PutBucketCors - set the bucket CORS config +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - confBody: the CORS config body stream +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketCors(cli bce.Client, bucket string, confBody *bce.Body, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("cors", "") + ctx.Bucket = bucket + if confBody != nil { + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + req.SetBody(confBody) + } + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketCors - get the CORS config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - result: the bucket CORS config result object +// - error: nil if success otherwise the specific error +func GetBucketCors(cli bce.Client, bucket string, ctx *BosContext) ( + *GetBucketCorsResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("cors", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketCorsResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// DeleteBucketCors - delete the CORS config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteBucketCors(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("cors", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PutBucketCopyrightProtection - set the copyright protection config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - resources: the resource items in the bucket to be protected +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketCopyrightProtection(cli bce.Client, ctx *BosContext, bucket string, resources ...string) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("copyrightProtection", "") + ctx.Bucket = bucket + if len(resources) == 0 { + return bce.NewBceClientError("the resource to set copyright protection is empty") + } + arg := &CopyrightProtectionType{resources} + jsonBytes, jsonErr := json.Marshal(arg) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + req.SetBody(body) + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetBucketCopyrightProtection - get the copyright protection config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - result: the bucket copyright protection resources array +// - error: nil if success otherwise the specific error +func GetBucketCopyrightProtection(cli bce.Client, bucket string, ctx *BosContext) ([]string, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("copyrightProtection", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &CopyrightProtectionType{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result.Resource, nil +} + +// DeleteBucketCopyrightProtection - delete the copyright protection config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteBucketCopyrightProtection(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("copyrightProtection", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PutBucketTrash - put the trash setting of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - trashDir: the trash dir name +// RETURNS: +// - error: nil if success otherwise the specific error +func PutBucketTrash(cli bce.Client, bucket string, trashReq PutBucketTrashReq, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("trash", "") + ctx.Bucket = bucket + reqByte, _ := json.Marshal(trashReq) + body, err := bce.NewBodyFromString(string(reqByte)) + if err != nil { + return err + } + req.SetBody(body) + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func GetBucketTrash(cli bce.Client, bucket string, ctx *BosContext) (*GetBucketTrashResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("trash", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketTrashResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +func DeleteBucketTrash(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("trash", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func PutBucketNotification(cli bce.Client, bucket string, putBucketNotificationReq PutBucketNotificationReq, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("notification", "") + ctx.Bucket = bucket + reqByte, _ := json.Marshal(putBucketNotificationReq) + body, err := bce.NewBodyFromString(string(reqByte)) + if err != nil { + return err + } + req.SetBody(body) + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func GetBucketNotification(cli bce.Client, bucket string, ctx *BosContext) (*PutBucketNotificationReq, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("notification", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &PutBucketNotificationReq{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +func DeleteBucketNotification(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("notification", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func PutBucketMirror(cli bce.Client, bucket string, putBucketMirrorArgs *PutBucketMirrorArgs, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("mirroring", "") + ctx.Bucket = bucket + reqByte, _ := json.Marshal(putBucketMirrorArgs) + body, err := bce.NewBodyFromString(string(reqByte)) + if err != nil { + return err + } + req.SetBody(body) + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func GetBucketMirror(cli bce.Client, bucket string, ctx *BosContext) (*PutBucketMirrorArgs, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("mirroring", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &PutBucketMirrorArgs{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +func DeleteBucketMirror(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("mirroring", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func PutBucketTag(cli bce.Client, bucket string, putBucketTagArgs *PutBucketTagArgs, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("tagging", "") + ctx.Bucket = bucket + reqByte, _ := json.Marshal(putBucketTagArgs) + body, err := bce.NewBodyFromString(string(reqByte)) + if err != nil { + return err + } + req.SetBody(body) + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func GetBucketTag(cli bce.Client, bucket string, ctx *BosContext) (*GetBucketTagResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("tagging", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetBucketTagResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +func DeleteBucketTag(cli bce.Client, bucket string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.DELETE) + req.SetParam("tagging", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func GetBosShareLink(cli bce.Client, bucket, prefix, shareCode string, duration int) (string, error) { + req := &bce.BceRequest{} + req.SetEndpoint(BOS_SHARE_ENDPOINT) + req.SetParam("action", "") + req.SetMethod(http.POST) + if len(shareCode) != 0 && len(shareCode) != 6 { + return "", fmt.Errorf("shareCode length must be 0 or 6") + } + if duration < 60 || duration > 64800 { + return "", fmt.Errorf("duration must between 1 minute and 18 hours") + } + bosShareReqBody := &BosShareLinkArgs{ + Bucket: bucket, + Endpoint: cli.GetBceClientConfig().Endpoint, + Prefix: prefix, + ShareCode: shareCode, + DurationSeconds: int64(duration), + } + jsonBytes, jsonErr := json.Marshal(bosShareReqBody) + if jsonErr != nil { + return "", jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return "", err + } + req.SetBody(body) + resp := &bce.BceResponse{} + if err = cli.SendRequest(req, resp); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + bosShareResBody := &BosShareResBody{} + if err := resp.ParseJsonBody(bosShareResBody); err != nil { + return "", err + } + jsonData, err := json.Marshal(bosShareResBody) + if err != nil { + return "", err + } + return string(jsonData), nil +} + +func PutBucketVersioning(cli bce.Client, bucket string, putBucketVersioningArgs *BucketVersioningArgs, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.PUT) + req.SetParam("versioning", "") + ctx.Bucket = bucket + reqByte, _ := json.Marshal(putBucketVersioningArgs) + body, err := bce.NewBodyFromString(string(reqByte)) + if err != nil { + return err + } + req.SetBody(body) + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func GetBucketVersioning(cli bce.Client, bucket string, ctx *BosContext) (*BucketVersioningArgs, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("versioning", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &BucketVersioningArgs{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/model.go b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/model.go new file mode 100644 index 00000000000..f896fd27d40 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/model.go @@ -0,0 +1,722 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// model.go - definitions of the request arguments and results data structure model + +package api + +import ( + "context" + "io" +) + +type OwnerType struct { + Id string `json:"id"` + DisplayName string `json:"displayName"` +} + +type BucketSummaryType struct { + Name string `json:"name"` + Location string `json:"location"` + CreationDate string `json:"creationDate"` + LccLocation string `json:"lccLocation,omitempty"` + EnableDedicated bool `json:"enableDedicated,omitempty"` +} + +// ListBucketsResult defines the result structure of ListBuckets api. +type ListBucketsResult struct { + Owner OwnerType `json:"owner"` + Buckets []BucketSummaryType `json:"buckets"` +} + +// ListObjectsArgs defines the optional arguments for ListObjects api. +type ListObjectsArgs struct { + Delimiter string `json:"delimiter"` + Marker string `json:"marker"` + MaxKeys int `json:"maxKeys"` + Prefix string `json:"prefix"` + VersionIdMarker string `json:"versionIdMarker,omitempty"` +} + +type ObjectSummaryType struct { + Key string `json:"key"` + LastModified string `json:"lastModified"` + ETag string `json:"eTag"` + Size int `json:"size"` + StorageClass string `json:"storageClass"` + Owner OwnerType `json:"owner"` + VersionId string `json:"versionId,omitempty"` + IsLatest int `json:"isLatest,omitempty"` +} + +type PrefixType struct { + Prefix string `json:"prefix"` +} + +type PutBucketArgs struct { + TagList string `json:"-"` + EnableMultiAz bool `json:"enableMultiAz"` + LccLocation string `json:"lccLocation,omitempty"` + EnableDedicated bool `json:"enableDedicated,omitempty"` +} + +// ListObjectsResult defines the result structure of ListObjects api. +type ListObjectsResult struct { + Name string `json:"name"` + Prefix string `json:"prefix"` + Delimiter string `json:"delimiter"` + Marker string `json:"marker"` + NextMarker string `json:"nextMarker,omitempty"` + NextVersionidMarker string `json:"nextVersionidMarker,omitempty"` + MaxKeys int `json:"maxKeys"` + IsTruncated bool `json:"isTruncated"` + Contents []ObjectSummaryType `json:"contents"` + CommonPrefixes []PrefixType `json:"commonPrefixes"` +} + +type LocationType struct { + LocationConstraint string `json:"locationConstraint"` +} + +// AclOwnerType defines the owner struct in ACL setting +type AclOwnerType struct { + Id string `json:"id"` +} + +// GranteeType defines the grantee struct in ACL setting +type GranteeType struct { + Id string `json:"id"` +} + +type AclRefererType struct { + StringLike []string `json:"stringLike"` + StringEquals []string `json:"stringEquals"` +} + +type AclCondType struct { + IpAddress []string `json:"ipAddress"` + Referer AclRefererType `json:"referer"` + VpcId []string `json:"vpcId"` +} + +// GrantType defines the grant struct in ACL setting +type GrantType struct { + Grantee []GranteeType `json:"grantee"` + Permission []string `json:"permission"` + Resource []string `json:"resource,omitempty"` + NotResource []string `json:"notResource,omitempty"` + Condition AclCondType `json:"condition,omitempty"` + Effect string `json:"effect,omitempty"` +} + +// PutBucketAclArgs defines the input args structure for putting bucket acl. +type PutBucketAclArgs struct { + AccessControlList []GrantType `json:"accessControlList"` +} + +// GetBucketAclResult defines the result structure of getting bucket acl. +type GetBucketAclResult struct { + AccessControlList []GrantType `json:"accessControlList"` + Owner AclOwnerType `json:"owner"` +} + +// PutBucketLoggingArgs defines the input args structure for putting bucket logging. +type PutBucketLoggingArgs struct { + TargetBucket string `json:"targetBucket"` + TargetPrefix string `json:"targetPrefix"` +} + +// GetBucketLoggingResult defines the result structure for getting bucket logging. +type GetBucketLoggingResult struct { + Status string `json:"status"` + TargetBucket string `json:"targetBucket,omitempty"` + TargetPrefix string `json:"targetPrefix,omitempty"` +} + +// LifecycleConditionTimeType defines the structure of time condition +type LifecycleConditionTimeType struct { + DateGreaterThan string `json:"dateGreaterThan"` +} + +// LifecycleConditionType defines the structure of condition +type LifecycleConditionType struct { + Time LifecycleConditionTimeType `json:"time"` +} + +// LifecycleActionType defines the structure of lifecycle action +type LifecycleActionType struct { + Name string `json:"name"` + StorageClass string `json:"storageClass,omitempty"` +} + +// LifecycleRuleType defines the structure of a single lifecycle rule +type LifecycleRuleType struct { + Id string `json:"id"` + Status string `json:"status"` + Resource []string `json:"resource"` + Condition LifecycleConditionType `json:"condition"` + Action LifecycleActionType `json:"action"` +} + +// GetBucketLifecycleResult defines the lifecycle argument structure for putting +type PutBucketLifecycleArgs struct { + Rule []LifecycleRuleType `json:"rule"` +} + +// GetBucketLifecycleResult defines the lifecycle result structure for getting +type GetBucketLifecycleResult struct { + Rule []LifecycleRuleType `json:"rule"` +} + +type StorageClassType struct { + StorageClass string `json:"storageClass"` +} + +// BucketReplicationDescriptor defines the description data structure +type BucketReplicationDescriptor struct { + Bucket string `json:"bucket,omitempty"` + StorageClass string `json:"storageClass,omitempty"` + Prefix string `json:"prefix,omitempty"` +} + +// BucketReplicationType defines the data structure for Put and Get of bucket replication +type BucketReplicationType struct { + Id string `json:"id"` + Status string `json:"status"` + Resource []string `json:"resource"` + NotIncludeResource []string `json:"notIncludeResource,omitempty"` + ReplicateDeletes string `json:"replicateDeletes"` + Destination *BucketReplicationDescriptor `json:"destination,omitempty"` + ReplicateHistory *BucketReplicationDescriptor `json:"replicateHistory,omitempty"` + CreateTime int64 `json:"createTime"` + DestRegion string `json:"destRegion"` +} + +type PutBucketReplicationArgs BucketReplicationType +type GetBucketReplicationResult BucketReplicationType + +// ListBucketReplicationResult defines output result for replication conf list +type ListBucketReplicationResult struct { + Rules []BucketReplicationType `json:"rules"` +} + +// GetBucketReplicationProgressResult defines output result for replication process +type GetBucketReplicationProgressResult struct { + Status string `json:"status"` + HistoryReplicationPercent float64 `json:"historyReplicationPercent"` + LatestReplicationTime string `json:"latestReplicationTime"` +} + +// BucketEncryptionType defines the data structure for Put and Get of bucket encryption +type BucketEncryptionType struct { + EncryptionAlgorithm string `json:"encryptionAlgorithm"` +} + +// BucketStaticWebsiteType defines the data structure for Put and Get of bucket static website +type BucketStaticWebsiteType struct { + Index string `json:"index"` + NotFound string `json:"notFound"` +} + +type PutBucketStaticWebsiteArgs BucketStaticWebsiteType +type GetBucketStaticWebsiteResult BucketStaticWebsiteType + +type BucketCORSType struct { + AllowedOrigins []string `json:"allowedOrigins"` + AllowedMethods []string `json:"allowedMethods"` + AllowedHeaders []string `json:"allowedHeaders,omitempty"` + AllowedExposeHeaders []string `json:"allowedExposeHeaders,omitempty"` + MaxAgeSeconds int64 `json:"maxAgeSeconds,omitempty"` +} + +// PutBucketCorsArgs defines the request argument for bucket CORS setting +type PutBucketCorsArgs struct { + CorsConfiguration []BucketCORSType `json:"corsConfiguration"` +} + +// GetBucketCorsResult defines the data structure of getting bucket CORS result +type GetBucketCorsResult struct { + CorsConfiguration []BucketCORSType `json:"corsConfiguration"` +} + +// CopyrightProtectionType defines the data structure for Put and Get copyright protection API +type CopyrightProtectionType struct { + Resource []string `json:"resource"` +} + +// ObjectAclType defines the data structure for Put and Get object acl API +type ObjectAclType struct { + AccessControlList []GrantType `json:"accessControlList"` +} + +type PutObjectAclArgs ObjectAclType +type GetObjectAclResult ObjectAclType + +// PutObjectArgs defines the optional args structure for the put object api. +type PutObjectArgs struct { + CacheControl string + ContentDisposition string + ContentMD5 string + ContentType string + ContentLength int64 + Expires string + UserMeta map[string]string + ContentSha256 string + ContentCrc32 string + StorageClass string + Process string + CannedAcl string + ObjectTagging string + TrafficLimit int64 + ContentCrc32c string + ContentCrc32cFlag bool +} + +// CopyObjectArgs defines the optional args structure for the copy object api. +type CopyObjectArgs struct { + ObjectMeta + MetadataDirective string + IfMatch string + IfNoneMatch string + IfModifiedSince string + IfUnmodifiedSince string + TrafficLimit int64 + CannedAcl string + TaggingDirective string + ObjectTagging string + ContentCrc32c string + ContentCrc32cFlag bool +} + +type MultiCopyObjectArgs struct { + StorageClass string + ObjectTagging string + TaggingDirective string +} + +type CallbackResult struct { + Result string `json:"result"` +} + +type PutObjectResult struct { + Callback CallbackResult `json:"callback"` + ContentCrc32 string `json:"-"` + ContentCrc32c string `json:"-"` +} + +// CopyObjectResult defines the result json structure for the copy object api. +type CopyObjectResult struct { + LastModified string `json:"lastModified"` + ETag string `json:"eTag"` + VersionId string `json:"versionId"` +} + +type ObjectMeta struct { + CacheControl string + ContentDisposition string + ContentEncoding string + ContentLength int64 + ContentRange string + ContentType string + ContentMD5 string + ContentSha256 string + ContentCrc32 string + Expires string + LastModified string + ETag string + UserMeta map[string]string + StorageClass string + NextAppendOffset string + ObjectType string + BceRestore string + BceObjectType string + VersionId string + ContentCrc32c string +} + +// GetObjectResult defines the result data of the get object api. +type GetObjectResult struct { + ObjectMeta + ContentLanguage string + Body io.ReadCloser +} + +// GetObjectMetaResult defines the result data of the get object meta api. +type GetObjectMetaResult struct { + ObjectMeta +} + +// SelectObjectResult defines the result data of the select object api. +type SelectObjectResult struct { + Body io.ReadCloser +} + +// selectObject request args +type SelectObjectArgs struct { + SelectType string `json:"-"` + SelectRequest *SelectObjectRequest `json:"selectRequest"` +} + +type SelectObjectRequest struct { + Expression string `json:"expression"` + ExpressionType string `json:"expressionType"` // SQL + InputSerialization *SelectObjectInput `json:"inputSerialization"` + OutputSerialization *SelectObjectOutput `json:"outputSerialization"` + RequestProgress *SelectObjectProgress `json:"requestProgress"` +} + +type SelectObjectInput struct { + CompressionType string `json:"compressionType"` + CsvParams map[string]string `json:"csv"` + JsonParams map[string]string `json:"json"` +} +type SelectObjectOutput struct { + OutputHeader bool `json:"outputHeader"` + CsvParams map[string]string `json:"csv"` + JsonParams map[string]string `json:"json"` +} +type SelectObjectProgress struct { + Enabled bool `json:"enabled"` +} + +type Prelude struct { + TotalLen uint32 + HeadersLen uint32 +} + +// selectObject response msg +type CommonMessage struct { + Prelude + Headers map[string]string // message-type/content-type…… + Crc32 uint32 // crc32 of RecordsMessage +} +type RecordsMessage struct { + CommonMessage + Records []string // csv/json seleted data, one or more records +} +type ContinuationMessage struct { + CommonMessage + BytesScanned uint64 + BytesReturned uint64 +} +type EndMessage struct { + CommonMessage +} + +// FetchObjectArgs defines the optional arguments structure for the fetch object api. +type FetchObjectArgs struct { + FetchMode string + StorageClass string + FetchCallBackAddress string +} + +// FetchObjectResult defines the result json structure for the fetch object api. +type FetchObjectResult struct { + Code string `json:"code"` + Message string `json:"message"` + RequestId string `json:"requestId"` + JobId string `json:"jobId"` +} + +// AppendObjectArgs defines the optional arguments structure for appending object. +type AppendObjectArgs struct { + Offset int64 + CacheControl string + ContentDisposition string + ContentMD5 string + ContentType string + Expires string + UserMeta map[string]string + ContentSha256 string + ContentCrc32 string + StorageClass string + TrafficLimit int64 + ContentCrc32c string + ContentCrc32cFlag bool +} + +// AppendObjectResult defines the result data structure for appending object. +type AppendObjectResult struct { + ContentMD5 string + NextAppendOffset int64 + ContentCrc32 string + ETag string + ContentCrc32c string +} + +// DeleteObjectArgs defines the input args structure for a single object. +type DeleteObjectArgs struct { + Key string `json:"key"` +} + +// DeleteMultipleObjectsResult defines the input args structure for deleting multiple objects. +type DeleteMultipleObjectsArgs struct { + Objects []DeleteObjectArgs `json:"objects"` +} + +// DeleteObjectResult defines the result structure for deleting a single object. +type DeleteObjectResult struct { + Key string `json:"key"` + Code string `json:"code"` + Message string `json:"message"` +} + +// DeleteMultipleObjectsResult defines the result structure for deleting multiple objects. +type DeleteMultipleObjectsResult struct { + Errors []DeleteObjectResult `json:"errors"` +} + +// InitiateMultipartUploadArgs defines the input arguments to initiate a multipart upload. +type InitiateMultipartUploadArgs struct { + CacheControl string + ContentDisposition string + Expires string + StorageClass string + ObjectTagging string + TaggingDirective string + CannedAcl string +} + +// InitiateMultipartUploadResult defines the result structure to initiate a multipart upload. +type InitiateMultipartUploadResult struct { + Bucket string `json:"bucket"` + Key string `json:"key"` + UploadId string `json:"uploadId"` +} + +// UploadPartArgs defines the optinoal argumets for uploading part. +type UploadPartArgs struct { + ContentMD5 string + ContentSha256 string + ContentCrc32 string + TrafficLimit int64 + ContentCrc32c string + ContentCrc32cFlag bool +} + +// UploadPartCopyArgs defines the optional arguments of UploadPartCopy. +type UploadPartCopyArgs struct { + SourceRange string + IfMatch string + IfNoneMatch string + IfModifiedSince string + IfUnmodifiedSince string + TrafficLimit int64 + ContentCrc32c string + ContentCrc32cFlag bool +} + +type PutSymlinkArgs struct { + ForbidOverwrite string + StorageClass string + UserMeta map[string]string + SymlinkBucket string +} + +// UploadInfoType defines an uploaded part info structure. +type UploadInfoType struct { + PartNumber int `json:"partNumber"` + ETag string `json:"eTag"` +} + +// CompleteMultipartUploadArgs defines the input arguments structure of CompleteMultipartUpload. +type CompleteMultipartUploadArgs struct { + Parts []UploadInfoType `json:"parts"` + UserMeta map[string]string `json:"-"` + Process string `json:"-"` + ContentCrc32 string `json:"-"` + ContentCrc32c string `json:"-"` + ContentCrc32cFlag bool `json:"-"` +} + +// CompleteMultipartUploadResult defines the result structure of CompleteMultipartUpload. +type CompleteMultipartUploadResult struct { + Location string `json:"location"` + Bucket string `json:"bucket"` + Key string `json:"key"` + ETag string `json:"eTag"` + ContentCrc32 string `json:"-"` + ContentCrc32c string `json:"-"` +} + +// ListPartsArgs defines the input optional arguments of listing parts information. +type ListPartsArgs struct { + MaxParts int + PartNumberMarker string +} + +type ListPartType struct { + PartNumber int `json:"partNumber"` + LastModified string `json:"lastModified"` + ETag string `json:"eTag"` + Size int `json:"size"` +} + +// ListPartsResult defines the parts info result from ListParts. +type ListPartsResult struct { + Bucket string `json:"bucket"` + Key string `json:"key"` + UploadId string `json:"uploadId"` + Initiated string `json:"initiated"` + Owner OwnerType `json:"owner"` + StorageClass string `json:"storageClass"` + PartNumberMarker int `json:"partNumberMarker"` + NextPartNumberMarker int `json:"nextPartNumberMarker"` + MaxParts int `json:"maxParts"` + IsTruncated bool `json:"isTruncated"` + Parts []ListPartType `json:"parts"` +} + +// ListMultipartUploadsArgs defines the optional arguments for ListMultipartUploads. +type ListMultipartUploadsArgs struct { + Delimiter string + KeyMarker string + MaxUploads int + Prefix string +} + +type ListMultipartUploadsType struct { + Key string `json:"key"` + UploadId string `json:"uploadId"` + Owner OwnerType `json:"owner"` + Initiated string `json:"initiated"` + StorageClass string `json:"storageClass,omitempty"` +} + +// ListMultipartUploadsResult defines the multipart uploads result structure. +type ListMultipartUploadsResult struct { + Bucket string `json:"bucket"` + CommonPrefixes []PrefixType `json:"commonPrefixes"` + Delimiter string `json:"delimiter"` + Prefix string `json:"prefix"` + IsTruncated bool `json:"isTruncated"` + KeyMarker string `json:"keyMarker"` + MaxUploads int `json:"maxUploads"` + NextKeyMarker string `json:"nextKeyMarker"` + Uploads []ListMultipartUploadsType `json:"uploads"` +} + +type ArchiveRestoreArgs struct { + RestoreTier string + RestoreDays int +} + +type GetBucketTrashResult struct { + TrashDir string `json:"trashDir"` +} + +type PutBucketTrashReq struct { + TrashDir string `json:"trashDir"` +} + +type PutBucketNotificationReq struct { + Notifications []PutBucketNotificationSt `json:"notifications"` +} + +type PutBucketNotificationSt struct { + Id string `json:"id"` + Name string `json:"name"` + AppId string `json:"appId"` + Status string `json:"status"` + Resources []string `json:"resources"` + Events []string `json:"events"` + Apps []PutBucketNotificationAppsSt `json:"apps"` +} + +type PutBucketNotificationAppsSt struct { + Id string `json:"id"` + EventUrl string `json:"eventUrl"` + XVars string `json:"xVars"` +} + +type MirrorConfigurationRule struct { + Prefix string `json:"prefix,omitempty"` + SourceUrl string `json:"sourceUrl"` + PassQueryString bool `json:"passQuerystring"` + Mode string `json:"mode"` + StorageClass string `json:"storageClass"` + PassHeaders []string `json:"passHeaders"` + IgnoreHeaders []string `json:"ignoreHeaders"` + CustomHeaders []HeaderPair `json:"customHeaders"` + BackSourceUrl string `json:"backSourceUrl"` + Resource string `json:"resource"` + Suffix string `json:"suffix"` + FixedKey string `json:"fixedKey"` + PrefixReplace string `json:"prefixReplace"` + Version string `json:"version"` +} + +type HeaderPair struct { + HeaderName string `json:"headerName"` + HeaderValue string `json:"headerValue"` +} + +type PutBucketMirrorArgs struct { + BucketMirroringConfiguration []MirrorConfigurationRule `json:"bucketMirroringConfiguration"` +} + +type PutBucketTagArgs struct { + Tags []Tag `json:"tags"` +} + +type Tag struct { + TagKey string `json:"tagKey"` + TagValue string `json:"tagValue"` +} + +type GetBucketTagResult struct { + Tags []BucketTag `json:"tag"` +} + +type BucketTag struct { + TagKey string `json:"tag_key"` + TagValue string `json:"tag_value"` +} + +type BosContext struct { + Bucket string + PathStyleEnable bool + Ctx context.Context +} + +type PutObjectTagArgs struct { + ObjectTags []ObjectTags `json:"tagSet"` +} + +type ObjectTags struct { + TagInfo []ObjectTag `json:"tagInfo"` +} + +type ObjectTag struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type BosShareLinkArgs struct { + Bucket string `json:"bucket"` + Endpoint string `json:"endpoint"` + Prefix string `json:"prefix"` + ShareCode string `json:"shareCode"` + DurationSeconds int64 `json:"durationSeconds"` +} + +type BosShareResBody struct { + ShareUrl string `json:"shareUrl"` + LinkExpireTime int64 `json:"linkExpireTime"` + ShareCode string `json:"shareCode"` +} + +type BucketVersioningArgs struct { + Status string `json:"status"` +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/multipart.go b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/multipart.go new file mode 100644 index 00000000000..4d13a7b29cf --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/multipart.go @@ -0,0 +1,491 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// multipart.go - the multipart-related APIs definition supported by the BOS service + +package api + +import ( + "bytes" + "fmt" + "strconv" + "strings" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" + "github.com/baidubce/bce-sdk-go/util" +) + +// InitiateMultipartUpload - initiate a multipart upload to get a upload ID +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - object: the object name +// - contentType: the content type of the object to be uploaded which should be specified, +// otherwise use the default(application/octet-stream) +// - args: the optional arguments +// +// RETURNS: +// - *InitiateMultipartUploadResult: the result data structure +// - error: nil if ok otherwise the specific error +func InitiateMultipartUpload(cli bce.Client, bucket, object, contentType string, + args *InitiateMultipartUploadArgs, ctx *BosContext) (*InitiateMultipartUploadResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.POST) + req.SetParam("uploads", "") + ctx.Bucket = bucket + if len(contentType) == 0 { + contentType = RAW_CONTENT_TYPE + } + req.SetHeader(http.CONTENT_TYPE, contentType) + + // Optional arguments settings + if args != nil { + setOptionalNullHeaders(req, map[string]string{ + http.CACHE_CONTROL: args.CacheControl, + http.CONTENT_DISPOSITION: args.ContentDisposition, + http.EXPIRES: args.Expires, + }) + + if validStorageClass(args.StorageClass) { + req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass) + } else { + if len(args.StorageClass) != 0 { + return nil, bce.NewBceClientError("invalid storage class value: " + + args.StorageClass) + } + } + if len(args.ObjectTagging) != 0 { + if ok, encodeTagging := validObjectTagging(args.ObjectTagging); ok { + req.SetHeader(http.BCE_OBJECT_TAGGING, encodeTagging) + } + } + if validMetadataDirective(args.TaggingDirective) { + req.SetHeader(http.BCE_COPY_TAGGING_DIRECTIVE, args.TaggingDirective) + } + if validCannedAcl(args.CannedAcl) { + req.SetHeader(http.BCE_ACL, args.CannedAcl) + } else { + if len(args.CannedAcl) != 0 { + return nil, bce.NewBceClientError("invalid canned acl value: " + + args.CannedAcl) + } + } + + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &InitiateMultipartUploadResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return result, nil +} + +// UploadPart - upload the single part in the multipart upload process +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - object: the object name +// - uploadId: the multipart upload id +// - partNumber: the current part number +// - content: the uploaded part content +// - args: the optional arguments +// +// RETURNS: +// - string: the etag of the uploaded part +// - error: nil if ok otherwise the specific error +func UploadPart(cli bce.Client, bucket, object, uploadId string, partNumber int, + content *bce.Body, args *UploadPartArgs, ctx *BosContext) (string, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.PUT) + req.SetParam("uploadId", uploadId) + req.SetParam("partNumber", fmt.Sprintf("%d", partNumber)) + ctx.Bucket = bucket + if content == nil { + return "", bce.NewBceClientError("upload part content should not be empty") + } + if content.Size() >= THRESHOLD_100_CONTINUE { + req.SetHeader("Expect", "100-continue") + } + req.SetBody(content) + + // Optional arguments settings + if args != nil { + setOptionalNullHeaders(req, map[string]string{ + http.CONTENT_MD5: args.ContentMD5, + http.BCE_CONTENT_SHA256: args.ContentSha256, + http.BCE_CONTENT_CRC32: args.ContentCrc32, + http.BCE_CONTENT_CRC32C: args.ContentCrc32c, + http.BCE_CONTENT_CRC32C_FLAG: strconv.FormatBool(args.ContentCrc32cFlag), + }) + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return "", bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return strings.Trim(resp.Header(http.ETAG), "\""), nil +} + +// UploadPartFromBytes - upload the single part in the multipart upload process +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - object: the object name +// - uploadId: the multipart upload id +// - partNumber: the current part number +// - content: the uploaded part content +// - args: the optional arguments +// +// RETURNS: +// - string: the etag of the uploaded part +// - error: nil if ok otherwise the specific error +func UploadPartFromBytes(cli bce.Client, bucket, object, uploadId string, partNumber int, + content []byte, args *UploadPartArgs, ctx *BosContext) (string, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.PUT) + req.SetParam("uploadId", uploadId) + req.SetParam("partNumber", fmt.Sprintf("%d", partNumber)) + ctx.Bucket = bucket + if content == nil { + return "", bce.NewBceClientError("upload part content should not be empty") + } + size := len(content) + if size >= THRESHOLD_100_CONTINUE { + req.SetHeader("Expect", "100-continue") + } + // set md5 and content-length + req.SetLength(int64(size)) + if size > 0 { + // calc md5 + if args == nil || args.ContentMD5 == "" { + buf := bytes.NewBuffer(content) + contentMD5, err := util.CalculateContentMD5(buf, int64(size)) + if err != nil { + return "", err + } + req.SetHeader(http.CONTENT_MD5, contentMD5) + } + req.SetHeader(http.CONTENT_LENGTH, fmt.Sprintf("%d", size)) + } + // Optional arguments settings + if args != nil { + setOptionalNullHeaders(req, map[string]string{ + http.CONTENT_MD5: args.ContentMD5, + http.BCE_CONTENT_SHA256: args.ContentSha256, + http.BCE_CONTENT_CRC32: args.ContentCrc32, + http.BCE_CONTENT_CRC32C: args.ContentCrc32c, + http.BCE_CONTENT_CRC32C_FLAG: strconv.FormatBool(args.ContentCrc32cFlag), + }) + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return "", bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", + TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + } + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequestFromBytes(cli, req, resp, ctx, content); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return strings.Trim(resp.Header(http.ETAG), "\""), nil +} + +// UploadPartCopy - copy the multipart data +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the destination bucket name +// - object: the destination object name +// - source: the copy source uri +// - uploadId: the multipart upload id +// - partNumber: the current part number +// - args: the optional arguments +// +// RETURNS: +// - *CopyObjectResult: the lastModified and eTag of the part +// - error: nil if ok otherwise the specific error +func UploadPartCopy(cli bce.Client, bucket, object, source, uploadId string, partNumber int, + args *UploadPartCopyArgs, ctx *BosContext) (*CopyObjectResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.PUT) + req.SetParam("uploadId", uploadId) + req.SetParam("partNumber", fmt.Sprintf("%d", partNumber)) + ctx.Bucket = bucket + if len(source) == 0 { + return nil, bce.NewBceClientError("upload part copy source should not be empty") + } + req.SetHeader(http.BCE_COPY_SOURCE, util.UriEncode(source, false)) + + // Optional arguments settings + if args != nil { + setOptionalNullHeaders(req, map[string]string{ + http.BCE_COPY_SOURCE_RANGE: args.SourceRange, + http.BCE_COPY_SOURCE_IF_MATCH: args.IfMatch, + http.BCE_COPY_SOURCE_IF_NONE_MATCH: args.IfNoneMatch, + http.BCE_COPY_SOURCE_IF_MODIFIED_SINCE: args.IfModifiedSince, + http.BCE_COPY_SOURCE_IF_UNMODIFIED_SINCE: args.IfUnmodifiedSince, + http.BCE_CONTENT_CRC32C: args.ContentCrc32c, + http.BCE_CONTENT_CRC32C_FLAG: strconv.FormatBool(args.ContentCrc32cFlag), + }) + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &CopyObjectResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// CompleteMultipartUpload - finish a multipart upload operation +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// - parts: all parts info stream +// - meta: user defined meta data +// +// RETURNS: +// - *CompleteMultipartUploadResult: the result data +// - error: nil if ok otherwise the specific error +func CompleteMultipartUpload(cli bce.Client, bucket, object, uploadId string, + body *bce.Body, args *CompleteMultipartUploadArgs, ctx *BosContext) (*CompleteMultipartUploadResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.POST) + req.SetParam("uploadId", uploadId) + ctx.Bucket = bucket + if body == nil { + return nil, bce.NewBceClientError("upload body info should not be emtpy") + } + if body.Size() >= THRESHOLD_100_CONTINUE { + req.SetHeader("Expect", "100-continue") + } + req.SetBody(body) + + // Optional arguments settings + if args.UserMeta != nil { + if err := setUserMetadata(req, args.UserMeta); err != nil { + return nil, err + } + } + if len(args.Process) != 0 { + req.SetHeader(http.BCE_PROCESS, args.Process) + } + if len(args.ContentCrc32) != 0 { + req.SetHeader(http.BCE_CONTENT_CRC32, args.ContentCrc32) + } + if len(args.ContentCrc32c) != 0 { + req.SetHeader(http.BCE_CONTENT_CRC32C, args.ContentCrc32c) + } + if args.ContentCrc32cFlag { + req.SetHeader(http.BCE_CONTENT_CRC32C_FLAG, strconv.FormatBool(args.ContentCrc32cFlag)) + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &CompleteMultipartUploadResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + headers := resp.Headers() + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok { + result.ContentCrc32 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32C)]; ok { + result.ContentCrc32c = val + } + return result, nil +} + +// AbortMultipartUpload - abort a multipart upload operation +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func AbortMultipartUpload(cli bce.Client, bucket, object, uploadId string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.DELETE) + req.SetParam("uploadId", uploadId) + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// ListParts - list the successfully uploaded parts info by upload id +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// - args: the optional arguments +// partNumberMarker: return parts after this marker +// maxParts: the max number of return parts, default and maximum is 1000 +// +// RETURNS: +// - *ListPartsResult: the uploaded parts info result +// - error: nil if ok otherwise the specific error +func ListParts(cli bce.Client, bucket, object, uploadId string, + args *ListPartsArgs, ctx *BosContext) (*ListPartsResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.GET) + req.SetParam("uploadId", uploadId) + ctx.Bucket = bucket + // Optional arguments settings + if args != nil { + if len(args.PartNumberMarker) > 0 { + req.SetParam("partNumberMarker", args.PartNumberMarker) + } + if args.MaxParts > 0 { + req.SetParam("maxParts", fmt.Sprintf("%d", args.MaxParts)) + } + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListPartsResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// ListMultipartUploads - list the unfinished uploaded parts of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the destination bucket name +// - args: the optional arguments +// +// RETURNS: +// - *ListMultipartUploadsResult: the unfinished uploaded parts info result +// - error: nil if ok otherwise the specific error +func ListMultipartUploads(cli bce.Client, bucket string, + args *ListMultipartUploadsArgs, ctx *BosContext) (*ListMultipartUploadsResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.GET) + req.SetParam("uploads", "") + ctx.Bucket = bucket + + // Optional arguments settings + if args != nil { + if len(args.Delimiter) > 0 { + req.SetParam("delimiter", args.Delimiter) + } + if len(args.KeyMarker) > 0 { + req.SetParam("keyMarker", args.KeyMarker) + } + if args.MaxUploads > 0 { + req.SetParam("maxUploads", fmt.Sprintf("%d", args.MaxUploads)) + } + if len(args.Prefix) > 0 { + req.SetParam("prefix", args.Prefix) + } + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListMultipartUploadsResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/object.go b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/object.go new file mode 100644 index 00000000000..b64196473c0 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/object.go @@ -0,0 +1,1164 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// object.go - the object APIs definition supported by the BOS service + +package api + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net" + "strconv" + "strings" + + "github.com/baidubce/bce-sdk-go/auth" + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" + "github.com/baidubce/bce-sdk-go/util" +) + +// PutObject - put the object from the string or the stream +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - object: the name of the object +// - body: the input content of the object +// - args: the optional arguments of this api +// +// RETURNS: +// - string: the etag of the object +// - error: nil if ok otherwise the specific error +func PutObject(cli bce.Client, bucket, object string, body *bce.Body, + args *PutObjectArgs, ctx *BosContext) (string, *PutObjectResult, error) { + req := &bce.BceRequest{} + NeedReturnCallback := false + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.PUT) + ctx.Bucket = bucket + if body == nil { + return "", nil, bce.NewBceClientError("PutObject body should not be emtpy") + } + if body.Size() >= THRESHOLD_100_CONTINUE { + req.SetHeader("Expect", "100-continue") + } + req.SetBody(body) + + // Optional arguments settings + if args != nil { + setOptionalNullHeaders(req, map[string]string{ + http.CACHE_CONTROL: args.CacheControl, + http.CONTENT_DISPOSITION: args.ContentDisposition, + http.CONTENT_TYPE: args.ContentType, + http.EXPIRES: args.Expires, + http.BCE_CONTENT_SHA256: args.ContentSha256, + http.BCE_CONTENT_CRC32: args.ContentCrc32, + http.BCE_CONTENT_CRC32C: args.ContentCrc32c, + http.BCE_CONTENT_CRC32C_FLAG: strconv.FormatBool(args.ContentCrc32cFlag), + }) + if args.ContentLength > 0 { + // User specified Content-Length can be smaller than the body size, so the body should + // be reset. The `net/http.Client' does not support the Content-Length bigger than the + // body size. + if args.ContentLength > body.Size() { + return "", nil, bce.NewBceClientError(fmt.Sprintf("ContentLength %d is bigger than body size %d", args.ContentLength, body.Size())) + } + body, err := bce.NewBodyFromSizedReader(body.Stream(), args.ContentLength) + if err != nil { + return "", nil, bce.NewBceClientError(err.Error()) + } + req.SetHeader(http.CONTENT_LENGTH, fmt.Sprintf("%d", args.ContentLength)) + req.SetBody(body) // re-assign body + } + + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return "", nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + + // Reset the contentMD5 if set by user + if len(args.ContentMD5) != 0 { + req.SetHeader(http.CONTENT_MD5, args.ContentMD5) + } + + if validStorageClass(args.StorageClass) { + req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass) + } else { + if len(args.StorageClass) != 0 { + return "", nil, bce.NewBceClientError("invalid storage class value: " + + args.StorageClass) + } + } + + if err := setUserMetadata(req, args.UserMeta); err != nil { + return "", nil, err + } + + if len(args.Process) != 0 { + req.SetHeader(http.BCE_PROCESS, args.Process) + if strings.HasPrefix(args.Process, "callback") { + NeedReturnCallback = true + } + } + if len(args.CannedAcl) != 0 { + if validCannedAcl(args.CannedAcl) { + req.SetHeader(http.BCE_ACL, args.CannedAcl) + } + } + if len(args.ObjectTagging) != 0 { + if ok, encodeTagging := validObjectTagging(args.ObjectTagging); ok { + req.SetHeader(http.BCE_OBJECT_TAGGING, encodeTagging) + } + } + } + // add content-type if not assigned by user + if req.Header(http.CONTENT_TYPE) == "" { + req.SetHeader(http.CONTENT_TYPE, getDefaultContentType(object)) + } + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return "", nil, err + } + if resp.IsFail() { + return "", nil, resp.ServiceError() + } + defer func() { resp.Body().Close() }() + headers := resp.Headers() + jsonBody := &PutObjectResult{} + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok { + jsonBody.ContentCrc32 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32C)]; ok { + jsonBody.ContentCrc32c = val + } + if NeedReturnCallback { + if err := resp.ParseJsonBody(jsonBody); err != nil { + return "", nil, err + } + return strings.Trim(resp.Header(http.ETAG), "\""), jsonBody, nil + } + return strings.Trim(resp.Header(http.ETAG), "\""), jsonBody, nil +} + +// CopyObject - copy one object to a new object with new bucket and/or name. It can alse set the +// metadata of the object with the same source and target. +// +// PARAMS: +// - cli: the client object which can perform sending request +// - bucket: the bucket name of the target object +// - object: the name of the target object +// - source: the source object uri +// - *CopyObjectArgs: the optional input args for copying object +// +// RETURNS: +// - *CopyObjectResult: the result object which contains etag and lastmodified +// - error: nil if ok otherwise the specific error +func CopyObject(cli bce.Client, bucket, object, source string, + args *CopyObjectArgs, ctx *BosContext) (*CopyObjectResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.PUT) + ctx.Bucket = bucket + if len(source) == 0 { + return nil, bce.NewBceClientError("copy source should not be null") + } + req.SetHeader(http.BCE_COPY_SOURCE, util.UriEncode(source, false)) + + // Optional arguments settings + if args != nil { + setOptionalNullHeaders(req, map[string]string{ + http.CACHE_CONTROL: args.CacheControl, + http.CONTENT_DISPOSITION: args.ContentDisposition, + http.CONTENT_ENCODING: args.ContentEncoding, + http.CONTENT_RANGE: args.ContentRange, + http.CONTENT_TYPE: args.ContentType, + http.EXPIRES: args.Expires, + http.LAST_MODIFIED: args.LastModified, + http.ETAG: args.ETag, + http.CONTENT_MD5: args.ContentMD5, + http.BCE_CONTENT_SHA256: args.ContentSha256, + http.BCE_OBJECT_TYPE: args.ObjectType, + http.BCE_NEXT_APPEND_OFFSET: args.NextAppendOffset, + http.BCE_COPY_SOURCE_IF_MATCH: args.IfMatch, + http.BCE_COPY_SOURCE_IF_NONE_MATCH: args.IfNoneMatch, + http.BCE_COPY_SOURCE_IF_MODIFIED_SINCE: args.IfModifiedSince, + http.BCE_COPY_SOURCE_IF_UNMODIFIED_SINCE: args.IfUnmodifiedSince, + http.BCE_CONTENT_CRC32C: args.ContentCrc32c, + http.BCE_CONTENT_CRC32C_FLAG: strconv.FormatBool(args.ContentCrc32cFlag), + }) + if validMetadataDirective(args.MetadataDirective) { + req.SetHeader(http.BCE_COPY_METADATA_DIRECTIVE, args.MetadataDirective) + } else { + if len(args.MetadataDirective) != 0 { + return nil, bce.NewBceClientError( + "invalid metadata directive value: " + args.MetadataDirective) + } + } + if validMetadataDirective(args.TaggingDirective) { + req.SetHeader(http.BCE_COPY_TAGGING_DIRECTIVE, args.TaggingDirective) + } + if len(args.ObjectTagging) != 0 { + if ok, encodeTagging := validObjectTagging(args.ObjectTagging); ok { + req.SetHeader(http.BCE_OBJECT_TAGGING, encodeTagging) + } + } + if validStorageClass(args.StorageClass) { + req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass) + } else { + if len(args.StorageClass) != 0 { + return nil, bce.NewBceClientError("invalid storage class value: " + + args.StorageClass) + } + } + + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + + if validCannedAcl(args.CannedAcl) { + req.SetHeader(http.BCE_ACL, args.CannedAcl) + } + + if err := setUserMetadata(req, args.UserMeta); err != nil { + return nil, err + } + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &CopyObjectResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + if resp.Header(http.BCE_VERSION_ID) != "" { + jsonBody.VersionId = resp.Header(http.BCE_VERSION_ID) + } + return jsonBody, nil +} + +// GetObject - get the object content with range and response-headers-specified support +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - object: the name of the object +// - args: the optional args in querysring +// - ranges: the optional range start and end to get the given object +// +// RETURNS: +// - *GetObjectResult: the output content result of the object +// - error: nil if ok otherwise the specific error +func GetObject(cli bce.Client, bucket, object string, ctx *BosContext, args map[string]string, // nolint:gocyclo + ranges ...int64) (*GetObjectResult, error) { + + if object == "" { + err := fmt.Errorf("Get Object don't accept \"\" as a parameter") + return nil, err + } + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.GET) + ctx.Bucket = bucket + // Optional arguments settings + if args != nil { + for k, v := range args { + if _, ok := GET_OBJECT_ALLOWED_RESPONSE_HEADERS[k]; ok { + req.SetParam("response"+k, v) + } + if strings.HasPrefix(k, http.BCE_PREFIX) { + req.SetParam(k, v) + } + } + } + if len(ranges) != 0 { + rangeStr := "bytes=" + if len(ranges) == 1 { + rangeStr += fmt.Sprintf("%d", ranges[0]) + "-" + } else { + rangeStr += fmt.Sprintf("%d", ranges[0]) + "-" + fmt.Sprintf("%d", ranges[1]) + } + req.SetHeader("Range", rangeStr) + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + headers := resp.Headers() + result := &GetObjectResult{} + if val, ok := headers[http.CACHE_CONTROL]; ok { + result.CacheControl = val + } + if val, ok := headers[http.CONTENT_DISPOSITION]; ok { + result.ContentDisposition = val + } + if val, ok := headers[http.CONTENT_LENGTH]; ok { + if length, err := strconv.ParseInt(val, 10, 64); err == nil { + result.ContentLength = length + } + } + if val, ok := headers[http.CONTENT_RANGE]; ok { + result.ContentRange = val + } + if val, ok := headers[http.CONTENT_TYPE]; ok { + result.ContentType = val + } + if val, ok := headers[http.CONTENT_MD5]; ok { + result.ContentMD5 = val + } + if val, ok := headers[http.EXPIRES]; ok { + result.Expires = val + } + if val, ok := headers[http.LAST_MODIFIED]; ok { + result.LastModified = val + } + if val, ok := headers[http.ETAG]; ok { + result.ETag = strings.Trim(val, "\"") + } + if val, ok := headers[http.CONTENT_LANGUAGE]; ok { + result.ContentLanguage = val + } + if val, ok := headers[http.CONTENT_ENCODING]; ok { + result.ContentEncoding = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_SHA256)]; ok { + result.ContentSha256 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok { + result.ContentCrc32 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_STORAGE_CLASS)]; ok { + result.StorageClass = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_VERSION_ID)]; ok { + result.VersionId = val + } + bcePrefix := toHttpHeaderKey(http.BCE_USER_METADATA_PREFIX) + for k, v := range headers { + if strings.Index(k, bcePrefix) == 0 { + if result.UserMeta == nil { + result.UserMeta = make(map[string]string) + } + result.UserMeta[k[len(bcePrefix):]] = v + } + } + if val, ok := headers[toHttpHeaderKey(http.BCE_OBJECT_TYPE)]; ok { + result.ObjectType = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_NEXT_APPEND_OFFSET)]; ok { + result.NextAppendOffset = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32C)]; ok { + result.ContentCrc32c = val + } + result.Body = resp.Body() + return result, nil +} + +// GetObjectMeta - get the meta data of the given object +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - object: the name of the object +// +// RETURNS: +// - *GetObjectMetaResult: the result of this api +// - error: nil if ok otherwise the specific error +func GetObjectMeta(cli bce.Client, bucket, object string, ctx *BosContext) (*GetObjectMetaResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.HEAD) + ctx.Bucket = bucket + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + headers := resp.Headers() + result := &GetObjectMetaResult{} + if val, ok := headers[http.CACHE_CONTROL]; ok { + result.CacheControl = val + } + if val, ok := headers[http.CONTENT_DISPOSITION]; ok { + result.ContentDisposition = val + } + if val, ok := headers[http.CONTENT_LENGTH]; ok { + if length, err := strconv.ParseInt(val, 10, 64); err == nil { + result.ContentLength = length + } + } + if val, ok := headers[http.CONTENT_RANGE]; ok { + result.ContentRange = val + } + if val, ok := headers[http.CONTENT_TYPE]; ok { + result.ContentType = val + } + if val, ok := headers[http.CONTENT_MD5]; ok { + result.ContentMD5 = val + } + if val, ok := headers[http.EXPIRES]; ok { + result.Expires = val + } + if val, ok := headers[http.LAST_MODIFIED]; ok { + result.LastModified = val + } + if val, ok := headers[http.ETAG]; ok { + result.ETag = strings.Trim(val, "\"") + } + if val, ok := headers[http.CONTENT_ENCODING]; ok { + result.ContentEncoding = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_SHA256)]; ok { + result.ContentSha256 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok { + result.ContentCrc32 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_STORAGE_CLASS)]; ok { + result.StorageClass = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_RESTORE)]; ok { + result.BceRestore = val + } + if val, ok := headers[http.BCE_OBJECT_TYPE]; ok { + result.BceObjectType = val + } + if val, ok := headers[http.BCE_VERSION_ID]; ok { + result.VersionId = val + } + bcePrefix := toHttpHeaderKey(http.BCE_USER_METADATA_PREFIX) + for k, v := range headers { + if strings.Index(k, bcePrefix) == 0 { + if result.UserMeta == nil { + result.UserMeta = make(map[string]string) + } + result.UserMeta[k[len(bcePrefix):]] = v + } + } + if val, ok := headers[toHttpHeaderKey(http.BCE_OBJECT_TYPE)]; ok { + result.ObjectType = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_NEXT_APPEND_OFFSET)]; ok { + result.NextAppendOffset = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32C)]; ok { + result.ContentCrc32c = val + } + defer func() { resp.Body().Close() }() + return result, nil +} + +// SelectObject - select the object content +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - object: the name of the object +// - args: the optional arguments to perform the select operation +// +// RETURNS: +// - *SelectObjectResult: the output select content result of the object +// - error: nil if ok otherwise the specific error +func SelectObject(cli bce.Client, bucket, object string, args *SelectObjectArgs, ctx *BosContext) (*SelectObjectResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.POST) + req.SetParam("select", "") + req.SetParam("type", args.SelectType) + ctx.Bucket = bucket + jsonBytes, jsonErr := json.Marshal(args) + if jsonErr != nil { + return nil, jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return nil, err + } + req.SetBody(body) + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + + result := &SelectObjectResult{} + + result.Body = resp.Body() + return result, nil +} + +// FetchObject - fetch the object by the given url and store it to a bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name to store the object +// - object: the name of the object to be stored +// - source: the source url to fetch +// - args: the optional arguments to perform the fetch operation +// +// RETURNS: +// - *FetchObjectArgs: the result of this api +// - error: nil if ok otherwise the specific error +func FetchObject(cli bce.Client, bucket, object, source string, + args *FetchObjectArgs, ctx *BosContext) (*FetchObjectResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.POST) + req.SetParam("fetch", "") + ctx.Bucket = bucket + if len(source) == 0 { + return nil, bce.NewBceClientError("invalid fetch source value: " + source) + } + req.SetHeader(http.BCE_PREFIX+"fetch-source", source) + + // Optional arguments settings + if args != nil { + if validFetchMode(args.FetchMode) { + req.SetHeader(http.BCE_PREFIX+"fetch-mode", args.FetchMode) + } else { + if len(args.FetchMode) != 0 { + return nil, bce.NewBceClientError("invalid fetch mode value: " + args.FetchMode) + } + } + if validStorageClass(args.StorageClass) { + req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass) + } else { + if len(args.StorageClass) != 0 { + return nil, bce.NewBceClientError("invalid storage class value: " + + args.StorageClass) + } + } + if len(args.FetchCallBackAddress) != 0 { + req.SetHeader(http.BCE_FETCH_CALLBACK_ADDRESS, args.FetchCallBackAddress) + } + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &FetchObjectResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +// AppendObject - append the given content to a new or existed object which is appendable +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - object: the name of the object +// - content: the content to be appended +// - args: the optional arguments to perform the append operation +// +// RETURNS: +// - *AppendObjectResult: the result status for this api +// - error: nil if ok otherwise the specific error +func AppendObject(cli bce.Client, bucket, object string, content *bce.Body, + args *AppendObjectArgs, ctx *BosContext) (*AppendObjectResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.POST) + req.SetParam("append", "") + ctx.Bucket = bucket + if content == nil { + return nil, bce.NewBceClientError("AppendObject body should not be emtpy") + } + if content.Size() >= THRESHOLD_100_CONTINUE { + req.SetHeader("Expect", "100-continue") + } + req.SetBody(content) + + // Optional arguments settings + if args != nil { + if args.Offset < 0 { + return nil, bce.NewBceClientError( + fmt.Sprintf("invalid append offset value: %d", args.Offset)) + } + if args.Offset > 0 { + req.SetParam("offset", fmt.Sprintf("%d", args.Offset)) + } + setOptionalNullHeaders(req, map[string]string{ + http.CACHE_CONTROL: args.CacheControl, + http.CONTENT_DISPOSITION: args.ContentDisposition, + http.CONTENT_MD5: args.ContentMD5, + http.CONTENT_TYPE: args.ContentType, + http.EXPIRES: args.Expires, + http.BCE_CONTENT_SHA256: args.ContentSha256, + http.BCE_CONTENT_CRC32: args.ContentCrc32, + http.BCE_CONTENT_CRC32C: args.ContentCrc32c, + http.BCE_CONTENT_CRC32C_FLAG: strconv.FormatBool(args.ContentCrc32cFlag), + }) + + if validStorageClass(args.StorageClass) { + req.SetHeader(http.BCE_STORAGE_CLASS, args.StorageClass) + } else { + if len(args.StorageClass) != 0 { + return nil, bce.NewBceClientError("invalid storage class value: " + + args.StorageClass) + } + } + if err := setUserMetadata(req, args.UserMeta); err != nil { + return nil, err + } + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + } + + // Send request and get the result + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + headers := resp.Headers() + result := &AppendObjectResult{} + if val, ok := headers[http.CONTENT_MD5]; ok { + result.ContentMD5 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_NEXT_APPEND_OFFSET)]; ok { + nextOffset, offsetErr := strconv.ParseInt(val, 10, 64) + if offsetErr != nil { + nextOffset = content.Size() + } + result.NextAppendOffset = nextOffset + } else { + result.NextAppendOffset = content.Size() + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32)]; ok { + result.ContentCrc32 = val + } + if val, ok := headers[toHttpHeaderKey(http.BCE_CONTENT_CRC32C)]; ok { + result.ContentCrc32c = val + } + if val, ok := headers[http.ETAG]; ok { + result.ETag = strings.Trim(val, "\"") + } + defer func() { resp.Body().Close() }() + return result, nil +} + +// DeleteObject - delete the given object +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object to be deleted +// - object: the name of the object +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func DeleteObject(cli bce.Client, bucket, object, versionId string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.DELETE) + if versionId != "" { + req.SetParam("versionId", versionId) + } + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// DeleteMultipleObjects - delete the given objects within a single http request +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the objects to be deleted +// - objectListStream: the objects list to be delete with json format +// +// RETURNS: +// - *DeleteMultipleObjectsResult: the objects failed to delete +// - error: nil if ok otherwise the specific error +func DeleteMultipleObjects(cli bce.Client, bucket string, + objectListStream *bce.Body, ctx *BosContext) (*DeleteMultipleObjectsResult, error) { + req := &bce.BceRequest{} + req.SetUri(getBucketUri(bucket)) + req.SetMethod(http.POST) + req.SetParam("delete", "") + req.SetHeader(http.CONTENT_TYPE, "application/json; charset=utf-8") + ctx.Bucket = bucket + if objectListStream == nil { + return nil, bce.NewBceClientError("DeleteMultipleObjects body should not be emtpy") + } + if objectListStream.Size() >= THRESHOLD_100_CONTINUE { + req.SetHeader("Expect", "100-continue") + } + req.SetBody(objectListStream) + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &DeleteMultipleObjectsResult{} + + if resp.Header(http.CONTENT_LENGTH) == "0" { + resp.Body().Close() + return jsonBody, nil + } + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +// GeneratePresignedUrl - generate an authorization url with expire time and optional arguments +// +// PARAMS: +// - conf: the client configuration +// - signer: the client signer object to generate the authorization string +// - bucket: the target bucket name +// - object: the target object name +// - expire: expire time in seconds +// - method: optional sign method, default is GET +// - headers: optional sign headers, default just set the Host +// - params: optional sign params, default is empty +// RETURNS: +// - string: the presigned url with authorization string + +func GeneratePresignedUrl(conf *bce.BceClientConfiguration, signer auth.Signer, bucket, + object string, expire int, method string, headers, params map[string]string) string { + return GeneratePresignedUrlInternal(conf, signer, bucket, object, expire, method, headers, params, false) +} +func GeneratePresignedUrlPathStyle(conf *bce.BceClientConfiguration, signer auth.Signer, bucket, + object string, expire int, method string, headers, params map[string]string) string { + return GeneratePresignedUrlInternal(conf, signer, bucket, object, expire, method, headers, params, true) +} + +func GeneratePresignedUrlInternal(conf *bce.BceClientConfiguration, signer auth.Signer, bucket, + object string, expire int, method string, headers, params map[string]string, path_style bool) string { + req := &bce.BceRequest{} + // Set basic arguments + if len(method) == 0 { + method = http.GET + } + req.SetMethod(method) + req.SetEndpoint(conf.Endpoint) + if req.Protocol() == "" { + req.SetProtocol(bce.DEFAULT_PROTOCOL) + } + domain := req.Host() + if pos := strings.Index(domain, ":"); pos != -1 { + domain = domain[:pos] + } + if path_style { + req.SetUri(getObjectUri(bucket, object)) + if conf.CnameEnabled || isCnameLikeHost(conf.Endpoint) { + req.SetUri(getCnameUri(req.Uri())) + } + } else { + if len(bucket) != 0 && net.ParseIP(domain) == nil { // not use an IP as the endpoint by client + req.SetUri(bce.URI_PREFIX + object) + if !conf.CnameEnabled && !isCnameLikeHost(conf.Endpoint) { + req.SetHost(bucket + "." + req.Host()) + } + } else { + req.SetUri(getObjectUri(bucket, object)) + if conf.CnameEnabled || isCnameLikeHost(conf.Endpoint) { + req.SetUri(getCnameUri(req.Uri())) + } + } + } + // Set headers and params if given. + req.SetHeader(http.HOST, req.Host()) + if headers != nil { + for k, v := range headers { + req.SetHeader(k, v) + } + } + if params != nil { + for k, v := range params { + req.SetParam(k, v) + } + } + // Copy one SignOptions object to rewrite it. + option := *conf.SignOption + if expire != 0 { + option.ExpireSeconds = expire + } + + if conf.Credentials.SessionToken != "" { + req.SetParam(http.BCE_SECURITY_TOKEN, conf.Credentials.SessionToken) + } + + // Generate the authorization string and return the signed url. + signer.Sign(&req.Request, conf.Credentials, &option) + req.SetParam("authorization", req.Header(http.AUTHORIZATION)) + return fmt.Sprintf("%s://%s%s?%s", req.Protocol(), req.Host(), + util.UriEncode(req.Uri(), false), req.QueryString()) +} + +// PutObjectAcl - set the ACL of the given object +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - object: the object name +// - cannedAcl: support private and public-read +// - grantRead: user id list +// - grantFullControl: user id list +// - aclBody: the acl file body +// +// RETURNS: +// - error: nil if success otherwise the specific error +func PutObjectAcl(cli bce.Client, bucket, object, cannedAcl string, + grantRead, grantFullControl []string, aclBody *bce.Body, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.PUT) + req.SetParam("acl", "") + ctx.Bucket = bucket + // Joiner for generate the user id list string for grant acl header + joiner := func(ids []string) string { + for i := range ids { + ids[i] = "id=\"" + ids[i] + "\"" + } + return strings.Join(ids, ",") + } + + // Choose a acl setting method + methods := 0 + if len(cannedAcl) != 0 { + methods += 1 + if validCannedAcl(cannedAcl) { + req.SetHeader(http.BCE_ACL, cannedAcl) + } + } + if len(grantRead) != 0 { + methods += 1 + req.SetHeader(http.BCE_GRANT_READ, joiner(grantRead)) + } + if len(grantFullControl) != 0 { + methods += 1 + req.SetHeader(http.BCE_GRANT_FULL_CONTROL, joiner(grantFullControl)) + } + if aclBody != nil { + methods += 1 + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + req.SetBody(aclBody) + } + if methods != 1 { + return bce.NewBceClientError("BOS only support one acl setting method at the same time") + } + + // Do sending request + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// GetObjectAcl - get the ACL of the given object +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - object: the object name +// +// RETURNS: +// - result: the object acl result object +// - error: nil if success otherwise the specific error +func GetObjectAcl(cli bce.Client, bucket, object string, ctx *BosContext) (*GetObjectAclResult, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.GET) + req.SetParam("acl", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &GetObjectAclResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// DeleteObjectAcl - delete the ACL of the given object +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - object: the object name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteObjectAcl(cli bce.Client, bucket, object string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.DELETE) + req.SetParam("acl", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// RestoreObject - restore the archive object +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - object: the object name +// - args: the restore args +// +// RETURNS: +// - error: nil if success otherwise the specific error +func RestoreObject(cli bce.Client, bucket string, object string, args ArchiveRestoreArgs, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetParam("restore", "") + req.SetMethod(http.POST) + req.SetHeader(http.BCE_RESTORE_DAYS, strconv.Itoa(args.RestoreDays)) + req.SetHeader(http.BCE_RESTORE_TIER, args.RestoreTier) + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + + return nil +} + +// PutObjectSymlink - put the object from the string or the stream +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - object: the name of the object +// - symlinkKey: the name of the symlink +// - symlinkArgs: the optional arguments of this api +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func PutObjectSymlink(cli bce.Client, bucket string, object string, symlinkKey string, symlinkArgs *PutSymlinkArgs, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, symlinkKey)) + req.SetParam("symlink", "") + req.SetMethod(http.PUT) + ctx.Bucket = bucket + if symlinkArgs != nil { + if len(symlinkArgs.ForbidOverwrite) != 0 { + if !validForbidOverwrite(symlinkArgs.ForbidOverwrite) { + return bce.NewBceClientError("invalid forbid overwrite val," + symlinkArgs.ForbidOverwrite) + } + req.SetHeader(http.BCE_FORBID_OVERWRITE, symlinkArgs.ForbidOverwrite) + } + + if len(symlinkArgs.StorageClass) != 0 { + if !validStorageClass(symlinkArgs.StorageClass) { + return bce.NewBceClientError("invalid storage class val," + symlinkArgs.StorageClass) + } + if symlinkArgs.StorageClass == STORAGE_CLASS_ARCHIVE { + return bce.NewBceClientError("archive storage class not support") + } + req.SetHeader(http.BCE_STORAGE_CLASS, symlinkArgs.StorageClass) + } + + if len(symlinkArgs.UserMeta) != 0 { + if err := setUserMetadata(req, symlinkArgs.UserMeta); err != nil { + return err + } + } + if len(symlinkArgs.SymlinkBucket) != 0 { + req.SetHeader(http.BCE_SYMLINK_BUCKET, symlinkArgs.SymlinkBucket) + } + } + req.SetHeader(http.BCE_SYMLINK_TARGET, object) + + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PutObjectSymlink - put the object from the string or the stream +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - symlinkKey: the name of the symlink +// +// RETURNS: +// - string: the name of the target object +// - error: nil if ok otherwise the specific error +func GetObjectSymlink(cli bce.Client, bucket string, symlinkKey string, ctx *BosContext) (string, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, symlinkKey)) + req.SetParam("symlink", "") + req.SetMethod(http.GET) + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return "", err + } + if resp.IsFail() { + return "", resp.ServiceError() + } + defer func() { resp.Body().Close() }() + if resp.Header(http.BCE_SYMLINK_BUCKET) != "" { + result := BOS_CONFIG_PREFIX + resp.Header(http.BCE_SYMLINK_BUCKET) + "/" + resp.Header(http.BCE_SYMLINK_TARGET) + return result, nil + } + return resp.Header(http.BCE_SYMLINK_TARGET), nil +} + +// PutObjectTag - set tag for given object +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name of the object +// - object: the name of the object +// - putObjectTagArgs: the arguments of object tag +// RETURNS: +// - error: nil if ok otherwise the specific error + +func PutObjectTag(cli bce.Client, bucket, object string, putObjectTagArgs *PutObjectTagArgs, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.PUT) + req.SetParam("tagging", "") + ctx.Bucket = bucket + reqByte, _ := json.Marshal(putObjectTagArgs) + body, err := bce.NewBodyFromString(string(reqByte)) + if err != nil { + return err + } + req.SetBody(body) + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func GetObjectTag(cli bce.Client, bucket, object string, ctx *BosContext) (map[string]interface{}, error) { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.GET) + req.SetParam("tagging", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + defer func() { resp.Body().Close() }() + bodyBytes, err := ioutil.ReadAll(resp.Body()) + if err != nil { + return nil, err + } + + result, err := ParseObjectTagResult(bodyBytes) + if err != nil { + return nil, err + } + return result, nil +} + +func DeleteObjectTag(cli bce.Client, bucket, object string, ctx *BosContext) error { + req := &bce.BceRequest{} + req.SetUri(getObjectUri(bucket, object)) + req.SetMethod(http.DELETE) + req.SetParam("tagging", "") + ctx.Bucket = bucket + resp := &bce.BceResponse{} + if err := SendRequest(cli, req, resp, ctx); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/util.go b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/util.go new file mode 100644 index 00000000000..bd426e60ac1 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/bos/api/util.go @@ -0,0 +1,481 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// util.go - define the utilities for api package of BOS service + +package api + +import ( + "bytes" + "encoding/json" + "fmt" + "net" + net_http "net/http" + "net/url" + "strings" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" + "github.com/baidubce/bce-sdk-go/util" +) + +const ( + METADATA_DIRECTIVE_COPY = "copy" + METADATA_DIRECTIVE_REPLACE = "replace" + + STORAGE_CLASS_STANDARD = "STANDARD" + STORAGE_CLASS_STANDARD_IA = "STANDARD_IA" + STORAGE_CLASS_COLD = "COLD" + STORAGE_CLASS_ARCHIVE = "ARCHIVE" + STORAGE_CLASS_MAZ_STANDARD = "MAZ_STANDARD" + STORAGE_CLASS_MAZ_STANDARD_IA = "MAZ_STANDARD_IA" + + FETCH_MODE_SYNC = "sync" + FETCH_MODE_ASYNC = "async" + + CANNED_ACL_PRIVATE = "private" + CANNED_ACL_PUBLIC_READ = "public-read" + CANNED_ACL_PUBLIC_READ_WRITE = "public-read-write" + + RAW_CONTENT_TYPE = "application/octet-stream" + + THRESHOLD_100_CONTINUE = 1 << 20 // add 100 continue header if body size bigger than 1MB + + TRAFFIC_LIMIT_MAX = 8 * (100 << 20) // 100M bit = 838860800 + TRAFFIC_LIMIT_MIN = 8 * (100 << 10) // 100K bit = 819200 + + STATUS_ENABLED = "enabled" + STATUS_DISABLED = "disabled" + + ENCRYPTION_AES256 = "AES256" + + RESTORE_TIER_STANDARD = "Standard" //标准取回对象 + RESTORE_TIER_EXPEDITED = "Expedited" //快速取回对象 + + FORBID_OVERWRITE_FALSE = "false" + FORBID_OVERWRITE_TRUE = "true" + + NAMESPACE_BUCKET = "namespace" + BOS_CONFIG_PREFIX = "bos://" + BOS_SHARE_ENDPOINT = "bos-share.baidubce.com" +) + +var DEFAULT_CNAME_LIKE_LIST = []string{ + ".cdn.bcebos.com", +} + +var VALID_STORAGE_CLASS_TYPE = map[string]int{ + STORAGE_CLASS_STANDARD: 0, + STORAGE_CLASS_STANDARD_IA: 1, + STORAGE_CLASS_COLD: 2, + STORAGE_CLASS_ARCHIVE: 3, + STORAGE_CLASS_MAZ_STANDARD: 4, + STORAGE_CLASS_MAZ_STANDARD_IA: 5, +} + +var VALID_RESTORE_TIER = map[string]int{ + RESTORE_TIER_STANDARD: 1, + RESTORE_TIER_EXPEDITED: 1, +} + +var VALID_FORBID_OVERWRITE = map[string]int{ + FORBID_OVERWRITE_FALSE: 1, + FORBID_OVERWRITE_TRUE: 1, +} + +var ( + GET_OBJECT_ALLOWED_RESPONSE_HEADERS = map[string]struct{}{ + "ContentDisposition": {}, + "ContentType": {}, + "ContentLanguage": {}, + "Expires": {}, + "CacheControl": {}, + "ContentEncoding": {}, + } +) + +func getBucketUri(bucketName string) string { + return bce.URI_PREFIX + bucketName +} + +func getObjectUri(bucketName, objectName string) string { + return bce.URI_PREFIX + bucketName + "/" + objectName +} + +func getCnameUri(uri string) string { + if len(uri) <= 0 { + return uri + } + slash_index := strings.Index(uri[1:], "/") + if slash_index == -1 { + return bce.URI_PREFIX + } else { + return uri[slash_index+1:] + } +} + +func validMetadataDirective(val string) bool { + if val == METADATA_DIRECTIVE_COPY || val == METADATA_DIRECTIVE_REPLACE { + return true + } + return false +} + +func validForbidOverwrite(val string) bool { + if _, ok := VALID_FORBID_OVERWRITE[val]; ok { + return true + } + return false +} + +func validStorageClass(val string) bool { + if _, ok := VALID_STORAGE_CLASS_TYPE[val]; ok { + return true + } + return false +} + +func validFetchMode(val string) bool { + if val == FETCH_MODE_SYNC || val == FETCH_MODE_ASYNC { + return true + } + return false +} + +func validCannedAcl(val string) bool { + if val == CANNED_ACL_PRIVATE || + val == CANNED_ACL_PUBLIC_READ || + val == CANNED_ACL_PUBLIC_READ_WRITE { + return true + } + return false +} + +func validObjectTagging(tagging string) (bool, string) { + if len(tagging) > 4000 { + return false, "" + } + encodeTagging := []string{} + pair := strings.Split(tagging, "&") + for _, p := range pair { + kv := strings.Split(p, "=") + if len(kv) != 2 { + return false, "" + } + key := kv[0] + value := kv[1] + encodeKey := url.QueryEscape(key) + encodeValue := url.QueryEscape(value) + if len(encodeKey) > 128 || len(encodeValue) > 256 { + return false, "" + } + encodeTagging = append(encodeTagging, encodeKey+"="+encodeValue) + } + return true, strings.Join(encodeTagging, "&") +} + +func toHttpHeaderKey(key string) string { + var result bytes.Buffer + needToUpper := true + for _, c := range []byte(key) { + if needToUpper && (c >= 'a' && c <= 'z') { + result.WriteByte(c - 32) + needToUpper = false + } else if c == '-' { + result.WriteByte(c) + needToUpper = true + } else { + result.WriteByte(c) + } + } + return result.String() +} + +func setOptionalNullHeaders(req *bce.BceRequest, args map[string]string) { + for k, v := range args { + if len(v) == 0 { + continue + } + switch k { + case http.CACHE_CONTROL: + fallthrough + case http.CONTENT_DISPOSITION: + fallthrough + case http.CONTENT_ENCODING: + fallthrough + case http.CONTENT_RANGE: + fallthrough + case http.CONTENT_MD5: + fallthrough + case http.CONTENT_TYPE: + fallthrough + case http.EXPIRES: + fallthrough + case http.LAST_MODIFIED: + fallthrough + case http.ETAG: + fallthrough + case http.BCE_OBJECT_TYPE: + fallthrough + case http.BCE_NEXT_APPEND_OFFSET: + fallthrough + case http.BCE_CONTENT_SHA256: + fallthrough + case http.BCE_CONTENT_CRC32: + fallthrough + case http.BCE_CONTENT_CRC32C: + fallthrough + case http.BCE_CONTENT_CRC32C_FLAG: + if v == "false" { + continue + } + fallthrough + case http.BCE_COPY_SOURCE_RANGE: + fallthrough + case http.BCE_COPY_SOURCE_IF_MATCH: + fallthrough + case http.BCE_COPY_SOURCE_IF_NONE_MATCH: + fallthrough + case http.BCE_COPY_SOURCE_IF_MODIFIED_SINCE: + fallthrough + case http.BCE_COPY_SOURCE_IF_UNMODIFIED_SINCE: + req.SetHeader(k, v) + } + } +} + +func setUserMetadata(req *bce.BceRequest, meta map[string]string) error { + if meta == nil { + return nil + } + for k, v := range meta { + if len(k) == 0 { + continue + } + if len(k)+len(v) > 32*1024 { + return bce.NewBceClientError("MetadataTooLarge") + } + req.SetHeader(http.BCE_USER_METADATA_PREFIX+k, v) + } + return nil +} + +func isCnameLikeHost(host string) bool { + for _, suffix := range DEFAULT_CNAME_LIKE_LIST { + if strings.HasSuffix(strings.ToLower(host), suffix) { + return true + } + } + if isVirtualHost(host) { + return true + } + return false +} + +func SendRequest(cli bce.Client, req *bce.BceRequest, resp *bce.BceResponse, ctx *BosContext) error { + var ( + err error + need_retry bool + ) + setUriAndEndpoint(cli, req, ctx, cli.GetBceClientConfig().Endpoint) + req.SetContext(ctx.Ctx) + if err = cli.SendRequest(req, resp); err != nil { + if serviceErr, isServiceErr := err.(*bce.BceServiceError); isServiceErr { + if serviceErr.StatusCode == net_http.StatusInternalServerError || + serviceErr.StatusCode == net_http.StatusBadGateway || + serviceErr.StatusCode == net_http.StatusServiceUnavailable || + (serviceErr.StatusCode == net_http.StatusBadRequest && serviceErr.Code == "Http400") { + need_retry = true + } + } + if _, isClientErr := err.(*bce.BceClientError); isClientErr { + need_retry = true + } + // retry backup endpoint + if need_retry && cli.GetBceClientConfig().BackupEndpoint != "" { + setUriAndEndpoint(cli, req, ctx, cli.GetBceClientConfig().BackupEndpoint) + if err = cli.SendRequest(req, resp); err != nil { + return err + } + } + } + return err +} + +func SendRequestFromBytes(cli bce.Client, req *bce.BceRequest, resp *bce.BceResponse, ctx *BosContext, content []byte) error { + var ( + err error + need_retry bool + ) + setUriAndEndpoint(cli, req, ctx, cli.GetBceClientConfig().Endpoint) + if err = cli.SendRequestFromBytes(req, resp, content); err != nil { + if serviceErr, isServiceErr := err.(*bce.BceServiceError); isServiceErr { + if serviceErr.StatusCode == net_http.StatusInternalServerError || + serviceErr.StatusCode == net_http.StatusBadGateway || + serviceErr.StatusCode == net_http.StatusServiceUnavailable || + (serviceErr.StatusCode == net_http.StatusBadRequest && serviceErr.Code == "Http400") { + need_retry = true + } + } + if _, isClientErr := err.(*bce.BceClientError); isClientErr { + need_retry = true + } + // retry backup endpoint + if need_retry && cli.GetBceClientConfig().BackupEndpoint != "" { + setUriAndEndpoint(cli, req, ctx, cli.GetBceClientConfig().BackupEndpoint) + if err = cli.SendRequestFromBytes(req, resp, content); err != nil { + return err + } + } + } + return err +} + +func isVirtualHost(host string) bool { + domain := getDomainWithoutPort(host) + arr := strings.Split(domain, ".") + if len(arr) != 4 { + return false + } + // bucket max length is 64 + if len(arr[0]) == 0 || len(arr[0]) > 64 { + return false + } + if arr[2] != "bcebos" || arr[3] != "com" { + return false + } + return true +} + +func isIpHost(host string) bool { + domain := getDomainWithoutPort(host) + validIp := net.ParseIP(domain) + return validIp != nil +} + +func isBosHost(host string) bool { + domain := getDomainWithoutPort(host) + arr := strings.Split(domain, ".") + if len(arr) != 3 { + return false + } + if arr[1] != "bcebos" || arr[2] != "com" { + return false + } + return true +} + +func getDomainWithoutPort(host string) string { + end := 0 + if end = strings.Index(host, ":"); end == -1 { + end = len(host) + } + return host[:end] +} + +func needCompatibleBucketAndEndpoint(bucket, endpoint string) bool { + if bucket == "" { + return false + } + if !isVirtualHost(endpoint) { + return false + } + if strings.Split(endpoint, ".")[0] == bucket { + return false + } + // bucket from sdk and from endpoint is different + return true +} + +// replace endpoint by bucket, only effective when two bucket are in same region, otherwise server return NoSuchBucket error +func replaceEndpointByBucket(bucket, endpoint string) string { + arr := strings.Split(endpoint, ".") + arr[0] = bucket + return strings.Join(arr, ".") +} + +func setUriAndEndpoint(cli bce.Client, req *bce.BceRequest, ctx *BosContext, endpoint string) { + origin_uri := req.Uri() + bucket := ctx.Bucket + protocol := bce.DEFAULT_PROTOCOL + // deal with protocal + if strings.HasPrefix(endpoint, "https://") { + protocol = bce.HTTPS_PROTOCAL + endpoint = strings.TrimPrefix(endpoint, "https://") + } else if strings.HasPrefix(endpoint, "http://") { + endpoint = strings.TrimPrefix(endpoint, "http://") + } + // set uri, endpoint for cname, cdn, virtual host + if cli.GetBceClientConfig().CnameEnabled || isCnameLikeHost(endpoint) { + req.SetEndpoint(endpoint) + // if virtual host endpoint and bucket is not empty, compatible bucket and endpoint + if needCompatibleBucketAndEndpoint(bucket, endpoint) { + req.SetEndpoint(replaceEndpointByBucket(bucket, endpoint)) + } + req.SetUri(getCnameUri(origin_uri)) + } else if isIpHost(endpoint) { + // set endpoint for ip host + req.SetEndpoint(endpoint) + } else if isBosHost(endpoint) { + // endpoint is xx.bcebos.com, set endpoint depends on PathStyleEnable + if bucket != "" && !ctx.PathStyleEnable { + req.SetEndpoint(bucket + "." + endpoint) + req.SetUri(getCnameUri(origin_uri)) + } else { + req.SetEndpoint(endpoint) + } + } else { + // user define custom endpoint + req.SetEndpoint(endpoint) + } + req.SetProtocol(protocol) +} + +func getDefaultContentType(object string) string { + dot := strings.LastIndex(object, ".") + if dot == -1 { + return "application/octet-stream" + } + ext := object[dot:] + mimeMap := util.GetMimeMap() + if contentType, ok := mimeMap[ext]; ok { + return contentType + } + return "application/octet-stream" + +} + +func ParseObjectTagResult(rawData []byte) (map[string]interface{}, error) { + var data map[string]interface{} + err := json.Unmarshal(rawData, &data) + if err != nil { + return nil, err + } + + tagSet, ok := data["tagSet"].([]interface{}) + if !ok || len(tagSet) == 0 { + return nil, fmt.Errorf("decode tagSet error") + } + + tagInfoMap, ok := tagSet[0].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("decode tagInfo error") + } + + tags, ok := tagInfoMap["tagInfo"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("decode tags error") + } + return tags, nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/bos/client.go b/vendor/github.com/baidubce/bce-sdk-go/services/bos/client.go new file mode 100644 index 00000000000..02ed8805109 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/bos/client.go @@ -0,0 +1,2637 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// client.go - define the client for BOS service + +// Package bos defines the BOS services of BCE. The supported APIs are all defined in sub-package +// model with three types: 16 bucket APIs, 9 object APIs and 7 multipart APIs. +package bos + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "net/http" + "os" + + "github.com/baidubce/bce-sdk-go/auth" + "github.com/baidubce/bce-sdk-go/bce" + sdk_http "github.com/baidubce/bce-sdk-go/http" + "github.com/baidubce/bce-sdk-go/services/bos/api" + "github.com/baidubce/bce-sdk-go/services/sts" + "github.com/baidubce/bce-sdk-go/util/log" +) + +const ( + DEFAULT_SERVICE_DOMAIN = bce.DEFAULT_REGION + ".bcebos.com" + DEFAULT_MAX_PARALLEL = 10 + MULTIPART_ALIGN = 1 << 20 // 1MB + MIN_MULTIPART_SIZE = 100 * (1 << 10) // 100 KB + DEFAULT_MULTIPART_SIZE = 12 * (1 << 20) // 12MB + + MAX_PART_NUMBER = 10000 + MAX_SINGLE_PART_SIZE = 5 * (1 << 30) // 5GB + MAX_SINGLE_OBJECT_SIZE = 48.8 * (1 << 40) // 48.8TB +) + +// Client of BOS service is a kind of BceClient, so derived from BceClient +type Client struct { + *bce.BceClient + + // Fileds that used in parallel operation for BOS service + MaxParallel int64 + MultipartSize int64 + BosContext *api.BosContext +} + +// BosClientConfiguration defines the config components structure by user. +type BosClientConfiguration struct { + Ak string + Sk string + Endpoint string + RedirectDisabled bool + PathStyleEnable bool +} + +// NewClient make the BOS service client with default configuration. +// Use `cli.Config.xxx` to access the config or change it to non-default value. +func NewClient(ak, sk, endpoint string) (*Client, error) { + return NewClientWithConfig(&BosClientConfiguration{ + Ak: ak, + Sk: sk, + Endpoint: endpoint, + RedirectDisabled: false, + PathStyleEnable: false, + }) +} + +// NewStsClient make the BOS service client with STS configuration, it will first apply stsAK,stsSK, sessionToken, then return bosClient using temporary sts Credential +func NewStsClient(ak, sk, endpoint string, expiration int) (*Client, error) { + stsClient, err := sts.NewClient(ak, sk) + if err != nil { + fmt.Println("create sts client object :", err) + return nil, err + } + sts, err := stsClient.GetSessionToken(expiration, "") + if err != nil { + fmt.Println("get session token failed:", err) + return nil, err + } + + bosClient, err := NewClient(sts.AccessKeyId, sts.SecretAccessKey, endpoint) + if err != nil { + fmt.Println("create bos client failed:", err) + return nil, err + } + stsCredential, err := auth.NewSessionBceCredentials( + sts.AccessKeyId, + sts.SecretAccessKey, + sts.SessionToken) + if err != nil { + fmt.Println("create sts credential object failed:", err) + return nil, err + } + bosClient.Config.Credentials = stsCredential + return bosClient, nil +} + +func NewClientWithConfig(config *BosClientConfiguration) (*Client, error) { + var credentials *auth.BceCredentials + var err error + ak, sk, endpoint := config.Ak, config.Sk, config.Endpoint + if len(ak) == 0 && len(sk) == 0 { // to support public-read-write request + credentials, err = nil, nil + } else { + credentials, err = auth.NewBceCredentials(ak, sk) + if err != nil { + return nil, err + } + } + if len(endpoint) == 0 { + endpoint = DEFAULT_SERVICE_DOMAIN + } + defaultSignOptions := &auth.SignOptions{ + HeadersToSign: auth.DEFAULT_HEADERS_TO_SIGN, + ExpireSeconds: auth.DEFAULT_EXPIRE_SECONDS} + defaultConf := &bce.BceClientConfiguration{ + Endpoint: endpoint, + Region: bce.DEFAULT_REGION, + UserAgent: bce.DEFAULT_USER_AGENT, + Credentials: credentials, + SignOption: defaultSignOptions, + Retry: bce.DEFAULT_RETRY_POLICY, + ConnectionTimeoutInMillis: bce.DEFAULT_CONNECTION_TIMEOUT_IN_MILLIS, + RedirectDisabled: config.RedirectDisabled} + v1Signer := &auth.BceV1Signer{} + defaultContext := &api.BosContext{ + PathStyleEnable: config.PathStyleEnable, + } + client := &Client{bce.NewBceClient(defaultConf, v1Signer), + DEFAULT_MAX_PARALLEL, DEFAULT_MULTIPART_SIZE, defaultContext} + return client, nil +} + +// ListBuckets - list all buckets +// +// RETURNS: +// - *api.ListBucketsResult: the all buckets +// - error: the return error if any occurs +func (c *Client) ListBuckets() (*api.ListBucketsResult, error) { + return api.ListBuckets(c, c.BosContext) +} + +// ListBucketsWithContext - support to cancel request by context.Context +func (c *Client) ListBucketsWithContext(ctx context.Context) (*api.ListBucketsResult, error) { + c.BosContext.Ctx = ctx + return api.ListBuckets(c, c.BosContext) +} + +// ListObjects - list all objects of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// - args: the optional arguments to list objects +// +// RETURNS: +// - *api.ListObjectsResult: the all objects of the bucket +// - error: the return error if any occurs +func (c *Client) ListObjects(bucket string, + args *api.ListObjectsArgs) (*api.ListObjectsResult, error) { + return api.ListObjects(c, bucket, args, c.BosContext) +} + +func (c *Client) ListObjectVersions(bucket string, args *api.ListObjectsArgs) (*api.ListObjectsResult, error) { + return api.ListObjectsVersions(c, bucket, args, c.BosContext) +} + +// ListObjectsWithContext - support to cancel request by context.Context +func (c *Client) ListObjectsWithContext(ctx context.Context, bucket string, + args *api.ListObjectsArgs) (*api.ListObjectsResult, error) { + c.BosContext.Ctx = ctx + return api.ListObjects(c, bucket, args, c.BosContext) +} + +// SimpleListObjects - list all objects of the given bucket with simple arguments +// +// PARAMS: +// - bucket: the bucket name +// - prefix: the prefix for listing +// - maxKeys: the max number of result objects +// - marker: the marker to mark the beginning for the listing +// - delimiter: the delimiter for list objects +// +// RETURNS: +// - *api.ListObjectsResult: the all objects of the bucket +// - error: the return error if any occurs +func (c *Client) SimpleListObjects(bucket, prefix string, maxKeys int, marker, + delimiter string) (*api.ListObjectsResult, error) { + args := &api.ListObjectsArgs{ + Delimiter: prefix, + Marker: marker, + MaxKeys: maxKeys, + Prefix: prefix, + VersionIdMarker: "", + } + return api.ListObjects(c, bucket, args, c.BosContext) +} + +// HeadBucket - test the given bucket existed and access authority +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if exists and have authority otherwise the specific error +func (c *Client) HeadBucket(bucket string) error { + err, _ := api.HeadBucket(c, bucket, c.BosContext) + return err +} + +// HeadBucket - support to cancel request by context.Context +func (c *Client) HeadBucketWithContext(ctx context.Context, bucket string) error { + c.BosContext.Ctx = ctx + err, _ := api.HeadBucket(c, bucket, c.BosContext) + return err +} + +// DoesBucketExist - test the given bucket existed or not +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - bool: true if exists and false if not exists or occurs error +// - error: nil if exists or not exist, otherwise the specific error +func (c *Client) DoesBucketExist(bucket string) (bool, error) { + err, _ := api.HeadBucket(c, bucket, c.BosContext) + if err == nil { + return true, nil + } + if realErr, ok := err.(*bce.BceServiceError); ok { + if realErr.StatusCode == http.StatusForbidden { + return true, nil + } + if realErr.StatusCode == http.StatusNotFound { + return false, nil + } + } + return false, err +} + +// IsNsBucket - test the given bucket is namespace bucket or not +func (c *Client) IsNsBucket(bucket string) bool { + err, resp := api.HeadBucket(c, bucket, c.BosContext) + if err == nil && resp.Header(sdk_http.BCE_BUCKET_TYPE) == api.NAMESPACE_BUCKET { + return true + } + if realErr, ok := err.(*bce.BceServiceError); ok { + if realErr.StatusCode == http.StatusForbidden && + resp.Header(sdk_http.BCE_BUCKET_TYPE) == api.NAMESPACE_BUCKET { + return true + } + } + return false +} + +// PutBucket - create a new bucket +// +// PARAMS: +// - bucket: the new bucket name +// +// RETURNS: +// - string: the location of the new bucket if create success +// - error: nil if create success otherwise the specific error +func (c *Client) PutBucket(bucket string) (string, error) { + return api.PutBucket(c, bucket, nil, c.BosContext) +} + +func (c *Client) PutBucketWithArgs(bucket string, args *api.PutBucketArgs) (string, error) { + return api.PutBucket(c, bucket, args, c.BosContext) +} + +// DeleteBucket - delete a empty bucket +// +// PARAMS: +// - bucket: the bucket name to be deleted +// +// RETURNS: +// - error: nil if delete success otherwise the specific error +func (c *Client) DeleteBucket(bucket string) error { + return api.DeleteBucket(c, bucket, c.BosContext) +} + +// GetBucketLocation - get the location fo the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - string: the location of the bucket +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketLocation(bucket string) (string, error) { + return api.GetBucketLocation(c, bucket, c.BosContext) +} + +// PutBucketAcl - set the acl of the given bucket with acl body stream +// +// PARAMS: +// - bucket: the bucket name +// - aclBody: the acl json body stream +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketAcl(bucket string, aclBody *bce.Body) error { + return api.PutBucketAcl(c, bucket, "", aclBody, c.BosContext) +} + +// PutBucketAclFromCanned - set the canned acl of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// - cannedAcl: the cannedAcl string +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketAclFromCanned(bucket, cannedAcl string) error { + return api.PutBucketAcl(c, bucket, cannedAcl, nil, c.BosContext) +} + +// PutBucketAclFromFile - set the acl of the given bucket with acl json file name +// +// PARAMS: +// - bucket: the bucket name +// - aclFile: the acl file name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketAclFromFile(bucket, aclFile string) error { + body, err := bce.NewBodyFromFile(aclFile) + if err != nil { + return err + } + return api.PutBucketAcl(c, bucket, "", body, c.BosContext) +} + +// PutBucketAclFromString - set the acl of the given bucket with acl json string +// +// PARAMS: +// - bucket: the bucket name +// - aclString: the acl string with json format +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketAclFromString(bucket, aclString string) error { + body, err := bce.NewBodyFromString(aclString) + if err != nil { + return err + } + return api.PutBucketAcl(c, bucket, "", body, c.BosContext) +} + +// PutBucketAclFromStruct - set the acl of the given bucket with acl data structure +// +// PARAMS: +// - bucket: the bucket name +// - aclObj: the acl struct object +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketAclFromStruct(bucket string, aclObj *api.PutBucketAclArgs) error { + jsonBytes, jsonErr := json.Marshal(aclObj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + return api.PutBucketAcl(c, bucket, "", body, c.BosContext) +} + +// GetBucketAcl - get the acl of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - *api.GetBucketAclResult: the result of the bucket acl +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketAcl(bucket string) (*api.GetBucketAclResult, error) { + return api.GetBucketAcl(c, bucket, c.BosContext) +} + +// PutBucketLogging - set the loging setting of the given bucket with json stream +// +// PARAMS: +// - bucket: the bucket name +// - body: the json body +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketLogging(bucket string, body *bce.Body) error { + return api.PutBucketLogging(c, bucket, body, c.BosContext) +} + +// PutBucketLoggingFromString - set the loging setting of the given bucket with json string +// +// PARAMS: +// - bucket: the bucket name +// - logging: the json format string +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketLoggingFromString(bucket, logging string) error { + body, err := bce.NewBodyFromString(logging) + if err != nil { + return err + } + return api.PutBucketLogging(c, bucket, body, c.BosContext) +} + +// PutBucketLoggingFromStruct - set the loging setting of the given bucket with args object +// +// PARAMS: +// - bucket: the bucket name +// - obj: the logging setting object +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketLoggingFromStruct(bucket string, obj *api.PutBucketLoggingArgs) error { + jsonBytes, jsonErr := json.Marshal(obj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + return api.PutBucketLogging(c, bucket, body, c.BosContext) +} + +// GetBucketLogging - get the logging setting of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - *api.GetBucketLoggingResult: the logging setting of the bucket +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketLogging(bucket string) (*api.GetBucketLoggingResult, error) { + return api.GetBucketLogging(c, bucket, c.BosContext) +} + +// DeleteBucketLogging - delete the logging setting of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketLogging(bucket string) error { + return api.DeleteBucketLogging(c, bucket, c.BosContext) +} + +// PutBucketLifecycle - set the lifecycle rule of the given bucket with raw stream +// +// PARAMS: +// - bucket: the bucket name +// - lifecycle: the lifecycle rule json body +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketLifecycle(bucket string, lifecycle *bce.Body) error { + return api.PutBucketLifecycle(c, bucket, lifecycle, c.BosContext) +} + +// PutBucketLifecycleFromString - set the lifecycle rule of the given bucket with string +// +// PARAMS: +// - bucket: the bucket name +// - lifecycle: the lifecycle rule json format string body +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketLifecycleFromString(bucket, lifecycle string) error { + body, err := bce.NewBodyFromString(lifecycle) + if err != nil { + return err + } + return api.PutBucketLifecycle(c, bucket, body, c.BosContext) +} + +// GetBucketLifecycle - get the lifecycle rule of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - *api.GetBucketLifecycleResult: the lifecycle rule of the bucket +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketLifecycle(bucket string) (*api.GetBucketLifecycleResult, error) { + return api.GetBucketLifecycle(c, bucket, c.BosContext) +} + +// DeleteBucketLifecycle - delete the lifecycle rule of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketLifecycle(bucket string) error { + return api.DeleteBucketLifecycle(c, bucket, c.BosContext) +} + +// PutBucketStorageclass - set the storage class of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// - storageClass: the storage class string value +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketStorageclass(bucket, storageClass string) error { + return api.PutBucketStorageclass(c, bucket, storageClass, c.BosContext) +} + +// GetBucketStorageclass - get the storage class of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - string: the storage class string value +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketStorageclass(bucket string) (string, error) { + return api.GetBucketStorageclass(c, bucket, c.BosContext) +} + +// PutBucketReplication - set the bucket replication config of different region +// +// PARAMS: +// - bucket: the bucket name +// - replicationConf: the replication config json body stream +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketReplication(bucket string, replicationConf *bce.Body, replicationRuleId string) error { + return api.PutBucketReplication(c, bucket, replicationConf, replicationRuleId, c.BosContext) +} + +// PutBucketReplicationFromFile - set the bucket replication config with json file name +// +// PARAMS: +// - bucket: the bucket name +// - confFile: the config json file name +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketReplicationFromFile(bucket, confFile string, replicationRuleId string) error { + body, err := bce.NewBodyFromFile(confFile) + if err != nil { + return err + } + return api.PutBucketReplication(c, bucket, body, replicationRuleId, c.BosContext) +} + +// PutBucketReplicationFromString - set the bucket replication config with json string +// +// PARAMS: +// - bucket: the bucket name +// - confString: the config string with json format +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketReplicationFromString(bucket, confString string, replicationRuleId string) error { + body, err := bce.NewBodyFromString(confString) + if err != nil { + return err + } + return api.PutBucketReplication(c, bucket, body, replicationRuleId, c.BosContext) +} + +// PutBucketReplicationFromStruct - set the bucket replication config with struct +// +// PARAMS: +// - bucket: the bucket name +// - confObj: the replication config struct object +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketReplicationFromStruct(bucket string, + confObj *api.PutBucketReplicationArgs, replicationRuleId string) error { + jsonBytes, jsonErr := json.Marshal(confObj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + return api.PutBucketReplication(c, bucket, body, replicationRuleId, c.BosContext) +} + +// GetBucketReplication - get the bucket replication config of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// +// RETURNS: +// - *api.GetBucketReplicationResult: the result of the bucket replication config +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketReplication(bucket string, replicationRuleId string) (*api.GetBucketReplicationResult, error) { + return api.GetBucketReplication(c, bucket, replicationRuleId, c.BosContext) +} + +// ListBucketReplication - get all replication config of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - *api.ListBucketReplicationResult: the list of the bucket replication config +// - error: nil if success otherwise the specific error +func (c *Client) ListBucketReplication(bucket string) (*api.ListBucketReplicationResult, error) { + return api.ListBucketReplication(c, bucket, c.BosContext) +} + +// DeleteBucketReplication - delete the bucket replication config of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketReplication(bucket string, replicationRuleId string) error { + return api.DeleteBucketReplication(c, bucket, replicationRuleId, c.BosContext) +} + +// GetBucketReplicationProgress - get the bucket replication process of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -] +// +// RETURNS: +// - *api.GetBucketReplicationProgressResult: the process of the bucket replication +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketReplicationProgress(bucket string, replicationRuleId string) ( + *api.GetBucketReplicationProgressResult, error) { + return api.GetBucketReplicationProgress(c, bucket, replicationRuleId, c.BosContext) +} + +// PutBucketEncryption - set the bucket encryption config of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// - algorithm: the encryption algorithm name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketEncryption(bucket, algorithm string) error { + return api.PutBucketEncryption(c, bucket, algorithm, c.BosContext) +} + +// GetBucketEncryption - get the bucket encryption config +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - string: the encryption algorithm name +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketEncryption(bucket string) (string, error) { + return api.GetBucketEncryption(c, bucket, c.BosContext) +} + +// DeleteBucketEncryption - delete the bucket encryption config of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketEncryption(bucket string) error { + return api.DeleteBucketEncryption(c, bucket, c.BosContext) +} + +// PutBucketStaticWebsite - set the bucket static website config +// +// PARAMS: +// - bucket: the bucket name +// - config: the static website config body stream +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketStaticWebsite(bucket string, config *bce.Body) error { + return api.PutBucketStaticWebsite(c, bucket, config, c.BosContext) +} + +// PutBucketStaticWebsiteFromString - set the bucket static website config from json string +// +// PARAMS: +// - bucket: the bucket name +// - jsonConfig: the static website config json string +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketStaticWebsiteFromString(bucket, jsonConfig string) error { + body, err := bce.NewBodyFromString(jsonConfig) + if err != nil { + return err + } + return api.PutBucketStaticWebsite(c, bucket, body, c.BosContext) +} + +// PutBucketStaticWebsiteFromStruct - set the bucket static website config from struct +// +// PARAMS: +// - bucket: the bucket name +// - confObj: the static website config object +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketStaticWebsiteFromStruct(bucket string, + confObj *api.PutBucketStaticWebsiteArgs) error { + jsonBytes, jsonErr := json.Marshal(confObj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + return api.PutBucketStaticWebsite(c, bucket, body, c.BosContext) +} + +// SimplePutBucketStaticWebsite - simple set the bucket static website config +// +// PARAMS: +// - bucket: the bucket name +// - index: the static website config for index file name +// - notFound: the static website config for notFound file name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) SimplePutBucketStaticWebsite(bucket, index, notFound string) error { + confObj := &api.PutBucketStaticWebsiteArgs{Index: index, NotFound: notFound} + return c.PutBucketStaticWebsiteFromStruct(bucket, confObj) +} + +// GetBucketStaticWebsite - get the bucket static website config +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - result: the static website config result object +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketStaticWebsite(bucket string) ( + *api.GetBucketStaticWebsiteResult, error) { + return api.GetBucketStaticWebsite(c, bucket, c.BosContext) +} + +// DeleteBucketStaticWebsite - delete the bucket static website config of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketStaticWebsite(bucket string) error { + return api.DeleteBucketStaticWebsite(c, bucket, c.BosContext) +} + +// PutBucketCors - set the bucket CORS config +// +// PARAMS: +// - bucket: the bucket name +// - config: the bucket CORS config body stream +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketCors(bucket string, config *bce.Body) error { + return api.PutBucketCors(c, bucket, config, c.BosContext) +} + +// PutBucketCorsFromFile - set the bucket CORS config from json config file +// +// PARAMS: +// - bucket: the bucket name +// - filename: the bucket CORS json config file name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketCorsFromFile(bucket, filename string) error { + body, err := bce.NewBodyFromFile(filename) + if err != nil { + return err + } + return api.PutBucketCors(c, bucket, body, c.BosContext) +} + +// PutBucketCorsFromString - set the bucket CORS config from json config string +// +// PARAMS: +// - bucket: the bucket name +// - filename: the bucket CORS json config string +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketCorsFromString(bucket, jsonConfig string) error { + body, err := bce.NewBodyFromString(jsonConfig) + if err != nil { + return err + } + return api.PutBucketCors(c, bucket, body, c.BosContext) +} + +// PutBucketCorsFromStruct - set the bucket CORS config from json config object +// +// PARAMS: +// - bucket: the bucket name +// - filename: the bucket CORS json config object +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketCorsFromStruct(bucket string, confObj *api.PutBucketCorsArgs) error { + jsonBytes, jsonErr := json.Marshal(confObj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + return api.PutBucketCors(c, bucket, body, c.BosContext) +} + +// GetBucketCors - get the bucket CORS config +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - result: the bucket CORS config result object +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketCors(bucket string) (*api.GetBucketCorsResult, error) { + return api.GetBucketCors(c, bucket, c.BosContext) +} + +// DeleteBucketCors - delete the bucket CORS config of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketCors(bucket string) error { + return api.DeleteBucketCors(c, bucket, c.BosContext) +} + +// PutBucketCopyrightProtection - set the copyright protection config of the given bucket +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - bucket: the bucket name +// - resources: the resource items in the bucket to be protected +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketCopyrightProtection(bucket string, resources ...string) error { + return api.PutBucketCopyrightProtection(c, c.BosContext, bucket, resources...) +} + +// GetBucketCopyrightProtection - get the bucket copyright protection config +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - result: the bucket copyright protection config resources +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketCopyrightProtection(bucket string) ([]string, error) { + return api.GetBucketCopyrightProtection(c, bucket, c.BosContext) +} + +// DeleteBucketCopyrightProtection - delete the bucket copyright protection config +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketCopyrightProtection(bucket string) error { + return api.DeleteBucketCopyrightProtection(c, bucket, c.BosContext) +} + +// PutObject - upload a new object or rewrite the existed object with raw stream +// +// PARAMS: +// - bucket: the name of the bucket to store the object +// - object: the name of the object +// - body: the object content body +// - args: the optional arguments +// +// RETURNS: +// - string: etag of the uploaded object +// - error: the uploaded error if any occurs +func (c *Client) PutObject(bucket, object string, body *bce.Body, + args *api.PutObjectArgs) (string, error) { + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// PutObjectWithContext - support to cancel request by context.Context +func (c *Client) PutObjectWithContext(ctx context.Context, bucket, object string, body *bce.Body, + args *api.PutObjectArgs) (string, error) { + c.BosContext.Ctx = ctx + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// BasicPutObject - the basic interface of uploading an object +// +// PARAMS: +// - bucket: the name of the bucket to store the object +// - object: the name of the object +// - body: the object content body +// +// RETURNS: +// - string: etag of the uploaded object +// - error: the uploaded error if any occurs +func (c *Client) BasicPutObject(bucket, object string, body *bce.Body) (string, error) { + etag, _, err := api.PutObject(c, bucket, object, body, nil, c.BosContext) + return etag, err +} + +// PutObjectFromBytes - upload a new object or rewrite the existed object from a byte array +// +// PARAMS: +// - bucket: the name of the bucket to store the object +// - object: the name of the object +// - bytesArr: the content byte array +// - args: the optional arguments +// +// RETURNS: +// - string: etag of the uploaded object +// - error: the uploaded error if any occurs +func (c *Client) PutObjectFromBytes(bucket, object string, bytesArr []byte, + args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromBytes(bytesArr) + if err != nil { + return "", err + } + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// PutObjectFromBytesWithContext - support to cancel request by context.Context +func (c *Client) PutObjectFromBytesWithContext(ctx context.Context, bucket, object string, + bytesArr []byte, args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromBytes(bytesArr) + if err != nil { + return "", err + } + c.BosContext.Ctx = ctx + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// PutObjectFromString - upload a new object or rewrite the existed object from a string +// +// PARAMS: +// - bucket: the name of the bucket to store the object +// - object: the name of the object +// - content: the content string +// - args: the optional arguments +// +// RETURNS: +// - string: etag of the uploaded object +// - error: the uploaded error if any occurs +func (c *Client) PutObjectFromString(bucket, object, content string, + args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromString(content) + if err != nil { + return "", err + } + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// PutObjectFromStringWithContext - support to cancel request by context.Context +func (c *Client) PutObjectFromStringWithContext(ctx context.Context, + bucket, object, content string, args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromString(content) + if err != nil { + return "", err + } + c.BosContext.Ctx = ctx + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err + +} + +// PutObjectFromFile - upload a new object or rewrite the existed object from a local file +// +// PARAMS: +// - bucket: the name of the bucket to store the object +// - object: the name of the object +// - fileName: the local file full path name +// - args: the optional arguments +// +// RETURNS: +// - string: etag of the uploaded object +// - error: the uploaded error if any occurs +func (c *Client) PutObjectFromFile(bucket, object, fileName string, + args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromFile(fileName) + if err != nil { + return "", err + } + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// PutObjectFromFileWithContext - support to cancel request by context.Context +func (c *Client) PutObjectFromFileWithContext(ctx context.Context, + bucket, object, fileName string, args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromFile(fileName) + if err != nil { + return "", err + } + c.BosContext.Ctx = ctx + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// PutObjectFromStream - upload a new object or rewrite the existed object from stream +// +// PARAMS: +// - bucket: the name of the bucket to store the object +// - object: the name of the object +// - fileName: the local file full path name +// - args: the optional arguments +// +// RETURNS: +// - string: etag of the uploaded object +// - error: the uploaded error if any occurs +func (c *Client) PutObjectFromStream(bucket, object string, reader io.Reader, + args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromSizedReader(reader, -1) + if err != nil { + return "", err + } + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +// PutObjectFromStreamWithContext - support to cancel request by context.Context +func (c *Client) PutObjectFromStreamWithContext(ctx context.Context, bucket, object string, + reader io.Reader, args *api.PutObjectArgs) (string, error) { + body, err := bce.NewBodyFromSizedReader(reader, -1) + if err != nil { + return "", err + } + c.BosContext.Ctx = ctx + etag, _, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, err +} + +func (c *Client) PutObjectFromFileWithCallback(bucket, object, fileName string, + args *api.PutObjectArgs) (string, *api.PutObjectResult, error) { + body, err := bce.NewBodyFromFile(fileName) + if err != nil { + return "", nil, err + } + etag, putObjectResult, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, putObjectResult, err +} + +func (c *Client) PutObjectWithCallback(bucket, object string, body *bce.Body, + args *api.PutObjectArgs) (string, *api.PutObjectResult, error) { + etag, putObjectResult, err := api.PutObject(c, bucket, object, body, args, c.BosContext) + return etag, putObjectResult, err +} + +// CopyObject - copy a remote object to another one +// +// PARAMS: +// - bucket: the name of the destination bucket +// - object: the name of the destination object +// - srcBucket: the name of the source bucket +// - srcObject: the name of the source object +// - args: the optional arguments for copying object which are MetadataDirective, StorageClass, +// IfMatch, IfNoneMatch, ifModifiedSince, IfUnmodifiedSince +// +// RETURNS: +// - *api.CopyObjectResult: result struct which contains "ETag" and "LastModified" fields +// - error: any error if it occurs +func (c *Client) CopyObject(bucket, object, srcBucket, srcObject string, + args *api.CopyObjectArgs) (*api.CopyObjectResult, error) { + source := fmt.Sprintf("/%s/%s", srcBucket, srcObject) + return api.CopyObject(c, bucket, object, source, args, c.BosContext) +} + +// CopyObjectWithContext - support to cancel request by context.Context +func (c *Client) CopyObjectWithContext(ctx context.Context, bucket, object, srcBucket, srcObject string, + args *api.CopyObjectArgs) (*api.CopyObjectResult, error) { + source := fmt.Sprintf("/%s/%s", srcBucket, srcObject) + c.BosContext.Ctx = ctx + return api.CopyObject(c, bucket, object, source, args, c.BosContext) +} + +// BasicCopyObject - the basic interface of copying a object to another one +// +// PARAMS: +// - bucket: the name of the destination bucket +// - object: the name of the destination object +// - srcBucket: the name of the source bucket +// - srcObject: the name of the source object +// +// RETURNS: +// - *api.CopyObjectResult: result struct which contains "ETag" and "LastModified" fields +// - error: any error if it occurs +func (c *Client) BasicCopyObject(bucket, object, srcBucket, + srcObject string) (*api.CopyObjectResult, error) { + source := fmt.Sprintf("/%s/%s", srcBucket, srcObject) + return api.CopyObject(c, bucket, object, source, nil, c.BosContext) +} + +// GetObject - get the given object with raw stream return +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - args: the optional args in querysring +// - ranges: the optional range start and end to get the given object +// +// RETURNS: +// - *api.GetObjectResult: result struct which contains "Body" and header fields +// for details reference https://cloud.baidu.com/doc/BOS/API.html#GetObject.E6.8E.A5.E5.8F.A3 +// - error: any error if it occurs +func (c *Client) GetObject(bucket, object string, args map[string]string, + ranges ...int64) (*api.GetObjectResult, error) { + return api.GetObject(c, bucket, object, c.BosContext, args, ranges...) +} + +// GetObjectWithContext - support to cancel request by context.Context +func (c *Client) GetObjectWithContext(ctx context.Context, bucket, object string, + args map[string]string, ranges ...int64) (*api.GetObjectResult, error) { + c.BosContext.Ctx = ctx + return api.GetObject(c, bucket, object, c.BosContext, args, ranges...) +} + +// BasicGetObject - the basic interface of geting the given object +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// +// RETURNS: +// - *api.GetObjectResult: result struct which contains "Body" and header fields +// for details reference https://cloud.baidu.com/doc/BOS/API.html#GetObject.E6.8E.A5.E5.8F.A3 +// - error: any error if it occurs +func (c *Client) BasicGetObject(bucket, object string) (*api.GetObjectResult, error) { + return api.GetObject(c, bucket, object, c.BosContext, nil) +} + +// BasicGetObjectToFile - use basic interface to get the given object to the given file path +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - filePath: the file path to store the object content +// +// RETURNS: +// - error: any error if it occurs +func (c *Client) BasicGetObjectToFile(bucket, object, filePath string) error { + res, err := api.GetObject(c, bucket, object, c.BosContext, nil) + if err != nil { + return err + } + defer res.Body.Close() + + file, fileErr := os.OpenFile(filePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) + if fileErr != nil { + return fileErr + } + defer file.Close() + + written, writeErr := io.CopyN(file, res.Body, res.ContentLength) + if writeErr != nil { + return writeErr + } + if written != res.ContentLength { + return fmt.Errorf("written content size does not match the response content") + } + return nil +} + +// GetObjectToFileWithContext - support to cancel request by context.Context +func (c *Client) GetObjectToFileWithContext(ctx context.Context, bucket, object, filePath string) error { + c.BosContext.Ctx = ctx + res, err := api.GetObject(c, bucket, object, c.BosContext, nil) + if err != nil { + return err + } + defer res.Body.Close() + + file, fileErr := os.OpenFile(filePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) + if fileErr != nil { + return fileErr + } + defer file.Close() + + written, writeErr := io.CopyN(file, res.Body, res.ContentLength) + if writeErr != nil { + return writeErr + } + if written != res.ContentLength { + return fmt.Errorf("written content size does not match the response content") + } + return nil +} + +// GetObjectMeta - get the given object metadata +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// +// RETURNS: +// - *api.GetObjectMetaResult: metadata result, for details reference +// https://cloud.baidu.com/doc/BOS/API.html#GetObjectMeta.E6.8E.A5.E5.8F.A3 +// - error: any error if it occurs +func (c *Client) GetObjectMeta(bucket, object string) (*api.GetObjectMetaResult, error) { + return api.GetObjectMeta(c, bucket, object, c.BosContext) +} + +// GetObjectMetaWithContext - support to cancel request by context.Context +func (c *Client) GetObjectMetaWithContext(ctx context.Context, + bucket, object string) (*api.GetObjectMetaResult, error) { + c.BosContext.Ctx = ctx + return api.GetObjectMeta(c, bucket, object, c.BosContext) +} + +// SelectObject - select the object content +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - args: the optional arguments to select the object +// +// RETURNS: +// - *api.SelectObjectResult: select object result +// - error: any error if it occurs +func (c *Client) SelectObject(bucket, object string, args *api.SelectObjectArgs) (*api.SelectObjectResult, error) { + return api.SelectObject(c, bucket, object, args, c.BosContext) +} + +// SelectObjectWithContext - support to cancel request by context.Context +func (c *Client) SelectObjectWithContext(ctx context.Context, bucket, object string, + args *api.SelectObjectArgs) (*api.SelectObjectResult, error) { + c.BosContext.Ctx = ctx + return api.SelectObject(c, bucket, object, args, c.BosContext) +} + +// FetchObject - fetch the object content from the given source and store +// +// PARAMS: +// - bucket: the name of the bucket to store +// - object: the name of the object to store +// - source: fetch source url +// - args: the optional arguments to fetch the object +// +// RETURNS: +// - *api.FetchObjectResult: result struct with Code, Message, RequestId and JobId fields +// - error: any error if it occurs +func (c *Client) FetchObject(bucket, object, source string, + args *api.FetchObjectArgs) (*api.FetchObjectResult, error) { + return api.FetchObject(c, bucket, object, source, args, c.BosContext) +} + +// FetchObjectWithContext - support to cancel request by context.Context +func (c *Client) FetchObjectWithContext(ctx context.Context, bucket, object, source string, + args *api.FetchObjectArgs) (*api.FetchObjectResult, error) { + c.BosContext.Ctx = ctx + return api.FetchObject(c, bucket, object, source, args, c.BosContext) +} + +// BasicFetchObject - the basic interface of the fetch object api +// +// PARAMS: +// - bucket: the name of the bucket to store +// - object: the name of the object to store +// - source: fetch source url +// +// RETURNS: +// - *api.FetchObjectResult: result struct with Code, Message, RequestId and JobId fields +// - error: any error if it occurs +func (c *Client) BasicFetchObject(bucket, object, source string) (*api.FetchObjectResult, error) { + return api.FetchObject(c, bucket, object, source, nil, c.BosContext) +} + +// SimpleFetchObject - fetch object with simple arguments interface +// +// PARAMS: +// - bucket: the name of the bucket to store +// - object: the name of the object to store +// - source: fetch source url +// - mode: fetch mode which supports sync and async +// - storageClass: the storage class of the fetched object +// +// RETURNS: +// - *api.FetchObjectResult: result struct with Code, Message, RequestId and JobId fields +// - error: any error if it occurs +func (c *Client) SimpleFetchObject(bucket, object, source, mode, + storageClass string) (*api.FetchObjectResult, error) { + args := &api.FetchObjectArgs{FetchMode: mode, StorageClass: storageClass, FetchCallBackAddress: ""} + return api.FetchObject(c, bucket, object, source, args, c.BosContext) +} + +// AppendObject - append the given content to a new or existed object which is appendable +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - content: the append object stream +// - args: the optional arguments to append object +// +// RETURNS: +// - *api.AppendObjectResult: the result of the appended object +// - error: any error if it occurs +func (c *Client) AppendObject(bucket, object string, content *bce.Body, + args *api.AppendObjectArgs) (*api.AppendObjectResult, error) { + return api.AppendObject(c, bucket, object, content, args, c.BosContext) +} + +// AppendObjectWithContext - support to cancel request by context.Context +func (c *Client) AppendObjectWithContext(ctx context.Context, bucket, object string, + content *bce.Body, args *api.AppendObjectArgs) (*api.AppendObjectResult, error) { + c.BosContext.Ctx = ctx + return api.AppendObject(c, bucket, object, content, args, c.BosContext) +} + +// SimpleAppendObject - the interface to append object with simple offset argument +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - content: the append object stream +// - offset: the offset of where to append +// +// RETURNS: +// - *api.AppendObjectResult: the result of the appended object +// - error: any error if it occurs +func (c *Client) SimpleAppendObject(bucket, object string, content *bce.Body, + offset int64) (*api.AppendObjectResult, error) { + return api.AppendObject(c, bucket, object, content, &api.AppendObjectArgs{Offset: offset}, c.BosContext) +} + +// SimpleAppendObjectFromString - the simple interface of appending an object from a string +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - content: the object string to append +// - offset: the offset of where to append +// +// RETURNS: +// - *api.AppendObjectResult: the result of the appended object +// - error: any error if it occurs +func (c *Client) SimpleAppendObjectFromString(bucket, object, content string, + offset int64) (*api.AppendObjectResult, error) { + body, err := bce.NewBodyFromString(content) + if err != nil { + return nil, err + } + return api.AppendObject(c, bucket, object, body, &api.AppendObjectArgs{Offset: offset}, c.BosContext) +} + +// SimpleAppendObjectFromFile - the simple interface of appending an object from a file +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - filePath: the full file path +// - offset: the offset of where to append +// +// RETURNS: +// - *api.AppendObjectResult: the result of the appended object +// - error: any error if it occurs +func (c *Client) SimpleAppendObjectFromFile(bucket, object, filePath string, + offset int64) (*api.AppendObjectResult, error) { + body, err := bce.NewBodyFromFile(filePath) + if err != nil { + return nil, err + } + return api.AppendObject(c, bucket, object, body, &api.AppendObjectArgs{Offset: offset}, c.BosContext) +} + +// DeleteObject - delete the given object +// +// PARAMS: +// - bucket: the name of the bucket to delete +// - object: the name of the object to delete +// +// RETURNS: +// - error: any error if it occurs +func (c *Client) DeleteObject(bucket, object string) error { + return api.DeleteObject(c, bucket, object, "", c.BosContext) +} + +func (c *Client) DeleteObjectVersion(bucket, object, versionId string) error { + return api.DeleteObject(c, bucket, object, versionId, c.BosContext) +} + +// DeleteMultipleObjects - delete a list of objects +// +// PARAMS: +// - bucket: the name of the bucket to delete +// - objectListStream: the object list stream to be deleted +// +// RETURNS: +// - *api.DeleteMultipleObjectsResult: the delete information +// - error: any error if it occurs +func (c *Client) DeleteMultipleObjects(bucket string, + objectListStream *bce.Body) (*api.DeleteMultipleObjectsResult, error) { + return api.DeleteMultipleObjects(c, bucket, objectListStream, c.BosContext) +} + +// DeleteMultipleObjectsFromString - delete a list of objects with json format string +// +// PARAMS: +// - bucket: the name of the bucket to delete +// - objectListString: the object list string to be deleted +// +// RETURNS: +// - *api.DeleteMultipleObjectsResult: the delete information +// - error: any error if it occurs +func (c *Client) DeleteMultipleObjectsFromString(bucket, + objectListString string) (*api.DeleteMultipleObjectsResult, error) { + body, err := bce.NewBodyFromString(objectListString) + if err != nil { + return nil, err + } + return api.DeleteMultipleObjects(c, bucket, body, c.BosContext) +} + +// DeleteMultipleObjectsFromStruct - delete a list of objects with object list struct +// +// PARAMS: +// - bucket: the name of the bucket to delete +// - objectListStruct: the object list struct to be deleted +// +// RETURNS: +// - *api.DeleteMultipleObjectsResult: the delete information +// - error: any error if it occurs +func (c *Client) DeleteMultipleObjectsFromStruct(bucket string, + objectListStruct *api.DeleteMultipleObjectsArgs) (*api.DeleteMultipleObjectsResult, error) { + jsonBytes, jsonErr := json.Marshal(objectListStruct) + if jsonErr != nil { + return nil, jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return nil, err + } + return api.DeleteMultipleObjects(c, bucket, body, c.BosContext) +} + +// DeleteMultipleObjectsFromKeyList - delete a list of objects with given key string array +// +// PARAMS: +// - bucket: the name of the bucket to delete +// - keyList: the key string list to be deleted +// +// RETURNS: +// - *api.DeleteMultipleObjectsResult: the delete information +// - error: any error if it occurs +func (c *Client) DeleteMultipleObjectsFromKeyList(bucket string, + keyList []string) (*api.DeleteMultipleObjectsResult, error) { + if len(keyList) == 0 { + return nil, fmt.Errorf("the key list to be deleted is empty") + } + args := make([]api.DeleteObjectArgs, len(keyList)) + for i, k := range keyList { + args[i].Key = k + } + argsContainer := &api.DeleteMultipleObjectsArgs{Objects: args} + + jsonBytes, jsonErr := json.Marshal(argsContainer) + if jsonErr != nil { + return nil, jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return nil, err + } + return api.DeleteMultipleObjects(c, bucket, body, c.BosContext) +} + +// InitiateMultipartUpload - initiate a multipart upload to get a upload ID +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - contentType: the content type of the object to be uploaded which should be specified, +// otherwise use the default(application/octet-stream) +// - args: the optional arguments +// +// RETURNS: +// - *InitiateMultipartUploadResult: the result data structure +// - error: nil if ok otherwise the specific error +func (c *Client) InitiateMultipartUpload(bucket, object, contentType string, + args *api.InitiateMultipartUploadArgs) (*api.InitiateMultipartUploadResult, error) { + return api.InitiateMultipartUpload(c, bucket, object, contentType, args, c.BosContext) +} + +// BasicInitiateMultipartUpload - basic interface to initiate a multipart upload +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// +// RETURNS: +// - *InitiateMultipartUploadResult: the result data structure +// - error: nil if ok otherwise the specific error +func (c *Client) BasicInitiateMultipartUpload(bucket, + object string) (*api.InitiateMultipartUploadResult, error) { + return api.InitiateMultipartUpload(c, bucket, object, "", nil, c.BosContext) +} + +// UploadPart - upload the single part in the multipart upload process +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - uploadId: the multipart upload id +// - partNumber: the current part number +// - content: the uploaded part content +// - args: the optional arguments +// +// RETURNS: +// - string: the etag of the uploaded part +// - error: nil if ok otherwise the specific error +func (c *Client) UploadPart(bucket, object, uploadId string, partNumber int, + content *bce.Body, args *api.UploadPartArgs) (string, error) { + return api.UploadPart(c, bucket, object, uploadId, partNumber, content, args, c.BosContext) +} + +// UploadPartWithContext - support to cancel request by context.Context +func (c *Client) UploadPartWithContext(ctx context.Context, bucket, object, uploadId string, + partNumber int, content *bce.Body, args *api.UploadPartArgs) (string, error) { + c.BosContext.Ctx = ctx + return api.UploadPart(c, bucket, object, uploadId, partNumber, content, args, c.BosContext) +} + +// BasicUploadPart - basic interface to upload the single part in the multipart upload process +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - uploadId: the multipart upload id +// - partNumber: the current part number +// - content: the uploaded part content +// +// RETURNS: +// - string: the etag of the uploaded part +// - error: nil if ok otherwise the specific error +func (c *Client) BasicUploadPart(bucket, object, uploadId string, partNumber int, + content *bce.Body) (string, error) { + return api.UploadPart(c, bucket, object, uploadId, partNumber, content, nil, c.BosContext) +} + +// UploadPartFromBytes - upload the single part in the multipart upload process +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - uploadId: the multipart upload id +// - partNumber: the current part number +// - content: the uploaded part content +// - args: the optional arguments +// +// RETURNS: +// - string: the etag of the uploaded part +// - error: nil if ok otherwise the specific error +func (c *Client) UploadPartFromBytes(bucket, object, uploadId string, partNumber int, + content []byte, args *api.UploadPartArgs) (string, error) { + return api.UploadPartFromBytes(c, bucket, object, uploadId, partNumber, content, args, c.BosContext) +} + +// UploadPartFromBytesWithContext - support to cancel request by context.Context +func (c *Client) UploadPartFromBytesWithContext(ctx context.Context, bucket, object, uploadId string, + partNumber int, content []byte, args *api.UploadPartArgs) (string, error) { + c.BosContext.Ctx = ctx + return api.UploadPartFromBytes(c, bucket, object, uploadId, partNumber, content, args, c.BosContext) +} + +// UploadPartCopy - copy the multipart object +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - srcBucket: the source bucket +// - srcObject: the source object +// - uploadId: the multipart upload id +// - partNumber: the current part number +// - args: the optional arguments +// +// RETURNS: +// - *CopyObjectResult: the lastModified and eTag of the part +// - error: nil if ok otherwise the specific error +func (c *Client) UploadPartCopy(bucket, object, srcBucket, srcObject, uploadId string, + partNumber int, args *api.UploadPartCopyArgs) (*api.CopyObjectResult, error) { + source := fmt.Sprintf("/%s/%s", srcBucket, srcObject) + return api.UploadPartCopy(c, bucket, object, source, uploadId, partNumber, args, c.BosContext) +} + +// UploadPartCopyWithContext - support to cancel request by context.Context +func (c *Client) UploadPartCopyWithContext(ctx context.Context, bucket, object, srcBucket, srcObject, uploadId string, + partNumber int, args *api.UploadPartCopyArgs) (*api.CopyObjectResult, error) { + source := fmt.Sprintf("/%s/%s", srcBucket, srcObject) + c.BosContext.Ctx = ctx + return api.UploadPartCopy(c, bucket, object, source, uploadId, partNumber, args, c.BosContext) +} + +// BasicUploadPartCopy - basic interface to copy the multipart object +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - srcBucket: the source bucket +// - srcObject: the source object +// - uploadId: the multipart upload id +// - partNumber: the current part number +// +// RETURNS: +// - *CopyObjectResult: the lastModified and eTag of the part +// - error: nil if ok otherwise the specific error +func (c *Client) BasicUploadPartCopy(bucket, object, srcBucket, srcObject, uploadId string, + partNumber int) (*api.CopyObjectResult, error) { + source := fmt.Sprintf("/%s/%s", srcBucket, srcObject) + return api.UploadPartCopy(c, bucket, object, source, uploadId, partNumber, nil, c.BosContext) +} + +// CompleteMultipartUpload - finish a multipart upload operation with parts stream +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// - parts: all parts info stream +// - meta: user defined meta data +// +// RETURNS: +// - *CompleteMultipartUploadResult: the result data +// - error: nil if ok otherwise the specific error +func (c *Client) CompleteMultipartUpload(bucket, object, uploadId string, + body *bce.Body, args *api.CompleteMultipartUploadArgs) (*api.CompleteMultipartUploadResult, error) { + return api.CompleteMultipartUpload(c, bucket, object, uploadId, body, args, c.BosContext) +} + +// CompleteMultipartUploadFromStruct - finish a multipart upload operation with parts struct +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// - args: args info struct object +// +// RETURNS: +// - *CompleteMultipartUploadResult: the result data +// - error: nil if ok otherwise the specific error +func (c *Client) CompleteMultipartUploadFromStruct(bucket, object, uploadId string, + args *api.CompleteMultipartUploadArgs) (*api.CompleteMultipartUploadResult, error) { + jsonBytes, jsonErr := json.Marshal(args) + if jsonErr != nil { + return nil, jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return nil, err + } + return api.CompleteMultipartUpload(c, bucket, object, uploadId, body, args, c.BosContext) +} + +// AbortMultipartUpload - abort a multipart upload operation +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func (c *Client) AbortMultipartUpload(bucket, object, uploadId string) error { + return api.AbortMultipartUpload(c, bucket, object, uploadId, c.BosContext) +} + +// ListParts - list the successfully uploaded parts info by upload id +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// - args: the optional arguments +// +// RETURNS: +// - *ListPartsResult: the uploaded parts info result +// - error: nil if ok otherwise the specific error +func (c *Client) ListParts(bucket, object, uploadId string, + args *api.ListPartsArgs) (*api.ListPartsResult, error) { + return api.ListParts(c, bucket, object, uploadId, args, c.BosContext) +} + +// ListPartsWithContext - support to cancel request by context.Context +func (c *Client) ListPartsWithContext(ctx context.Context, bucket, object, uploadId string, + args *api.ListPartsArgs) (*api.ListPartsResult, error) { + c.BosContext.Ctx = ctx + return api.ListParts(c, bucket, object, uploadId, args, c.BosContext) +} + +// BasicListParts - basic interface to list the successfully uploaded parts info by upload id +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - uploadId: the multipart upload id +// +// RETURNS: +// - *ListPartsResult: the uploaded parts info result +// - error: nil if ok otherwise the specific error +func (c *Client) BasicListParts(bucket, object, uploadId string) (*api.ListPartsResult, error) { + return api.ListParts(c, bucket, object, uploadId, nil, c.BosContext) +} + +// ListMultipartUploads - list the unfinished uploaded parts of the given bucket +// +// PARAMS: +// - bucket: the destination bucket name +// - args: the optional arguments +// +// RETURNS: +// - *ListMultipartUploadsResult: the unfinished uploaded parts info result +// - error: nil if ok otherwise the specific error +func (c *Client) ListMultipartUploads(bucket string, + args *api.ListMultipartUploadsArgs) (*api.ListMultipartUploadsResult, error) { + return api.ListMultipartUploads(c, bucket, args, c.BosContext) +} + +// ListMultipartUploadsWithContext - support to cancel request by context.Context +func (c *Client) ListMultipartUploadsWithContext(ctx context.Context, bucket string, + args *api.ListMultipartUploadsArgs) (*api.ListMultipartUploadsResult, error) { + c.BosContext.Ctx = ctx + return api.ListMultipartUploads(c, bucket, args, c.BosContext) +} + +// BasicListMultipartUploads - basic interface to list the unfinished uploaded parts +// +// PARAMS: +// - bucket: the destination bucket name +// +// RETURNS: +// - *ListMultipartUploadsResult: the unfinished uploaded parts info result +// - error: nil if ok otherwise the specific error +func (c *Client) BasicListMultipartUploads(bucket string) ( + *api.ListMultipartUploadsResult, error) { + return api.ListMultipartUploads(c, bucket, nil, c.BosContext) +} + +// UploadSuperFile - parallel upload the super file by using the multipart upload interface +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - fileName: the local full path filename of the super file +// - storageClass: the storage class to be set to the uploaded file +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func (c *Client) UploadSuperFile(bucket, object, fileName, storageClass string) error { + // Get the file size and check the size for multipart upload + file, fileErr := os.Open(fileName) + if fileErr != nil { + return fileErr + } + oldTimeout := c.Config.ConnectionTimeoutInMillis + c.Config.ConnectionTimeoutInMillis = 0 + defer func() { + c.Config.ConnectionTimeoutInMillis = oldTimeout + file.Close() + }() + fileInfo, infoErr := file.Stat() + if infoErr != nil { + return infoErr + } + size := fileInfo.Size() + if size < MIN_MULTIPART_SIZE || c.MultipartSize < MIN_MULTIPART_SIZE { + return bce.NewBceClientError("multipart size should not be less than 1MB") + } + + // Calculate part size and total part number + partSize := (c.MultipartSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN + partNum := (size + partSize - 1) / partSize + if partNum > MAX_PART_NUMBER { + partSize = (size + MAX_PART_NUMBER - 1) / MAX_PART_NUMBER + partSize = (partSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN + partNum = (size + partSize - 1) / partSize + } + log.Debugf("starting upload super file, total parts: %d, part size: %d", partNum, partSize) + + // Inner wrapper function of parallel uploading each part to get the ETag of the part + uploadPart := func(bucket, object, uploadId string, partNumber int, body *bce.Body, + result chan *api.UploadInfoType, ret chan error, id int64, pool chan int64) { + etag, err := c.BasicUploadPart(bucket, object, uploadId, partNumber, body) + if err != nil { + result <- nil + ret <- err + } else { + result <- &api.UploadInfoType{PartNumber: partNumber, ETag: etag} + } + pool <- id + } + + // Do the parallel multipart upload + resp, err := c.InitiateMultipartUpload(bucket, object, "", + &api.InitiateMultipartUploadArgs{StorageClass: storageClass}) + if err != nil { + return err + } + uploadId := resp.UploadId + uploadedResult := make(chan *api.UploadInfoType, partNum) + retChan := make(chan error, partNum) + workerPool := make(chan int64, c.MaxParallel) + for i := int64(0); i < c.MaxParallel; i++ { + workerPool <- i + } + for partId := int64(1); partId <= partNum; partId++ { + uploadSize := partSize + offset := (partId - 1) * partSize + left := size - offset + if uploadSize > left { + uploadSize = left + } + partBody, _ := bce.NewBodyFromSectionFile(file, offset, uploadSize) + select { // wait until get a worker to upload + case workerId := <-workerPool: + go uploadPart(bucket, object, uploadId, int(partId), partBody, + uploadedResult, retChan, workerId, workerPool) + case uploadPartErr := <-retChan: + c.AbortMultipartUpload(bucket, object, uploadId) + return uploadPartErr + } + } + + // Check the return of each part uploading, and decide to complete or abort it + completeArgs := &api.CompleteMultipartUploadArgs{ + Parts: make([]api.UploadInfoType, partNum), + } + for i := partNum; i > 0; i-- { + uploaded := <-uploadedResult + if uploaded == nil { // error occurs and not be caught in `select' statement + c.AbortMultipartUpload(bucket, object, uploadId) + return <-retChan + } + completeArgs.Parts[uploaded.PartNumber-1] = *uploaded + log.Debugf("upload part %d success, etag: %s", uploaded.PartNumber, uploaded.ETag) + } + if _, err := c.CompleteMultipartUploadFromStruct(bucket, object, + uploadId, completeArgs); err != nil { + c.AbortMultipartUpload(bucket, object, uploadId) + return err + } + return nil +} + +// DownloadSuperFile - parallel download the super file using the get object with range +// +// PARAMS: +// - bucket: the destination bucket name +// - object: the destination object name +// - fileName: the local full path filename to store the object +// +// RETURNS: +// - error: nil if ok otherwise the specific error +func (c *Client) DownloadSuperFile(bucket, object, fileName string) (err error) { + file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) + if err != nil { + return + } + oldTimeout := c.Config.ConnectionTimeoutInMillis + c.Config.ConnectionTimeoutInMillis = 0 + defer func() { + c.Config.ConnectionTimeoutInMillis = oldTimeout + file.Close() + if err != nil { + os.Remove(fileName) + } + }() + + meta, err := c.GetObjectMeta(bucket, object) + if err != nil { + return + } + size := meta.ContentLength + partSize := (c.MultipartSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN + partNum := (size + partSize - 1) / partSize + log.Debugf("starting download super file, total parts: %d, part size: %d", partNum, partSize) + + doneChan := make(chan struct{}, partNum) + abortChan := make(chan struct{}) + + // Set up multiple goroutine workers to download the object + workerPool := make(chan int64, c.MaxParallel) + for i := int64(0); i < c.MaxParallel; i++ { + workerPool <- i + } + for i := int64(0); i < partNum; i++ { + rangeStart := i * partSize + rangeEnd := (i+1)*partSize - 1 + if rangeEnd > size-1 { + rangeEnd = size - 1 + } + select { + case workerId := <-workerPool: + go func(rangeStart, rangeEnd, workerId int64) { + res, rangeGetErr := c.GetObject(bucket, object, nil, rangeStart, rangeEnd) + if rangeGetErr != nil { + log.Errorf("download object part(offset:%d, size:%d) failed: %v", + rangeStart, res.ContentLength, rangeGetErr) + abortChan <- struct{}{} + err = rangeGetErr + return + } + defer res.Body.Close() + log.Debugf("writing part %d with offset=%d, size=%d", rangeStart/partSize, + rangeStart, res.ContentLength) + buf := make([]byte, 4096) + offset := rangeStart + for { + n, e := res.Body.Read(buf) + if e != nil && e != io.EOF { + abortChan <- struct{}{} + err = e + return + } + if n == 0 { + break + } + if _, writeErr := file.WriteAt(buf[:n], offset); writeErr != nil { + abortChan <- struct{}{} + err = writeErr + return + } + offset += int64(n) + } + log.Debugf("writing part %d done", rangeStart/partSize) + workerPool <- workerId + doneChan <- struct{}{} + }(rangeStart, rangeEnd, workerId) + case <-abortChan: // abort range get if error occurs during downloading any part + return + } + } + + // Wait for writing to local file done + for i := partNum; i > 0; i-- { + <-doneChan + } + return nil +} + +// GeneratePresignedUrl - generate an authorization url with expire time and optional arguments +// +// PARAMS: +// - bucket: the target bucket name +// - object: the target object name +// - expireInSeconds: the expire time in seconds of the signed url +// - method: optional sign method, default is GET +// - headers: optional sign headers, default just set the Host +// - params: optional sign params, default is empty +// +// RETURNS: +// - string: the presigned url with authorization string +func (c *Client) GeneratePresignedUrl(bucket, object string, expireInSeconds int, method string, + headers, params map[string]string) string { + return api.GeneratePresignedUrl(c.Config, c.Signer, bucket, object, + expireInSeconds, method, headers, params) +} + +func (c *Client) GeneratePresignedUrlPathStyle(bucket, object string, expireInSeconds int, method string, + headers, params map[string]string) string { + return api.GeneratePresignedUrlPathStyle(c.Config, c.Signer, bucket, object, + expireInSeconds, method, headers, params) +} + +// BasicGeneratePresignedUrl - basic interface to generate an authorization url with expire time +// +// PARAMS: +// - bucket: the target bucket name +// - object: the target object name +// - expireInSeconds: the expire time in seconds of the signed url +// +// RETURNS: +// - string: the presigned url with authorization string +func (c *Client) BasicGeneratePresignedUrl(bucket, object string, expireInSeconds int) string { + return api.GeneratePresignedUrl(c.Config, c.Signer, bucket, object, + expireInSeconds, "", nil, nil) +} + +// PutObjectAcl - set the ACL of the given object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - aclBody: the acl json body stream +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutObjectAcl(bucket, object string, aclBody *bce.Body) error { + return api.PutObjectAcl(c, bucket, object, "", nil, nil, aclBody, c.BosContext) +} + +// PutObjectAclFromCanned - set the canned acl of the given object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - cannedAcl: the cannedAcl string +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutObjectAclFromCanned(bucket, object, cannedAcl string) error { + return api.PutObjectAcl(c, bucket, object, cannedAcl, nil, nil, nil, c.BosContext) +} + +// PutObjectAclGrantRead - set the canned grant read acl of the given object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - ids: the user id list to grant read for this object +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutObjectAclGrantRead(bucket, object string, ids ...string) error { + return api.PutObjectAcl(c, bucket, object, "", ids, nil, nil, c.BosContext) +} + +// PutObjectAclGrantFullControl - set the canned grant full-control acl of the given object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - ids: the user id list to grant full-control for this object +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutObjectAclGrantFullControl(bucket, object string, ids ...string) error { + return api.PutObjectAcl(c, bucket, object, "", nil, ids, nil, c.BosContext) +} + +// PutObjectAclFromFile - set the acl of the given object with acl json file name +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - aclFile: the acl file name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutObjectAclFromFile(bucket, object, aclFile string) error { + body, err := bce.NewBodyFromFile(aclFile) + if err != nil { + return err + } + return api.PutObjectAcl(c, bucket, object, "", nil, nil, body, c.BosContext) +} + +// PutObjectAclFromString - set the acl of the given object with acl json string +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - aclString: the acl string with json format +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutObjectAclFromString(bucket, object, aclString string) error { + body, err := bce.NewBodyFromString(aclString) + if err != nil { + return err + } + return api.PutObjectAcl(c, bucket, object, "", nil, nil, body, c.BosContext) +} + +// PutObjectAclFromStruct - set the acl of the given object with acl data structure +// +// PARAMS: +// - bucket: the bucket name +// - aclObj: the acl struct object +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutObjectAclFromStruct(bucket, object string, aclObj *api.PutObjectAclArgs) error { + jsonBytes, jsonErr := json.Marshal(aclObj) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return err + } + return api.PutObjectAcl(c, bucket, object, "", nil, nil, body, c.BosContext) +} + +// GetObjectAcl - get the acl of the given object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// +// RETURNS: +// - *api.GetObjectAclResult: the result of the object acl +// - error: nil if success otherwise the specific error +func (c *Client) GetObjectAcl(bucket, object string) (*api.GetObjectAclResult, error) { + return api.GetObjectAcl(c, bucket, object, c.BosContext) +} + +// DeleteObjectAcl - delete the acl of the given object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteObjectAcl(bucket, object string) error { + return api.DeleteObjectAcl(c, bucket, object, c.BosContext) +} + +// RestoreObject - restore the archive object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - restoreDays: the effective time of restore +// - restoreTier: the tier of restore +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) RestoreObject(bucket string, object string, restoreDays int, restoreTier string) error { + if _, ok := api.VALID_RESTORE_TIER[restoreTier]; !ok { + return errors.New("invalid restore tier") + } + + if restoreDays <= 0 { + return errors.New("invalid restore days") + } + + args := api.ArchiveRestoreArgs{ + RestoreTier: restoreTier, + RestoreDays: restoreDays, + } + return api.RestoreObject(c, bucket, object, args, c.BosContext) +} + +// PutBucketTrash - put the bucket trash +// +// PARAMS: +// - bucket: the bucket name +// - trashReq: the trash request +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketTrash(bucket string, trashReq api.PutBucketTrashReq) error { + return api.PutBucketTrash(c, bucket, trashReq, c.BosContext) +} + +// GetBucketTrash - get the bucket trash +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - *api.GetBucketTrashResult,: the result of the bucket trash +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketTrash(bucket string) (*api.GetBucketTrashResult, error) { + return api.GetBucketTrash(c, bucket, c.BosContext) +} + +// DeleteBucketTrash - delete the trash of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketTrash(bucket string) error { + return api.DeleteBucketTrash(c, bucket, c.BosContext) +} + +// PutBucketNotification - put the bucket notification +// +// PARAMS: +// - bucket: the bucket name +// - putBucketNotificationReq: the bucket notification request +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) PutBucketNotification(bucket string, putBucketNotificationReq api.PutBucketNotificationReq) error { + return api.PutBucketNotification(c, bucket, putBucketNotificationReq, c.BosContext) +} + +// GetBucketNotification - get the bucket notification +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - *api.PutBucketNotificationReq,: the result of the bucket notification +// - error: nil if success otherwise the specific error +func (c *Client) GetBucketNotification(bucket string) (*api.PutBucketNotificationReq, error) { + return api.GetBucketNotification(c, bucket, c.BosContext) +} + +// DeleteBucketNotification - delete the notification of the given bucket +// +// PARAMS: +// - bucket: the bucket name +// +// RETURNS: +// - error: nil if success otherwise the specific error +func (c *Client) DeleteBucketNotification(bucket string) error { + return api.DeleteBucketNotification(c, bucket, c.BosContext) +} + +// ParallelUpload - auto multipart upload object +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - filename: the filename +// - contentType: the content type default(application/octet-stream) +// - args: the bucket name nil using default +// +// RETURNS: +// - *api.CompleteMultipartUploadResult: multipart upload result +// - error: nil if success otherwise the specific error +func (c *Client) ParallelUpload(bucket string, object string, filename string, contentType string, args *api.InitiateMultipartUploadArgs) (*api.CompleteMultipartUploadResult, error) { + + initiateMultipartUploadResult, err := api.InitiateMultipartUpload(c, bucket, object, contentType, args, c.BosContext) + if err != nil { + return nil, err + } + + partEtags, err := c.parallelPartUpload(bucket, object, filename, initiateMultipartUploadResult.UploadId) + if err != nil { + c.AbortMultipartUpload(bucket, object, initiateMultipartUploadResult.UploadId) + return nil, err + } + + completeMultipartUploadResult, err := c.CompleteMultipartUploadFromStruct(bucket, object, initiateMultipartUploadResult.UploadId, &api.CompleteMultipartUploadArgs{Parts: partEtags}) + if err != nil { + c.AbortMultipartUpload(bucket, object, initiateMultipartUploadResult.UploadId) + return nil, err + } + return completeMultipartUploadResult, nil +} + +// parallelPartUpload - single part upload +// +// PARAMS: +// - bucket: the bucket name +// - object: the object name +// - filename: the uploadId +// - uploadId: the uploadId +// +// RETURNS: +// - []api.UploadInfoType: multipart upload result +// - error: nil if success otherwise the specific error +func (c *Client) parallelPartUpload(bucket string, object string, filename string, uploadId string) ([]api.UploadInfoType, error) { + file, err := os.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + // 分块大小按MULTIPART_ALIGN=1MB对齐 + partSize := (c.MultipartSize + + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN + + // 获取文件大小,并计算分块数目,最大分块数MAX_PART_NUMBER=10000 + fileInfo, _ := file.Stat() + fileSize := fileInfo.Size() + partNum := (fileSize + partSize - 1) / partSize + if partNum > MAX_PART_NUMBER { // 超过最大分块数,需调整分块大小 + partSize = (fileSize + MAX_PART_NUMBER + 1) / MAX_PART_NUMBER + partSize = (partSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN + partNum = (fileSize + partSize - 1) / partSize + } + + parallelChan := make(chan int, c.MaxParallel) + + errChan := make(chan error, c.MaxParallel) + + resultChan := make(chan api.UploadInfoType, partNum) + + // 逐个分块上传 + for i := int64(1); i <= partNum; i++ { + // 计算偏移offset和本次上传的大小uploadSize + uploadSize := partSize + offset := partSize * (i - 1) + left := fileSize - offset + if left < partSize { + uploadSize = left + } + + // 创建指定偏移、指定大小的文件流 + partBody, _ := bce.NewBodyFromSectionFile(file, offset, uploadSize) + + select { + case err = <-errChan: + return nil, err + default: + select { + case err = <-errChan: + return nil, err + case parallelChan <- 1: + go c.singlePartUpload(bucket, object, uploadId, int(i), partBody, parallelChan, errChan, resultChan) + } + + } + } + + partEtags := make([]api.UploadInfoType, partNum) + for i := int64(0); i < partNum; i++ { + select { + case err := <-errChan: + return nil, err + case result := <-resultChan: + partEtags[result.PartNumber-1].PartNumber = result.PartNumber + partEtags[result.PartNumber-1].ETag = result.ETag + } + } + return partEtags, nil +} + +// singlePartUpload - single part upload +// +// PARAMS: +// - pararelChan: the pararelChan +// - errChan: the error chan +// - result: the upload result chan +// - bucket: the bucket name +// - object: the object name +// - uploadId: the uploadId +// - partNumber: the part number of the object +// - content: the content of current part +func (c *Client) singlePartUpload( + bucket string, object string, uploadId string, + partNumber int, content *bce.Body, + parallelChan chan int, errChan chan error, result chan api.UploadInfoType) { + + defer func() { + if r := recover(); r != nil { + log.Fatal("parallelPartUpload recovered in f:", r) + errChan <- errors.New("parallelPartUpload panic") + } + <-parallelChan + }() + + var args api.UploadPartArgs + args.ContentMD5 = content.ContentMD5() + + etag, err := api.UploadPart(c, bucket, object, uploadId, partNumber, content, &args, c.BosContext) + if err != nil { + errChan <- err + log.Error("upload part fail,err:%v", err) + return + } + result <- api.UploadInfoType{PartNumber: partNumber, ETag: etag} + return +} + +// ParallelCopy - auto multipart copy object +// +// PARAMS: +// - srcBucketName: the src bucket name +// - srcObjectName: the src object name +// - destBucketName: the dest bucket name +// - destObjectName: the dest object name +// - args: the copy args +// - srcClient: the src region client +// +// RETURNS: +// - *api.CompleteMultipartUploadResult: multipart upload result +// - error: nil if success otherwise the specific error +func (c *Client) ParallelCopy(srcBucketName string, srcObjectName string, + destBucketName string, destObjectName string, + args *api.MultiCopyObjectArgs, srcClient *Client) (*api.CompleteMultipartUploadResult, error) { + + if srcClient == nil { + srcClient = c + } + objectMeta, err := srcClient.GetObjectMeta(srcBucketName, srcObjectName) + if err != nil { + return nil, err + } + + initArgs := api.InitiateMultipartUploadArgs{ + CacheControl: objectMeta.CacheControl, + ContentDisposition: objectMeta.ContentDisposition, + Expires: objectMeta.Expires, + StorageClass: objectMeta.StorageClass, + } + if args != nil { + if len(args.StorageClass) != 0 { + initArgs.StorageClass = args.StorageClass + } + if len(args.ObjectTagging) != 0 { + initArgs.ObjectTagging = args.ObjectTagging + } + if len(args.TaggingDirective) != 0 { + initArgs.TaggingDirective = args.TaggingDirective + } + } + initiateMultipartUploadResult, err := api.InitiateMultipartUpload(c, destBucketName, destObjectName, objectMeta.ContentType, &initArgs, c.BosContext) + + if err != nil { + return nil, err + } + + source := fmt.Sprintf("/%s/%s", srcBucketName, srcObjectName) + partEtags, err := c.parallelPartCopy(*objectMeta, source, destBucketName, destObjectName, initiateMultipartUploadResult.UploadId) + + if err != nil { + c.AbortMultipartUpload(destBucketName, destObjectName, initiateMultipartUploadResult.UploadId) + return nil, err + } + + completeMultipartUploadResult, err := c.CompleteMultipartUploadFromStruct(destBucketName, destObjectName, initiateMultipartUploadResult.UploadId, &api.CompleteMultipartUploadArgs{Parts: partEtags}) + if err != nil { + c.AbortMultipartUpload(destBucketName, destObjectName, initiateMultipartUploadResult.UploadId) + return nil, err + } + return completeMultipartUploadResult, nil +} + +// parallelPartCopy - parallel part copy +// +// PARAMS: +// - srcMeta: the copy source object meta +// - source: the copy source +// - bucket: the dest bucket name +// - object: the dest object name +// - uploadId: the uploadId +// +// RETURNS: +// - []api.UploadInfoType: multipart upload result +// - error: nil if success otherwise the specific error +func (c *Client) parallelPartCopy(srcMeta api.GetObjectMetaResult, source string, bucket string, object string, uploadId string) ([]api.UploadInfoType, error) { + var err error + size := srcMeta.ContentLength + partSize := int64(DEFAULT_MULTIPART_SIZE) + if partSize*MAX_PART_NUMBER < size { + lowerLimit := int64(math.Ceil(float64(size) / MAX_PART_NUMBER)) + partSize = int64(math.Ceil(float64(lowerLimit)/float64(partSize))) * partSize + } + partNum := (size + partSize - 1) / partSize + + parallelChan := make(chan int, c.MaxParallel) + + errChan := make(chan error, c.MaxParallel) + + resultChan := make(chan api.UploadInfoType, partNum) + + for i := int64(1); i <= partNum; i++ { + // 计算偏移offset和本次上传的大小uploadSize + uploadSize := partSize + offset := partSize * (i - 1) + left := size - offset + if left < partSize { + uploadSize = left + } + + partCopyArgs := api.UploadPartCopyArgs{ + SourceRange: fmt.Sprintf("bytes=%d-%d", (i-1)*partSize, (i-1)*partSize+uploadSize-1), + IfMatch: srcMeta.ETag, + } + + select { + case err = <-errChan: + return nil, err + default: + select { + case err = <-errChan: + return nil, err + case parallelChan <- 1: + go c.singlePartCopy(source, bucket, object, uploadId, int(i), &partCopyArgs, parallelChan, errChan, resultChan) + } + + } + } + + partEtags := make([]api.UploadInfoType, partNum) + for i := int64(0); i < partNum; i++ { + select { + case err := <-errChan: + return nil, err + case result := <-resultChan: + partEtags[result.PartNumber-1].PartNumber = result.PartNumber + partEtags[result.PartNumber-1].ETag = result.ETag + } + } + return partEtags, nil +} + +// singlePartCopy - single part copy +// +// PARAMS: +// - pararelChan: the pararelChan +// - errChan: the error chan +// - result: the upload result chan +// - source: the copy source +// - bucket: the bucket name +// - object: the object name +// - uploadId: the uploadId +// - partNumber: the part number of the object +// - args: the copy args +func (c *Client) singlePartCopy(source string, bucket string, object string, uploadId string, + partNumber int, args *api.UploadPartCopyArgs, + parallelChan chan int, errChan chan error, result chan api.UploadInfoType) { + + defer func() { + if r := recover(); r != nil { + log.Fatal("parallelPartUpload recovered in f:", r) + errChan <- errors.New("parallelPartUpload panic") + } + <-parallelChan + }() + + copyObjectResult, err := api.UploadPartCopy(c, bucket, object, source, uploadId, partNumber, args, c.BosContext) + if err != nil { + errChan <- err + log.Error("upload part fail,err:%v", err) + return + } + result <- api.UploadInfoType{PartNumber: partNumber, ETag: copyObjectResult.ETag} + return +} + +// PutSymlink - create symlink for exist target object +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the object +// - symlinkKey: the name of the symlink +// - symlinkArgs: the optional arguments +// +// RETURNS: +// - error: the put error if any occurs +func (c *Client) PutSymlink(bucket string, object string, symlinkKey string, symlinkArgs *api.PutSymlinkArgs) error { + return api.PutObjectSymlink(c, bucket, object, symlinkKey, symlinkArgs, c.BosContext) +} + +// PutSymlink - create symlink for exist target object +// +// PARAMS: +// - bucket: the name of the bucket +// - object: the name of the symlink +// +// RETURNS: +// - string: the target of the symlink +// - error: the put error if any occurs +func (c *Client) GetSymlink(bucket string, object string) (string, error) { + return api.GetObjectSymlink(c, bucket, object, c.BosContext) +} + +func (c *Client) PutBucketMirror(bucket string, putBucketMirrorArgs *api.PutBucketMirrorArgs) error { + return api.PutBucketMirror(c, bucket, putBucketMirrorArgs, c.BosContext) +} + +func (c *Client) GetBucketMirror(bucket string) (*api.PutBucketMirrorArgs, error) { + return api.GetBucketMirror(c, bucket, c.BosContext) +} + +func (c *Client) DeleteBucketMirror(bucket string) error { + return api.DeleteBucketMirror(c, bucket, c.BosContext) +} + +func (c *Client) PutBucketTag(bucket string, putBucketTagArgs *api.PutBucketTagArgs) error { + return api.PutBucketTag(c, bucket, putBucketTagArgs, c.BosContext) +} + +func (c *Client) GetBucketTag(bucket string) (*api.GetBucketTagResult, error) { + return api.GetBucketTag(c, bucket, c.BosContext) +} + +func (c *Client) DeleteBucketTag(bucket string) error { + return api.DeleteBucketTag(c, bucket, c.BosContext) +} + +func (c *Client) PutObjectTag(bucket string, object string, putObjectTagArgs *api.PutObjectTagArgs) error { + return api.PutObjectTag(c, bucket, object, putObjectTagArgs, c.BosContext) +} + +func (c *Client) GetObjectTag(bucket string, object string) (map[string]interface{}, error) { + return api.GetObjectTag(c, bucket, object, c.BosContext) +} + +func (c *Client) DeleteObjectTag(bucket string, object string) error { + return api.DeleteObjectTag(c, bucket, object, c.BosContext) +} + +func (c *Client) BosShareLinkGet(bucket string, prefix string, shareCode string, duration int) (string, error) { + return api.GetBosShareLink(c, bucket, prefix, shareCode, duration) +} + +func (c *Client) PutBucketVersioning(bucket string, putBucketVersioningArgs *api.BucketVersioningArgs) error { + return api.PutBucketVersioning(c, bucket, putBucketVersioningArgs, c.BosContext) +} + +func (c *Client) GetBucketVersioning(bucket string) (*api.BucketVersioningArgs, error) { + return api.GetBucketVersioning(c, bucket, c.BosContext) +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/sts/api/mode.go b/vendor/github.com/baidubce/bce-sdk-go/services/sts/api/mode.go new file mode 100644 index 00000000000..ef43330d800 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/sts/api/mode.go @@ -0,0 +1,30 @@ +package api + +import "time" + +type GetSessionTokenResult struct { + AccessKeyId string + SecretAccessKey string + SessionToken string + CreateTime string + Expiration string + UserId string +} + +type AssumeRoleArgs struct { + DurationSeconds int + AccountId string + UserId string + RoleName string + Acl string +} + +type Credential struct { + AccessKeyId string + SecretAccessKey string + SessionToken string + CreateTime time.Time + Expiration time.Time + UserId string + RoleId string +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/sts/api/sts.go b/vendor/github.com/baidubce/bce-sdk-go/services/sts/api/sts.go new file mode 100644 index 00000000000..0de76a0d23f --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/sts/api/sts.go @@ -0,0 +1,140 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// sts.go - define the response for STS service + +// Package api defines all APIs supported by the STS service of BCE. +package api + +import ( + "fmt" + "strconv" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +const ( + DEFAULT_DURATION_SECONDS = 43200 // default duration is 12 hours + URI_PREFIX = bce.URI_PREFIX + "v1" // sts service not support uri without prefix "v1" + REQUEST_URI = "/sessionToken" + + DEFAULT_ASSUMEROLE_DURATION_SECONDS = 7200 // default duration is 2 hours + REQUEST_ASSUMEROLE_URI = "/credential" +) + + +// GetSessionToken - get the session token from the STS service +// +// PARAMS: +// - cli: the client object which can perform sending request +// - durationSec: the duration seconds of the token +// - acl: the acl string +// +// RETURNS: +// - *GetSessionTokenResult: result of this api +// - error: nil if ok otherwise the specific error +func GetSessionToken(cli bce.Client, durationSec int, acl string) (*GetSessionTokenResult, error) { + // If the duration seconds is not a positive, use the default value + if durationSec <= 0 { + durationSec = DEFAULT_DURATION_SECONDS + } + + // Build the request + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + REQUEST_URI) + req.SetMethod(http.POST) + req.SetParam("durationSeconds", strconv.Itoa(durationSec)) + if len(acl) > 0 { + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + body, err := bce.NewBodyFromString(acl) + if err != nil { + return nil, err + } + req.SetBody(body) + } + + // Send requet and get response + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &GetSessionTokenResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +// AssumeRole - get the credential for the assume role from the STS service +// +// PARAMS: +// - cli: the client object which can perform sending request +// - args: the args for assumeRole +// RETURNS: +// - *Credential: result of this api +// - error: nil if ok otherwise the specific error +func AssumeRole(cli bce.Client, args *AssumeRoleArgs) (*Credential, error) { + // If the duration seconds is not a positive, use the default value + if args.DurationSeconds <= 0 { + args.DurationSeconds = DEFAULT_ASSUMEROLE_DURATION_SECONDS + } + + if args.AccountId == "" { + return nil, fmt.Errorf("please set accountId") + } + + if args.RoleName == "" { + return nil, fmt.Errorf("please set roleName") + } + + // Build the request + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + REQUEST_ASSUMEROLE_URI) + req.SetMethod(http.POST) + req.SetParam("assumeRole", "") + req.SetParam("durationSeconds", strconv.Itoa(args.DurationSeconds)) + req.SetParam("accountId", args.AccountId) + req.SetParam("roleName", args.RoleName) + + if args.UserId != "" { + req.SetParam("userId", args.UserId) + } + + if len(args.Acl) > 0 { + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + body, err := bce.NewBodyFromString(args.Acl) + if err != nil { + return nil, err + } + req.SetBody(body) + } + + // Send requet and get response + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &Credential{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/services/sts/client.go b/vendor/github.com/baidubce/bce-sdk-go/services/sts/client.go new file mode 100644 index 00000000000..2c5ef91b817 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/services/sts/client.go @@ -0,0 +1,74 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// client.go - define the client for STS service which is derived from BceClient + +// Package sts defines the STS service of BCE. +// It contains the model sub package to implement the concrete request and response of the +// GetSessionToken API. +package sts + +import ( + "github.com/baidubce/bce-sdk-go/auth" + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/services/sts/api" +) + +const DEFAULT_SERVICE_DOMAIN = "sts." + bce.DEFAULT_REGION + "." + bce.DEFAULT_DOMAIN + +// Client of STS service is a kind of BceClient, so it derived from the BceClient and it only +// supports the GetSessionToken API. There is no other fields needed. +type Client struct { + *bce.BceClient +} + +func (c *Client) GetSessionToken(duration int, acl string) (*api.GetSessionTokenResult, error) { + return api.GetSessionToken(c, duration, acl) +} + +func (c *Client) AssumeRole(args *api.AssumeRoleArgs) (*api.Credential, error) { + return api.AssumeRole(c, args) +} + +// NewClient make the STS service client with default configuration. +// Use `cli.Config.xxx` to access the config or change it to non-default value. +func NewClient(ak, sk string) (*Client, error) { + return NewStsClient(ak, sk, DEFAULT_SERVICE_DOMAIN) +} + +func NewStsClient(ak, sk, endpoint string) (*Client, error) { + credentials, err := auth.NewBceCredentials(ak, sk) + if err != nil { + return nil, err + } + if len(endpoint) == 0 { + endpoint = DEFAULT_SERVICE_DOMAIN + } + defaultSignOptions := &auth.SignOptions{ + HeadersToSign: auth.DEFAULT_HEADERS_TO_SIGN, + Timestamp: 0, + ExpireSeconds: auth.DEFAULT_EXPIRE_SECONDS} + defaultConf := &bce.BceClientConfiguration{ + Endpoint: endpoint, + Region: bce.DEFAULT_REGION, + UserAgent: bce.DEFAULT_USER_AGENT, + Credentials: credentials, + SignOption: defaultSignOptions, + Retry: bce.DEFAULT_RETRY_POLICY, + ConnectionTimeoutInMillis: bce.DEFAULT_CONNECTION_TIMEOUT_IN_MILLIS} + v1Signer := &auth.BceV1Signer{} + + client := &Client{bce.NewBceClient(defaultConf, v1Signer)} + return client, nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/util/log/logger.go b/vendor/github.com/baidubce/bce-sdk-go/util/log/logger.go new file mode 100644 index 00000000000..81f54987cf1 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/util/log/logger.go @@ -0,0 +1,393 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// logger.go - defines the logger structure and methods + +// Package log implements the log facilities for BCE. It supports log to stderr, stdout as well as +// log to file with rotating. It is safe to be called by multiple goroutines. +// By using the package level function to use the default logger: +// log.SetLogHandler(log.STDOUT | log.FILE) // default is log to stdout +// log.SetLogDir("/tmp") // default is /tmp +// log.SetRotateType(log.ROTATE_DAY) // default is log.HOUR +// log.SetRotateSize(1 << 30) // default is 1GB +// log.SetLogLevel(log.INFO) // default is log.DEBUG +// log.Debug(1, 1.2, "a") +// log.Debugln(1, 1.2, "a") +// log.Debugf(1, 1.2, "a") +// User can also create new logger without using the default logger: +// customLogger := log.NewLogger() +// customLogger.SetLogHandler(log.FILE) +// customLogger.Debug(1, 1.2, "a") +// The log format can also support custom setting by using the following interface: +// log.SetLogFormat([]string{log.FMT_LEVEL, log.FMT_TIME, log.FMT_MSG}) +// Most of the cases just use the default format is enough: +// []string{FMT_LEVEL, FMT_LTIME, FMT_LOCATION, FMT_MSG} +package log + +import ( + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "strings" + "time" +) + +type Handler uint8 + +// Constants for log handler flags, default is STDOUT +const ( + NONE Handler = 0 + STDOUT Handler = 1 + STDERR Handler = 1 << 1 + FILE Handler = 1 << 2 +) + +type RotateStrategy uint8 + +// Constants for log rotating strategy when logging to file, default is by hour +const ( + ROTATE_NONE RotateStrategy = iota + ROTATE_DAY + ROTATE_HOUR + ROTATE_MINUTE + ROTATE_SIZE + + DEFAULT_ROTATE_TYPE = ROTATE_HOUR + DEFAULT_ROTATE_SIZE int64 = 1 << 30 + DEFAULT_LOG_DIR = "/tmp" + ROTATE_SIZE_FILE_PREFIX = "rotating" +) + +type Level uint8 + +// Constants for log levels, default is DEBUG +const ( + DEBUG Level = iota + INFO + WARN + ERROR + FATAL + PANIC +) + +var gLevelString = [...]string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL", "PANIC"} + +// Constants of the log format components to support user custom specification +const ( + FMT_LEVEL = "level" + FMT_LTIME = "ltime" // long time with microsecond + FMT_TIME = "time" // just with second + FMT_LOCATION = "location" // caller's location with file, line, function + FMT_MSG = "msg" +) + +var ( + LOG_FMT_STR = map[string]string{ + FMT_LEVEL: "[%s]", + FMT_LTIME: "2006-01-02 15:04:05.000000", + FMT_TIME: "2006-01-02 15:04:05", + FMT_LOCATION: "%s:%d:%s:", + FMT_MSG: "%s", + } + gDefaultLogFormat = []string{FMT_LEVEL, FMT_LTIME, FMT_LOCATION, FMT_MSG} +) + +type writerArgs struct { + record string + rotateArgs interface{} // used for rotating: the size of the record or the logging time +} + +// Logger defines the internal implementation of the log facility +type logger struct { + writers map[Handler]io.WriteCloser // the destination writer to log message + writerChan chan *writerArgs // the writer channal to pass each record and time or size + logFormat []string + levelThreshold Level + handler Handler + + // Fields that used when logging to file + logDir string + logFile string + rotateType RotateStrategy + rotateSize int64 + done chan bool +} + +func (l *logger) logging(level Level, format string, args ...interface{}) { + // Only log message that set the handler and is greater than or equal to the threshold + if l.handler == NONE || level < l.levelThreshold { + return + } + + // Generate the log record string and pass it to the writer channel + now := time.Now() + pc, file, line, ok, funcname := uintptr(0), "???", 0, true, "???" + pc, file, line, ok = runtime.Caller(2) + if ok { + funcname = runtime.FuncForPC(pc).Name() + funcname = filepath.Ext(funcname) + funcname = strings.TrimPrefix(funcname, ".") + file = filepath.Base(file) + } + buf := make([]string, 0, len(l.logFormat)) + msg := fmt.Sprintf(format, args...) + for _, f := range l.logFormat { + if _, exists := LOG_FMT_STR[f]; !exists { // skip not supported part + continue + } + fmtStr := LOG_FMT_STR[f] + switch f { + case FMT_LEVEL: + buf = append(buf, fmt.Sprintf(fmtStr, gLevelString[level])) + case FMT_LTIME: + buf = append(buf, now.Format(fmtStr)) + case FMT_TIME: + buf = append(buf, now.Format(fmtStr)) + case FMT_LOCATION: + buf = append(buf, fmt.Sprintf(fmtStr, file, line, funcname)) + case FMT_MSG: + buf = append(buf, fmt.Sprintf(fmtStr, msg)) + } + } + record := strings.Join(buf, " ") + if l.rotateType == ROTATE_SIZE { + l.writerChan <- &writerArgs{record, int64(len(record))} + } else { + l.writerChan <- &writerArgs{record, now} + } + + // wait for current record done logging +} + +func (l *logger) buildWriter(args interface{}) { + if l.handler&STDOUT == STDOUT { + l.writers[STDOUT] = os.Stdout + } else { + delete(l.writers, STDOUT) + } + if l.handler&STDERR == STDERR { + l.writers[STDERR] = os.Stderr + } else { + delete(l.writers, STDERR) + } + if l.handler&FILE == FILE { + l.writers[FILE] = l.buildFileWriter(args) + } else { + delete(l.writers, FILE) + } +} + +func (l *logger) buildFileWriter(args interface{}) io.WriteCloser { + if l.handler&FILE != FILE { + return os.Stderr + } + + if len(l.logDir) == 0 { + l.logDir = DEFAULT_LOG_DIR + } + if l.rotateType < ROTATE_NONE || l.rotateType > ROTATE_SIZE { + l.rotateType = DEFAULT_ROTATE_TYPE + } + if l.rotateType == ROTATE_SIZE && l.rotateSize == 0 { + l.rotateSize = DEFAULT_ROTATE_SIZE + } + + logFile, needCreateFile := "", false + if l.rotateType == ROTATE_SIZE { + recordSize, _ := args.(int64) + logFile, needCreateFile = l.buildFileWriterBySize(recordSize) + } else { + recordTime, _ := args.(time.Time) + switch l.rotateType { + case ROTATE_NONE: + logFile = "default.log" + case ROTATE_DAY: + logFile = recordTime.Format("2006-01-02.log") + case ROTATE_HOUR: + logFile = recordTime.Format("2006-01-02_15.log") + case ROTATE_MINUTE: + logFile = recordTime.Format("2006-01-02_15-04.log") + } + if _, exist := getFileInfo(filepath.Join(l.logDir, logFile)); !exist { + needCreateFile = true + } + } + l.logFile = logFile + logFile = filepath.Join(l.logDir, l.logFile) + + // Should create new file + if needCreateFile { + if w, ok := l.writers[FILE]; ok { + w.Close() + } + if writer, err := os.Create(logFile); err == nil { + return writer + } else { + return os.Stderr + } + } + + // Already open the file + if w, ok := l.writers[FILE]; ok { + return w + } + + // Newly open the file + if writer, err := os.OpenFile(logFile, os.O_WRONLY|os.O_APPEND, 0666); err == nil { + return writer + } else { + return os.Stderr + } +} + +func (l *logger) buildFileWriterBySize(recordSize int64) (string, bool) { + logFile, needCreateFile := "", false + // First running the program and need to get filename by checking the existed files + if len(l.logFile) == 0 { + fname := fmt.Sprintf("%s-%s.0.log", ROTATE_SIZE_FILE_PREFIX, getSizeString(l.rotateSize)) + for { + size, exist := getFileInfo(filepath.Join(l.logDir, fname)) + if !exist { + logFile, needCreateFile = fname, true + break + } + if exist && size+recordSize <= l.rotateSize { + logFile, needCreateFile = fname, false + break + } + fname = getNextFileName(fname) + } + } else { // check the file size to append to the existed file or create a new file + currentFile := filepath.Join(l.logDir, l.logFile) + size, exist := getFileInfo(currentFile) + if !exist { + logFile, needCreateFile = l.logFile, true + } else { + if size+recordSize > l.rotateSize { // size exceeded + logFile, needCreateFile = getNextFileName(l.logFile), true + } else { + logFile, needCreateFile = l.logFile, false + } + } + } + return logFile, needCreateFile +} + +func (l *logger) SetHandler(h Handler) { l.handler = h } + +func (l *logger) SetLogDir(dir string) { l.logDir = dir } + +func (l *logger) SetLogLevel(level Level) { l.levelThreshold = level } + +func (l *logger) SetLogFormat(format []string) { l.logFormat = format } + +func (l *logger) SetRotateType(rotate RotateStrategy) { l.rotateType = rotate } + +func (l *logger) SetRotateSize(size int64) { l.rotateSize = size } + +func (l *logger) Debug(msg ...interface{}) { l.logging(DEBUG, "%s\n", concat(msg...)) } + +func (l *logger) Debugln(msg ...interface{}) { l.logging(DEBUG, "%s\n", concat(msg...)) } + +func (l *logger) Debugf(f string, msg ...interface{}) { l.logging(DEBUG, f+"\n", msg...) } + +func (l *logger) Info(msg ...interface{}) { l.logging(INFO, "%s\n", concat(msg...)) } + +func (l *logger) Infoln(msg ...interface{}) { l.logging(INFO, "%s\n", concat(msg...)) } + +func (l *logger) Infof(f string, msg ...interface{}) { l.logging(INFO, f+"\n", msg...) } + +func (l *logger) Warn(msg ...interface{}) { l.logging(WARN, "%s\n", concat(msg...)) } + +func (l *logger) Warnln(msg ...interface{}) { l.logging(WARN, "%s\n", concat(msg...)) } + +func (l *logger) Warnf(f string, msg ...interface{}) { l.logging(WARN, f+"\n", msg...) } + +func (l *logger) Error(msg ...interface{}) { l.logging(ERROR, "%s\n", concat(msg...)) } + +func (l *logger) Errorln(msg ...interface{}) { l.logging(ERROR, "%s\n", concat(msg...)) } + +func (l *logger) Errorf(f string, msg ...interface{}) { l.logging(ERROR, f+"\n", msg...) } + +func (l *logger) Fatal(msg ...interface{}) { l.logging(FATAL, "%s\n", concat(msg...)) } + +func (l *logger) Fatalln(msg ...interface{}) { l.logging(FATAL, "%s\n", concat(msg...)) } + +func (l *logger) Fatalf(f string, msg ...interface{}) { l.logging(FATAL, f+"\n", msg...) } + +func (l *logger) Panic(msg ...interface{}) { + record := concat(msg...) + l.logging(PANIC, "%s\n", record) + panic(record) +} + +func (l *logger) Panicln(msg ...interface{}) { + record := concat(msg...) + l.logging(PANIC, "%s\n", record) + panic(record) +} + +func (l *logger) Panicf(format string, msg ...interface{}) { + record := fmt.Sprintf(format, msg...) + l.logging(PANIC, format+"\n", msg...) + panic(record) +} + +func (l *logger) Close() { + select { + case <-l.done: + return + default: + } + l.writerChan <- nil +} + +func NewLogger() *logger { + obj := &logger{ + writers: make(map[Handler]io.WriteCloser, 3), // now only support 3 kinds of handler + writerChan: make(chan *writerArgs, 100), + logFormat: gDefaultLogFormat, + levelThreshold: DEBUG, + handler: NONE, + done: make(chan bool), + } + // The backend writer goroutine to write each log record + go func() { + defer func() { + if e := recover(); e != nil { + fmt.Println(e) + } + }() + for { + select { + case <-obj.done: + return + case args := <-obj.writerChan: // wait until a record comes to log + if args == nil { + close(obj.done) + close(obj.writerChan) + return + } + obj.buildWriter(args.rotateArgs) + for _, w := range obj.writers { + fmt.Fprint(w, args.record) + } + } + } + }() + + return obj +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/util/log/util.go b/vendor/github.com/baidubce/bce-sdk-go/util/log/util.go new file mode 100644 index 00000000000..23a6b39c55c --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/util/log/util.go @@ -0,0 +1,227 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// util.go - define the package-level default logger and functions for easily use. + +package log + +import ( + "fmt" + "os" + "strconv" + "strings" +) + +// The global default logger object to perform logging in this package-level functions +var gDefaultLogger *logger + +func init() { + gDefaultLogger = NewLogger() +} + +// Helper functions +func getFileInfo(path string) (int64, bool) { + info, err := os.Stat(path) + if err != nil { + return -1, false + } else { + return info.Size(), true + } +} + +func getSizeString(size int64) string { + if size < 0 { + return fmt.Sprintf("%d", size) + } + if size < (1 << 10) { + return fmt.Sprintf("%dB", size) + } else if size < (1 << 20) { + return fmt.Sprintf("%dkB", size>>10) + } else if size < (1 << 30) { + return fmt.Sprintf("%dMB", size>>20) + } else if size < (1 << 40) { + return fmt.Sprintf("%dGB", size>>30) + } else { + return "SUPER-LARGE" + } +} + +func getNextFileName(nowFileName string) string { + pos1 := strings.Index(nowFileName, ".") + rest := nowFileName[pos1+1:] + pos2 := strings.Index(rest, ".") + num, _ := strconv.Atoi(rest[0:pos2]) + return fmt.Sprintf("%s.%d.log", nowFileName[0:pos1], num+1) +} + +func concat(msg ...interface{}) string { + buf := make([]string, 0, len(msg)) + for _, m := range msg { + buf = append(buf, fmt.Sprintf("%v", m)) + } + return strings.Join(buf, " ") +} + +// Export package-level functions for logging messages by using the default logger. It supports 3 +// kinds of interface which is similar to the standard package "fmt": with suffix of "ln", "f" or +// nothing. +func Debug(msg ...interface{}) { + gDefaultLogger.logging(DEBUG, "%s\n", concat(msg...)) +} + +func Debugln(msg ...interface{}) { + gDefaultLogger.logging(DEBUG, "%s\n", concat(msg...)) +} + +func Debugf(format string, msg ...interface{}) { + gDefaultLogger.logging(DEBUG, format+"\n", msg...) +} + +func Info(msg ...interface{}) { + gDefaultLogger.logging(INFO, "%s\n", concat(msg...)) +} + +func Infoln(msg ...interface{}) { + gDefaultLogger.logging(INFO, "%s\n", concat(msg...)) +} + +func Infof(format string, msg ...interface{}) { + gDefaultLogger.logging(INFO, format+"\n", msg...) +} + +func Warn(msg ...interface{}) { + gDefaultLogger.logging(WARN, "%s\n", concat(msg...)) +} + +func Warnln(msg ...interface{}) { + gDefaultLogger.logging(WARN, "%s\n", concat(msg...)) +} + +func Warnf(format string, msg ...interface{}) { + gDefaultLogger.logging(WARN, format+"\n", msg...) +} + +func Error(msg ...interface{}) { + gDefaultLogger.logging(ERROR, "%s\n", concat(msg...)) +} + +func Errorln(msg ...interface{}) { + gDefaultLogger.logging(ERROR, "%s\n", concat(msg...)) +} + +func Errorf(format string, msg ...interface{}) { + gDefaultLogger.logging(ERROR, format+"\n", msg...) +} + +func Fatal(msg ...interface{}) { + gDefaultLogger.logging(FATAL, "%s\n", concat(msg...)) +} + +func Fatalln(msg ...interface{}) { + gDefaultLogger.logging(FATAL, "%s\n", concat(msg...)) +} + +func Fatalf(format string, msg ...interface{}) { + gDefaultLogger.logging(FATAL, format+"\n", msg...) +} + +func Panic(msg ...interface{}) { + record := concat(msg...) + gDefaultLogger.logging(PANIC, "%s\n", record) + panic(record) +} + +func Panicln(msg ...interface{}) { + record := concat(msg...) + gDefaultLogger.logging(PANIC, "%s\n", record) + panic(record) +} + +func Panicf(format string, msg ...interface{}) { + record := fmt.Sprintf(format, msg...) + gDefaultLogger.logging(PANIC, format+"\n", msg...) + panic(record) +} + +func Close() { + gDefaultLogger.Close() +} + +// SetLogHandler - set the handler of the logger +// +// PARAMS: +// - Handler: the handler defined in this package, now just support STDOUT, STDERR, FILE +func SetLogHandler(h Handler) { + gDefaultLogger.handler = h +} + +// SetLogLevel - set the level threshold of the logger, only level equal to or bigger than this +// value will be logged. +// +// PARAMS: +// - Level: the level defined in this package, now support 6 levels. +func SetLogLevel(l Level) { + gDefaultLogger.levelThreshold = l +} + +// SetLogFormat - set the log component of each record when logging it. The default log format is +// {FMT_LEVEL, FMT_LTIME, FMT_LOCATION, FMT_MSG}. +// +// PARAMS: +// - format: the format component array. +func SetLogFormat(format []string) { + gDefaultLogger.logFormat = format +} + +// SetLogDir - set the logging directory if logging to file. +// +// PARAMS: +// - dir: the logging directory +// RETURNS: +// - error: check the directory and try to make it, otherwise return the error. +func SetLogDir(dir string) error { + if _, err := os.Stat(dir); err != nil { + if os.IsNotExist(err) { + if mkErr := os.Mkdir(dir, os.ModePerm); mkErr != nil { + return mkErr + } + } else { + return err + } + } + gDefaultLogger.logDir = dir + return nil +} + +// SetRotateType - set the rotating strategy if logging to file. +// +// PARAMS: +// - RotateStrategy: the rotate strategy defined in this package, now support 5 strategy. +func SetRotateType(r RotateStrategy) { + gDefaultLogger.rotateType = r +} + +// SetRotateSize - set the rotating size if logging to file and set the strategy of size. +// +// PARAMS: +// - size: the rotating size +// RETURNS: +// - error: check the value and return any error if error occurs. +func SetRotateSize(size int64) error { + if size <= 0 { + return fmt.Errorf("%s", "rotate size should not be negative") + } + gDefaultLogger.rotateSize = size + return nil +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/util/mime.go b/vendor/github.com/baidubce/bce-sdk-go/util/mime.go new file mode 100644 index 00000000000..42463444674 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/util/mime.go @@ -0,0 +1,664 @@ +package util + +import ( + "sync" +) + +var DefaultMimeMap map[string]string +var once sync.Once + +func LoadMimeMap() { + DefaultMimeMap = make(map[string]string) + DefaultMimeMap[".ez"] = "application/andrew-inset" + DefaultMimeMap[".atom"] = "application/atom+xml" + DefaultMimeMap[".atomcat"] = "application/atomcat+xml" + DefaultMimeMap[".atomsvc"] = "application/atomsvc+xml" + DefaultMimeMap[".ccxml"] = "application/ccxml+xml" + DefaultMimeMap[".davmount"] = "application/davmount+xml" + DefaultMimeMap[".ecma"] = "application/ecmascript" + DefaultMimeMap[".pfr"] = "application/font-tdpfr" + DefaultMimeMap[".stk"] = "application/hyperstudio" + DefaultMimeMap[".js"] = "text/javascript" + DefaultMimeMap[".json"] = "text/json" + DefaultMimeMap[".hqx"] = "application/mac-binhex40" + DefaultMimeMap[".cpt"] = "application/mac-compactpro" + DefaultMimeMap[".mrc"] = "application/marc" + DefaultMimeMap[".ma"] = "application/mathematica" + DefaultMimeMap[".nb"] = "application/mathematica" + DefaultMimeMap[".mb"] = "application/mathematica" + DefaultMimeMap[".mathml"] = "application/mathml+xml" + DefaultMimeMap[".mbox"] = "application/mbox" + DefaultMimeMap[".mscml"] = "application/mediaservercontrol+xml" + DefaultMimeMap[".mp4s"] = "application/mp4" + DefaultMimeMap[".doc"] = "application/msword" + DefaultMimeMap[".dot"] = "application/msword" + DefaultMimeMap[".mxf"] = "application/mxf" + DefaultMimeMap[".bin"] = "application/octet-stream" + DefaultMimeMap[".dms"] = "application/octet-stream" + DefaultMimeMap[".lha"] = "application/octet-stream" + DefaultMimeMap[".lzh"] = "application/octet-stream" + DefaultMimeMap[".class"] = "application/octet-stream" + DefaultMimeMap[".so"] = "application/octet-stream" + DefaultMimeMap[".iso"] = "application/octet-stream" + DefaultMimeMap[".dmg"] = "application/octet-stream" + DefaultMimeMap[".dist"] = "application/octet-stream" + DefaultMimeMap[".distz"] = "application/octet-stream" + DefaultMimeMap[".pkg"] = "application/octet-stream" + DefaultMimeMap[".bpk"] = "application/octet-stream" + DefaultMimeMap[".dump"] = "application/octet-stream" + DefaultMimeMap[".elc"] = "application/octet-stream" + DefaultMimeMap[".oda"] = "application/oda" + DefaultMimeMap[".ogg"] = "application/ogg" + DefaultMimeMap[".pdf"] = "application/pdf" + DefaultMimeMap[".pgp"] = "application/pgp-encrypted" + DefaultMimeMap[".asc"] = "application/pgp-signature" + DefaultMimeMap[".sig"] = "application/pgp-signature" + DefaultMimeMap[".prf"] = "application/pics-rules" + DefaultMimeMap[".p10"] = "application/pkcs10" + DefaultMimeMap[".p7m"] = "application/pkcs7-mime" + DefaultMimeMap[".p7c"] = "application/pkcs7-mime" + DefaultMimeMap[".p7s"] = "application/pkcs7-signature" + DefaultMimeMap[".cer"] = "application/pkix-cert" + DefaultMimeMap[".crl"] = "application/pkix-crl" + DefaultMimeMap[".pkipath"] = "application/pkix-pkipath" + DefaultMimeMap[".pki"] = "application/pkixcmp" + DefaultMimeMap[".pls"] = "application/pls+xml" + DefaultMimeMap[".ai"] = "application/postscript" + DefaultMimeMap[".eps"] = "application/postscript" + DefaultMimeMap[".ps"] = "application/postscript" + DefaultMimeMap[".cww"] = "application/prs.cww" + DefaultMimeMap[".rdf"] = "application/rdf+xml" + DefaultMimeMap[".rif"] = "application/reginfo+xml" + DefaultMimeMap[".rnc"] = "application/relax-ng-compact-syntax" + DefaultMimeMap[".rl"] = "application/resource-lists+xml" + DefaultMimeMap[".rs"] = "application/rls-services+xml" + DefaultMimeMap[".rsd"] = "application/rsd+xml" + DefaultMimeMap[".rss"] = "application/rss+xml" + DefaultMimeMap[".rtf"] = "application/rtf" + DefaultMimeMap[".sbml"] = "application/sbml+xml" + DefaultMimeMap[".scq"] = "application/scvp-cv-request" + DefaultMimeMap[".scs"] = "application/scvp-cv-response" + DefaultMimeMap[".spq"] = "application/scvp-vp-request" + DefaultMimeMap[".spp"] = "application/scvp-vp-response" + DefaultMimeMap[".sdp"] = "application/sdp" + DefaultMimeMap[".setpay"] = "application/set-payment-initiation" + DefaultMimeMap[".setreg"] = "application/set-registration-initiation" + DefaultMimeMap[".shf"] = "application/shf+xml" + DefaultMimeMap[".smi"] = "application/smil+xml" + DefaultMimeMap[".smil"] = "application/smil+xml" + DefaultMimeMap[".rq"] = "application/sparql-query" + DefaultMimeMap[".srx"] = "application/sparql-results+xml" + DefaultMimeMap[".gram"] = "application/srgs" + DefaultMimeMap[".grxml"] = "application/srgs+xml" + DefaultMimeMap[".ssml"] = "application/ssml+xml" + DefaultMimeMap[".plb"] = "application/vnd.3gpp.pic-bw-large" + DefaultMimeMap[".psb"] = "application/vnd.3gpp.pic-bw-small" + DefaultMimeMap[".pvb"] = "application/vnd.3gpp.pic-bw-var" + DefaultMimeMap[".tcap"] = "application/vnd.3gpp2.tcap" + DefaultMimeMap[".pwn"] = "application/vnd.3m.post-it-notes" + DefaultMimeMap[".aso"] = "application/vnd.accpac.simply.aso" + DefaultMimeMap[".imp"] = "application/vnd.accpac.simply.imp" + DefaultMimeMap[".acu"] = "application/vnd.acucobol" + DefaultMimeMap[".atc"] = "application/vnd.acucorp" + DefaultMimeMap[".acutc"] = "application/vnd.acucorp" + DefaultMimeMap[".xdp"] = "application/vnd.adobe.xdp+xml" + DefaultMimeMap[".xfdf"] = "application/vnd.adobe.xfdf" + DefaultMimeMap[".ami"] = "application/vnd.amiga.ami" + DefaultMimeMap[".cii"] = "application/vnd.anser-web-certificate-issue-initiation" + DefaultMimeMap[".fti"] = "application/vnd.anser-web-funds-transfer-initiation" + DefaultMimeMap[".atx"] = "application/vnd.antix.game-component" + DefaultMimeMap[".mpkg"] = "application/vnd.apple.installer+xml" + DefaultMimeMap[".aep"] = "application/vnd.audiograph" + DefaultMimeMap[".mpm"] = "application/vnd.blueice.multipass" + DefaultMimeMap[".bmi"] = "application/vnd.bmi" + DefaultMimeMap[".rep"] = "application/vnd.businessobjects" + DefaultMimeMap[".cdxml"] = "application/vnd.chemdraw+xml" + DefaultMimeMap[".mmd"] = "application/vnd.chipnuts.karaoke-mmd" + DefaultMimeMap[".cdy"] = "application/vnd.cinderella" + DefaultMimeMap[".cla"] = "application/vnd.claymore" + DefaultMimeMap[".c4g"] = "application/vnd.clonk.c4group" + DefaultMimeMap[".c4d"] = "application/vnd.clonk.c4group" + DefaultMimeMap[".c4f"] = "application/vnd.clonk.c4group" + DefaultMimeMap[".c4p"] = "application/vnd.clonk.c4group" + DefaultMimeMap[".c4u"] = "application/vnd.clonk.c4group" + DefaultMimeMap[".csp"] = "application/vnd.commonspace" + DefaultMimeMap[".cst"] = "application/vnd.commonspace" + DefaultMimeMap[".cdbcmsg"] = "application/vnd.contact.cmsg" + DefaultMimeMap[".cmc"] = "application/vnd.cosmocaller" + DefaultMimeMap[".clkx"] = "application/vnd.crick.clicker" + DefaultMimeMap[".clkk"] = "application/vnd.crick.clicker.keyboard" + DefaultMimeMap[".clkp"] = "application/vnd.crick.clicker.palette" + DefaultMimeMap[".clkt"] = "application/vnd.crick.clicker.template" + DefaultMimeMap[".clkw"] = "application/vnd.crick.clicker.wordbank" + DefaultMimeMap[".wbs"] = "application/vnd.criticaltools.wbs+xml" + DefaultMimeMap[".pml"] = "application/vnd.ctc-posml" + DefaultMimeMap[".ppd"] = "application/vnd.cups-ppd" + DefaultMimeMap[".curl"] = "application/vnd.curl" + DefaultMimeMap[".rdz"] = "application/vnd.data-vision.rdz" + DefaultMimeMap[".fe_launch"] = "application/vnd.denovo.fcselayout-link" + DefaultMimeMap[".dna"] = "application/vnd.dna" + DefaultMimeMap[".mlp"] = "application/vnd.dolby.mlp" + DefaultMimeMap[".dpg"] = "application/vnd.dpgraph" + DefaultMimeMap[".dfac"] = "application/vnd.dreamfactory" + DefaultMimeMap[".mag"] = "application/vnd.ecowin.chart" + DefaultMimeMap[".nml"] = "application/vnd.enliven" + DefaultMimeMap[".esf"] = "application/vnd.epson.esf" + DefaultMimeMap[".msf"] = "application/vnd.epson.msf" + DefaultMimeMap[".qam"] = "application/vnd.epson.quickanime" + DefaultMimeMap[".slt"] = "application/vnd.epson.salt" + DefaultMimeMap[".ssf"] = "application/vnd.epson.ssf" + DefaultMimeMap[".es3"] = "application/vnd.eszigno3+xml" + DefaultMimeMap[".et3"] = "application/vnd.eszigno3+xml" + DefaultMimeMap[".ez2"] = "application/vnd.ezpix-album" + DefaultMimeMap[".ez3"] = "application/vnd.ezpix-package" + DefaultMimeMap[".fdf"] = "application/vnd.fdf" + DefaultMimeMap[".gph"] = "application/vnd.flographit" + DefaultMimeMap[".ftc"] = "application/vnd.fluxtime.clip" + DefaultMimeMap[".fm"] = "application/vnd.framemaker" + DefaultMimeMap[".frame"] = "application/vnd.framemaker" + DefaultMimeMap[".maker"] = "application/vnd.framemaker" + DefaultMimeMap[".fnc"] = "application/vnd.frogans.fnc" + DefaultMimeMap[".ltf"] = "application/vnd.frogans.ltf" + DefaultMimeMap[".fsc"] = "application/vnd.fsc.weblaunch" + DefaultMimeMap[".oas"] = "application/vnd.fujitsu.oasys" + DefaultMimeMap[".oa2"] = "application/vnd.fujitsu.oasys2" + DefaultMimeMap[".oa3"] = "application/vnd.fujitsu.oasys3" + DefaultMimeMap[".fg5"] = "application/vnd.fujitsu.oasysgp" + DefaultMimeMap[".bh2"] = "application/vnd.fujitsu.oasysprs" + DefaultMimeMap[".ddd"] = "application/vnd.fujixerox.ddd" + DefaultMimeMap[".xdw"] = "application/vnd.fujixerox.docuworks" + DefaultMimeMap[".xbd"] = "application/vnd.fujixerox.docuworks.binder" + DefaultMimeMap[".fzs"] = "application/vnd.fuzzysheet" + DefaultMimeMap[".txd"] = "application/vnd.genomatix.tuxedo" + DefaultMimeMap[".kml"] = "application/vnd.google-earth.kml+xml" + DefaultMimeMap[".kmz"] = "application/vnd.google-earth.kmz" + DefaultMimeMap[".gqf"] = "application/vnd.grafeq" + DefaultMimeMap[".gqs"] = "application/vnd.grafeq" + DefaultMimeMap[".gac"] = "application/vnd.groove-account" + DefaultMimeMap[".ghf"] = "application/vnd.groove-help" + DefaultMimeMap[".gim"] = "application/vnd.groove-identity-message" + DefaultMimeMap[".grv"] = "application/vnd.groove-injector" + DefaultMimeMap[".gtm"] = "application/vnd.groove-tool-message" + DefaultMimeMap[".tpl"] = "application/vnd.groove-tool-template" + DefaultMimeMap[".vcg"] = "application/vnd.groove-vcard" + DefaultMimeMap[".zmm"] = "application/vnd.handheld-entertainment+xml" + DefaultMimeMap[".hbci"] = "application/vnd.hbci" + DefaultMimeMap[".les"] = "application/vnd.hhe.lesson-player" + DefaultMimeMap[".hpgl"] = "application/vnd.hp-hpgl" + DefaultMimeMap[".hpid"] = "application/vnd.hp-hpid" + DefaultMimeMap[".hps"] = "application/vnd.hp-hps" + DefaultMimeMap[".jlt"] = "application/vnd.hp-jlyt" + DefaultMimeMap[".pcl"] = "application/vnd.hp-pcl" + DefaultMimeMap[".pclxl"] = "application/vnd.hp-pclxl" + DefaultMimeMap[".x3d"] = "application/vnd.hzn-3d-crossword" + DefaultMimeMap[".mpy"] = "application/vnd.ibm.minipay" + DefaultMimeMap[".afp"] = "application/vnd.ibm.modcap" + DefaultMimeMap[".listafp"] = "application/vnd.ibm.modcap" + DefaultMimeMap[".list3820"] = "application/vnd.ibm.modcap" + DefaultMimeMap[".irm"] = "application/vnd.ibm.rights-management" + DefaultMimeMap[".sc"] = "application/vnd.ibm.secure-container" + DefaultMimeMap[".igl"] = "application/vnd.igloader" + DefaultMimeMap[".ivp"] = "application/vnd.immervision-ivp" + DefaultMimeMap[".ivu"] = "application/vnd.immervision-ivu" + DefaultMimeMap[".xpw"] = "application/vnd.intercon.formnet" + DefaultMimeMap[".xpx"] = "application/vnd.intercon.formnet" + DefaultMimeMap[".qbo"] = "application/vnd.intu.qbo" + DefaultMimeMap[".qfx"] = "application/vnd.intu.qfx" + DefaultMimeMap[".rcprofile"] = "application/vnd.ipunplugged.rcprofile" + DefaultMimeMap[".irp"] = "application/vnd.irepository.package+xml" + DefaultMimeMap[".xpr"] = "application/vnd.is-xpr" + DefaultMimeMap[".jam"] = "application/vnd.jam" + DefaultMimeMap[".rms"] = "application/vnd.jcp.javame.midlet-rms" + DefaultMimeMap[".jisp"] = "application/vnd.jisp" + DefaultMimeMap[".joda"] = "application/vnd.joost.joda-archive" + DefaultMimeMap[".ktz"] = "application/vnd.kahootz" + DefaultMimeMap[".ktr"] = "application/vnd.kahootz" + DefaultMimeMap[".karbon"] = "application/vnd.kde.karbon" + DefaultMimeMap[".chrt"] = "application/vnd.kde.kchart" + DefaultMimeMap[".kfo"] = "application/vnd.kde.kformula" + DefaultMimeMap[".flw"] = "application/vnd.kde.kivio" + DefaultMimeMap[".kon"] = "application/vnd.kde.kontour" + DefaultMimeMap[".kpr"] = "application/vnd.kde.kpresenter" + DefaultMimeMap[".kpt"] = "application/vnd.kde.kpresenter" + DefaultMimeMap[".ksp"] = "application/vnd.kde.kspread" + DefaultMimeMap[".kwd"] = "application/vnd.kde.kword" + DefaultMimeMap[".kwt"] = "application/vnd.kde.kword" + DefaultMimeMap[".htke"] = "application/vnd.kenameaapp" + DefaultMimeMap[".kia"] = "application/vnd.kidspiration" + DefaultMimeMap[".kne"] = "application/vnd.kinar" + DefaultMimeMap[".knp"] = "application/vnd.kinar" + DefaultMimeMap[".skp"] = "application/vnd.koan" + DefaultMimeMap[".skd"] = "application/vnd.koan" + DefaultMimeMap[".skt"] = "application/vnd.koan" + DefaultMimeMap[".skm"] = "application/vnd.koan" + DefaultMimeMap[".lbd"] = "application/vnd.llamagraphics.life-balance.desktop" + DefaultMimeMap[".lbe"] = "application/vnd.llamagraphics.life-balance.exchange+xml" + DefaultMimeMap[".123"] = "application/vnd.lotus-1-2-3" + DefaultMimeMap[".apr"] = "application/vnd.lotus-approach" + DefaultMimeMap[".pre"] = "application/vnd.lotus-freelance" + DefaultMimeMap[".nsf"] = "application/vnd.lotus-notes" + DefaultMimeMap[".org"] = "application/vnd.lotus-organizer" + DefaultMimeMap[".scm"] = "application/vnd.lotus-screencam" + DefaultMimeMap[".lwp"] = "application/vnd.lotus-wordpro" + DefaultMimeMap[".portpkg"] = "application/vnd.macports.portpkg" + DefaultMimeMap[".mcd"] = "application/vnd.mcd" + DefaultMimeMap[".mc1"] = "application/vnd.medcalcdata" + DefaultMimeMap[".cdkey"] = "application/vnd.mediastation.cdkey" + DefaultMimeMap[".mwf"] = "application/vnd.mfer" + DefaultMimeMap[".mfm"] = "application/vnd.mfmp" + DefaultMimeMap[".flo"] = "application/vnd.micrografx.flo" + DefaultMimeMap[".igx"] = "application/vnd.micrografx.igx" + DefaultMimeMap[".mif"] = "application/vnd.mif" + DefaultMimeMap[".daf"] = "application/vnd.mobius.daf" + DefaultMimeMap[".dis"] = "application/vnd.mobius.dis" + DefaultMimeMap[".mbk"] = "application/vnd.mobius.mbk" + DefaultMimeMap[".mqy"] = "application/vnd.mobius.mqy" + DefaultMimeMap[".msl"] = "application/vnd.mobius.msl" + DefaultMimeMap[".plc"] = "application/vnd.mobius.plc" + DefaultMimeMap[".txf"] = "application/vnd.mobius.txf" + DefaultMimeMap[".mpn"] = "application/vnd.mophun.application" + DefaultMimeMap[".mpc"] = "application/vnd.mophun.certificate" + DefaultMimeMap[".cil"] = "application/vnd.ms-artgalry" + DefaultMimeMap[".asf"] = "application/vnd.ms-asf" + DefaultMimeMap[".cab"] = "application/vnd.ms-cab-compressed" + DefaultMimeMap[".xls"] = "application/vnd.ms-excel" + DefaultMimeMap[".xlm"] = "application/vnd.ms-excel" + DefaultMimeMap[".xla"] = "application/vnd.ms-excel" + DefaultMimeMap[".xlc"] = "application/vnd.ms-excel" + DefaultMimeMap[".xlt"] = "application/vnd.ms-excel" + DefaultMimeMap[".xlw"] = "application/vnd.ms-excel" + DefaultMimeMap[".eot"] = "application/vnd.ms-fontobject" + DefaultMimeMap[".chm"] = "application/vnd.ms-htmlhelp" + DefaultMimeMap[".ims"] = "application/vnd.ms-ims" + DefaultMimeMap[".lrm"] = "application/vnd.ms-lrm" + DefaultMimeMap[".ppt"] = "application/vnd.ms-powerpoint" + DefaultMimeMap[".pps"] = "application/vnd.ms-powerpoint" + DefaultMimeMap[".pot"] = "application/vnd.ms-powerpoint" + DefaultMimeMap[".mpp"] = "application/vnd.ms-project" + DefaultMimeMap[".mpt"] = "application/vnd.ms-project" + DefaultMimeMap[".wps"] = "application/vnd.ms-works" + DefaultMimeMap[".wks"] = "application/vnd.ms-works" + DefaultMimeMap[".wcm"] = "application/vnd.ms-works" + DefaultMimeMap[".wdb"] = "application/vnd.ms-works" + DefaultMimeMap[".wpl"] = "application/vnd.ms-wpl" + DefaultMimeMap[".xps"] = "application/vnd.ms-xpsdocument" + DefaultMimeMap[".mseq"] = "application/vnd.mseq" + DefaultMimeMap[".mus"] = "application/vnd.musician" + DefaultMimeMap[".msty"] = "application/vnd.muvee.style" + DefaultMimeMap[".nlu"] = "application/vnd.neurolanguage.nlu" + DefaultMimeMap[".nnd"] = "application/vnd.noblenet-directory" + DefaultMimeMap[".nns"] = "application/vnd.noblenet-sealer" + DefaultMimeMap[".nnw"] = "application/vnd.noblenet-web" + DefaultMimeMap[".ngdat"] = "application/vnd.nokia.n-gage.data" + DefaultMimeMap[".n-gage"] = "application/vnd.nokia.n-gage.symbian.install" + DefaultMimeMap[".rpst"] = "application/vnd.nokia.radio-preset" + DefaultMimeMap[".rpss"] = "application/vnd.nokia.radio-presets" + DefaultMimeMap[".edm"] = "application/vnd.novadigm.edm" + DefaultMimeMap[".edx"] = "application/vnd.novadigm.edx" + DefaultMimeMap[".ext"] = "application/vnd.novadigm.ext" + DefaultMimeMap[".odc"] = "application/vnd.oasis.opendocument.chart" + DefaultMimeMap[".otc"] = "application/vnd.oasis.opendocument.chart-template" + DefaultMimeMap[".odf"] = "application/vnd.oasis.opendocument.formula" + DefaultMimeMap[".otf"] = "application/vnd.oasis.opendocument.formula-template" + DefaultMimeMap[".odg"] = "application/vnd.oasis.opendocument.graphics" + DefaultMimeMap[".otg"] = "application/vnd.oasis.opendocument.graphics-template" + DefaultMimeMap[".odi"] = "application/vnd.oasis.opendocument.image" + DefaultMimeMap[".oti"] = "application/vnd.oasis.opendocument.image-template" + DefaultMimeMap[".odp"] = "application/vnd.oasis.opendocument.presentation" + DefaultMimeMap[".otp"] = "application/vnd.oasis.opendocument.presentation-template" + DefaultMimeMap[".ods"] = "application/vnd.oasis.opendocument.spreadsheet" + DefaultMimeMap[".ots"] = "application/vnd.oasis.opendocument.spreadsheet-template" + DefaultMimeMap[".odt"] = "application/vnd.oasis.opendocument.text" + DefaultMimeMap[".otm"] = "application/vnd.oasis.opendocument.text-master" + DefaultMimeMap[".ott"] = "application/vnd.oasis.opendocument.text-template" + DefaultMimeMap[".oth"] = "application/vnd.oasis.opendocument.text-web" + DefaultMimeMap[".xo"] = "application/vnd.olpc-sugar" + DefaultMimeMap[".dd2"] = "application/vnd.oma.dd2+xml" + DefaultMimeMap[".oxt"] = "application/vnd.openofficeorg.extension" + DefaultMimeMap[".dp"] = "application/vnd.osgi.dp" + DefaultMimeMap[".prc"] = "application/vnd.palm" + DefaultMimeMap[".pdb"] = "application/vnd.palm" + DefaultMimeMap[".pqa"] = "application/vnd.palm" + DefaultMimeMap[".oprc"] = "application/vnd.palm" + DefaultMimeMap[".str"] = "application/vnd.pg.format" + DefaultMimeMap[".ei6"] = "application/vnd.pg.osasli" + DefaultMimeMap[".efif"] = "application/vnd.picsel" + DefaultMimeMap[".plf"] = "application/vnd.pocketlearn" + DefaultMimeMap[".pbd"] = "application/vnd.powerbuilder6" + DefaultMimeMap[".box"] = "application/vnd.previewsystems.box" + DefaultMimeMap[".mgz"] = "application/vnd.proteus.magazine" + DefaultMimeMap[".qps"] = "application/vnd.publishare-delta-tree" + DefaultMimeMap[".ptid"] = "application/vnd.pvi.ptid1" + DefaultMimeMap[".qxd"] = "application/vnd.quark.quarkxpress" + DefaultMimeMap[".qxt"] = "application/vnd.quark.quarkxpress" + DefaultMimeMap[".qwd"] = "application/vnd.quark.quarkxpress" + DefaultMimeMap[".qwt"] = "application/vnd.quark.quarkxpress" + DefaultMimeMap[".qxl"] = "application/vnd.quark.quarkxpress" + DefaultMimeMap[".qxb"] = "application/vnd.quark.quarkxpress" + DefaultMimeMap[".mxl"] = "application/vnd.recordare.musicxml" + DefaultMimeMap[".rm"] = "application/vnd.rn-realmedia" + DefaultMimeMap[".see"] = "application/vnd.seemail" + DefaultMimeMap[".sema"] = "application/vnd.sema" + DefaultMimeMap[".semd"] = "application/vnd.semd" + DefaultMimeMap[".semf"] = "application/vnd.semf" + DefaultMimeMap[".ifm"] = "application/vnd.shana.informed.formdata" + DefaultMimeMap[".itp"] = "application/vnd.shana.informed.formtemplate" + DefaultMimeMap[".iif"] = "application/vnd.shana.informed.interchange" + DefaultMimeMap[".ipk"] = "application/vnd.shana.informed.package" + DefaultMimeMap[".twd"] = "application/vnd.simtech-mindmapper" + DefaultMimeMap[".twds"] = "application/vnd.simtech-mindmapper" + DefaultMimeMap[".mmf"] = "application/vnd.smaf" + DefaultMimeMap[".sdkm"] = "application/vnd.solent.sdkm+xml" + DefaultMimeMap[".sdkd"] = "application/vnd.solent.sdkm+xml" + DefaultMimeMap[".dxp"] = "application/vnd.spotfire.dxp" + DefaultMimeMap[".sfs"] = "application/vnd.spotfire.sfs" + DefaultMimeMap[".sus"] = "application/vnd.sus-calendar" + DefaultMimeMap[".susp"] = "application/vnd.sus-calendar" + DefaultMimeMap[".svd"] = "application/vnd.svd" + DefaultMimeMap[".xsm"] = "application/vnd.syncml+xml" + DefaultMimeMap[".bdm"] = "application/vnd.syncml.dm+wbxml" + DefaultMimeMap[".xdm"] = "application/vnd.syncml.dm+xml" + DefaultMimeMap[".tao"] = "application/vnd.tao.intent-module-archive" + DefaultMimeMap[".tmo"] = "application/vnd.tmobile-livetv" + DefaultMimeMap[".tpt"] = "application/vnd.trid.tpt" + DefaultMimeMap[".mxs"] = "application/vnd.triscape.mxs" + DefaultMimeMap[".tra"] = "application/vnd.trueapp" + DefaultMimeMap[".ufd"] = "application/vnd.ufdl" + DefaultMimeMap[".ufdl"] = "application/vnd.ufdl" + DefaultMimeMap[".utz"] = "application/vnd.uiq.theme" + DefaultMimeMap[".umj"] = "application/vnd.umajin" + DefaultMimeMap[".unityweb"] = "application/vnd.unity" + DefaultMimeMap[".uoml"] = "application/vnd.uoml+xml" + DefaultMimeMap[".vcx"] = "application/vnd.vcx" + DefaultMimeMap[".vsd"] = "application/vnd.visio" + DefaultMimeMap[".vst"] = "application/vnd.visio" + DefaultMimeMap[".vss"] = "application/vnd.visio" + DefaultMimeMap[".vsw"] = "application/vnd.visio" + DefaultMimeMap[".vis"] = "application/vnd.visionary" + DefaultMimeMap[".vsf"] = "application/vnd.vsf" + DefaultMimeMap[".wbxml"] = "application/vnd.wap.wbxml" + DefaultMimeMap[".wmlc"] = "application/vnd.wap.wmlc" + DefaultMimeMap[".wmlsc"] = "application/vnd.wap.wmlscriptc" + DefaultMimeMap[".wtb"] = "application/vnd.webturbo" + DefaultMimeMap[".wpd"] = "application/vnd.wordperfect" + DefaultMimeMap[".wqd"] = "application/vnd.wqd" + DefaultMimeMap[".stf"] = "application/vnd.wt.stf" + DefaultMimeMap[".xar"] = "application/vnd.xara" + DefaultMimeMap[".xfdl"] = "application/vnd.xfdl" + DefaultMimeMap[".hvd"] = "application/vnd.yamaha.hv-dic" + DefaultMimeMap[".hvs"] = "application/vnd.yamaha.hv-script" + DefaultMimeMap[".hvp"] = "application/vnd.yamaha.hv-voice" + DefaultMimeMap[".saf"] = "application/vnd.yamaha.smaf-audio" + DefaultMimeMap[".spf"] = "application/vnd.yamaha.smaf-phrase" + DefaultMimeMap[".cmp"] = "application/vnd.yellowriver-custom-menu" + DefaultMimeMap[".zaz"] = "application/vnd.zzazz.deck+xml" + DefaultMimeMap[".vxml"] = "application/voicexml+xml" + DefaultMimeMap[".hlp"] = "application/winhlp" + DefaultMimeMap[".wsdl"] = "application/wsdl+xml" + DefaultMimeMap[".wspolicy"] = "application/wspolicy+xml" + DefaultMimeMap[".ace"] = "application/x-ace-compressed" + DefaultMimeMap[".bcpio"] = "application/x-bcpio" + DefaultMimeMap[".torrent"] = "application/x-bittorrent" + DefaultMimeMap[".bz"] = "application/x-bzip" + DefaultMimeMap[".bz2"] = "application/x-bzip2" + DefaultMimeMap[".boz"] = "application/x-bzip2" + DefaultMimeMap[".vcd"] = "application/x-cdlink" + DefaultMimeMap[".chat"] = "application/x-chat" + DefaultMimeMap[".pgn"] = "application/x-chess-pgn" + DefaultMimeMap[".cpio"] = "application/x-cpio" + DefaultMimeMap[".csh"] = "application/x-csh" + DefaultMimeMap[".dcr"] = "application/x-director" + DefaultMimeMap[".dir"] = "application/x-director" + DefaultMimeMap[".dxr"] = "application/x-director" + DefaultMimeMap[".fgd"] = "application/x-director" + DefaultMimeMap[".dvi"] = "application/x-dvi" + DefaultMimeMap[".spl"] = "application/x-futuresplash" + DefaultMimeMap[".gtar"] = "application/x-gtar" + DefaultMimeMap[".hdf"] = "application/x-hdf" + DefaultMimeMap[".latex"] = "application/x-latex" + DefaultMimeMap[".wmd"] = "application/x-ms-wmd" + DefaultMimeMap[".wmz"] = "application/x-ms-wmz" + DefaultMimeMap[".mdb"] = "application/x-msaccess" + DefaultMimeMap[".obd"] = "application/x-msbinder" + DefaultMimeMap[".crd"] = "application/x-mscardfile" + DefaultMimeMap[".clp"] = "application/x-msclip" + DefaultMimeMap[".exe"] = "application/x-msdownload" + DefaultMimeMap[".dll"] = "application/x-msdownload" + DefaultMimeMap[".com"] = "application/x-msdownload" + DefaultMimeMap[".bat"] = "application/x-msdownload" + DefaultMimeMap[".msi"] = "application/x-msdownload" + DefaultMimeMap[".mvb"] = "application/x-msmediaview" + DefaultMimeMap[".m13"] = "application/x-msmediaview" + DefaultMimeMap[".m14"] = "application/x-msmediaview" + DefaultMimeMap[".wmf"] = "application/x-msmetafile" + DefaultMimeMap[".mny"] = "application/x-msmoney" + DefaultMimeMap[".pub"] = "application/x-mspublisher" + DefaultMimeMap[".scd"] = "application/x-msschedule" + DefaultMimeMap[".trm"] = "application/x-msterminal" + DefaultMimeMap[".wri"] = "application/x-mswrite" + DefaultMimeMap[".nc"] = "application/x-netcdf" + DefaultMimeMap[".cdf"] = "application/x-netcdf" + DefaultMimeMap[".p12"] = "application/x-pkcs12" + DefaultMimeMap[".pfx"] = "application/x-pkcs12" + DefaultMimeMap[".p7b"] = "application/x-pkcs7-certificates" + DefaultMimeMap[".spc"] = "application/x-pkcs7-certificates" + DefaultMimeMap[".p7r"] = "application/x-pkcs7-certreqresp" + DefaultMimeMap[".rar"] = "application/x-rar-compressed" + DefaultMimeMap[".sh"] = "application/x-sh" + DefaultMimeMap[".shar"] = "application/x-shar" + DefaultMimeMap[".swf"] = "application/x-shockwave-flash" + DefaultMimeMap[".sit"] = "application/x-stuffit" + DefaultMimeMap[".sitx"] = "application/x-stuffitx" + DefaultMimeMap[".sv4cpio"] = "application/x-sv4cpio" + DefaultMimeMap[".sv4crc"] = "application/x-sv4crc" + DefaultMimeMap[".tar"] = "application/x-tar" + DefaultMimeMap[".tcl"] = "application/x-tcl" + DefaultMimeMap[".tex"] = "application/x-tex" + DefaultMimeMap[".texinfo"] = "application/x-texinfo" + DefaultMimeMap[".texi"] = "application/x-texinfo" + DefaultMimeMap[".ustar"] = "application/x-ustar" + DefaultMimeMap[".src"] = "application/x-wais-source" + DefaultMimeMap[".der"] = "application/x-x509-ca-cert" + DefaultMimeMap[".crt"] = "application/x-x509-ca-cert" + DefaultMimeMap[".xenc"] = "application/xenc+xml" + DefaultMimeMap[".xhtml"] = "application/xhtml+xml" + DefaultMimeMap[".xht"] = "application/xhtml+xml" + DefaultMimeMap[".xml"] = "text/xml" + DefaultMimeMap[".xsl"] = "application/xml" + DefaultMimeMap[".dtd"] = "application/xml-dtd" + DefaultMimeMap[".xop"] = "application/xop+xml" + DefaultMimeMap[".xslt"] = "application/xslt+xml" + DefaultMimeMap[".xspf"] = "application/xspf+xml" + DefaultMimeMap[".mxml"] = "application/xv+xml" + DefaultMimeMap[".xhvml"] = "application/xv+xml" + DefaultMimeMap[".xvml"] = "application/xv+xml" + DefaultMimeMap[".xvm"] = "application/xv+xml" + DefaultMimeMap[".zip"] = "application/zip" + DefaultMimeMap[".au"] = "audio/basic" + DefaultMimeMap[".snd"] = "audio/basic" + DefaultMimeMap[".mid"] = "audio/midi" + DefaultMimeMap[".midi"] = "audio/midi" + DefaultMimeMap[".kar"] = "audio/midi" + DefaultMimeMap[".rmi"] = "audio/midi" + DefaultMimeMap[".mp4a"] = "audio/mp4" + DefaultMimeMap[".mpga"] = "audio/mpeg" + DefaultMimeMap[".mp2"] = "audio/mpeg" + DefaultMimeMap[".mp2a"] = "audio/mpeg" + DefaultMimeMap[".mp3"] = "audio/mpeg" + DefaultMimeMap[".m2a"] = "audio/mpeg" + DefaultMimeMap[".m3a"] = "audio/mpeg" + DefaultMimeMap[".eol"] = "audio/vnd.digital-winds" + DefaultMimeMap[".lvp"] = "audio/vnd.lucent.voice" + DefaultMimeMap[".ecelp4800"] = "audio/vnd.nuera.ecelp4800" + DefaultMimeMap[".ecelp7470"] = "audio/vnd.nuera.ecelp7470" + DefaultMimeMap[".ecelp9600"] = "audio/vnd.nuera.ecelp9600" + DefaultMimeMap[".wav"] = "audio/wav" + DefaultMimeMap[".aif"] = "audio/x-aiff" + DefaultMimeMap[".aiff"] = "audio/x-aiff" + DefaultMimeMap[".aifc"] = "audio/x-aiff" + DefaultMimeMap[".m3u"] = "audio/x-mpegurl" + DefaultMimeMap[".wax"] = "audio/x-ms-wax" + DefaultMimeMap[".wma"] = "audio/x-ms-wma" + DefaultMimeMap[".ram"] = "audio/x-pn-realaudio" + DefaultMimeMap[".ra"] = "audio/x-pn-realaudio" + DefaultMimeMap[".rmp"] = "audio/x-pn-realaudio-plugin" + DefaultMimeMap[".cdx"] = "chemical/x-cdx" + DefaultMimeMap[".cif"] = "chemical/x-cif" + DefaultMimeMap[".cmdf"] = "chemical/x-cmdf" + DefaultMimeMap[".cml"] = "chemical/x-cml" + DefaultMimeMap[".csml"] = "chemical/x-csml" + DefaultMimeMap[".xyz"] = "chemical/x-xyz" + DefaultMimeMap[".bmp"] = "image/bmp" + DefaultMimeMap[".cgm"] = "image/cgm" + DefaultMimeMap[".g3"] = "image/g3fax" + DefaultMimeMap[".gif"] = "image/gif" + DefaultMimeMap[".ief"] = "image/ief" + DefaultMimeMap[".jpeg"] = "image/jpeg" + DefaultMimeMap[".jpg"] = "image/jpeg" + DefaultMimeMap[".jpe"] = "image/jpeg" + DefaultMimeMap[".png"] = "image/png" + DefaultMimeMap[".webp"] = "image/webp" + DefaultMimeMap[".heic"] = "image/heic" + DefaultMimeMap[".btif"] = "image/prs.btif" + DefaultMimeMap[".svg"] = "image/svg+xml" + DefaultMimeMap[".svgz"] = "image/svg+xml" + DefaultMimeMap[".tiff"] = "image/tiff" + DefaultMimeMap[".tif"] = "image/tiff" + DefaultMimeMap[".psd"] = "image/vnd.adobe.photoshop" + DefaultMimeMap[".djvu"] = "image/vnd.djvu" + DefaultMimeMap[".djv"] = "image/vnd.djvu" + DefaultMimeMap[".dwg"] = "image/vnd.dwg" + DefaultMimeMap[".dxf"] = "image/vnd.dxf" + DefaultMimeMap[".fbs"] = "image/vnd.fastbidsheet" + DefaultMimeMap[".fpx"] = "image/vnd.fpx" + DefaultMimeMap[".fst"] = "image/vnd.fst" + DefaultMimeMap[".mmr"] = "image/vnd.fujixerox.edmics-mmr" + DefaultMimeMap[".rlc"] = "image/vnd.fujixerox.edmics-rlc" + DefaultMimeMap[".mdi"] = "image/vnd.ms-modi" + DefaultMimeMap[".npx"] = "image/vnd.net-fpx" + DefaultMimeMap[".wbmp"] = "image/vnd.wap.wbmp" + DefaultMimeMap[".xif"] = "image/vnd.xiff" + DefaultMimeMap[".ras"] = "image/x-cmu-raster" + DefaultMimeMap[".cmx"] = "image/x-cmx" + DefaultMimeMap[".ico"] = "image/x-icon" + DefaultMimeMap[".pcx"] = "image/x-pcx" + DefaultMimeMap[".pic"] = "image/x-pict" + DefaultMimeMap[".pct"] = "image/x-pict" + DefaultMimeMap[".pnm"] = "image/x-portable-anymap" + DefaultMimeMap[".pbm"] = "image/x-portable-bitmap" + DefaultMimeMap[".pgm"] = "image/x-portable-graymap" + DefaultMimeMap[".ppm"] = "image/x-portable-pixmap" + DefaultMimeMap[".rgb"] = "image/x-rgb" + DefaultMimeMap[".xbm"] = "image/x-xbitmap" + DefaultMimeMap[".xpm"] = "image/x-xpixmap" + DefaultMimeMap[".xwd"] = "image/x-xwindowdump" + DefaultMimeMap[".eml"] = "message/rfc822" + DefaultMimeMap[".mime"] = "message/rfc822" + DefaultMimeMap[".mht"] = "message/rfc822" + DefaultMimeMap[".mhtml"] = "message/rfc822" + DefaultMimeMap[".igs"] = "model/iges" + DefaultMimeMap[".iges"] = "model/iges" + DefaultMimeMap[".msh"] = "model/mesh" + DefaultMimeMap[".mesh"] = "model/mesh" + DefaultMimeMap[".silo"] = "model/mesh" + DefaultMimeMap[".dwf"] = "model/vnd.dwf" + DefaultMimeMap[".gdl"] = "model/vnd.gdl" + DefaultMimeMap[".gtw"] = "model/vnd.gtw" + DefaultMimeMap[".mts"] = "model/vnd.mts" + DefaultMimeMap[".vtu"] = "model/vnd.vtu" + DefaultMimeMap[".wrl"] = "model/vrml" + DefaultMimeMap[".vrml"] = "model/vrml" + DefaultMimeMap[".ics"] = "text/calendar" + DefaultMimeMap[".ifb"] = "text/calendar" + DefaultMimeMap[".css"] = "text/css" + DefaultMimeMap[".csv"] = "text/csv" + DefaultMimeMap[".html"] = "text/html" + DefaultMimeMap[".htm"] = "text/html" + DefaultMimeMap[".txt"] = "text/plain" + DefaultMimeMap[".text"] = "text/plain" + DefaultMimeMap[".conf"] = "text/plain" + DefaultMimeMap[".def"] = "text/plain" + DefaultMimeMap[".list"] = "text/plain" + DefaultMimeMap[".log"] = "text/plain" + DefaultMimeMap[".in"] = "text/plain" + DefaultMimeMap[".dsc"] = "text/prs.lines.tag" + DefaultMimeMap[".rtx"] = "text/richtext" + DefaultMimeMap[".sgml"] = "text/sgml" + DefaultMimeMap[".sgm"] = "text/sgml" + DefaultMimeMap[".tsv"] = "text/tab-separated-values" + DefaultMimeMap[".t"] = "text/troff" + DefaultMimeMap[".tr"] = "text/troff" + DefaultMimeMap[".roff"] = "text/troff" + DefaultMimeMap[".man"] = "text/troff" + DefaultMimeMap[".me"] = "text/troff" + DefaultMimeMap[".ms"] = "text/troff" + DefaultMimeMap[".uri"] = "text/uri-list" + DefaultMimeMap[".uris"] = "text/uri-list" + DefaultMimeMap[".urls"] = "text/uri-list" + DefaultMimeMap[".fly"] = "text/vnd.fly" + DefaultMimeMap[".flx"] = "text/vnd.fmi.flexstor" + DefaultMimeMap[".3dml"] = "text/vnd.in3d.3dml" + DefaultMimeMap[".spot"] = "text/vnd.in3d.spot" + DefaultMimeMap[".jad"] = "text/vnd.sun.j2me.app-descriptor" + DefaultMimeMap[".wml"] = "text/vnd.wap.wml" + DefaultMimeMap[".wmls"] = "text/vnd.wap.wmlscript" + DefaultMimeMap[".s"] = "text/x-asm" + DefaultMimeMap[".asm"] = "text/x-asm" + DefaultMimeMap[".c"] = "text/x-c" + DefaultMimeMap[".cc"] = "text/x-c" + DefaultMimeMap[".cxx"] = "text/x-c" + DefaultMimeMap[".cpp"] = "text/x-c" + DefaultMimeMap[".h"] = "text/x-c" + DefaultMimeMap[".hh"] = "text/x-c" + DefaultMimeMap[".dic"] = "text/x-c" + DefaultMimeMap[".f"] = "text/x-fortran" + DefaultMimeMap[".for"] = "text/x-fortran" + DefaultMimeMap[".f77"] = "text/x-fortran" + DefaultMimeMap[".f90"] = "text/x-fortran" + DefaultMimeMap[".p"] = "text/x-pascal" + DefaultMimeMap[".pas"] = "text/x-pascal" + DefaultMimeMap[".java"] = "text/x-java-source" + DefaultMimeMap[".etx"] = "text/x-setext" + DefaultMimeMap[".uu"] = "text/x-uuencode" + DefaultMimeMap[".vcs"] = "text/x-vcalendar" + DefaultMimeMap[".vcf"] = "text/x-vcard" + DefaultMimeMap[".3gp"] = "video/3gpp" + DefaultMimeMap[".3g2"] = "video/3gpp2" + DefaultMimeMap[".h261"] = "video/h261" + DefaultMimeMap[".h263"] = "video/h263" + DefaultMimeMap[".h264"] = "video/h264" + DefaultMimeMap[".jpgv"] = "video/jpeg" + DefaultMimeMap[".jpm"] = "video/jpm" + DefaultMimeMap[".jpgm"] = "video/jpm" + DefaultMimeMap[".mj2"] = "video/mj2" + DefaultMimeMap[".mjp2"] = "video/mj2" + DefaultMimeMap[".mp4"] = "video/mp4" + DefaultMimeMap[".mp4v"] = "video/mp4" + DefaultMimeMap[".mpg4"] = "video/mp4" + DefaultMimeMap[".mpeg"] = "video/mpeg" + DefaultMimeMap[".mpg"] = "video/mpeg" + DefaultMimeMap[".mpe"] = "video/mpeg" + DefaultMimeMap[".m1v"] = "video/mpeg" + DefaultMimeMap[".m2v"] = "video/mpeg" + DefaultMimeMap[".qt"] = "video/quicktime" + DefaultMimeMap[".mov"] = "video/quicktime" + DefaultMimeMap[".fvt"] = "video/vnd.fvt" + DefaultMimeMap[".mxu"] = "video/vnd.mpegurl" + DefaultMimeMap[".m4u"] = "video/vnd.mpegurl" + DefaultMimeMap[".viv"] = "video/vnd.vivo" + DefaultMimeMap[".fli"] = "video/x-fli" + DefaultMimeMap[".wm"] = "video/x-ms-wm" + DefaultMimeMap[".wmv"] = "video/x-ms-wmv" + DefaultMimeMap[".wmx"] = "video/x-ms-wmx" + DefaultMimeMap[".wvx"] = "video/x-ms-wvx" + DefaultMimeMap[".avi"] = "video/x-msvideo" + DefaultMimeMap[".movie"] = "video/x-sgi-movie" + DefaultMimeMap[".ice"] = "x-conference/x-cooltalk" + DefaultMimeMap[".ipa"] = "application/vnd.iphone" + DefaultMimeMap[".apk"] = "application/vnd.android.package-archive" +} + +func GetMimeMap() map[string]string { + once.Do(LoadMimeMap) + return DefaultMimeMap +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/util/string.go b/vendor/github.com/baidubce/bce-sdk-go/util/string.go new file mode 100644 index 00000000000..3bb0b10de24 --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/util/string.go @@ -0,0 +1,88 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// string.go - define the string util function + +// Package util defines the common utilities including string and time. +package util + +import ( + "bytes" + "crypto/hmac" + "crypto/md5" + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "fmt" + "io" +) + +func HmacSha256Hex(key, str_to_sign string) string { + hasher := hmac.New(sha256.New, []byte(key)) + hasher.Write([]byte(str_to_sign)) + return hex.EncodeToString(hasher.Sum(nil)) +} + +func CalculateContentMD5(data io.Reader, size int64) (string, error) { + hasher := md5.New() + n, err := io.CopyN(hasher, data, size) + if err != nil { + return "", fmt.Errorf("calculate content-md5 occurs error: %v", err) + } + if n != size { + return "", fmt.Errorf("calculate content-md5 writing size %d != size %d", n, size) + } + return base64.StdEncoding.EncodeToString(hasher.Sum(nil)), nil +} + +func UriEncode(uri string, encodeSlash bool) string { + var byte_buf bytes.Buffer + for _, b := range []byte(uri) { + if (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') || (b >= '0' && b <= '9') || + b == '-' || b == '_' || b == '.' || b == '~' || (b == '/' && !encodeSlash) { + byte_buf.WriteByte(b) + } else { + byte_buf.WriteString(fmt.Sprintf("%%%02X", b)) + } + } + return byte_buf.String() +} + +func NewUUID() string { + var buf [16]byte + for { + if _, err := rand.Read(buf[:]); err == nil { + break + } + } + buf[6] = (buf[6] & 0x0f) | (4 << 4) + buf[8] = (buf[8] & 0xbf) | 0x80 + + res := make([]byte, 36) + hex.Encode(res[0:8], buf[0:4]) + res[8] = '-' + hex.Encode(res[9:13], buf[4:6]) + res[13] = '-' + hex.Encode(res[14:18], buf[6:8]) + res[18] = '-' + hex.Encode(res[19:23], buf[8:10]) + res[23] = '-' + hex.Encode(res[24:], buf[10:]) + return string(res) +} + +func NewRequestId() string { + return NewUUID() +} diff --git a/vendor/github.com/baidubce/bce-sdk-go/util/time.go b/vendor/github.com/baidubce/bce-sdk-go/util/time.go new file mode 100644 index 00000000000..e9f9e3d1bab --- /dev/null +++ b/vendor/github.com/baidubce/bce-sdk-go/util/time.go @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +// time.go - define the time utility functions for BCE + +package util + +import "time" + +const ( + RFC822Format = "Mon, 02 Jan 2006 15:04:05 MST" + ISO8601Format = "2006-01-02T15:04:05Z" +) + +func NowUTCSeconds() int64 { return time.Now().UTC().Unix() } + +func NowUTCNanoSeconds() int64 { return time.Now().UTC().UnixNano() } + +func FormatRFC822Date(timestamp_second int64) string { + tm := time.Unix(timestamp_second, 0).UTC() + return tm.Format(RFC822Format) +} + +func ParseRFC822Date(time_string string) (time.Time, error) { + return time.Parse(RFC822Format, time_string) +} + +func FormatISO8601Date(timestamp_second int64) string { + tm := time.Unix(timestamp_second, 0).UTC() + return tm.Format(ISO8601Format) +} + +func ParseISO8601Date(time_string string) (time.Time, error) { + return time.Parse(ISO8601Format, time_string) +} diff --git a/vendor/github.com/clbanning/mxj/LICENSE b/vendor/github.com/clbanning/mxj/LICENSE new file mode 100644 index 00000000000..f27bccdf06e --- /dev/null +++ b/vendor/github.com/clbanning/mxj/LICENSE @@ -0,0 +1,55 @@ +Copyright (c) 2012-2016 Charles Banning . All rights reserved. + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=============================================================================== + +Go Language Copyright & License - + +Copyright 2009 The Go Authors. All rights reserved. +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/clbanning/mxj/anyxml.go b/vendor/github.com/clbanning/mxj/anyxml.go new file mode 100644 index 00000000000..ec2f3dfddac --- /dev/null +++ b/vendor/github.com/clbanning/mxj/anyxml.go @@ -0,0 +1,189 @@ +package mxj + +import ( + "encoding/xml" + "reflect" +) + +const ( + DefaultElementTag = "element" +) + +// Encode arbitrary value as XML. +// +// Note: unmarshaling the resultant +// XML may not return the original value, since tag labels may have been injected +// to create the XML representation of the value. +/* + Encode an arbitrary JSON object. + package main + + import ( + "encoding/json" + "fmt" + "github.com/clbanning/mxj" + ) + + func main() { + jsondata := []byte(`[ + { "somekey":"somevalue" }, + "string", + 3.14159265, + true + ]`) + var i interface{} + err := json.Unmarshal(jsondata, &i) + if err != nil { + // do something + } + x, err := mxj.AnyXmlIndent(i, "", " ", "mydoc") + if err != nil { + // do something else + } + fmt.Println(string(x)) + } + + output: + + somevalue + string + 3.14159265 + true + +*/ +// Alternative values for DefaultRootTag and DefaultElementTag can be set as: +// AnyXml( v, myRootTag, myElementTag). +func AnyXml(v interface{}, tags ...string) ([]byte, error) { + var rt, et string + if len(tags) == 1 || len(tags) == 2 { + rt = tags[0] + } else { + rt = DefaultRootTag + } + if len(tags) == 2 { + et = tags[1] + } else { + et = DefaultElementTag + } + + if v == nil { + if useGoXmlEmptyElemSyntax { + return []byte("<" + rt + ">"), nil + } + return []byte("<" + rt + "/>"), nil + } + if reflect.TypeOf(v).Kind() == reflect.Struct { + return xml.Marshal(v) + } + + var err error + s := new(string) + p := new(pretty) + + var ss string + var b []byte + switch v.(type) { + case []interface{}: + ss = "<" + rt + ">" + for _, vv := range v.([]interface{}) { + switch vv.(type) { + case map[string]interface{}: + m := vv.(map[string]interface{}) + if len(m) == 1 { + for tag, val := range m { + err = mapToXmlIndent(false, s, tag, val, p) + } + } else { + err = mapToXmlIndent(false, s, et, vv, p) + } + default: + err = mapToXmlIndent(false, s, et, vv, p) + } + if err != nil { + break + } + } + ss += *s + "" + b = []byte(ss) + case map[string]interface{}: + m := Map(v.(map[string]interface{})) + b, err = m.Xml(rt) + default: + err = mapToXmlIndent(false, s, rt, v, p) + b = []byte(*s) + } + + return b, err +} + +// Encode an arbitrary value as a pretty XML string. +// Alternative values for DefaultRootTag and DefaultElementTag can be set as: +// AnyXmlIndent( v, "", " ", myRootTag, myElementTag). +func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) { + var rt, et string + if len(tags) == 1 || len(tags) == 2 { + rt = tags[0] + } else { + rt = DefaultRootTag + } + if len(tags) == 2 { + et = tags[1] + } else { + et = DefaultElementTag + } + + if v == nil { + if useGoXmlEmptyElemSyntax { + return []byte(prefix + "<" + rt + ">"), nil + } + return []byte(prefix + "<" + rt + "/>"), nil + } + if reflect.TypeOf(v).Kind() == reflect.Struct { + return xml.MarshalIndent(v, prefix, indent) + } + + var err error + s := new(string) + p := new(pretty) + p.indent = indent + p.padding = prefix + + var ss string + var b []byte + switch v.(type) { + case []interface{}: + ss = "<" + rt + ">\n" + p.Indent() + for _, vv := range v.([]interface{}) { + switch vv.(type) { + case map[string]interface{}: + m := vv.(map[string]interface{}) + if len(m) == 1 { + for tag, val := range m { + err = mapToXmlIndent(true, s, tag, val, p) + } + } else { + p.start = 1 // we 1 tag in + err = mapToXmlIndent(true, s, et, vv, p) + *s += "\n" + } + default: + p.start = 0 // in case trailing p.start = 1 + err = mapToXmlIndent(true, s, et, vv, p) + } + if err != nil { + break + } + } + ss += *s + "" + b = []byte(ss) + case map[string]interface{}: + m := Map(v.(map[string]interface{})) + b, err = m.XmlIndent(prefix, indent, rt) + default: + err = mapToXmlIndent(true, s, rt, v, p) + b = []byte(*s) + } + + return b, err +} diff --git a/vendor/github.com/clbanning/mxj/atomFeedString.xml b/vendor/github.com/clbanning/mxj/atomFeedString.xml new file mode 100644 index 00000000000..474575a41ca --- /dev/null +++ b/vendor/github.com/clbanning/mxj/atomFeedString.xml @@ -0,0 +1,54 @@ + +Code Review - My issueshttp://codereview.appspot.com/rietveld<>rietveld: an attempt at pubsubhubbub +2009-10-04T01:35:58+00:00email-address-removedurn:md5:134d9179c41f806be79b3a5f7877d19a + An attempt at adding pubsubhubbub support to Rietveld. +http://code.google.com/p/pubsubhubbub +http://code.google.com/p/rietveld/issues/detail?id=155 + +The server side of the protocol is trivial: + 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all + feeds that will be pubsubhubbubbed. + 2. every time one of those feeds changes, tell the hub + with a simple POST request. + +I have tested this by adding debug prints to a local hub +server and checking that the server got the right publish +requests. + +I can&#39;t quite get the server to work, but I think the bug +is not in my code. I think that the server expects to be +able to grab the feed and see the feed&#39;s actual URL in +the link rel=&quot;self&quot;, but the default value for that drops +the :port from the URL, and I cannot for the life of me +figure out how to get the Atom generator deep inside +django not to do that, or even where it is doing that, +or even what code is running to generate the Atom feed. +(I thought I knew but I added some assert False statements +and it kept running!) + +Ignoring that particular problem, I would appreciate +feedback on the right way to get the two values at +the top of feeds.py marked NOTE(rsc). + + +rietveld: correct tab handling +2009-10-03T23:02:17+00:00email-address-removedurn:md5:0a2a4f19bb815101f0ba2904aed7c35a + This fixes the buggy tab rendering that can be seen at +http://codereview.appspot.com/116075/diff/1/2 + +The fundamental problem was that the tab code was +not being told what column the text began in, so it +didn&#39;t know where to put the tab stops. Another problem +was that some of the code assumed that string byte +offsets were the same as column offsets, which is only +true if there are no tabs. + +In the process of fixing this, I cleaned up the arguments +to Fold and ExpandTabs and renamed them Break and +_ExpandTabs so that I could be sure that I found all the +call sites. I also wanted to verify that ExpandTabs was +not being used from outside intra_region_diff.py. + + + ` + diff --git a/vendor/github.com/clbanning/mxj/doc.go b/vendor/github.com/clbanning/mxj/doc.go new file mode 100644 index 00000000000..8ed79a5a77a --- /dev/null +++ b/vendor/github.com/clbanning/mxj/doc.go @@ -0,0 +1,134 @@ +// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. +// Copyright 2012-2015, 2018 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +/* +Marshal/Unmarshal XML to/from map[string]interface{} values (and JSON); extract/modify values from maps by key or key-path, including wildcards. + +mxj supplants the legacy x2j and j2x packages. The subpackage x2j-wrapper is provided to facilitate migrating from the x2j package. The x2j and j2x subpackages provide similar functionality of the old packages but are not function-name compatible with them. + +Note: this library was designed for processing ad hoc anonymous messages. Bulk processing large data sets may be much more efficiently performed using the encoding/xml or encoding/json packages from Go's standard library directly. + +Related Packages: + checkxml: github.com/clbanning/checkxml provides functions for validating XML data. + +Notes: + 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc. + 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps. + 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package. + 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing. + 2017.02.21: github.com/clbanning/checkxml provides functions for validating XML data. + 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods. + 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag(). + 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc. + 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix(). + 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable. + 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars(). + 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf". + To cast them to float64, first set flag with CastNanInf(true). + 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure. + 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization. + 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM). + 2015-12-02: NewMapXmlSeq() with mv.XmlSeq() & co. will try to preserve structure of XML doc when re-encoding. + 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML. + +SUMMARY + + type Map map[string]interface{} + + Create a Map value, 'mv', from any map[string]interface{} value, 'v': + mv := Map(v) + + Unmarshal / marshal XML as a Map value, 'mv': + mv, err := NewMapXml(xmlValue) // unmarshal + xmlValue, err := mv.Xml() // marshal + + Unmarshal XML from an io.Reader as a Map value, 'mv': + mv, err := NewMapXmlReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream + mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded + + Marshal Map value, 'mv', to an XML Writer (io.Writer): + err := mv.XmlWriter(xmlWriter) + raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter + + Also, for prettified output: + xmlValue, err := mv.XmlIndent(prefix, indent, ...) + err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...) + raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...) + + Bulk process XML with error handling (note: handlers must return a boolean value): + err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error)) + err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte)) + + Converting XML to JSON: see Examples for NewMapXml and HandleXmlReader. + + There are comparable functions and methods for JSON processing. + + Arbitrary structure values can be decoded to / encoded from Map values: + mv, err := NewMapStruct(structVal) + err := mv.Struct(structPointer) + + To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON + or structure to a Map value, 'mv', or cast a map[string]interface{} value to a Map value, 'mv', then: + paths := mv.PathsForKey(key) + path := mv.PathForKeyShortest(key) + values, err := mv.ValuesForKey(key, subkeys) + values, err := mv.ValuesForPath(path, subkeys) // 'path' can be dot-notation with wildcards and indexed arrays. + count, err := mv.UpdateValuesForPath(newVal, path, subkeys) + + Get everything at once, irrespective of path depth: + leafnodes := mv.LeafNodes() + leafvalues := mv.LeafValues() + + A new Map with whatever keys are desired can be created from the current Map and then encoded in XML + or JSON. (Note: keys can use dot-notation. 'oldKey' can also use wildcards and indexed arrays.) + newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N") + newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go" + newXml, err := newMap.Xml() // for example + newJson, err := newMap.Json() // ditto + +XML PARSING CONVENTIONS + + Using NewMapXml() + + - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`, + to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or + `SetAttrPrefix()`.) + - If the element is a simple element and has attributes, the element value + is given the key `#text` for its `map[string]interface{}` representation. (See + the 'atomFeedString.xml' test data, below.) + - XML comments, directives, and process instructions are ignored. + - If CoerceKeysToLower() has been called, then the resultant keys will be lower case. + + Using NewMapXmlSeq() + + - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values + where the `` value has "#text" and "#seq" keys - the "#text" key holds the + value for ``. + - All elements, except for the root, have a "#seq" key. + - Comments, directives, and process instructions are unmarshalled into the Map using the + keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more + specifics.) + - Name space syntax is preserved: + - something parses to map["ns:key"]interface{}{"something"} + - xmlns:ns="http://myns.com/ns" parses to map["xmlns:ns"]interface{}{"http://myns.com/ns"} + + Both + + - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them + to be cast, set a flag to cast them using CastNanInf(true). + +XML ENCODING CONVENTIONS + + - 'nil' Map values, which may represent 'null' JSON values, are encoded as "". + NOTE: the operation is not symmetric as "" elements are decoded as 'tag:""' Map values, + which, then, encode in JSON as '"tag":""' values.. + - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go + randomizes the walk through map[string]interface{} values.) If you plan to re-encode the + Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and + mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when + working with the Map representation. + +*/ +package mxj diff --git a/vendor/github.com/clbanning/mxj/escapechars.go b/vendor/github.com/clbanning/mxj/escapechars.go new file mode 100644 index 00000000000..bee0442c9c1 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/escapechars.go @@ -0,0 +1,54 @@ +// Copyright 2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "bytes" +) + +var xmlEscapeChars bool + +// XMLEscapeChars(true) forces escaping invalid characters in attribute and element values. +// NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is +// then '&' will be re-escaped as '&amp;'. +// +/* + The values are: + " " + ' ' + < < + > > + & & +*/ +func XMLEscapeChars(b bool) { + xmlEscapeChars = b +} + +// Scan for '&' first, since 's' may contain "&" that is parsed to "&amp;" +// - or "<" that is parsed to "&lt;". +var escapechars = [][2][]byte{ + {[]byte(`&`), []byte(`&`)}, + {[]byte(`<`), []byte(`<`)}, + {[]byte(`>`), []byte(`>`)}, + {[]byte(`"`), []byte(`"`)}, + {[]byte(`'`), []byte(`'`)}, +} + +func escapeChars(s string) string { + if len(s) == 0 { + return s + } + + b := []byte(s) + for _, v := range escapechars { + n := bytes.Count(b, v[0]) + if n == 0 { + continue + } + b = bytes.Replace(b, v[0], v[1], n) + } + return string(b) +} + diff --git a/vendor/github.com/clbanning/mxj/exists.go b/vendor/github.com/clbanning/mxj/exists.go new file mode 100644 index 00000000000..2fb3084b599 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/exists.go @@ -0,0 +1,7 @@ +package mxj + +// Checks whether the path exists +func (mv Map) Exists(path string, subkeys ...string) bool { + v, err := mv.ValuesForPath(path, subkeys...) + return err == nil && len(v) > 0 +} diff --git a/vendor/github.com/clbanning/mxj/files.go b/vendor/github.com/clbanning/mxj/files.go new file mode 100644 index 00000000000..27e06e1e801 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files.go @@ -0,0 +1,287 @@ +package mxj + +import ( + "fmt" + "io" + "os" +) + +type Maps []Map + +func NewMaps() Maps { + return make(Maps, 0) +} + +type MapRaw struct { + M Map + R []byte +} + +// NewMapsFromXmlFile - creates an array from a file of JSON values. +func NewMapsFromJsonFile(name string) (Maps, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]Map, 0) + for { + m, raw, err := NewMapJsonReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw)) + } + if len(m) > 0 { + am = append(am, m) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// ReadMapsFromJsonFileRaw - creates an array of MapRaw from a file of JSON values. +func NewMapsFromJsonFileRaw(name string) ([]MapRaw, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]MapRaw, 0) + for { + mr := new(MapRaw) + mr.M, mr.R, err = NewMapJsonReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R)) + } + if len(mr.M) > 0 { + am = append(am, *mr) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// NewMapsFromXmlFile - creates an array from a file of XML values. +func NewMapsFromXmlFile(name string) (Maps, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]Map, 0) + for { + m, raw, err := NewMapXmlReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw)) + } + if len(m) > 0 { + am = append(am, m) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// NewMapsFromXmlFileRaw - creates an array of MapRaw from a file of XML values. +// NOTE: the slice with the raw XML is clean with no extra capacity - unlike NewMapXmlReaderRaw(). +// It is slow at parsing a file from disk and is intended for relatively small utility files. +func NewMapsFromXmlFileRaw(name string) ([]MapRaw, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("file %s is not a regular file", name) + } + + fh, err := os.Open(name) + if err != nil { + return nil, err + } + defer fh.Close() + + am := make([]MapRaw, 0) + for { + mr := new(MapRaw) + mr.M, mr.R, err = NewMapXmlReaderRaw(fh) + if err != nil && err != io.EOF { + return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R)) + } + if len(mr.M) > 0 { + am = append(am, *mr) + } + if err == io.EOF { + break + } + } + return am, nil +} + +// ------------------------ Maps writing ------------------------- +// These are handy-dandy methods for dumping configuration data, etc. + +// JsonString - analogous to mv.Json() +func (mvs Maps) JsonString(safeEncoding ...bool) (string, error) { + var s string + for _, v := range mvs { + j, err := v.Json() + if err != nil { + return s, err + } + s += string(j) + } + return s, nil +} + +// JsonStringIndent - analogous to mv.JsonIndent() +func (mvs Maps) JsonStringIndent(prefix, indent string, safeEncoding ...bool) (string, error) { + var s string + var haveFirst bool + for _, v := range mvs { + j, err := v.JsonIndent(prefix, indent) + if err != nil { + return s, err + } + if haveFirst { + s += "\n" + } else { + haveFirst = true + } + s += string(j) + } + return s, nil +} + +// XmlString - analogous to mv.Xml() +func (mvs Maps) XmlString() (string, error) { + var s string + for _, v := range mvs { + x, err := v.Xml() + if err != nil { + return s, err + } + s += string(x) + } + return s, nil +} + +// XmlStringIndent - analogous to mv.XmlIndent() +func (mvs Maps) XmlStringIndent(prefix, indent string) (string, error) { + var s string + for _, v := range mvs { + x, err := v.XmlIndent(prefix, indent) + if err != nil { + return s, err + } + s += string(x) + } + return s, nil +} + +// JsonFile - write Maps to named file as JSON +// Note: the file will be created, if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use JsonWriter method. +func (mvs Maps) JsonFile(file string, safeEncoding ...bool) error { + var encoding bool + if len(safeEncoding) == 1 { + encoding = safeEncoding[0] + } + s, err := mvs.JsonString(encoding) + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} + +// JsonFileIndent - write Maps to named file as pretty JSON +// Note: the file will be created, if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use JsonIndentWriter method. +func (mvs Maps) JsonFileIndent(file, prefix, indent string, safeEncoding ...bool) error { + var encoding bool + if len(safeEncoding) == 1 { + encoding = safeEncoding[0] + } + s, err := mvs.JsonStringIndent(prefix, indent, encoding) + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} + +// XmlFile - write Maps to named file as XML +// Note: the file will be created, if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use XmlWriter method. +func (mvs Maps) XmlFile(file string) error { + s, err := mvs.XmlString() + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} + +// XmlFileIndent - write Maps to named file as pretty XML +// Note: the file will be created,if necessary; if it exists it will be truncated. +// If you need to append to a file, open it and use XmlIndentWriter method. +func (mvs Maps) XmlFileIndent(file, prefix, indent string) error { + s, err := mvs.XmlStringIndent(prefix, indent) + if err != nil { + return err + } + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + fh.WriteString(s) + return nil +} diff --git a/vendor/github.com/clbanning/mxj/files_test.badjson b/vendor/github.com/clbanning/mxj/files_test.badjson new file mode 100644 index 00000000000..d18720044ac --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test.badjson @@ -0,0 +1,2 @@ +{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" } +{ "with":"some", "bad":JSON, "in":"it" } diff --git a/vendor/github.com/clbanning/mxj/files_test.badxml b/vendor/github.com/clbanning/mxj/files_test.badxml new file mode 100644 index 00000000000..4736ef973dd --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test.badxml @@ -0,0 +1,9 @@ + + test + for files.go + + + some + doc + test case + diff --git a/vendor/github.com/clbanning/mxj/files_test.json b/vendor/github.com/clbanning/mxj/files_test.json new file mode 100644 index 00000000000..e9a3ddf40ec --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test.json @@ -0,0 +1,2 @@ +{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" } +{ "with":"just", "two":2, "JSON":"values", "true":true } diff --git a/vendor/github.com/clbanning/mxj/files_test.xml b/vendor/github.com/clbanning/mxj/files_test.xml new file mode 100644 index 00000000000..65cf021fb70 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test.xml @@ -0,0 +1,9 @@ + + test + for files.go + + + some + doc + test case + diff --git a/vendor/github.com/clbanning/mxj/files_test_dup.json b/vendor/github.com/clbanning/mxj/files_test_dup.json new file mode 100644 index 00000000000..2becb6a4512 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test_dup.json @@ -0,0 +1 @@ +{"a":"test","file":"for","files_test.go":"case","this":"is"}{"JSON":"values","true":true,"two":2,"with":"just"} \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/files_test_dup.xml b/vendor/github.com/clbanning/mxj/files_test_dup.xml new file mode 100644 index 00000000000..f68d22e28ea --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test_dup.xml @@ -0,0 +1 @@ +for files.gotestdoctest casesome \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/files_test_indent.json b/vendor/github.com/clbanning/mxj/files_test_indent.json new file mode 100644 index 00000000000..6fde15634df --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test_indent.json @@ -0,0 +1,12 @@ +{ + "a": "test", + "file": "for", + "files_test.go": "case", + "this": "is" +} +{ + "JSON": "values", + "true": true, + "two": 2, + "with": "just" +} \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/files_test_indent.xml b/vendor/github.com/clbanning/mxj/files_test_indent.xml new file mode 100644 index 00000000000..8c91a1dc20a --- /dev/null +++ b/vendor/github.com/clbanning/mxj/files_test_indent.xml @@ -0,0 +1,8 @@ + + for files.go + test + + doc + test case + some + \ No newline at end of file diff --git a/vendor/github.com/clbanning/mxj/gob.go b/vendor/github.com/clbanning/mxj/gob.go new file mode 100644 index 00000000000..d56c2fd6fe8 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/gob.go @@ -0,0 +1,35 @@ +// gob.go - Encode/Decode a Map into a gob object. + +package mxj + +import ( + "bytes" + "encoding/gob" +) + +// NewMapGob returns a Map value for a gob object that has been +// encoded from a map[string]interface{} (or compatible type) value. +// It is intended to provide symmetric handling of Maps that have +// been encoded using mv.Gob. +func NewMapGob(gobj []byte) (Map, error) { + m := make(map[string]interface{}, 0) + if len(gobj) == 0 { + return m, nil + } + r := bytes.NewReader(gobj) + dec := gob.NewDecoder(r) + if err := dec.Decode(&m); err != nil { + return m, err + } + return m, nil +} + +// Gob returns a gob-encoded value for the Map 'mv'. +func (mv Map) Gob() ([]byte, error) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + if err := enc.Encode(map[string]interface{}(mv)); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/clbanning/mxj/json.go b/vendor/github.com/clbanning/mxj/json.go new file mode 100644 index 00000000000..eb2c05a1869 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/json.go @@ -0,0 +1,323 @@ +// Copyright 2012-2014 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "time" +) + +// ------------------------------ write JSON ----------------------- + +// Just a wrapper on json.Marshal. +// If option safeEncoding is'true' then safe encoding of '<', '>' and '&' +// is preserved. (see encoding/json#Marshal, encoding/json#Encode) +func (mv Map) Json(safeEncoding ...bool) ([]byte, error) { + var s bool + if len(safeEncoding) == 1 { + s = safeEncoding[0] + } + + b, err := json.Marshal(mv) + + if !s { + b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1) + b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1) + b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1) + } + return b, err +} + +// Just a wrapper on json.MarshalIndent. +// If option safeEncoding is'true' then safe encoding of '<' , '>' and '&' +// is preserved. (see encoding/json#Marshal, encoding/json#Encode) +func (mv Map) JsonIndent(prefix, indent string, safeEncoding ...bool) ([]byte, error) { + var s bool + if len(safeEncoding) == 1 { + s = safeEncoding[0] + } + + b, err := json.MarshalIndent(mv, prefix, indent) + if !s { + b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1) + b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1) + b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1) + } + return b, err +} + +// The following implementation is provided for symmetry with NewMapJsonReader[Raw] +// The names will also provide a key for the number of return arguments. + +// Writes the Map as JSON on the Writer. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonWriter(jsonWriter io.Writer, safeEncoding ...bool) error { + b, err := mv.Json(safeEncoding...) + if err != nil { + return err + } + + _, err = jsonWriter.Write(b) + return err +} + +// Writes the Map as JSON on the Writer. []byte is the raw JSON that was written. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonWriterRaw(jsonWriter io.Writer, safeEncoding ...bool) ([]byte, error) { + b, err := mv.Json(safeEncoding...) + if err != nil { + return b, err + } + + _, err = jsonWriter.Write(b) + return b, err +} + +// Writes the Map as pretty JSON on the Writer. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonIndentWriter(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) error { + b, err := mv.JsonIndent(prefix, indent, safeEncoding...) + if err != nil { + return err + } + + _, err = jsonWriter.Write(b) + return err +} + +// Writes the Map as pretty JSON on the Writer. []byte is the raw JSON that was written. +// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. +func (mv Map) JsonIndentWriterRaw(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) ([]byte, error) { + b, err := mv.JsonIndent(prefix, indent, safeEncoding...) + if err != nil { + return b, err + } + + _, err = jsonWriter.Write(b) + return b, err +} + +// --------------------------- read JSON ----------------------------- + +// Decode numericvalues as json.Number type Map values - see encoding/json#Number. +// NOTE: this is for decoding JSON into a Map with NewMapJson(), NewMapJsonReader(), +// etc.; it does not affect NewMapXml(), etc. The XML encoders mv.Xml() and mv.XmlIndent() +// do recognize json.Number types; a JSON object can be decoded to a Map with json.Number +// value types and the resulting Map can be correctly encoded into a XML object. +var JsonUseNumber bool + +// Just a wrapper on json.Unmarshal +// Converting JSON to XML is a simple as: +// ... +// mapVal, merr := mxj.NewMapJson(jsonVal) +// if merr != nil { +// // handle error +// } +// xmlVal, xerr := mapVal.Xml() +// if xerr != nil { +// // handle error +// } +// NOTE: as a special case, passing a list, e.g., [{"some-null-value":"", "a-non-null-value":"bar"}], +// will be interpreted as having the root key 'object' prepended - {"object":[ ... ]} - to unmarshal to a Map. +// See mxj/j2x/j2x_test.go. +func NewMapJson(jsonVal []byte) (Map, error) { + // empty or nil begets empty + if len(jsonVal) == 0 { + m := make(map[string]interface{}, 0) + return m, nil + } + // handle a goofy case ... + if jsonVal[0] == '[' { + jsonVal = []byte(`{"object":` + string(jsonVal) + `}`) + } + m := make(map[string]interface{}) + // err := json.Unmarshal(jsonVal, &m) + buf := bytes.NewReader(jsonVal) + dec := json.NewDecoder(buf) + if JsonUseNumber { + dec.UseNumber() + } + err := dec.Decode(&m) + return m, err +} + +// Retrieve a Map value from an io.Reader. +// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an +// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte +// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal +// a JSON object. +func NewMapJsonReader(jsonReader io.Reader) (Map, error) { + jb, err := getJson(jsonReader) + if err != nil || len(*jb) == 0 { + return nil, err + } + + // Unmarshal the 'presumed' JSON string + return NewMapJson(*jb) +} + +// Retrieve a Map value and raw JSON - []byte - from an io.Reader. +// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an +// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte +// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal +// a JSON object and retrieve the raw JSON in a single call. +func NewMapJsonReaderRaw(jsonReader io.Reader) (Map, []byte, error) { + jb, err := getJson(jsonReader) + if err != nil || len(*jb) == 0 { + return nil, *jb, err + } + + // Unmarshal the 'presumed' JSON string + m, merr := NewMapJson(*jb) + return m, *jb, merr +} + +// Pull the next JSON string off the stream: just read from first '{' to its closing '}'. +// Returning a pointer to the slice saves 16 bytes - maybe unnecessary, but internal to package. +func getJson(rdr io.Reader) (*[]byte, error) { + bval := make([]byte, 1) + jb := make([]byte, 0) + var inQuote, inJson bool + var parenCnt int + var previous byte + + // scan the input for a matched set of {...} + // json.Unmarshal will handle syntax checking. + for { + _, err := rdr.Read(bval) + if err != nil { + if err == io.EOF && inJson && parenCnt > 0 { + return &jb, fmt.Errorf("no closing } for JSON string: %s", string(jb)) + } + return &jb, err + } + switch bval[0] { + case '{': + if !inQuote { + parenCnt++ + inJson = true + } + case '}': + if !inQuote { + parenCnt-- + } + if parenCnt < 0 { + return nil, fmt.Errorf("closing } without opening {: %s", string(jb)) + } + case '"': + if inQuote { + if previous == '\\' { + break + } + inQuote = false + } else { + inQuote = true + } + case '\n', '\r', '\t', ' ': + if !inQuote { + continue + } + } + if inJson { + jb = append(jb, bval[0]) + if parenCnt == 0 { + break + } + } + previous = bval[0] + } + + return &jb, nil +} + +// ------------------------------- JSON Reader handler via Map values ----------------------- + +// Default poll delay to keep Handler from spinning on an open stream +// like sitting on os.Stdin waiting for imput. +var jhandlerPollInterval = time.Duration(1e6) + +// While unnecessary, we make HandleJsonReader() have the same signature as HandleXmlReader(). +// This avoids treating one or other as a special case and discussing the underlying stdlib logic. + +// Bulk process JSON using handlers that process a Map value. +// 'rdr' is an io.Reader for the JSON (stream). +// 'mapHandler' is the Map processing handler. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'. +func HandleJsonReader(jsonReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error { + var n int + for { + m, merr := NewMapJsonReader(jsonReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m); !ok { + break + } + } else if merr != io.EOF { + <-time.After(jhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} + +// Bulk process JSON using handlers that process a Map value and the raw JSON. +// 'rdr' is an io.Reader for the JSON (stream). +// 'mapHandler' is the Map and raw JSON - []byte - processor. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error and raw JSON processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'. +func HandleJsonReaderRaw(jsonReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error { + var n int + for { + m, raw, merr := NewMapJsonReaderRaw(jsonReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr, raw); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m, raw); !ok { + break + } + } else if merr != io.EOF { + <-time.After(jhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} diff --git a/vendor/github.com/clbanning/mxj/keyvalues.go b/vendor/github.com/clbanning/mxj/keyvalues.go new file mode 100644 index 00000000000..0b244c879ce --- /dev/null +++ b/vendor/github.com/clbanning/mxj/keyvalues.go @@ -0,0 +1,671 @@ +// Copyright 2012-2014 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// keyvalues.go: Extract values from an arbitrary XML doc. Tag path can include wildcard characters. + +package mxj + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +// ----------------------------- get everything FOR a single key ------------------------- + +const ( + minArraySize = 32 +) + +var defaultArraySize int = minArraySize + +// Adjust the buffers for expected number of values to return from ValuesForKey() and ValuesForPath(). +// This can have the effect of significantly reducing memory allocation-copy functions for large data sets. +// Returns the initial buffer size. +func SetArraySize(size int) int { + if size > minArraySize { + defaultArraySize = size + } else { + defaultArraySize = minArraySize + } + return defaultArraySize +} + +// Return all values in Map, 'mv', associated with a 'key'. If len(returned_values) == 0, then no match. +// On error, the returned slice is 'nil'. NOTE: 'key' can be wildcard, "*". +// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list. +// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them. +// - For attributes prefix the label with a hyphen, '-', e.g., "-seq:3". +// - If the 'key' refers to a list, then "key:value" could select a list member of the list. +// - The subkey can be wildcarded - "key:*" - to require that it's there with some value. +// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an +// exclusion critera - e.g., "!author:William T. Gaddis". +// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|". +func (mv Map) ValuesForKey(key string, subkeys ...string) ([]interface{}, error) { + m := map[string]interface{}(mv) + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return nil, err + } + } + + ret := make([]interface{}, 0, defaultArraySize) + var cnt int + hasKey(m, key, &ret, &cnt, subKeyMap) + return ret[:cnt], nil +} + +var KeyNotExistError = errors.New("Key does not exist") + +// ValueForKey is a wrapper on ValuesForKey. It returns the first member of []interface{}, if any. +// If there is no value, "nil, nil" is returned. +func (mv Map) ValueForKey(key string, subkeys ...string) (interface{}, error) { + vals, err := mv.ValuesForKey(key, subkeys...) + if err != nil { + return nil, err + } + if len(vals) == 0 { + return nil, KeyNotExistError + } + return vals[0], nil +} + +// hasKey - if the map 'key' exists append it to array +// if it doesn't do nothing except scan array and map values +func hasKey(iv interface{}, key string, ret *[]interface{}, cnt *int, subkeys map[string]interface{}) { + // func hasKey(iv interface{}, key string, ret *[]interface{}, subkeys map[string]interface{}) { + switch iv.(type) { + case map[string]interface{}: + vv := iv.(map[string]interface{}) + // see if the current value is of interest + if v, ok := vv[key]; ok { + switch v.(type) { + case map[string]interface{}: + if hasSubKeys(v, subkeys) { + *ret = append(*ret, v) + *cnt++ + } + case []interface{}: + for _, av := range v.([]interface{}) { + if hasSubKeys(av, subkeys) { + *ret = append(*ret, av) + *cnt++ + } + } + default: + if len(subkeys) == 0 { + *ret = append(*ret, v) + *cnt++ + } + } + } + + // wildcard case + if key == "*" { + for _, v := range vv { + switch v.(type) { + case map[string]interface{}: + if hasSubKeys(v, subkeys) { + *ret = append(*ret, v) + *cnt++ + } + case []interface{}: + for _, av := range v.([]interface{}) { + if hasSubKeys(av, subkeys) { + *ret = append(*ret, av) + *cnt++ + } + } + default: + if len(subkeys) == 0 { + *ret = append(*ret, v) + *cnt++ + } + } + } + } + + // scan the rest + for _, v := range vv { + hasKey(v, key, ret, cnt, subkeys) + } + case []interface{}: + for _, v := range iv.([]interface{}) { + hasKey(v, key, ret, cnt, subkeys) + } + } +} + +// ----------------------- get everything for a node in the Map --------------------------- + +// Allow indexed arrays in "path" specification. (Request from Abhijit Kadam - abhijitk100@gmail.com.) +// 2014.04.28 - implementation note. +// Implemented as a wrapper of (old)ValuesForPath() because we need look-ahead logic to handle expansion +// of wildcards and unindexed arrays. Embedding such logic into valuesForKeyPath() would have made the +// code much more complicated; this wrapper is straightforward, easy to debug, and doesn't add significant overhead. + +// Retrieve all values for a path from the Map. If len(returned_values) == 0, then no match. +// On error, the returned array is 'nil'. +// 'path' is a dot-separated path of key values. +// - If a node in the path is '*', then everything beyond is walked. +// - 'path' can contain indexed array references, such as, "*.data[1]" and "msgs[2].data[0].field" - +// even "*[2].*[0].field". +// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list. +// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them. +// - For attributes prefix the label with a hyphen, '-', e.g., "-seq:3". +// - If the 'path' refers to a list, then "tag:value" would return member of the list. +// - The subkey can be wildcarded - "key:*" - to require that it's there with some value. +// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an +// exclusion critera - e.g., "!author:William T. Gaddis". +// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|". +func (mv Map) ValuesForPath(path string, subkeys ...string) ([]interface{}, error) { + // If there are no array indexes in path, use legacy ValuesForPath() logic. + if strings.Index(path, "[") < 0 { + return mv.oldValuesForPath(path, subkeys...) + } + + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return nil, err + } + } + + keys, kerr := parsePath(path) + if kerr != nil { + return nil, kerr + } + + vals, verr := valuesForArray(keys, mv) + if verr != nil { + return nil, verr // Vals may be nil, but return empty array. + } + + // Need to handle subkeys ... only return members of vals that satisfy conditions. + retvals := make([]interface{}, 0) + for _, v := range vals { + if hasSubKeys(v, subKeyMap) { + retvals = append(retvals, v) + } + } + return retvals, nil +} + +func valuesForArray(keys []*key, m Map) ([]interface{}, error) { + var tmppath string + var haveFirst bool + var vals []interface{} + var verr error + + lastkey := len(keys) - 1 + for i := 0; i <= lastkey; i++ { + if !haveFirst { + tmppath = keys[i].name + haveFirst = true + } else { + tmppath += "." + keys[i].name + } + + // Look-ahead: explode wildcards and unindexed arrays. + // Need to handle un-indexed list recursively: + // e.g., path is "stuff.data[0]" rather than "stuff[0].data[0]". + // Need to treat it as "stuff[0].data[0]", "stuff[1].data[0]", ... + if !keys[i].isArray && i < lastkey && keys[i+1].isArray { + // Can't pass subkeys because we may not be at literal end of path. + vv, vverr := m.oldValuesForPath(tmppath) + if vverr != nil { + return nil, vverr + } + for _, v := range vv { + // See if we can walk the value. + am, ok := v.(map[string]interface{}) + if !ok { + continue + } + // Work the backend. + nvals, nvalserr := valuesForArray(keys[i+1:], Map(am)) + if nvalserr != nil { + return nil, nvalserr + } + vals = append(vals, nvals...) + } + break // have recursed the whole path - return + } + + if keys[i].isArray || i == lastkey { + // Don't pass subkeys because may not be at literal end of path. + vals, verr = m.oldValuesForPath(tmppath) + } else { + continue + } + if verr != nil { + return nil, verr + } + + if i == lastkey && !keys[i].isArray { + break + } + + // Now we're looking at an array - supposedly. + // Is index in range of vals? + if len(vals) <= keys[i].position { + vals = nil + break + } + + // Return the array member of interest, if at end of path. + if i == lastkey { + vals = vals[keys[i].position:(keys[i].position + 1)] + break + } + + // Extract the array member of interest. + am := vals[keys[i].position:(keys[i].position + 1)] + + // must be a map[string]interface{} value so we can keep walking the path + amm, ok := am[0].(map[string]interface{}) + if !ok { + vals = nil + break + } + + m = Map(amm) + haveFirst = false + } + + return vals, nil +} + +type key struct { + name string + isArray bool + position int +} + +func parsePath(s string) ([]*key, error) { + keys := strings.Split(s, ".") + + ret := make([]*key, 0) + + for i := 0; i < len(keys); i++ { + if keys[i] == "" { + continue + } + + newkey := new(key) + if strings.Index(keys[i], "[") < 0 { + newkey.name = keys[i] + ret = append(ret, newkey) + continue + } + + p := strings.Split(keys[i], "[") + newkey.name = p[0] + p = strings.Split(p[1], "]") + if p[0] == "" { // no right bracket + return nil, fmt.Errorf("no right bracket on key index: %s", keys[i]) + } + // convert p[0] to a int value + pos, nerr := strconv.ParseInt(p[0], 10, 32) + if nerr != nil { + return nil, fmt.Errorf("cannot convert index to int value: %s", p[0]) + } + newkey.position = int(pos) + newkey.isArray = true + ret = append(ret, newkey) + } + + return ret, nil +} + +// legacy ValuesForPath() - now wrapped to handle special case of indexed arrays in 'path'. +func (mv Map) oldValuesForPath(path string, subkeys ...string) ([]interface{}, error) { + m := map[string]interface{}(mv) + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return nil, err + } + } + + keys := strings.Split(path, ".") + if keys[len(keys)-1] == "" { + keys = keys[:len(keys)-1] + } + ivals := make([]interface{}, 0, defaultArraySize) + var cnt int + valuesForKeyPath(&ivals, &cnt, m, keys, subKeyMap) + return ivals[:cnt], nil +} + +func valuesForKeyPath(ret *[]interface{}, cnt *int, m interface{}, keys []string, subkeys map[string]interface{}) { + lenKeys := len(keys) + + // load 'm' values into 'ret' + // expand any lists + if lenKeys == 0 { + switch m.(type) { + case map[string]interface{}: + if subkeys != nil { + if ok := hasSubKeys(m, subkeys); !ok { + return + } + } + *ret = append(*ret, m) + *cnt++ + case []interface{}: + for i, v := range m.([]interface{}) { + if subkeys != nil { + if ok := hasSubKeys(v, subkeys); !ok { + continue // only load list members with subkeys + } + } + *ret = append(*ret, (m.([]interface{}))[i]) + *cnt++ + } + default: + if subkeys != nil { + return // must be map[string]interface{} if there are subkeys + } + *ret = append(*ret, m) + *cnt++ + } + return + } + + // key of interest + key := keys[0] + switch key { + case "*": // wildcard - scan all values + switch m.(type) { + case map[string]interface{}: + for _, v := range m.(map[string]interface{}) { + // valuesForKeyPath(ret, v, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) + } + case []interface{}: + for _, v := range m.([]interface{}) { + switch v.(type) { + // flatten out a list of maps - keys are processed + case map[string]interface{}: + for _, vv := range v.(map[string]interface{}) { + // valuesForKeyPath(ret, vv, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys) + } + default: + // valuesForKeyPath(ret, v, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) + } + } + } + default: // key - must be map[string]interface{} + switch m.(type) { + case map[string]interface{}: + if v, ok := m.(map[string]interface{})[key]; ok { + // valuesForKeyPath(ret, v, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) + } + case []interface{}: // may be buried in list + for _, v := range m.([]interface{}) { + switch v.(type) { + case map[string]interface{}: + if vv, ok := v.(map[string]interface{})[key]; ok { + // valuesForKeyPath(ret, vv, keys[1:], subkeys) + valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys) + } + } + } + } + } +} + +// hasSubKeys() - interface{} equality works for string, float64, bool +// 'v' must be a map[string]interface{} value to have subkeys +// 'a' can have k:v pairs with v.(string) == "*", which is treated like a wildcard. +func hasSubKeys(v interface{}, subkeys map[string]interface{}) bool { + if len(subkeys) == 0 { + return true + } + + switch v.(type) { + case map[string]interface{}: + // do all subKey name:value pairs match? + mv := v.(map[string]interface{}) + for skey, sval := range subkeys { + isNotKey := false + if skey[:1] == "!" { // a NOT-key + skey = skey[1:] + isNotKey = true + } + vv, ok := mv[skey] + if !ok { // key doesn't exist + if isNotKey { // key not there, but that's what we want + if kv, ok := sval.(string); ok && kv == "*" { + continue + } + } + return false + } + // wildcard check + if kv, ok := sval.(string); ok && kv == "*" { + if isNotKey { // key is there, and we don't want it + return false + } + continue + } + switch sval.(type) { + case string: + if s, ok := vv.(string); ok && s == sval.(string) { + if isNotKey { + return false + } + continue + } + case bool: + if b, ok := vv.(bool); ok && b == sval.(bool) { + if isNotKey { + return false + } + continue + } + case float64: + if f, ok := vv.(float64); ok && f == sval.(float64) { + if isNotKey { + return false + } + continue + } + } + // key there but didn't match subkey value + if isNotKey { // that's what we want + continue + } + return false + } + // all subkeys matched + return true + } + + // not a map[string]interface{} value, can't have subkeys + return false +} + +// Generate map of key:value entries as map[string]string. +// 'kv' arguments are "name:value" pairs: attribute keys are designated with prepended hyphen, '-'. +// If len(kv) == 0, the return is (nil, nil). +func getSubKeyMap(kv ...string) (map[string]interface{}, error) { + if len(kv) == 0 { + return nil, nil + } + m := make(map[string]interface{}, 0) + for _, v := range kv { + vv := strings.Split(v, fieldSep) + switch len(vv) { + case 2: + m[vv[0]] = interface{}(vv[1]) + case 3: + switch vv[2] { + case "string", "char", "text": + m[vv[0]] = interface{}(vv[1]) + case "bool", "boolean": + // ParseBool treats "1"==true & "0"==false + b, err := strconv.ParseBool(vv[1]) + if err != nil { + return nil, fmt.Errorf("can't convert subkey value to bool: %s", vv[1]) + } + m[vv[0]] = interface{}(b) + case "float", "float64", "num", "number", "numeric": + f, err := strconv.ParseFloat(vv[1], 64) + if err != nil { + return nil, fmt.Errorf("can't convert subkey value to float: %s", vv[1]) + } + m[vv[0]] = interface{}(f) + default: + return nil, fmt.Errorf("unknown subkey conversion spec: %s", v) + } + default: + return nil, fmt.Errorf("unknown subkey spec: %s", v) + } + } + return m, nil +} + +// ------------------------------- END of valuesFor ... ---------------------------- + +// ----------------------- locate where a key value is in the tree ------------------- + +//----------------------------- find all paths to a key -------------------------------- + +// Get all paths through Map, 'mv', (in dot-notation) that terminate with the specified key. +// Results can be used with ValuesForPath. +func (mv Map) PathsForKey(key string) []string { + m := map[string]interface{}(mv) + breadbasket := make(map[string]bool, 0) + breadcrumbs := "" + + hasKeyPath(breadcrumbs, m, key, breadbasket) + if len(breadbasket) == 0 { + return nil + } + + // unpack map keys to return + res := make([]string, len(breadbasket)) + var i int + for k := range breadbasket { + res[i] = k + i++ + } + + return res +} + +// Extract the shortest path from all possible paths - from PathsForKey() - in Map, 'mv'.. +// Paths are strings using dot-notation. +func (mv Map) PathForKeyShortest(key string) string { + paths := mv.PathsForKey(key) + + lp := len(paths) + if lp == 0 { + return "" + } + if lp == 1 { + return paths[0] + } + + shortest := paths[0] + shortestLen := len(strings.Split(shortest, ".")) + + for i := 1; i < len(paths); i++ { + vlen := len(strings.Split(paths[i], ".")) + if vlen < shortestLen { + shortest = paths[i] + shortestLen = vlen + } + } + + return shortest +} + +// hasKeyPath - if the map 'key' exists append it to KeyPath.path and increment KeyPath.depth +// This is really just a breadcrumber that saves all trails that hit the prescribed 'key'. +func hasKeyPath(crumbs string, iv interface{}, key string, basket map[string]bool) { + switch iv.(type) { + case map[string]interface{}: + vv := iv.(map[string]interface{}) + if _, ok := vv[key]; ok { + // create a new breadcrumb, intialized with the one we have + var nbc string + if crumbs == "" { + nbc = key + } else { + nbc = crumbs + "." + key + } + basket[nbc] = true + } + // walk on down the path, key could occur again at deeper node + for k, v := range vv { + // create a new breadcrumb, intialized with the one we have + var nbc string + if crumbs == "" { + nbc = k + } else { + nbc = crumbs + "." + k + } + hasKeyPath(nbc, v, key, basket) + } + case []interface{}: + // crumb-trail doesn't change, pass it on + for _, v := range iv.([]interface{}) { + hasKeyPath(crumbs, v, key, basket) + } + } +} + +var PathNotExistError = errors.New("Path does not exist") + +// ValueForPath wrap ValuesFor Path and returns the first value returned. +// If no value is found it returns 'nil' and PathNotExistError. +func (mv Map) ValueForPath(path string) (interface{}, error) { + vals, err := mv.ValuesForPath(path) + if err != nil { + return nil, err + } + if len(vals) == 0 { + return nil, PathNotExistError + } + return vals[0], nil +} + +// Returns the first found value for the path as a string. +func (mv Map) ValueForPathString(path string) (string, error) { + vals, err := mv.ValuesForPath(path) + if err != nil { + return "", err + } + if len(vals) == 0 { + return "", errors.New("ValueForPath: path not found") + } + val := vals[0] + switch str := val.(type) { + case string: + return str, nil + default: + return "", fmt.Errorf("ValueForPath: unsupported type: %T", str) + } +} + +// Returns the first found value for the path as a string. +// If the path is not found then it returns an empty string. +func (mv Map) ValueOrEmptyForPathString(path string) string { + str, _ := mv.ValueForPathString(path) + return str +} diff --git a/vendor/github.com/clbanning/mxj/leafnode.go b/vendor/github.com/clbanning/mxj/leafnode.go new file mode 100644 index 00000000000..cf413ebdd4f --- /dev/null +++ b/vendor/github.com/clbanning/mxj/leafnode.go @@ -0,0 +1,112 @@ +package mxj + +// leafnode.go - return leaf nodes with paths and values for the Map +// inspired by: https://groups.google.com/forum/#!topic/golang-nuts/3JhuVKRuBbw + +import ( + "strconv" + "strings" +) + +const ( + NoAttributes = true // suppress LeafNode values that are attributes +) + +// LeafNode - a terminal path value in a Map. +// For XML Map values it represents an attribute or simple element value - of type +// string unless Map was created using Cast flag. For JSON Map values it represents +// a string, numeric, boolean, or null value. +type LeafNode struct { + Path string // a dot-notation representation of the path with array subscripting + Value interface{} // the value at the path termination +} + +// LeafNodes - returns an array of all LeafNode values for the Map. +// The option no_attr argument suppresses attribute values (keys with prepended hyphen, '-') +// as well as the "#text" key for the associated simple element value. +// +// PrependAttrWithHypen(false) will result in attributes having .attr-name as +// terminal node in 'path' while the path for the element value, itself, will be +// the base path w/o "#text". +// +// LeafUseDotNotation(true) causes list members to be identified using ".N" syntax +// rather than "[N]" syntax. +func (mv Map) LeafNodes(no_attr ...bool) []LeafNode { + var a bool + if len(no_attr) == 1 { + a = no_attr[0] + } + + l := make([]LeafNode, 0) + getLeafNodes("", "", map[string]interface{}(mv), &l, a) + return l +} + +func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) { + // if stripping attributes, then also strip "#text" key + if !noattr || node != "#text" { + if path != "" && node[:1] != "[" { + path += "." + } + path += node + } + switch mv.(type) { + case map[string]interface{}: + for k, v := range mv.(map[string]interface{}) { + // if noattr && k[:1] == "-" { + if noattr && len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 { + continue + } + getLeafNodes(path, k, v, l, noattr) + } + case []interface{}: + for i, v := range mv.([]interface{}) { + if useDotNotation { + getLeafNodes(path, strconv.Itoa(i), v, l, noattr) + } else { + getLeafNodes(path, "["+strconv.Itoa(i)+"]", v, l, noattr) + } + } + default: + // can't walk any further, so create leaf + n := LeafNode{path, mv} + *l = append(*l, n) + } +} + +// LeafPaths - all paths that terminate in LeafNode values. +func (mv Map) LeafPaths(no_attr ...bool) []string { + ln := mv.LeafNodes() + ss := make([]string, len(ln)) + for i := 0; i < len(ln); i++ { + ss[i] = ln[i].Path + } + return ss +} + +// LeafValues - all terminal values in the Map. +func (mv Map) LeafValues(no_attr ...bool) []interface{} { + ln := mv.LeafNodes() + vv := make([]interface{}, len(ln)) + for i := 0; i < len(ln); i++ { + vv[i] = ln[i].Value + } + return vv +} + +// ====================== utilities ====================== + +// https://groups.google.com/forum/#!topic/golang-nuts/pj0C5IrZk4I +var useDotNotation bool + +// LeafUseDotNotation sets a flag that list members in LeafNode paths +// should be identified using ".N" syntax rather than the default "[N]" +// syntax. Calling LeafUseDotNotation with no arguments toggles the +// flag on/off; otherwise, the argument sets the flag value 'true'/'false'. +func LeafUseDotNotation(b ...bool) { + if len(b) == 0 { + useDotNotation = !useDotNotation + return + } + useDotNotation = b[0] +} diff --git a/vendor/github.com/clbanning/mxj/misc.go b/vendor/github.com/clbanning/mxj/misc.go new file mode 100644 index 00000000000..5b4fab2165d --- /dev/null +++ b/vendor/github.com/clbanning/mxj/misc.go @@ -0,0 +1,86 @@ +// Copyright 2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// misc.go - mimic functions (+others) called out in: +// https://groups.google.com/forum/#!topic/golang-nuts/jm_aGsJNbdQ +// Primarily these methods let you retrive XML structure information. + +package mxj + +import ( + "fmt" + "sort" + "strings" +) + +// Return the root element of the Map. If there is not a single key in Map, +// then an error is returned. +func (mv Map) Root() (string, error) { + mm := map[string]interface{}(mv) + if len(mm) != 1 { + return "", fmt.Errorf("Map does not have singleton root. Len: %d.", len(mm)) + } + for k, _ := range mm { + return k, nil + } + return "", nil +} + +// If the path is an element with sub-elements, return a list of the sub-element +// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are prefixed with +// '-', a hyphen, are considered attributes; see m.Attributes(path). +func (mv Map) Elements(path string) ([]string, error) { + e, err := mv.ValueForPath(path) + if err != nil { + return nil, err + } + switch e.(type) { + case map[string]interface{}: + ee := e.(map[string]interface{}) + elems := make([]string, len(ee)) + var i int + for k, _ := range ee { + if len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 { + continue // skip attributes + } + elems[i] = k + i++ + } + elems = elems[:i] + // alphabetic sort keeps things tidy + sort.Strings(elems) + return elems, nil + } + return nil, fmt.Errorf("no elements for path: %s", path) +} + +// If the path is an element with attributes, return a list of the attribute +// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are not prefixed with +// '-', a hyphen, are not treated as attributes; see m.Elements(path). Also, if the +// attribute prefix is "" - SetAttrPrefix("") or PrependAttrWithHyphen(false) - then +// there are no identifiable attributes. +func (mv Map) Attributes(path string) ([]string, error) { + a, err := mv.ValueForPath(path) + if err != nil { + return nil, err + } + switch a.(type) { + case map[string]interface{}: + aa := a.(map[string]interface{}) + attrs := make([]string, len(aa)) + var i int + for k, _ := range aa { + if len(attrPrefix) == 0 || strings.Index(k, attrPrefix) != 0 { + continue // skip non-attributes + } + attrs[i] = k[len(attrPrefix):] + i++ + } + attrs = attrs[:i] + // alphabetic sort keeps things tidy + sort.Strings(attrs) + return attrs, nil + } + return nil, fmt.Errorf("no attributes for path: %s", path) +} diff --git a/vendor/github.com/clbanning/mxj/mxj.go b/vendor/github.com/clbanning/mxj/mxj.go new file mode 100644 index 00000000000..f0592f06c8e --- /dev/null +++ b/vendor/github.com/clbanning/mxj/mxj.go @@ -0,0 +1,128 @@ +// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. +// Copyright 2012-2014 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "fmt" + "sort" +) + +const ( + Cast = true // for clarity - e.g., mxj.NewMapXml(doc, mxj.Cast) + SafeEncoding = true // ditto - e.g., mv.Json(mxj.SafeEncoding) +) + +type Map map[string]interface{} + +// Allocate a Map. +func New() Map { + m := make(map[string]interface{}, 0) + return m +} + +// Cast a Map to map[string]interface{} +func (mv Map) Old() map[string]interface{} { + return mv +} + +// Return a copy of mv as a newly allocated Map. If the Map only contains string, +// numeric, map[string]interface{}, and []interface{} values, then it can be thought +// of as a "deep copy." Copying a structure (or structure reference) value is subject +// to the noted restrictions. +// NOTE: If 'mv' includes structure values with, possibly, JSON encoding tags +// then only public fields of the structure are in the new Map - and with +// keys that conform to any encoding tag instructions. The structure itself will +// be represented as a map[string]interface{} value. +func (mv Map) Copy() (Map, error) { + // this is the poor-man's deep copy + // not efficient, but it works + j, jerr := mv.Json() + // must handle, we don't know how mv got built + if jerr != nil { + return nil, jerr + } + return NewMapJson(j) +} + +// --------------- StringIndent ... from x2j.WriteMap ------------- + +// Pretty print a Map. +func (mv Map) StringIndent(offset ...int) string { + return writeMap(map[string]interface{}(mv), true, true, offset...) +} + +// Pretty print a Map without the value type information - just key:value entries. +func (mv Map) StringIndentNoTypeInfo(offset ...int) string { + return writeMap(map[string]interface{}(mv), false, true, offset...) +} + +// writeMap - dumps the map[string]interface{} for examination. +// 'typeInfo' causes value type to be printed. +// 'offset' is initial indentation count; typically: Write(m). +func writeMap(m interface{}, typeInfo, root bool, offset ...int) string { + var indent int + if len(offset) == 1 { + indent = offset[0] + } + + var s string + switch m.(type) { + case []interface{}: + if typeInfo { + s += "[[]interface{}]" + } + for _, v := range m.([]interface{}) { + s += "\n" + for i := 0; i < indent; i++ { + s += " " + } + s += writeMap(v, typeInfo, false, indent+1) + } + case map[string]interface{}: + list := make([][2]string, len(m.(map[string]interface{}))) + var n int + for k, v := range m.(map[string]interface{}) { + list[n][0] = k + list[n][1] = writeMap(v, typeInfo, false, indent+1) + n++ + } + sort.Sort(mapList(list)) + for _, v := range list { + if root { + root = false + } else { + s += "\n" + } + for i := 0; i < indent; i++ { + s += " " + } + s += v[0] + " : " + v[1] + } + default: + if typeInfo { + s += fmt.Sprintf("[%T] %+v", m, m) + } else { + s += fmt.Sprintf("%+v", m) + } + } + return s +} + +// ======================== utility =============== + +type mapList [][2]string + +func (ml mapList) Len() int { + return len(ml) +} + +func (ml mapList) Swap(i, j int) { + ml[i], ml[j] = ml[j], ml[i] +} + +func (ml mapList) Less(i, j int) bool { + return ml[i][0] <= ml[j][0] +} diff --git a/vendor/github.com/clbanning/mxj/newmap.go b/vendor/github.com/clbanning/mxj/newmap.go new file mode 100644 index 00000000000..b293949056d --- /dev/null +++ b/vendor/github.com/clbanning/mxj/newmap.go @@ -0,0 +1,184 @@ +// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. +// Copyright 2012-2014, 2018 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// remap.go - build a new Map from the current Map based on keyOld:keyNew mapppings +// keys can use dot-notation, keyOld can use wildcard, '*' +// +// Computational strategy - +// Using the key path - []string - traverse a new map[string]interface{} and +// insert the oldVal as the newVal when we arrive at the end of the path. +// If the type at the end is nil, then that is newVal +// If the type at the end is a singleton (string, float64, bool) an array is created. +// If the type at the end is an array, newVal is just appended. +// If the type at the end is a map, it is inserted if possible or the map value +// is converted into an array if necessary. + +package mxj + +import ( + "errors" + "strings" +) + +// (Map)NewMap - create a new Map from data in the current Map. +// 'keypairs' are key mappings "oldKey:newKey" and specify that the current value of 'oldKey' +// should be the value for 'newKey' in the returned Map. +// - 'oldKey' supports dot-notation as described for (Map)ValuesForPath() +// - 'newKey' supports dot-notation but with no wildcards, '*', or indexed arrays +// - "oldKey" is shorthand for the keypair value "oldKey:oldKey" +// - "oldKey:" and ":newKey" are invalid keypair values +// - if 'oldKey' does not exist in the current Map, it is not written to the new Map. +// "null" is not supported unless it is the current Map. +// - see newmap_test.go for several syntax examples +// - mv.NewMap() == mxj.New() +// +// NOTE: "examples/partial.go" shows how to create arbitrary sub-docs of an XML doc. +func (mv Map) NewMap(keypairs ...string) (Map, error) { + n := make(map[string]interface{}, 0) + if len(keypairs) == 0 { + return n, nil + } + + // loop through the pairs + var oldKey, newKey string + var path []string + for _, v := range keypairs { + if len(v) == 0 { + continue // just skip over empty keypair arguments + } + + // initialize oldKey, newKey and check + vv := strings.Split(v, ":") + if len(vv) > 2 { + return n, errors.New("oldKey:newKey keypair value not valid - " + v) + } + if len(vv) == 1 { + oldKey, newKey = vv[0], vv[0] + } else { + oldKey, newKey = vv[0], vv[1] + } + strings.TrimSpace(oldKey) + strings.TrimSpace(newKey) + if i := strings.Index(newKey, "*"); i > -1 { + return n, errors.New("newKey value cannot contain wildcard character - " + v) + } + if i := strings.Index(newKey, "["); i > -1 { + return n, errors.New("newKey value cannot contain indexed arrays - " + v) + } + if oldKey == "" || newKey == "" { + return n, errors.New("oldKey or newKey is not specified - " + v) + } + + // get oldKey value + oldVal, err := mv.ValuesForPath(oldKey) + if err != nil { + return n, err + } + if len(oldVal) == 0 { + continue // oldKey has no value, may not exist in mv + } + + // break down path + path = strings.Split(newKey, ".") + if path[len(path)-1] == "" { // ignore a trailing dot in newKey spec + path = path[:len(path)-1] + } + + addNewVal(&n, path, oldVal) + } + + return n, nil +} + +// navigate 'n' to end of path and add val +func addNewVal(n *map[string]interface{}, path []string, val []interface{}) { + // newVal - either singleton or array + var newVal interface{} + if len(val) == 1 { + newVal = val[0] // is type interface{} + } else { + newVal = interface{}(val) + } + + // walk to the position of interest, create it if necessary + m := (*n) // initialize map walker + var k string // key for m + lp := len(path) - 1 // when to stop looking + for i := 0; i < len(path); i++ { + k = path[i] + if i == lp { + break + } + var nm map[string]interface{} // holds position of next-map + switch m[k].(type) { + case nil: // need a map for next node in path, so go there + nm = make(map[string]interface{}, 0) + m[k] = interface{}(nm) + m = m[k].(map[string]interface{}) + case map[string]interface{}: + // OK - got somewhere to walk to, go there + m = m[k].(map[string]interface{}) + case []interface{}: + // add a map and nm points to new map unless there's already + // a map in the array, then nm points there + // The placement of the next value in the array is dependent + // on the sequence of members - could land on a map or a nil + // value first. TODO: how to test this. + a := make([]interface{}, 0) + var foundmap bool + for _, vv := range m[k].([]interface{}) { + switch vv.(type) { + case nil: // doesn't appear that this occurs, need a test case + if foundmap { // use the first one in array + a = append(a, vv) + continue + } + nm = make(map[string]interface{}, 0) + a = append(a, interface{}(nm)) + foundmap = true + case map[string]interface{}: + if foundmap { // use the first one in array + a = append(a, vv) + continue + } + nm = vv.(map[string]interface{}) + a = append(a, vv) + foundmap = true + default: + a = append(a, vv) + } + } + // no map found in array + if !foundmap { + nm = make(map[string]interface{}, 0) + a = append(a, interface{}(nm)) + } + m[k] = interface{}(a) // must insert in map + m = nm + default: // it's a string, float, bool, etc. + aa := make([]interface{}, 0) + nm = make(map[string]interface{}, 0) + aa = append(aa, m[k], nm) + m[k] = interface{}(aa) + m = nm + } + } + + // value is nil, array or a singleton of some kind + // initially m.(type) == map[string]interface{} + v := m[k] + switch v.(type) { + case nil: // initialized + m[k] = newVal + case []interface{}: + a := m[k].([]interface{}) + a = append(a, newVal) + m[k] = interface{}(a) + default: // v exists:string, float64, bool, map[string]interface, etc. + a := make([]interface{}, 0) + a = append(a, v, newVal) + m[k] = interface{}(a) + } +} diff --git a/vendor/github.com/clbanning/mxj/readme.md b/vendor/github.com/clbanning/mxj/readme.md new file mode 100644 index 00000000000..6bb21dca82a --- /dev/null +++ b/vendor/github.com/clbanning/mxj/readme.md @@ -0,0 +1,179 @@ +

mxj - to/from maps, XML and JSON

+Decode/encode XML to/from map[string]interface{} (or JSON) values, and extract/modify values from maps by key or key-path, including wildcards. + +mxj supplants the legacy x2j and j2x packages. If you want the old syntax, use mxj/x2j and mxj/j2x packages. + +

Related Packages

+ +https://github.com/clbanning/checkxml provides functions for validating XML data. + +

Refactor Decoder - 2015.11.15

+For over a year I've wanted to refactor the XML-to-map[string]interface{} decoder to make it more performant. I recently took the time to do that, since we were using github.com/clbanning/mxj in a production system that could be deployed on a Raspberry Pi. Now the decoder is comparable to the stdlib JSON-to-map[string]interface{} decoder in terms of its additional processing overhead relative to decoding to a structure value. As shown by: + + BenchmarkNewMapXml-4 100000 18043 ns/op + BenchmarkNewStructXml-4 100000 14892 ns/op + BenchmarkNewMapJson-4 300000 4633 ns/op + BenchmarkNewStructJson-4 300000 3427 ns/op + BenchmarkNewMapXmlBooks-4 20000 82850 ns/op + BenchmarkNewStructXmlBooks-4 20000 67822 ns/op + BenchmarkNewMapJsonBooks-4 100000 17222 ns/op + BenchmarkNewStructJsonBooks-4 100000 15309 ns/op + +

Notices

+ + 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc. + 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps. + 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package. + 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing. + 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods. + 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag(). + 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc. + 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix(). + 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable. + 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars(). + 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf". + To cast them to float64, first set flag with CastNanInf(true). + 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure. + 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization. + 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM). + 2015.12.02: XML decoding/encoding that preserves original structure of document. See NewMapXmlSeq() + and mv.XmlSeq() / mv.XmlSeqIndent(). + 2015-05-20: New: mv.StringIndentNoTypeInfo(). + Also, alphabetically sort map[string]interface{} values by key to prettify output for mv.Xml(), + mv.XmlIndent(), mv.StringIndent(), mv.StringIndentNoTypeInfo(). + 2014-11-09: IncludeTagSeqNum() adds "_seq" key with XML doc positional information. + (NOTE: PreserveXmlList() is similar and will be here soon.) + 2014-09-18: inspired by NYTimes fork, added PrependAttrWithHyphen() to allow stripping hyphen from attribute tag. + 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML. + 2014-04-28: ValuesForPath() and NewMap() now accept path with indexed array references. + +

Basic Unmarshal XML to map[string]interface{}

+
type Map map[string]interface{}
+ +Create a `Map` value, 'mv', from any `map[string]interface{}` value, 'v': +
mv := Map(v)
+ +Unmarshal / marshal XML as a `Map` value, 'mv': +
mv, err := NewMapXml(xmlValue) // unmarshal
+xmlValue, err := mv.Xml()      // marshal
+ +Unmarshal XML from an `io.Reader` as a `Map` value, 'mv': +
mv, err := NewMapXmlReader(xmlReader)         // repeated calls, as with an os.File Reader, will process stream
+mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
+ +Marshal `Map` value, 'mv', to an XML Writer (`io.Writer`): +
err := mv.XmlWriter(xmlWriter)
+raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
+ +Also, for prettified output: +
xmlValue, err := mv.XmlIndent(prefix, indent, ...)
+err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...)
+raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...)
+ +Bulk process XML with error handling (note: handlers must return a boolean value): +
err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error))
+err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte))
+ +Converting XML to JSON: see Examples for `NewMapXml` and `HandleXmlReader`. + +There are comparable functions and methods for JSON processing. + +Arbitrary structure values can be decoded to / encoded from `Map` values: +
mv, err := NewMapStruct(structVal)
+err := mv.Struct(structPointer)
+ +

Extract / modify Map values

+To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON +or structure to a `Map` value, 'mv', or cast a `map[string]interface{}` value to a `Map` value, 'mv', then: +
paths := mv.PathsForKey(key)
+path := mv.PathForKeyShortest(key)
+values, err := mv.ValuesForKey(key, subkeys)
+values, err := mv.ValuesForPath(path, subkeys)
+count, err := mv.UpdateValuesForPath(newVal, path, subkeys)
+ +Get everything at once, irrespective of path depth: +
leafnodes := mv.LeafNodes()
+leafvalues := mv.LeafValues()
+ +A new `Map` with whatever keys are desired can be created from the current `Map` and then encoded in XML +or JSON. (Note: keys can use dot-notation.) +
newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
+newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go"
+newXml, err := newMap.Xml()   // for example
+newJson, err := newMap.Json() // ditto
+ +

Usage

+ +The package is fairly well [self-documented with examples](http://godoc.org/github.com/clbanning/mxj). + +Also, the subdirectory "examples" contains a wide range of examples, several taken from golang-nuts discussions. + +

XML parsing conventions

+ +Using NewMapXml() + + - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`, + to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or + `SetAttrPrefix()`.) + - If the element is a simple element and has attributes, the element value + is given the key `#text` for its `map[string]interface{}` representation. (See + the 'atomFeedString.xml' test data, below.) + - XML comments, directives, and process instructions are ignored. + - If CoerceKeysToLower() has been called, then the resultant keys will be lower case. + +Using NewMapXmlSeq() + + - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values + where the `` value has "#text" and "#seq" keys - the "#text" key holds the + value for ``. + - All elements, except for the root, have a "#seq" key. + - Comments, directives, and process instructions are unmarshalled into the Map using the + keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more + specifics.) + - Name space syntax is preserved: + - `something` parses to `map["ns:key"]interface{}{"something"}` + - `xmlns:ns="http://myns.com/ns"` parses to `map["xmlns:ns"]interface{}{"http://myns.com/ns"}` + +Both + + - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them + to be cast, set a flag to cast them using CastNanInf(true). + +

XML encoding conventions

+ + - 'nil' `Map` values, which may represent 'null' JSON values, are encoded as ``. + NOTE: the operation is not symmetric as `` elements are decoded as `tag:""` `Map` values, + which, then, encode in JSON as `"tag":""` values. + - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go + randomizes the walk through map[string]interface{} values.) If you plan to re-encode the + Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and + mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when + working with the Map representation. + +

Running "go test"

+ +Because there are no guarantees on the sequence map elements are retrieved, the tests have been +written for visual verification in most cases. One advantage is that you can easily use the +output from running "go test" as examples of calling the various functions and methods. + +

Motivation

+ +I make extensive use of JSON for messaging and typically unmarshal the messages into +`map[string]interface{}` values. This is easily done using `json.Unmarshal` from the +standard Go libraries. Unfortunately, many legacy solutions use structured +XML messages; in those environments the applications would have to be refactored to +interoperate with my components. + +The better solution is to just provide an alternative HTTP handler that receives +XML messages and parses it into a `map[string]interface{}` value and then reuse +all the JSON-based code. The Go `xml.Unmarshal()` function does not provide the same +option of unmarshaling XML messages into `map[string]interface{}` values. So I wrote +a couple of small functions to fill this gap and released them as the x2j package. + +Over the next year and a half additional features were added, and the companion j2x +package was released to address XML encoding of arbitrary JSON and `map[string]interface{}` +values. As part of a refactoring of our production system and looking at how we had been +using the x2j and j2x packages we found that we rarely performed direct XML-to-JSON or +JSON-to_XML conversion and that working with the XML or JSON as `map[string]interface{}` +values was the primary value. Thus, everything was refactored into the mxj package. + diff --git a/vendor/github.com/clbanning/mxj/remove.go b/vendor/github.com/clbanning/mxj/remove.go new file mode 100644 index 00000000000..8362ab17fa4 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/remove.go @@ -0,0 +1,37 @@ +package mxj + +import "strings" + +// Removes the path. +func (mv Map) Remove(path string) error { + m := map[string]interface{}(mv) + return remove(m, path) +} + +func remove(m interface{}, path string) error { + val, err := prevValueByPath(m, path) + if err != nil { + return err + } + + lastKey := lastKey(path) + delete(val, lastKey) + + return nil +} + +// returns the last key of the path. +// lastKey("a.b.c") would had returned "c" +func lastKey(path string) string { + keys := strings.Split(path, ".") + key := keys[len(keys)-1] + return key +} + +// returns the path without the last key +// parentPath("a.b.c") whould had returned "a.b" +func parentPath(path string) string { + keys := strings.Split(path, ".") + parentPath := strings.Join(keys[0:len(keys)-1], ".") + return parentPath +} diff --git a/vendor/github.com/clbanning/mxj/rename.go b/vendor/github.com/clbanning/mxj/rename.go new file mode 100644 index 00000000000..e95a9639af7 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/rename.go @@ -0,0 +1,54 @@ +package mxj + +import ( + "errors" + "strings" +) + +// RenameKey renames a key in a Map. +// It works only for nested maps. It doesn't work for cases when it buried in a list. +func (mv Map) RenameKey(path string, newName string) error { + if !mv.Exists(path) { + return errors.New("RenameKey: path not found: " + path) + } + if mv.Exists(parentPath(path) + "." + newName) { + return errors.New("RenameKey: key already exists: " + newName) + } + + m := map[string]interface{}(mv) + return renameKey(m, path, newName) +} + +func renameKey(m interface{}, path string, newName string) error { + val, err := prevValueByPath(m, path) + if err != nil { + return err + } + + oldName := lastKey(path) + val[newName] = val[oldName] + delete(val, oldName) + + return nil +} + +// returns a value which contains a last key in the path +// For example: prevValueByPath("a.b.c", {a{b{c: 3}}}) returns {c: 3} +func prevValueByPath(m interface{}, path string) (map[string]interface{}, error) { + keys := strings.Split(path, ".") + + switch mValue := m.(type) { + case map[string]interface{}: + for key, value := range mValue { + if key == keys[0] { + if len(keys) == 1 { + return mValue, nil + } else { + // keep looking for the full path to the key + return prevValueByPath(value, strings.Join(keys[1:], ".")) + } + } + } + } + return nil, errors.New("prevValueByPath: didn't find path – " + path) +} diff --git a/vendor/github.com/clbanning/mxj/set.go b/vendor/github.com/clbanning/mxj/set.go new file mode 100644 index 00000000000..a297fc38887 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/set.go @@ -0,0 +1,26 @@ +package mxj + +import ( + "strings" +) + +// Sets the value for the path +func (mv Map) SetValueForPath(value interface{}, path string) error { + pathAry := strings.Split(path, ".") + parentPathAry := pathAry[0 : len(pathAry)-1] + parentPath := strings.Join(parentPathAry, ".") + + val, err := mv.ValueForPath(parentPath) + if err != nil { + return err + } + if val == nil { + return nil // we just ignore the request if there's no val + } + + key := pathAry[len(pathAry)-1] + cVal := val.(map[string]interface{}) + cVal[key] = value + + return nil +} diff --git a/vendor/github.com/clbanning/mxj/setfieldsep.go b/vendor/github.com/clbanning/mxj/setfieldsep.go new file mode 100644 index 00000000000..b70715ebc65 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/setfieldsep.go @@ -0,0 +1,20 @@ +package mxj + +// Per: https://github.com/clbanning/mxj/issues/37#issuecomment-278651862 +var fieldSep string = ":" + +// SetFieldSeparator changes the default field separator, ":", for the +// newVal argument in mv.UpdateValuesForPath and the optional 'subkey' arguments +// in mv.ValuesForKey and mv.ValuesForPath. +// +// E.g., if the newVal value is "http://blah/blah", setting the field separator +// to "|" will allow the newVal specification, "|http://blah/blah" to parse +// properly. If called with no argument or an empty string value, the field +// separator is set to the default, ":". +func SetFieldSeparator(s ...string) { + if len(s) == 0 || s[0] == "" { + fieldSep = ":" // the default + return + } + fieldSep = s[0] +} diff --git a/vendor/github.com/clbanning/mxj/songtext.xml b/vendor/github.com/clbanning/mxj/songtext.xml new file mode 100644 index 00000000000..8c0f2becb12 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/songtext.xml @@ -0,0 +1,29 @@ + + help me! + + + + Henry was a renegade + Didn't like to play it safe + One component at a time + There's got to be a better way + Oh, people came from miles around + Searching for a steady job + Welcome to the Motor Town + Booming like an atom bomb + + + Oh, Henry was the end of the story + Then everything went wrong + And we'll return it to its former glory + But it just takes so long + + + + It's going to take a long time + It's going to take it, but we'll make it one day + It's going to take a long time + It's going to take it, but we'll make it one day + + + diff --git a/vendor/github.com/clbanning/mxj/strict.go b/vendor/github.com/clbanning/mxj/strict.go new file mode 100644 index 00000000000..1e769560ba0 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/strict.go @@ -0,0 +1,30 @@ +// Copyright 2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// strict.go actually addresses setting xml.Decoder attribute +// values. This'll let you parse non-standard XML. + +package mxj + +import ( + "encoding/xml" +) + +// CustomDecoder can be used to specify xml.Decoder attribute +// values, e.g., Strict:false, to be used. By default CustomDecoder +// is nil. If CustomeDecoder != nil, then mxj.XmlCharsetReader variable is +// ignored and must be set as part of the CustomDecoder value, if needed. +// Usage: +// mxj.CustomDecoder = &xml.Decoder{Strict:false} +var CustomDecoder *xml.Decoder + +// useCustomDecoder copy over public attributes from customDecoder +func useCustomDecoder(d *xml.Decoder) { + d.Strict = CustomDecoder.Strict + d.AutoClose = CustomDecoder.AutoClose + d.Entity = CustomDecoder.Entity + d.CharsetReader = CustomDecoder.CharsetReader + d.DefaultSpace = CustomDecoder.DefaultSpace +} + diff --git a/vendor/github.com/clbanning/mxj/struct.go b/vendor/github.com/clbanning/mxj/struct.go new file mode 100644 index 00000000000..9be636cdcab --- /dev/null +++ b/vendor/github.com/clbanning/mxj/struct.go @@ -0,0 +1,54 @@ +// Copyright 2012-2017 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package mxj + +import ( + "encoding/json" + "errors" + "reflect" + + // "github.com/fatih/structs" +) + +// Create a new Map value from a structure. Error returned if argument is not a structure. +// Only public structure fields are decoded in the Map value. See github.com/fatih/structs#Map +// for handling of "structs" tags. + +// DEPRECATED - import github.com/fatih/structs and cast result of structs.Map to mxj.Map. +// import "github.com/fatih/structs" +// ... +// sm, err := structs.Map() +// if err != nil { +// // handle error +// } +// m := mxj.Map(sm) +// Alernatively uncomment the old source and import in struct.go. +func NewMapStruct(structVal interface{}) (Map, error) { + return nil, errors.New("deprecated - see package documentation") + /* + if !structs.IsStruct(structVal) { + return nil, errors.New("NewMapStruct() error: argument is not type Struct") + } + return structs.Map(structVal), nil + */ +} + +// Marshal a map[string]interface{} into a structure referenced by 'structPtr'. Error returned +// if argument is not a pointer or if json.Unmarshal returns an error. +// json.Unmarshal structure encoding rules are followed to encode public structure fields. +func (mv Map) Struct(structPtr interface{}) error { + // should check that we're getting a pointer. + if reflect.ValueOf(structPtr).Kind() != reflect.Ptr { + return errors.New("mv.Struct() error: argument is not type Ptr") + } + + m := map[string]interface{}(mv) + j, err := json.Marshal(m) + if err != nil { + return err + } + + return json.Unmarshal(j, structPtr) +} diff --git a/vendor/github.com/clbanning/mxj/updatevalues.go b/vendor/github.com/clbanning/mxj/updatevalues.go new file mode 100644 index 00000000000..46779f4f063 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/updatevalues.go @@ -0,0 +1,256 @@ +// Copyright 2012-2014, 2017 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// updatevalues.go - modify a value based on path and possibly sub-keys +// TODO(clb): handle simple elements with attributes and NewMapXmlSeq Map values. + +package mxj + +import ( + "fmt" + "strconv" + "strings" +) + +// Update value based on path and possible sub-key values. +// A count of the number of values changed and any error are returned. +// If the count == 0, then no path (and subkeys) matched. +// 'newVal' can be a Map or map[string]interface{} value with a single 'key' that is the key to be modified +// or a string value "key:value[:type]" where type is "bool" or "num" to cast the value. +// 'path' is dot-notation list of keys to traverse; last key in path can be newVal key +// NOTE: 'path' spec does not currently support indexed array references. +// 'subkeys' are "key:value[:type]" entries that must match for path node +// The subkey can be wildcarded - "key:*" - to require that it's there with some value. +// If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an +// exclusion critera - e.g., "!author:William T. Gaddis". +// +// NOTES: +// 1. Simple elements with attributes need a path terminated as ".#text" to modify the actual value. +// 2. Values in Maps created using NewMapXmlSeq are map[string]interface{} values with a "#text" key. +// 3. If values in 'newVal' or 'subkeys' args contain ":", use SetFieldSeparator to an unused symbol, +// perhaps "|". +func (mv Map) UpdateValuesForPath(newVal interface{}, path string, subkeys ...string) (int, error) { + m := map[string]interface{}(mv) + + // extract the subkeys + var subKeyMap map[string]interface{} + if len(subkeys) > 0 { + var err error + subKeyMap, err = getSubKeyMap(subkeys...) + if err != nil { + return 0, err + } + } + + // extract key and value from newVal + var key string + var val interface{} + switch newVal.(type) { + case map[string]interface{}, Map: + switch newVal.(type) { // "fallthrough is not permitted in type switch" (Spec) + case Map: + newVal = newVal.(Map).Old() + } + if len(newVal.(map[string]interface{})) != 1 { + return 0, fmt.Errorf("newVal map can only have len == 1 - %+v", newVal) + } + for key, val = range newVal.(map[string]interface{}) { + } + case string: // split it as a key:value pair + ss := strings.Split(newVal.(string), fieldSep) + n := len(ss) + if n < 2 || n > 3 { + return 0, fmt.Errorf("unknown newVal spec - %+v", newVal) + } + key = ss[0] + if n == 2 { + val = interface{}(ss[1]) + } else if n == 3 { + switch ss[2] { + case "bool", "boolean": + nv, err := strconv.ParseBool(ss[1]) + if err != nil { + return 0, fmt.Errorf("can't convert newVal to bool - %+v", newVal) + } + val = interface{}(nv) + case "num", "numeric", "float", "int": + nv, err := strconv.ParseFloat(ss[1], 64) + if err != nil { + return 0, fmt.Errorf("can't convert newVal to float64 - %+v", newVal) + } + val = interface{}(nv) + default: + return 0, fmt.Errorf("unknown type for newVal value - %+v", newVal) + } + } + default: + return 0, fmt.Errorf("invalid newVal type - %+v", newVal) + } + + // parse path + keys := strings.Split(path, ".") + + var count int + updateValuesForKeyPath(key, val, m, keys, subKeyMap, &count) + + return count, nil +} + +// navigate the path +func updateValuesForKeyPath(key string, value interface{}, m interface{}, keys []string, subkeys map[string]interface{}, cnt *int) { + // ----- at end node: looking at possible node to get 'key' ---- + if len(keys) == 1 { + updateValue(key, value, m, keys[0], subkeys, cnt) + return + } + + // ----- here we are navigating the path thru the penultimate node -------- + // key of interest is keys[0] - the next in the path + switch keys[0] { + case "*": // wildcard - scan all values + switch m.(type) { + case map[string]interface{}: + for _, v := range m.(map[string]interface{}) { + updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) + } + case []interface{}: + for _, v := range m.([]interface{}) { + switch v.(type) { + // flatten out a list of maps - keys are processed + case map[string]interface{}: + for _, vv := range v.(map[string]interface{}) { + updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt) + } + default: + updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) + } + } + } + default: // key - must be map[string]interface{} + switch m.(type) { + case map[string]interface{}: + if v, ok := m.(map[string]interface{})[keys[0]]; ok { + updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) + } + case []interface{}: // may be buried in list + for _, v := range m.([]interface{}) { + switch v.(type) { + case map[string]interface{}: + if vv, ok := v.(map[string]interface{})[keys[0]]; ok { + updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt) + } + } + } + } + } +} + +// change value if key and subkeys are present +func updateValue(key string, value interface{}, m interface{}, keys0 string, subkeys map[string]interface{}, cnt *int) { + // there are two possible options for the value of 'keys0': map[string]interface, []interface{} + // and 'key' is a key in the map or is a key in a map in a list. + switch m.(type) { + case map[string]interface{}: // gotta have the last key + if keys0 == "*" { + for k := range m.(map[string]interface{}) { + updateValue(key, value, m, k, subkeys, cnt) + } + return + } + endVal, _ := m.(map[string]interface{})[keys0] + + // if newV key is the end of path, replace the value for path-end + // may be []interface{} - means replace just an entry w/ subkeys + // otherwise replace the keys0 value if subkeys are there + // NOTE: this will replace the subkeys, also + if key == keys0 { + switch endVal.(type) { + case map[string]interface{}: + if hasSubKeys(m, subkeys) { + (m.(map[string]interface{}))[keys0] = value + (*cnt)++ + } + case []interface{}: + // without subkeys can't select list member to modify + // so key:value spec is it ... + if hasSubKeys(m, subkeys) { + (m.(map[string]interface{}))[keys0] = value + (*cnt)++ + break + } + nv := make([]interface{}, 0) + var valmodified bool + for _, v := range endVal.([]interface{}) { + // check entry subkeys + if hasSubKeys(v, subkeys) { + // replace v with value + nv = append(nv, value) + valmodified = true + (*cnt)++ + continue + } + nv = append(nv, v) + } + if valmodified { + (m.(map[string]interface{}))[keys0] = interface{}(nv) + } + default: // anything else is a strict replacement + if hasSubKeys(m, subkeys) { + (m.(map[string]interface{}))[keys0] = value + (*cnt)++ + } + } + return + } + + // so value is for an element of endVal + // if endVal is a map then 'key' must be there w/ subkeys + // if endVal is a list then 'key' must be in a list member w/ subkeys + switch endVal.(type) { + case map[string]interface{}: + if !hasSubKeys(endVal, subkeys) { + return + } + if _, ok := (endVal.(map[string]interface{}))[key]; ok { + (endVal.(map[string]interface{}))[key] = value + (*cnt)++ + } + case []interface{}: // keys0 points to a list, check subkeys + for _, v := range endVal.([]interface{}) { + // got to be a map so we can replace value for 'key' + vv, vok := v.(map[string]interface{}) + if !vok { + continue + } + if _, ok := vv[key]; !ok { + continue + } + if !hasSubKeys(vv, subkeys) { + continue + } + vv[key] = value + (*cnt)++ + } + } + case []interface{}: // key may be in a list member + // don't need to handle keys0 == "*"; we're looking at everything, anyway. + for _, v := range m.([]interface{}) { + // only map values - we're looking for 'key' + mm, ok := v.(map[string]interface{}) + if !ok { + continue + } + if _, ok := mm[key]; !ok { + continue + } + if !hasSubKeys(mm, subkeys) { + continue + } + mm[key] = value + (*cnt)++ + } + } + + // return +} diff --git a/vendor/github.com/clbanning/mxj/xml.go b/vendor/github.com/clbanning/mxj/xml.go new file mode 100644 index 00000000000..fac0f1d3bb5 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/xml.go @@ -0,0 +1,1139 @@ +// Copyright 2012-2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// xml.go - basically the core of X2j for map[string]interface{} values. +// NewMapXml, NewMapXmlReader, mv.Xml, mv.XmlWriter +// see x2j and j2x for wrappers to provide end-to-end transformation of XML and JSON messages. + +package mxj + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "reflect" + "sort" + "strconv" + "strings" + "time" +) + +// ------------------- NewMapXml & NewMapXmlReader ... ------------------------- + +// If XmlCharsetReader != nil, it will be used to decode the XML, if required. +// Note: if CustomDecoder != nil, then XmlCharsetReader is ignored; +// set the CustomDecoder attribute instead. +// import ( +// charset "code.google.com/p/go-charset/charset" +// github.com/clbanning/mxj +// ) +// ... +// mxj.XmlCharsetReader = charset.NewReader +// m, merr := mxj.NewMapXml(xmlValue) +var XmlCharsetReader func(charset string, input io.Reader) (io.Reader, error) + +// NewMapXml - convert a XML doc into a Map +// (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().) +// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible. +// +// Converting XML to JSON is a simple as: +// ... +// mapVal, merr := mxj.NewMapXml(xmlVal) +// if merr != nil { +// // handle error +// } +// jsonVal, jerr := mapVal.Json() +// if jerr != nil { +// // handle error +// } +// +// NOTES: +// 1. The 'xmlVal' will be parsed looking for an xml.StartElement, so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 2. If CoerceKeysToLower() has been called, then all key values will be lower case. +// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +func NewMapXml(xmlVal []byte, cast ...bool) (Map, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + return xmlToMap(xmlVal, r) +} + +// Get next XML doc from an io.Reader as a Map value. Returns Map value. +// NOTES: +// 1. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 2. If CoerceKeysToLower() has been called, then all key values will be lower case. +// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +func NewMapXmlReader(xmlReader io.Reader, cast ...bool) (Map, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + + // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder + // will wrap it in a bufio.Reader and seek on the file beyond where the + // xml.Decoder parses! + if _, ok := xmlReader.(io.ByteReader); !ok { + xmlReader = myByteReader(xmlReader) // see code at EOF + } + + // build the map + return xmlReaderToMap(xmlReader, r) +} + +// Get next XML doc from an io.Reader as a Map value. Returns Map value and slice with the raw XML. +// NOTES: +// 1. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte +// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact. +// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large +// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body +// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call. +// 2. The 'raw' return value may be larger than the XML text value. +// 3. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 4. If CoerceKeysToLower() has been called, then all key values will be lower case. +// 5. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +func NewMapXmlReaderRaw(xmlReader io.Reader, cast ...bool) (Map, []byte, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + // create TeeReader so we can retrieve raw XML + buf := make([]byte, 0) + wb := bytes.NewBuffer(buf) + trdr := myTeeReader(xmlReader, wb) // see code at EOF + + m, err := xmlReaderToMap(trdr, r) + + // retrieve the raw XML that was decoded + b := wb.Bytes() + + if err != nil { + return nil, b, err + } + + return m, b, nil +} + +// xmlReaderToMap() - parse a XML io.Reader to a map[string]interface{} value +func xmlReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) { + // parse the Reader + p := xml.NewDecoder(rdr) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlToMapParser("", nil, p, r) +} + +// xmlToMap - convert a XML doc into map[string]interface{} value +func xmlToMap(doc []byte, r bool) (map[string]interface{}, error) { + b := bytes.NewReader(doc) + p := xml.NewDecoder(b) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlToMapParser("", nil, p, r) +} + +// ===================================== where the work happens ============================= + +// PrependAttrWithHyphen. Prepend attribute tags with a hyphen. +// Default is 'true'. (Not applicable to NewMapXmlSeq(), mv.XmlSeq(), etc.) +// Note: +// If 'false', unmarshaling and marshaling is not symmetric. Attributes will be +// marshal'd as attr and may be part of a list. +func PrependAttrWithHyphen(v bool) { + if v { + attrPrefix = "-" + lenAttrPrefix = len(attrPrefix) + return + } + attrPrefix = "" + lenAttrPrefix = len(attrPrefix) +} + +// Include sequence id with inner tags. - per Sean Murphy, murphysean84@gmail.com. +var includeTagSeqNum bool + +// IncludeTagSeqNum - include a "_seq":N key:value pair with each inner tag, denoting +// its position when parsed. This is of limited usefulness, since list values cannot +// be tagged with "_seq" without changing their depth in the Map. +// So THIS SHOULD BE USED WITH CAUTION - see the test cases. Here's a sample of what +// you get. +/* + + + + + hello + + + parses as: + + { + Obj:{ + "-c":"la", + "-h":"da", + "-x":"dee", + "intObj":[ + { + "-id"="3", + "_seq":"0" // if mxj.Cast is passed, then: "_seq":0 + }, + { + "-id"="2", + "_seq":"2" + }], + "intObj1":{ + "-id":"1", + "_seq":"1" + }, + "StrObj":{ + "#text":"hello", // simple element value gets "#text" tag + "_seq":"3" + } + } + } +*/ +func IncludeTagSeqNum(b bool) { + includeTagSeqNum = b +} + +// all keys will be "lower case" +var lowerCase bool + +// Coerce all tag values to keys in lower case. This is useful if you've got sources with variable +// tag capitalization, and you want to use m.ValuesForKeys(), etc., with the key or path spec +// in lower case. +// CoerceKeysToLower() will toggle the coercion flag true|false - on|off +// CoerceKeysToLower(true|false) will set the coercion flag on|off +// +// NOTE: only recognized by NewMapXml, NewMapXmlReader, and NewMapXmlReaderRaw functions as well as +// the associated HandleXmlReader and HandleXmlReaderRaw. +func CoerceKeysToLower(b ...bool) { + if len(b) == 0 { + lowerCase = !lowerCase + } else if len(b) == 1 { + lowerCase = b[0] + } +} + +// 25jun16: Allow user to specify the "prefix" character for XML attribute key labels. +// We do this by replacing '`' constant with attrPrefix var, replacing useHyphen with attrPrefix = "", +// and adding a SetAttrPrefix(s string) function. + +var attrPrefix string = `-` // the default +var lenAttrPrefix int = 1 // the default + +// SetAttrPrefix changes the default, "-", to the specified value, s. +// SetAttrPrefix("") is the same as PrependAttrWithHyphen(false). +// (Not applicable for NewMapXmlSeq(), mv.XmlSeq(), etc.) +func SetAttrPrefix(s string) { + attrPrefix = s + lenAttrPrefix = len(attrPrefix) +} + +// 18jan17: Allows user to specify if the map keys should be in snake case instead +// of the default hyphenated notation. +var snakeCaseKeys bool + +// CoerceKeysToSnakeCase changes the default, false, to the specified value, b. +// Note: the attribute prefix will be a hyphen, '-', or what ever string value has +// been specified using SetAttrPrefix. +func CoerceKeysToSnakeCase(b ...bool) { + if len(b) == 0 { + snakeCaseKeys = !snakeCaseKeys + } else if len(b) == 1 { + snakeCaseKeys = b[0] + } +} + +// 05feb17: support processing XMPP streams (issue #36) +var handleXMPPStreamTag bool + +// HandleXMPPStreamTag causes decoder to parse XMPP elements. +// If called with no argument, XMPP stream element handling is toggled on/off. +// (See xmppStream_test.go for example.) +// If called with NewMapXml, NewMapXmlReader, New MapXmlReaderRaw the "stream" +// element will be returned as: +// map["stream"]interface{}{map[-]interface{}}. +// If called with NewMapSeq, NewMapSeqReader, NewMapSeqReaderRaw the "stream" +// element will be returned as: +// map["stream:stream"]interface{}{map["#attr"]interface{}{map[string]interface{}}} +// where the "#attr" values have "#text" and "#seq" keys. (See NewMapXmlSeq.) +func HandleXMPPStreamTag(b ...bool) { + if len(b) == 0 { + handleXMPPStreamTag = !handleXMPPStreamTag + } else if len(b) == 1 { + handleXMPPStreamTag = b[0] + } +} + +// 21jan18 - decode all values as map["#text":value] (issue #56) +var decodeSimpleValuesAsMap bool + +// DecodeSimpleValuesAsMap forces all values to be decoded as map["#text":]. +// If called with no argument, the decoding is toggled on/off. +// +// By default the NewMapXml functions decode simple values without attributes as +// map[:]. This function causes simple values without attributes to be +// decoded the same as simple values with attributes - map[:map["#text":]]. +func DecodeSimpleValuesAsMap(b ...bool) { + if len(b) == 0 { + decodeSimpleValuesAsMap = !decodeSimpleValuesAsMap + } else if len(b) == 1 { + decodeSimpleValuesAsMap = b[0] + } +} + +// xmlToMapParser (2015.11.12) - load a 'clean' XML doc into a map[string]interface{} directly. +// A refactoring of xmlToTreeParser(), markDuplicate() and treeToMap() - here, all-in-one. +// We've removed the intermediate *node tree with the allocation and subsequent rescanning. +func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) { + if lowerCase { + skey = strings.ToLower(skey) + } + if snakeCaseKeys { + skey = strings.Replace(skey, "-", "_", -1) + } + + // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'. + // Unless 'skey' is a simple element w/o attributes, in which case the xml.CharData value is the value. + var n, na map[string]interface{} + var seq int // for includeTagSeqNum + + // Allocate maps and load attributes, if any. + // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through + // to get StartElement then recurse with skey==xml.StartElement.Name.Local + // where we begin allocating map[string]interface{} values 'n' and 'na'. + if skey != "" { + n = make(map[string]interface{}) // old n + na = make(map[string]interface{}) // old n.nodes + if len(a) > 0 { + for _, v := range a { + if snakeCaseKeys { + v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1) + } + var key string + key = attrPrefix + v.Name.Local + if lowerCase { + key = strings.ToLower(key) + } + na[key] = cast(v.Value, r) + } + } + } + // Return XMPP message. + if handleXMPPStreamTag && skey == "stream" { + n[skey] = na + return n, nil + } + + for { + t, err := p.Token() + if err != nil { + if err != io.EOF { + return nil, errors.New("xml.Decoder.Token() - " + err.Error()) + } + return nil, err + } + switch t.(type) { + case xml.StartElement: + tt := t.(xml.StartElement) + + // First call to xmlToMapParser() doesn't pass xml.StartElement - the map key. + // So when the loop is first entered, the first token is the root tag along + // with any attributes, which we process here. + // + // Subsequent calls to xmlToMapParser() will pass in tag+attributes for + // processing before getting the next token which is the element value, + // which is done above. + if skey == "" { + return xmlToMapParser(tt.Name.Local, tt.Attr, p, r) + } + + // If not initializing the map, parse the element. + // len(nn) == 1, necessarily - it is just an 'n'. + nn, err := xmlToMapParser(tt.Name.Local, tt.Attr, p, r) + if err != nil { + return nil, err + } + + // The nn map[string]interface{} value is a na[nn_key] value. + // We need to see if nn_key already exists - means we're parsing a list. + // This may require converting na[nn_key] value into []interface{} type. + // First, extract the key:val for the map - it's a singleton. + // Note: + // * if CoerceKeysToLower() called, then key will be lower case. + // * if CoerceKeysToSnakeCase() called, then key will be converted to snake case. + var key string + var val interface{} + for key, val = range nn { + break + } + + // IncludeTagSeqNum requests that the element be augmented with a "_seq" sub-element. + // In theory, we don't need this if len(na) == 1. But, we don't know what might + // come next - we're only parsing forward. So if you ask for 'includeTagSeqNum' you + // get it on every element. (Personally, I never liked this, but I added it on request + // and did get a $50 Amazon gift card in return - now we support it for backwards compatibility!) + if includeTagSeqNum { + switch val.(type) { + case []interface{}: + // noop - There's no clean way to handle this w/o changing message structure. + case map[string]interface{}: + val.(map[string]interface{})["_seq"] = seq // will overwrite an "_seq" XML tag + seq++ + case interface{}: // a non-nil simple element: string, float64, bool + v := map[string]interface{}{"#text": val} + v["_seq"] = seq + seq++ + val = v + } + } + + // 'na' holding sub-elements of n. + // See if 'key' already exists. + // If 'key' exists, then this is a list, if not just add key:val to na. + if v, ok := na[key]; ok { + var a []interface{} + switch v.(type) { + case []interface{}: + a = v.([]interface{}) + default: // anything else - note: v.(type) != nil + a = []interface{}{v} + } + a = append(a, val) + na[key] = a + } else { + na[key] = val // save it as a singleton + } + case xml.EndElement: + // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case. + if len(n) == 0 { + // If len(na)==0 we have an empty element == ""; + // it has no xml.Attr nor xml.CharData. + // Note: in original node-tree parser, val defaulted to ""; + // so we always had the default if len(node.nodes) == 0. + if len(na) > 0 { + n[skey] = na + } else { + n[skey] = "" // empty element + } + } + return n, nil + case xml.CharData: + // clean up possible noise + tt := strings.Trim(string(t.(xml.CharData)), "\t\r\b\n ") + if len(tt) > 0 { + if len(na) > 0 || decodeSimpleValuesAsMap { + na["#text"] = cast(tt, r) + } else if skey != "" { + n[skey] = cast(tt, r) + } else { + // per Adrian (http://www.adrianlungu.com/) catch stray text + // in decoder stream - + // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374 + // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get + // a p.Token() decoding error when the BOM is UTF-16 or UTF-32. + continue + } + } + default: + // noop + } + } +} + +var castNanInf bool + +// Cast "Nan", "Inf", "-Inf" XML values to 'float64'. +// By default, these values will be decoded as 'string'. +func CastNanInf(b bool) { + castNanInf = b +} + +// cast - try to cast string values to bool or float64 +func cast(s string, r bool) interface{} { + if r { + // handle nan and inf + if !castNanInf { + switch strings.ToLower(s) { + case "nan", "inf", "-inf": + return s + } + } + + // handle numeric strings ahead of boolean + if f, err := strconv.ParseFloat(s, 64); err == nil { + return f + } + // ParseBool treats "1"==true & "0"==false, we've already scanned those + // values as float64. See if value has 't' or 'f' as initial screen to + // minimize calls to ParseBool; also, see if len(s) < 6. + if len(s) > 0 && len(s) < 6 { + switch s[:1] { + case "t", "T", "f", "F": + if b, err := strconv.ParseBool(s); err == nil { + return b + } + } + } + } + return s +} + +// ------------------ END: NewMapXml & NewMapXmlReader ------------------------- + +// ------------------ mv.Xml & mv.XmlWriter - from j2x ------------------------ + +const ( + DefaultRootTag = "doc" +) + +var useGoXmlEmptyElemSyntax bool + +// XmlGoEmptyElemSyntax() - rather than . +// Go's encoding/xml package marshals empty XML elements as . By default this package +// encodes empty elements as . If you're marshaling Map values that include structures +// (which are passed to xml.Marshal for encoding), this will let you conform to the standard package. +func XmlGoEmptyElemSyntax() { + useGoXmlEmptyElemSyntax = true +} + +// XmlDefaultEmptyElemSyntax() - rather than . +// Return XML encoding for empty elements to the default package setting. +// Reverses effect of XmlGoEmptyElemSyntax(). +func XmlDefaultEmptyElemSyntax() { + useGoXmlEmptyElemSyntax = false +} + +// Encode a Map as XML. The companion of NewMapXml(). +// The following rules apply. +// - The key label "#text" is treated as the value for a simple element with attributes. +// - Map keys that begin with a hyphen, '-', are interpreted as attributes. +// It is an error if the attribute doesn't have a []byte, string, number, or boolean value. +// - Map value type encoding: +// > string, bool, float64, int, int32, int64, float32: per "%v" formating +// > []bool, []uint8: by casting to string +// > structures, etc.: handed to xml.Marshal() - if there is an error, the element +// value is "UNKNOWN" +// - Elements with only attribute values or are null are terminated using "/>". +// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible. +// Thus, `{ "key":"value" }` encodes as "value". +// - To encode empty elements in a syntax consistent with encoding/xml call UseGoXmlEmptyElementSyntax(). +// The attributes tag=value pairs are alphabetized by "tag". Also, when encoding map[string]interface{} values - +// complex elements, etc. - the key:value pairs are alphabetized by key so the resulting tags will appear sorted. +func (mv Map) Xml(rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + var err error + s := new(string) + p := new(pretty) // just a stub + + if len(m) == 1 && len(rootTag) == 0 { + for key, value := range m { + // if it an array, see if all values are map[string]interface{} + // we force a new root tag if we'll end up with no key:value in the list + // so: key:[string_val, bool:true] --> string_valtrue + switch value.(type) { + case []interface{}: + for _, v := range value.([]interface{}) { + switch v.(type) { + case map[string]interface{}: // noop + default: // anything else + err = mapToXmlIndent(false, s, DefaultRootTag, m, p) + goto done + } + } + } + err = mapToXmlIndent(false, s, key, value, p) + } + } else if len(rootTag) == 1 { + err = mapToXmlIndent(false, s, rootTag[0], m, p) + } else { + err = mapToXmlIndent(false, s, DefaultRootTag, m, p) + } +done: + return []byte(*s), err +} + +// The following implementation is provided only for symmetry with NewMapXmlReader[Raw] +// The names will also provide a key for the number of return arguments. + +// Writes the Map as XML on the Writer. +// See Xml() for encoding rules. +func (mv Map) XmlWriter(xmlWriter io.Writer, rootTag ...string) error { + x, err := mv.Xml(rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// Writes the Map as XML on the Writer. []byte is the raw XML that was written. +// See Xml() for encoding rules. +func (mv Map) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) { + x, err := mv.Xml(rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} + +// Writes the Map as pretty XML on the Writer. +// See Xml() for encoding rules. +func (mv Map) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error { + x, err := mv.XmlIndent(prefix, indent, rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// Writes the Map as pretty XML on the Writer. []byte is the raw XML that was written. +// See Xml() for encoding rules. +func (mv Map) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) { + x, err := mv.XmlIndent(prefix, indent, rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} + +// -------------------- END: mv.Xml & mv.XmlWriter ------------------------------- + +// -------------- Handle XML stream by processing Map value -------------------- + +// Default poll delay to keep Handler from spinning on an open stream +// like sitting on os.Stdin waiting for imput. +var xhandlerPollInterval = time.Millisecond + +// Bulk process XML using handlers that process a Map value. +// 'rdr' is an io.Reader for XML (stream) +// 'mapHandler' is the Map processor. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'. +func HandleXmlReader(xmlReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error { + var n int + for { + m, merr := NewMapXmlReader(xmlReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m); !ok { + break + } + } else if merr != io.EOF { + time.Sleep(xhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} + +// Bulk process XML using handlers that process a Map value and the raw XML. +// 'rdr' is an io.Reader for XML (stream) +// 'mapHandler' is the Map and raw XML - []byte - processor. Return of 'false' stops io.Reader processing. +// 'errHandler' is the error and raw XML processor. Return of 'false' stops io.Reader processing and returns the error. +// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. +// This means that you can stop reading the file on error or after processing a particular message. +// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'. +// See NewMapXmlReaderRaw for comment on performance associated with retrieving raw XML from a Reader. +func HandleXmlReaderRaw(xmlReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error { + var n int + for { + m, raw, merr := NewMapXmlReaderRaw(xmlReader) + n++ + + // handle error condition with errhandler + if merr != nil && merr != io.EOF { + merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error()) + if ok := errHandler(merr, raw); !ok { + // caused reader termination + return merr + } + continue + } + + // pass to maphandler + if len(m) != 0 { + if ok := mapHandler(m, raw); !ok { + break + } + } else if merr != io.EOF { + time.Sleep(xhandlerPollInterval) + } + + if merr == io.EOF { + break + } + } + return nil +} + +// ----------------- END: Handle XML stream by processing Map value -------------- + +// -------- a hack of io.TeeReader ... need one that's an io.ByteReader for xml.NewDecoder() ---------- + +// This is a clone of io.TeeReader with the additional method t.ReadByte(). +// Thus, this TeeReader is also an io.ByteReader. +// This is necessary because xml.NewDecoder uses a ByteReader not a Reader. It appears to have been written +// with bufio.Reader or bytes.Reader in mind ... not a generic io.Reader, which doesn't have to have ReadByte().. +// If NewDecoder is passed a Reader that does not satisfy ByteReader() it wraps the Reader with +// bufio.NewReader and uses ReadByte rather than Read that runs the TeeReader pipe logic. + +type teeReader struct { + r io.Reader + w io.Writer + b []byte +} + +func myTeeReader(r io.Reader, w io.Writer) io.Reader { + b := make([]byte, 1) + return &teeReader{r, w, b} +} + +// need for io.Reader - but we don't use it ... +func (t *teeReader) Read(p []byte) (int, error) { + return 0, nil +} + +func (t *teeReader) ReadByte() (byte, error) { + n, err := t.r.Read(t.b) + if n > 0 { + if _, err := t.w.Write(t.b[:1]); err != nil { + return t.b[0], err + } + } + return t.b[0], err +} + +// For use with NewMapXmlReader & NewMapXmlSeqReader. +type byteReader struct { + r io.Reader + b []byte +} + +func myByteReader(r io.Reader) io.Reader { + b := make([]byte, 1) + return &byteReader{r, b} +} + +// Need for io.Reader interface ... +// Needed if reading a malformed http.Request.Body - issue #38. +func (b *byteReader) Read(p []byte) (int, error) { + return b.r.Read(p) +} + +func (b *byteReader) ReadByte() (byte, error) { + _, err := b.r.Read(b.b) + if len(b.b) > 0 { + return b.b[0], err + } + var c byte + return c, err +} + +// ----------------------- END: io.TeeReader hack ----------------------------------- + +// ---------------------- XmlIndent - from j2x package ---------------------------- + +// Encode a map[string]interface{} as a pretty XML string. +// See Xml for encoding rules. +func (mv Map) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + + var err error + s := new(string) + p := new(pretty) + p.indent = indent + p.padding = prefix + + if len(m) == 1 && len(rootTag) == 0 { + // this can extract the key for the single map element + // use it if it isn't a key for a list + for key, value := range m { + if _, ok := value.([]interface{}); ok { + err = mapToXmlIndent(true, s, DefaultRootTag, m, p) + } else { + err = mapToXmlIndent(true, s, key, value, p) + } + } + } else if len(rootTag) == 1 { + err = mapToXmlIndent(true, s, rootTag[0], m, p) + } else { + err = mapToXmlIndent(true, s, DefaultRootTag, m, p) + } + return []byte(*s), err +} + +type pretty struct { + indent string + cnt int + padding string + mapDepth int + start int +} + +func (p *pretty) Indent() { + p.padding += p.indent + p.cnt++ +} + +func (p *pretty) Outdent() { + if p.cnt > 0 { + p.padding = p.padding[:len(p.padding)-len(p.indent)] + p.cnt-- + } +} + +// where the work actually happens +// returns an error if an attribute is not atomic +func mapToXmlIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error { + var endTag bool + var isSimple bool + var elen int + p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start} + + // per issue #48, 18apr18 - try and coerce maps to map[string]interface{} + // Don't need for mapToXmlSeqIndent, since maps there are decoded by NewMapXmlSeq(). + if reflect.ValueOf(value).Kind() == reflect.Map { + switch value.(type) { + case map[string]interface{}: + default: + val := make(map[string]interface{}) + vv := reflect.ValueOf(value) + keys := vv.MapKeys() + for _, k := range keys { + val[fmt.Sprint(k)] = vv.MapIndex(k).Interface() + } + value = val + } + } + + switch value.(type) { + // special handling of []interface{} values when len(value) == 0 + case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32, json.Number: + if doIndent { + *s += p.padding + } + *s += `<` + key + } + switch value.(type) { + case map[string]interface{}: + vv := value.(map[string]interface{}) + lenvv := len(vv) + // scan out attributes - attribute keys have prepended attrPrefix + attrlist := make([][2]string, len(vv)) + var n int + var ss string + for k, v := range vv { + if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix { + switch v.(type) { + case string: + if xmlEscapeChars { + ss = escapeChars(v.(string)) + } else { + ss = v.(string) + } + attrlist[n][0] = k[lenAttrPrefix:] + attrlist[n][1] = ss + case float64, bool, int, int32, int64, float32, json.Number: + attrlist[n][0] = k[lenAttrPrefix:] + attrlist[n][1] = fmt.Sprintf("%v", v) + case []byte: + if xmlEscapeChars { + ss = escapeChars(string(v.([]byte))) + } else { + ss = string(v.([]byte)) + } + attrlist[n][0] = k[lenAttrPrefix:] + attrlist[n][1] = ss + default: + return fmt.Errorf("invalid attribute value for: %s:<%T>", k, v) + } + n++ + } + } + if n > 0 { + attrlist = attrlist[:n] + sort.Sort(attrList(attrlist)) + for _, v := range attrlist { + *s += ` ` + v[0] + `="` + v[1] + `"` + } + } + // only attributes? + if n == lenvv { + if useGoXmlEmptyElemSyntax { + *s += `" + } else { + *s += `/>` + } + break + } + + // simple element? Note: '#text" is an invalid XML tag. + if v, ok := vv["#text"]; ok && n+1 == lenvv { + switch v.(type) { + case string: + if xmlEscapeChars { + v = escapeChars(v.(string)) + } else { + v = v.(string) + } + case []byte: + if xmlEscapeChars { + v = escapeChars(string(v.([]byte))) + } + } + *s += ">" + fmt.Sprintf("%v", v) + endTag = true + elen = 1 + isSimple = true + break + } else if ok { + // Handle edge case where simple element with attributes + // is unmarshal'd using NewMapXml() where attribute prefix + // has been set to "". + // TODO(clb): should probably scan all keys for invalid chars. + return fmt.Errorf("invalid attribute key label: #text - due to attributes not being prefixed") + } + + // close tag with possible attributes + *s += ">" + if doIndent { + *s += "\n" + } + // something more complex + p.mapDepth++ + // extract the map k:v pairs and sort on key + elemlist := make([][2]interface{}, len(vv)) + n = 0 + for k, v := range vv { + if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix { + continue + } + elemlist[n][0] = k + elemlist[n][1] = v + n++ + } + elemlist = elemlist[:n] + sort.Sort(elemList(elemlist)) + var i int + for _, v := range elemlist { + switch v[1].(type) { + case []interface{}: + default: + if i == 0 && doIndent { + p.Indent() + } + } + i++ + if err := mapToXmlIndent(doIndent, s, v[0].(string), v[1], p); err != nil { + return err + } + switch v[1].(type) { + case []interface{}: // handled in []interface{} case + default: + if doIndent { + p.Outdent() + } + } + i-- + } + p.mapDepth-- + endTag = true + elen = 1 // we do have some content ... + case []interface{}: + // special case - found during implementing Issue #23 + if len(value.([]interface{})) == 0 { + if doIndent { + *s += p.padding + p.indent + } + *s += "<" + key + elen = 0 + endTag = true + break + } + for _, v := range value.([]interface{}) { + if doIndent { + p.Indent() + } + if err := mapToXmlIndent(doIndent, s, key, v, p); err != nil { + return err + } + if doIndent { + p.Outdent() + } + } + return nil + case []string: + // This was added by https://github.com/slotix ... not a type that + // would be encountered if mv generated from NewMapXml, NewMapJson. + // Could be encountered in AnyXml(), so we'll let it stay, though + // it should be merged with case []interface{}, above. + //quick fix for []string type + //[]string should be treated exaclty as []interface{} + if len(value.([]string)) == 0 { + if doIndent { + *s += p.padding + p.indent + } + *s += "<" + key + elen = 0 + endTag = true + break + } + for _, v := range value.([]string) { + if doIndent { + p.Indent() + } + if err := mapToXmlIndent(doIndent, s, key, v, p); err != nil { + return err + } + if doIndent { + p.Outdent() + } + } + return nil + case nil: + // terminate the tag + if doIndent { + *s += p.padding + } + *s += "<" + key + endTag, isSimple = true, true + break + default: // handle anything - even goofy stuff + elen = 0 + switch value.(type) { + case string: + v := value.(string) + if xmlEscapeChars { + v = escapeChars(v) + } + elen = len(v) + if elen > 0 { + *s += ">" + v + } + case float64, bool, int, int32, int64, float32, json.Number: + v := fmt.Sprintf("%v", value) + elen = len(v) // always > 0 + *s += ">" + v + case []byte: // NOTE: byte is just an alias for uint8 + // similar to how xml.Marshal handles []byte structure members + v := string(value.([]byte)) + if xmlEscapeChars { + v = escapeChars(v) + } + elen = len(v) + if elen > 0 { + *s += ">" + v + } + default: + var v []byte + var err error + if doIndent { + v, err = xml.MarshalIndent(value, p.padding, p.indent) + } else { + v, err = xml.Marshal(value) + } + if err != nil { + *s += ">UNKNOWN" + } else { + elen = len(v) + if elen > 0 { + *s += string(v) + } + } + } + isSimple = true + endTag = true + } + if endTag { + if doIndent { + if !isSimple { + *s += p.padding + } + } + if elen > 0 || useGoXmlEmptyElemSyntax { + if elen == 0 { + *s += ">" + } + *s += `" + } else { + *s += `/>` + } + } + if doIndent { + if p.cnt > p.start { + *s += "\n" + } + p.Outdent() + } + + return nil +} + +// ============================ sort interface implementation ================= + +type attrList [][2]string + +func (a attrList) Len() int { + return len(a) +} + +func (a attrList) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func (a attrList) Less(i, j int) bool { + return a[i][0] <= a[j][0] +} + +type elemList [][2]interface{} + +func (e elemList) Len() int { + return len(e) +} + +func (e elemList) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +func (e elemList) Less(i, j int) bool { + return e[i][0].(string) <= e[j][0].(string) +} diff --git a/vendor/github.com/clbanning/mxj/xmlseq.go b/vendor/github.com/clbanning/mxj/xmlseq.go new file mode 100644 index 00000000000..6be73ae60d9 --- /dev/null +++ b/vendor/github.com/clbanning/mxj/xmlseq.go @@ -0,0 +1,828 @@ +// Copyright 2012-2016 Charles Banning. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// xmlseq.go - version of xml.go with sequence # injection on Decoding and sorting on Encoding. +// Also, handles comments, directives and process instructions. + +package mxj + +import ( + "bytes" + "encoding/xml" + "errors" + "fmt" + "io" + "sort" + "strings" +) + +var NoRoot = errors.New("no root key") +var NO_ROOT = NoRoot // maintain backwards compatibility + +// ------------------- NewMapXmlSeq & NewMapXmlSeqReader ... ------------------------- + +// This is only useful if you want to re-encode the Map as XML using mv.XmlSeq(), etc., to preserve the original structure. +// The xml.Decoder.RawToken method is used to parse the XML, so there is no checking for appropriate xml.EndElement values; +// thus, it is assumed that the XML is valid. +// +// NewMapXmlSeq - convert a XML doc into a Map with elements id'd with decoding sequence int - #seq. +// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible. +// NOTE: "#seq" key/value pairs are removed on encoding with mv.XmlSeq() / mv.XmlSeqIndent(). +// • attributes are a map - map["#attr"]map["attr_key"]map[string]interface{}{"#text":, "#seq":} +// • all simple elements are decoded as map["#text"]interface{} with a "#seq" k:v pair, as well. +// • lists always decode as map["list_tag"][]map[string]interface{} where the array elements are maps that +// include a "#seq" k:v pair based on sequence they are decoded. Thus, XML like: +// +// value 1 +// value 2 +// value 3 +// +// is decoded as: +// doc : +// ltag :[[]interface{}] +// [item: 0] +// #seq :[int] 0 +// #text :[string] value 1 +// [item: 1] +// #seq :[int] 2 +// #text :[string] value 3 +// newtag : +// #seq :[int] 1 +// #text :[string] value 2 +// It will encode in proper sequence even though the Map representation merges all "ltag" elements in an array. +// • comments - "" - are decoded as map["#comment"]map["#text"]"cmnt_text" with a "#seq" k:v pair. +// • directives - "" - are decoded as map["#directive"]map[#text"]"directive_text" with a "#seq" k:v pair. +// • process instructions - "" - are decoded as map["#procinst"]interface{} where the #procinst value +// is of map[string]interface{} type with the following keys: #target, #inst, and #seq. +// • comments, directives, and procinsts that are NOT part of a document with a root key will be returned as +// map[string]interface{} and the error value 'NoRoot'. +// • note: ": tag preserve the +// ":" notation rather than stripping it as with NewMapXml(). +// 2. Attribute keys for name space prefix declarations preserve "xmlns:" notation. +func NewMapXmlSeq(xmlVal []byte, cast ...bool) (Map, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + return xmlSeqToMap(xmlVal, r) +} + +// This is only useful if you want to re-encode the Map as XML using mv.XmlSeq(), etc., to preserve the original structure. +// +// Get next XML doc from an io.Reader as a Map value. Returns Map value. +// NOTES: +// 1. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 2. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to +// re-encode the message in its original structure. +// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +func NewMapXmlSeqReader(xmlReader io.Reader, cast ...bool) (Map, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + + // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder + // will wrap it in a bufio.Reader and seek on the file beyond where the + // xml.Decoder parses! + if _, ok := xmlReader.(io.ByteReader); !ok { + xmlReader = myByteReader(xmlReader) // see code at EOF + } + + // build the map + return xmlSeqReaderToMap(xmlReader, r) +} + +// This is only useful if you want to re-encode the Map as XML using mv.XmlSeq(), etc., to preserve the original structure. +// +// Get next XML doc from an io.Reader as a Map value. Returns Map value and slice with the raw XML. +// NOTES: +// 1. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte +// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact. +// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large +// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body +// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call. +// 2. The 'raw' return value may be larger than the XML text value. +// 3. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other +// extraneous xml.CharData will be ignored unless io.EOF is reached first. +// 4. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to +// re-encode the message in its original structure. +// 5. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. +func NewMapXmlSeqReaderRaw(xmlReader io.Reader, cast ...bool) (Map, []byte, error) { + var r bool + if len(cast) == 1 { + r = cast[0] + } + // create TeeReader so we can retrieve raw XML + buf := make([]byte, 0) + wb := bytes.NewBuffer(buf) + trdr := myTeeReader(xmlReader, wb) + + m, err := xmlSeqReaderToMap(trdr, r) + + // retrieve the raw XML that was decoded + b := wb.Bytes() + + // err may be NoRoot + return m, b, err +} + +// xmlSeqReaderToMap() - parse a XML io.Reader to a map[string]interface{} value +func xmlSeqReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) { + // parse the Reader + p := xml.NewDecoder(rdr) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlSeqToMapParser("", nil, p, r) +} + +// xmlSeqToMap - convert a XML doc into map[string]interface{} value +func xmlSeqToMap(doc []byte, r bool) (map[string]interface{}, error) { + b := bytes.NewReader(doc) + p := xml.NewDecoder(b) + if CustomDecoder != nil { + useCustomDecoder(p) + } else { + p.CharsetReader = XmlCharsetReader + } + return xmlSeqToMapParser("", nil, p, r) +} + +// ===================================== where the work happens ============================= + +// xmlSeqToMapParser - load a 'clean' XML doc into a map[string]interface{} directly. +// Add #seq tag value for each element decoded - to be used for Encoding later. +func xmlSeqToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) { + if snakeCaseKeys { + skey = strings.Replace(skey, "-", "_", -1) + } + + // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'. + var n, na map[string]interface{} + var seq int // for including seq num when decoding + + // Allocate maps and load attributes, if any. + // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through + // to get StartElement then recurse with skey==xml.StartElement.Name.Local + // where we begin allocating map[string]interface{} values 'n' and 'na'. + if skey != "" { + // 'n' only needs one slot - save call to runtime•hashGrow() + // 'na' we don't know + n = make(map[string]interface{}, 1) + na = make(map[string]interface{}) + if len(a) > 0 { + // xml.Attr is decoded into: map["#attr"]map[]interface{} + // where interface{} is map[string]interface{}{"#text":, "#seq":} + aa := make(map[string]interface{}, len(a)) + for i, v := range a { + if snakeCaseKeys { + v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1) + } + if len(v.Name.Space) > 0 { + aa[v.Name.Space+`:`+v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r), "#seq": i} + } else { + aa[v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r), "#seq": i} + } + } + na["#attr"] = aa + } + } + + // Return XMPP message. + if handleXMPPStreamTag && skey == "stream:stream" { + n[skey] = na + return n, nil + } + + for { + t, err := p.RawToken() + if err != nil { + if err != io.EOF { + return nil, errors.New("xml.Decoder.Token() - " + err.Error()) + } + return nil, err + } + switch t.(type) { + case xml.StartElement: + tt := t.(xml.StartElement) + + // First call to xmlSeqToMapParser() doesn't pass xml.StartElement - the map key. + // So when the loop is first entered, the first token is the root tag along + // with any attributes, which we process here. + // + // Subsequent calls to xmlSeqToMapParser() will pass in tag+attributes for + // processing before getting the next token which is the element value, + // which is done above. + if skey == "" { + if len(tt.Name.Space) > 0 { + return xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r) + } else { + return xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r) + } + } + + // If not initializing the map, parse the element. + // len(nn) == 1, necessarily - it is just an 'n'. + var nn map[string]interface{} + if len(tt.Name.Space) > 0 { + nn, err = xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r) + } else { + nn, err = xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r) + } + if err != nil { + return nil, err + } + + // The nn map[string]interface{} value is a na[nn_key] value. + // We need to see if nn_key already exists - means we're parsing a list. + // This may require converting na[nn_key] value into []interface{} type. + // First, extract the key:val for the map - it's a singleton. + var key string + var val interface{} + for key, val = range nn { + break + } + + // add "#seq" k:v pair - + // Sequence number included even in list elements - this should allow us + // to properly resequence even something goofy like: + // item 1 + // item 2 + // item 3 + // where all the "list" subelements are decoded into an array. + switch val.(type) { + case map[string]interface{}: + val.(map[string]interface{})["#seq"] = seq + seq++ + case interface{}: // a non-nil simple element: string, float64, bool + v := map[string]interface{}{"#text": val, "#seq": seq} + seq++ + val = v + } + + // 'na' holding sub-elements of n. + // See if 'key' already exists. + // If 'key' exists, then this is a list, if not just add key:val to na. + if v, ok := na[key]; ok { + var a []interface{} + switch v.(type) { + case []interface{}: + a = v.([]interface{}) + default: // anything else - note: v.(type) != nil + a = []interface{}{v} + } + a = append(a, val) + na[key] = a + } else { + na[key] = val // save it as a singleton + } + case xml.EndElement: + if skey != "" { + tt := t.(xml.EndElement) + if snakeCaseKeys { + tt.Name.Local = strings.Replace(tt.Name.Local, "-", "_", -1) + } + var name string + if len(tt.Name.Space) > 0 { + name = tt.Name.Space + `:` + tt.Name.Local + } else { + name = tt.Name.Local + } + if skey != name { + return nil, fmt.Errorf("element %s not properly terminated, got %s at #%d", + skey, name, p.InputOffset()) + } + } + // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case. + if len(n) == 0 { + // If len(na)==0 we have an empty element == ""; + // it has no xml.Attr nor xml.CharData. + // Empty element content will be map["etag"]map["#text"]"" + // after #seq injection - map["etag"]map["#seq"]seq - after return. + if len(na) > 0 { + n[skey] = na + } else { + n[skey] = "" // empty element + } + } + return n, nil + case xml.CharData: + // clean up possible noise + tt := strings.Trim(string(t.(xml.CharData)), "\t\r\b\n ") + if skey == "" { + // per Adrian (http://www.adrianlungu.com/) catch stray text + // in decoder stream - + // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374 + // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get + // a p.Token() decoding error when the BOM is UTF-16 or UTF-32. + continue + } + if len(tt) > 0 { + // every simple element is a #text and has #seq associated with it + na["#text"] = cast(tt, r) + na["#seq"] = seq + seq++ + } + case xml.Comment: + if n == nil { // no root 'key' + n = map[string]interface{}{"#comment": string(t.(xml.Comment))} + return n, NoRoot + } + cm := make(map[string]interface{}, 2) + cm["#text"] = string(t.(xml.Comment)) + cm["#seq"] = seq + seq++ + na["#comment"] = cm + case xml.Directive: + if n == nil { // no root 'key' + n = map[string]interface{}{"#directive": string(t.(xml.Directive))} + return n, NoRoot + } + dm := make(map[string]interface{}, 2) + dm["#text"] = string(t.(xml.Directive)) + dm["#seq"] = seq + seq++ + na["#directive"] = dm + case xml.ProcInst: + if n == nil { + na = map[string]interface{}{"#target": t.(xml.ProcInst).Target, "#inst": string(t.(xml.ProcInst).Inst)} + n = map[string]interface{}{"#procinst": na} + return n, NoRoot + } + pm := make(map[string]interface{}, 3) + pm["#target"] = t.(xml.ProcInst).Target + pm["#inst"] = string(t.(xml.ProcInst).Inst) + pm["#seq"] = seq + seq++ + na["#procinst"] = pm + default: + // noop - shouldn't ever get here, now, since we handle all token types + } + } +} + +// ------------------ END: NewMapXml & NewMapXmlReader ------------------------- + +// --------------------- mv.XmlSeq & mv.XmlSeqWriter ------------------------- + +// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co. +// +// Encode a Map as XML with elements sorted on #seq. The companion of NewMapXmlSeq(). +// The following rules apply. +// - The key label "#text" is treated as the value for a simple element with attributes. +// - The "#seq" key is used to seqence the subelements or attributes but is ignored for writing. +// - The "#attr" map key identifies the map of attribute map[string]interface{} values with "#text" key. +// - The "#comment" map key identifies a comment in the value "#text" map entry - . +// - The "#directive" map key identifies a directive in the value "#text" map entry - . +// - The "#procinst" map key identifies a process instruction in the value "#target" and "#inst" +// map entries - . +// - Value type encoding: +// > string, bool, float64, int, int32, int64, float32: per "%v" formating +// > []bool, []uint8: by casting to string +// > structures, etc.: handed to xml.Marshal() - if there is an error, the element +// value is "UNKNOWN" +// - Elements with only attribute values or are null are terminated using "/>" unless XmlGoEmptyElemSystax() called. +// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible. +// Thus, `{ "key":"value" }` encodes as "value". +func (mv Map) XmlSeq(rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + var err error + s := new(string) + p := new(pretty) // just a stub + + if len(m) == 1 && len(rootTag) == 0 { + for key, value := range m { + // if it's an array, see if all values are map[string]interface{} + // we force a new root tag if we'll end up with no key:value in the list + // so: key:[string_val, bool:true] --> string_valtrue + switch value.(type) { + case []interface{}: + for _, v := range value.([]interface{}) { + switch v.(type) { + case map[string]interface{}: // noop + default: // anything else + err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p) + goto done + } + } + } + err = mapToXmlSeqIndent(false, s, key, value, p) + } + } else if len(rootTag) == 1 { + err = mapToXmlSeqIndent(false, s, rootTag[0], m, p) + } else { + err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p) + } +done: + return []byte(*s), err +} + +// The following implementation is provided only for symmetry with NewMapXmlReader[Raw] +// The names will also provide a key for the number of return arguments. + +// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co. +// +// Writes the Map as XML on the Writer. +// See XmlSeq() for encoding rules. +func (mv Map) XmlSeqWriter(xmlWriter io.Writer, rootTag ...string) error { + x, err := mv.XmlSeq(rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co. +// +// Writes the Map as XML on the Writer. []byte is the raw XML that was written. +// See XmlSeq() for encoding rules. +func (mv Map) XmlSeqWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) { + x, err := mv.XmlSeq(rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} + +// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co. +// +// Writes the Map as pretty XML on the Writer. +// See Xml() for encoding rules. +func (mv Map) XmlSeqIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error { + x, err := mv.XmlSeqIndent(prefix, indent, rootTag...) + if err != nil { + return err + } + + _, err = xmlWriter.Write(x) + return err +} + +// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co. +// +// Writes the Map as pretty XML on the Writer. []byte is the raw XML that was written. +// See XmlSeq() for encoding rules. +func (mv Map) XmlSeqIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) { + x, err := mv.XmlSeqIndent(prefix, indent, rootTag...) + if err != nil { + return x, err + } + + _, err = xmlWriter.Write(x) + return x, err +} + +// -------------------- END: mv.Xml & mv.XmlWriter ------------------------------- + +// ---------------------- XmlSeqIndent ---------------------------- + +// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co. +// +// Encode a map[string]interface{} as a pretty XML string. +// See mv.XmlSeq() for encoding rules. +func (mv Map) XmlSeqIndent(prefix, indent string, rootTag ...string) ([]byte, error) { + m := map[string]interface{}(mv) + + var err error + s := new(string) + p := new(pretty) + p.indent = indent + p.padding = prefix + + if len(m) == 1 && len(rootTag) == 0 { + // this can extract the key for the single map element + // use it if it isn't a key for a list + for key, value := range m { + if _, ok := value.([]interface{}); ok { + err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p) + } else { + err = mapToXmlSeqIndent(true, s, key, value, p) + } + } + } else if len(rootTag) == 1 { + err = mapToXmlSeqIndent(true, s, rootTag[0], m, p) + } else { + err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p) + } + return []byte(*s), err +} + +// where the work actually happens +// returns an error if an attribute is not atomic +func mapToXmlSeqIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error { + var endTag bool + var isSimple bool + var noEndTag bool + var elen int + var ss string + p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start} + + switch value.(type) { + case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32: + if doIndent { + *s += p.padding + } + if key != "#comment" && key != "#directive" && key != "#procinst" { + *s += `<` + key + } + } + switch value.(type) { + case map[string]interface{}: + val := value.(map[string]interface{}) + + if key == "#comment" { + *s += `` + noEndTag = true + break + } + + if key == "#directive" { + *s += `` + noEndTag = true + break + } + + if key == "#procinst" { + *s += `` + noEndTag = true + break + } + + haveAttrs := false + // process attributes first + if v, ok := val["#attr"].(map[string]interface{}); ok { + // First, unroll the map[string]interface{} into a []keyval array. + // Then sequence it. + kv := make([]keyval, len(v)) + n := 0 + for ak, av := range v { + kv[n] = keyval{ak, av} + n++ + } + sort.Sort(elemListSeq(kv)) + // Now encode the attributes in original decoding sequence, using keyval array. + for _, a := range kv { + vv := a.v.(map[string]interface{}) + switch vv["#text"].(type) { + case string: + if xmlEscapeChars { + ss = escapeChars(vv["#text"].(string)) + } else { + ss = vv["#text"].(string) + } + *s += ` ` + a.k + `="` + ss + `"` + case float64, bool, int, int32, int64, float32: + *s += ` ` + a.k + `="` + fmt.Sprintf("%v", vv["#text"]) + `"` + case []byte: + if xmlEscapeChars { + ss = escapeChars(string(vv["#text"].([]byte))) + } else { + ss = string(vv["#text"].([]byte)) + } + *s += ` ` + a.k + `="` + ss + `"` + default: + return fmt.Errorf("invalid attribute value for: %s", a.k) + } + } + haveAttrs = true + } + + // simple element? + // every map value has, at least, "#seq" and, perhaps, "#text" and/or "#attr" + _, seqOK := val["#seq"] // have key + if v, ok := val["#text"]; ok && ((len(val) == 3 && haveAttrs) || (len(val) == 2 && !haveAttrs)) && seqOK { + if stmp, ok := v.(string); ok && stmp != "" { + if xmlEscapeChars { + stmp = escapeChars(stmp) + } + *s += ">" + stmp + endTag = true + elen = 1 + } + isSimple = true + break + } else if !ok && ((len(val) == 2 && haveAttrs) || (len(val) == 1 && !haveAttrs)) && seqOK { + // here no #text but have #seq or #seq+#attr + endTag = false + break + } + + // we now need to sequence everything except attributes + // 'kv' will hold everything that needs to be written + kv := make([]keyval, 0) + for k, v := range val { + if k == "#attr" { // already processed + continue + } + if k == "#seq" { // ignore - just for sorting + continue + } + switch v.(type) { + case []interface{}: + // unwind the array as separate entries + for _, vv := range v.([]interface{}) { + kv = append(kv, keyval{k, vv}) + } + default: + kv = append(kv, keyval{k, v}) + } + } + + // close tag with possible attributes + *s += ">" + if doIndent { + *s += "\n" + } + // something more complex + p.mapDepth++ + sort.Sort(elemListSeq(kv)) + i := 0 + for _, v := range kv { + switch v.v.(type) { + case []interface{}: + default: + if i == 0 && doIndent { + p.Indent() + } + } + i++ + if err := mapToXmlSeqIndent(doIndent, s, v.k, v.v, p); err != nil { + return err + } + switch v.v.(type) { + case []interface{}: // handled in []interface{} case + default: + if doIndent { + p.Outdent() + } + } + i-- + } + p.mapDepth-- + endTag = true + elen = 1 // we do have some content other than attrs + case []interface{}: + for _, v := range value.([]interface{}) { + if doIndent { + p.Indent() + } + if err := mapToXmlSeqIndent(doIndent, s, key, v, p); err != nil { + return err + } + if doIndent { + p.Outdent() + } + } + return nil + case nil: + // terminate the tag + if doIndent { + *s += p.padding + } + *s += "<" + key + endTag, isSimple = true, true + break + default: // handle anything - even goofy stuff + elen = 0 + switch value.(type) { + case string: + if xmlEscapeChars { + ss = escapeChars(value.(string)) + } else { + ss = value.(string) + } + elen = len(ss) + if elen > 0 { + *s += ">" + ss + } + case float64, bool, int, int32, int64, float32: + v := fmt.Sprintf("%v", value) + elen = len(v) + if elen > 0 { + *s += ">" + v + } + case []byte: // NOTE: byte is just an alias for uint8 + // similar to how xml.Marshal handles []byte structure members + if xmlEscapeChars { + ss = escapeChars(string(value.([]byte))) + } else { + ss = string(value.([]byte)) + } + elen = len(ss) + if elen > 0 { + *s += ">" + ss + } + default: + var v []byte + var err error + if doIndent { + v, err = xml.MarshalIndent(value, p.padding, p.indent) + } else { + v, err = xml.Marshal(value) + } + if err != nil { + *s += ">UNKNOWN" + } else { + elen = len(v) + if elen > 0 { + *s += string(v) + } + } + } + isSimple = true + endTag = true + } + if endTag && !noEndTag { + if doIndent { + if !isSimple { + *s += p.padding + } + } + switch value.(type) { + case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32: + if elen > 0 || useGoXmlEmptyElemSyntax { + if elen == 0 { + *s += ">" + } + *s += `" + } else { + *s += `/>` + } + } + } else if !noEndTag { + if useGoXmlEmptyElemSyntax { + *s += `" + // *s += ">" + } else { + *s += "/>" + } + } + if doIndent { + if p.cnt > p.start { + *s += "\n" + } + p.Outdent() + } + + return nil +} + +// the element sort implementation + +type keyval struct { + k string + v interface{} +} +type elemListSeq []keyval + +func (e elemListSeq) Len() int { + return len(e) +} + +func (e elemListSeq) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +func (e elemListSeq) Less(i, j int) bool { + var iseq, jseq int + var ok bool + if iseq, ok = e[i].v.(map[string]interface{})["#seq"].(int); !ok { + iseq = 9999999 + } + + if jseq, ok = e[j].v.(map[string]interface{})["#seq"].(int); !ok { + jseq = 9999999 + } + + return iseq <= jseq +} + +// =============== https://groups.google.com/forum/#!topic/golang-nuts/lHPOHD-8qio + +// BeautifyXml (re)formats an XML doc similar to Map.XmlIndent(). +func BeautifyXml(b []byte, prefix, indent string) ([]byte, error) { + x, err := NewMapXmlSeq(b) + if err != nil { + return nil, err + } + return x.XmlSeqIndent(prefix, indent) +} diff --git a/vendor/github.com/gofrs/flock/.gitignore b/vendor/github.com/gofrs/flock/.gitignore new file mode 100644 index 00000000000..daf913b1b34 --- /dev/null +++ b/vendor/github.com/gofrs/flock/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/gofrs/flock/.golangci.yml b/vendor/github.com/gofrs/flock/.golangci.yml new file mode 100644 index 00000000000..bc837b266a9 --- /dev/null +++ b/vendor/github.com/gofrs/flock/.golangci.yml @@ -0,0 +1,116 @@ +version: "2" + +formatters: + enable: + - gofumpt + - goimports + settings: + gofumpt: + extra-rules: true + +linters: + enable: + - asasalint + - bidichk + - dogsled + - dupword + - durationcheck + - err113 + - errname + - errorlint + - fatcontext + - forbidigo + - gocheckcompilerdirectives + - gochecknoinits + - gocritic + - godot + - godox + - goheader + - gomoddirectives + - goprintffuncname + - gosec + - inamedparam + - interfacebloat + - ireturn + - mirror + - misspell + - nolintlint + - revive + - staticcheck + - testifylint + - thelper + - unconvert + - unparam + - usestdlibvars + - whitespace + - wsl_v5 + settings: + gocritic: + disabled-checks: + - paramTypeCombine # already handle by gofumpt.extra-rules + - whyNoLint # already handle by nonolint + - unnamedResult + - hugeParam + - sloppyReassign + - rangeValCopy + - octalLiteral + - ptrToRefParam + - appendAssign + - ruleguard + - httpNoBody + - exposedSyncMutex + enabled-tags: + - diagnostic + - style + - performance + godox: + keywords: + - FIXME + goheader: + template: |- + Copyright 2015 Tim Heckman. All rights reserved. + Copyright 2018-{{ YEAR }} The Gofrs. All rights reserved. + Use of this source code is governed by the BSD 3-Clause + license that can be found in the LICENSE file. + gosec: + excludes: + - G115 + misspell: + locale: US + revive: + rules: + - name: struct-tag + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: package-comments + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + - name: unreachable-code + - name: redefines-builtin-id + exclusions: + presets: + - comments + - common-false-positives + - std-error-handling + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 + diff --git a/vendor/github.com/gofrs/flock/LICENSE b/vendor/github.com/gofrs/flock/LICENSE new file mode 100644 index 00000000000..c785e5e4b24 --- /dev/null +++ b/vendor/github.com/gofrs/flock/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2018-2025, The Gofrs +Copyright (c) 2015-2020, Tim Heckman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of gofrs nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gofrs/flock/Makefile b/vendor/github.com/gofrs/flock/Makefile new file mode 100644 index 00000000000..65c139d68c0 --- /dev/null +++ b/vendor/github.com/gofrs/flock/Makefile @@ -0,0 +1,15 @@ +.PHONY: lint test test_race build_cross_os + +default: lint test build_cross_os + +test: + go test -v -cover ./... + +test_race: + CGO_ENABLED=1 go test -v -race ./... + +lint: + golangci-lint run + +build_cross_os: + ./build.sh diff --git a/vendor/github.com/gofrs/flock/README.md b/vendor/github.com/gofrs/flock/README.md new file mode 100644 index 00000000000..f7ca0dd9c24 --- /dev/null +++ b/vendor/github.com/gofrs/flock/README.md @@ -0,0 +1,45 @@ +# flock + +[![Go Reference](https://pkg.go.dev/badge/github.com/gofrs/flock.svg)](https://pkg.go.dev/github.com/gofrs/flock) +[![License](https://img.shields.io/badge/license-BSD_3--Clause-brightgreen.svg?style=flat)](https://github.com/gofrs/flock/blob/main/LICENSE) +[![Go Report Card](https://goreportcard.com/badge/github.com/gofrs/flock)](https://goreportcard.com/report/github.com/gofrs/flock) + +`flock` implements a thread-safe file lock. + +It also includes a non-blocking `TryLock()` function to allow locking without blocking execution. + +## Installation + +```bash +go get -u github.com/gofrs/flock +``` + +## Usage + +```go +import "github.com/gofrs/flock" + +fileLock := flock.New("/var/lock/go-lock.lock") + +locked, err := fileLock.TryLock() + +if err != nil { + // handle locking error +} + +if locked { + // do work + fileLock.Unlock() +} +``` + +For more detailed usage information take a look at the package API docs on +[GoDoc](https://pkg.go.dev/github.com/gofrs/flock). + +## License + +`flock` is released under the BSD 3-Clause License. See the [`LICENSE`](./LICENSE) file for more details. + +## Project History + +This project was originally `github.com/theckman/go-flock`, it was transferred to Gofrs by the original author [Tim Heckman ](https://github.com/theckman). diff --git a/vendor/github.com/gofrs/flock/SECURITY.md b/vendor/github.com/gofrs/flock/SECURITY.md new file mode 100644 index 00000000000..01419bd592a --- /dev/null +++ b/vendor/github.com/gofrs/flock/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +We support the latest version of this library. +We do not guarantee support of previous versions. + +If a defect is reported, it will generally be fixed on the latest version (provided it exists) irrespective of whether it was introduced in a prior version. + +## Reporting a Vulnerability + +To report a potential security vulnerability, please create a [security advisory](https://github.com/gofrs/flock/security/advisories/new). + +For us to respond to your report most effectively, please include any of the following: + +- Steps to reproduce or a proof-of-concept +- Any relevant information, including the versions used + +## Security Scorecard + +This project submits security [results](https://scorecard.dev/viewer/?uri=github.com/gofrs/flock) to the [OpenSSF Scorecard](https://securityscorecards.dev/). diff --git a/vendor/github.com/gofrs/flock/build.sh b/vendor/github.com/gofrs/flock/build.sh new file mode 100644 index 00000000000..60f7809f065 --- /dev/null +++ b/vendor/github.com/gofrs/flock/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash -e + +# Not supported by flock: +# - plan9/* +# - js/wasm +# - wasp1/wasm + +for row in $(go tool dist list -json | jq -r '.[] | @base64'); do + _jq() { + echo ${row} | base64 --decode | jq -r ${1} + } + + GOOS=$(_jq '.GOOS') + GOARCH=$(_jq '.GOARCH') + + echo "$GOOS/$GOARCH" + GOOS=$GOOS GOARCH=$GOARCH go build +done diff --git a/vendor/github.com/gofrs/flock/flock.go b/vendor/github.com/gofrs/flock/flock.go new file mode 100644 index 00000000000..4cb0746a716 --- /dev/null +++ b/vendor/github.com/gofrs/flock/flock.go @@ -0,0 +1,222 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +// Package flock implements a thread-safe interface for file locking. +// It also includes a non-blocking TryLock() function to allow locking +// without blocking execution. +// +// Package flock is released under the BSD 3-Clause License. See the LICENSE file +// for more details. +// +// While using this library, remember that the locking behaviors are not +// guaranteed to be the same on each platform. For example, some UNIX-like +// operating systems will transparently convert a shared lock to an exclusive +// lock. If you Unlock() the flock from a location where you believe that you +// have the shared lock, you may accidentally drop the exclusive lock. +package flock + +import ( + "context" + "io/fs" + "os" + "runtime" + "sync" + "time" +) + +type Option func(f *Flock) + +// SetFlag sets the flag used to create/open the file. +func SetFlag(flag int) Option { + return func(f *Flock) { + f.flag = flag + } +} + +// SetPermissions sets the OS permissions to set on the file. +func SetPermissions(perm fs.FileMode) Option { + return func(f *Flock) { + f.perm = perm + } +} + +// Flock is the struct type to handle file locking. All fields are unexported, +// with access to some of the fields provided by getter methods (Path() and Locked()). +type Flock struct { + path string + m sync.RWMutex + fh *os.File + l bool + r bool + + // flag is the flag used to create/open the file. + flag int + // perm is the OS permissions to set on the file. + perm fs.FileMode +} + +// New returns a new instance of *Flock. The only parameter +// it takes is the path to the desired lockfile. +func New(path string, opts ...Option) *Flock { + // create it if it doesn't exist, and open the file read-only. + flags := os.O_CREATE + + switch runtime.GOOS { + case "aix", "solaris", "illumos": + // AIX cannot preform write-lock (i.e. exclusive) on a read-only file. + flags |= os.O_RDWR + default: + flags |= os.O_RDONLY + } + + f := &Flock{ + path: path, + flag: flags, + perm: fs.FileMode(0o600), + } + + for _, opt := range opts { + opt(f) + } + + return f +} + +// NewFlock returns a new instance of *Flock. The only parameter +// it takes is the path to the desired lockfile. +// +// Deprecated: Use New instead. +func NewFlock(path string) *Flock { + return New(path) +} + +// Close is equivalent to calling Unlock. +// +// This will release the lock and close the underlying file descriptor. +// It will not remove the file from disk, that's up to your application. +func (f *Flock) Close() error { + return f.Unlock() +} + +// Path returns the path as provided in NewFlock(). +func (f *Flock) Path() string { + return f.path +} + +// Locked returns the lock state (locked: true, unlocked: false). +// +// Warning: by the time you use the returned value, the state may have changed. +func (f *Flock) Locked() bool { + f.m.RLock() + defer f.m.RUnlock() + + return f.l +} + +// RLocked returns the read lock state (locked: true, unlocked: false). +// +// Warning: by the time you use the returned value, the state may have changed. +func (f *Flock) RLocked() bool { + f.m.RLock() + defer f.m.RUnlock() + + return f.r +} + +// Stat returns the FileInfo structure describing the lock file. +// If the lock file does not exist or cannot be accessed, an error is returned. +// +// This can be used to check the modification time of the lock file, +// which is useful for detecting stale locks. +func (f *Flock) Stat() (fs.FileInfo, error) { + f.m.RLock() + defer f.m.RUnlock() + + if f.fh != nil { + return f.fh.Stat() + } + + return os.Stat(f.path) +} + +func (f *Flock) String() string { + return f.path +} + +// TryLockContext repeatedly tries to take an exclusive lock until one of the conditions is met: +// - TryLock succeeds +// - TryLock fails with error +// - Context Done channel is closed. +func (f *Flock) TryLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) { + return tryCtx(ctx, f.TryLock, retryDelay) +} + +// TryRLockContext repeatedly tries to take a shared lock until one of the conditions is met: +// - TryRLock succeeds +// - TryRLock fails with error +// - Context Done channel is closed. +func (f *Flock) TryRLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) { + return tryCtx(ctx, f.TryRLock, retryDelay) +} + +func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Duration) (bool, error) { + if ctx.Err() != nil { + return false, ctx.Err() + } + + for { + if ok, err := fn(); ok || err != nil { + return ok, err + } + + select { + case <-ctx.Done(): + return false, ctx.Err() + case <-time.After(retryDelay): + } + } +} + +func (f *Flock) setFh(flag int) error { + // open a new os.File instance + fh, err := os.OpenFile(f.path, flag, f.perm) + if err != nil { + return err + } + + // set the file handle on the struct + f.fh = fh + + return nil +} + +// resetFh resets file handle: +// - tries to close the file (ignore errors) +// - sets fh to nil. +func (f *Flock) resetFh() { + if f.fh == nil { + return + } + + _ = f.fh.Close() + + f.fh = nil +} + +// ensure the file handle is closed if no lock is held. +func (f *Flock) ensureFhState() { + if f.l || f.r || f.fh == nil { + return + } + + f.resetFh() +} + +func (f *Flock) reset() { + f.l = false + f.r = false + + f.resetFh() +} diff --git a/vendor/github.com/gofrs/flock/flock_others.go b/vendor/github.com/gofrs/flock/flock_others.go new file mode 100644 index 00000000000..92d0f7e95a9 --- /dev/null +++ b/vendor/github.com/gofrs/flock/flock_others.go @@ -0,0 +1,45 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +//go:build (!unix && !windows) || plan9 + +package flock + +import ( + "errors" + "io/fs" +) + +func (f *Flock) Lock() error { + return &fs.PathError{ + Op: "Lock", + Path: f.Path(), + Err: errors.ErrUnsupported, + } +} + +func (f *Flock) RLock() error { + return &fs.PathError{ + Op: "RLock", + Path: f.Path(), + Err: errors.ErrUnsupported, + } +} + +func (f *Flock) Unlock() error { + return &fs.PathError{ + Op: "Unlock", + Path: f.Path(), + Err: errors.ErrUnsupported, + } +} + +func (f *Flock) TryLock() (bool, error) { + return false, f.Lock() +} + +func (f *Flock) TryRLock() (bool, error) { + return false, f.RLock() +} diff --git a/vendor/github.com/gofrs/flock/flock_unix.go b/vendor/github.com/gofrs/flock/flock_unix.go new file mode 100644 index 00000000000..77de7a8837a --- /dev/null +++ b/vendor/github.com/gofrs/flock/flock_unix.go @@ -0,0 +1,211 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd + +package flock + +import ( + "errors" + "os" + + "golang.org/x/sys/unix" +) + +// Lock is a blocking call to try and take an exclusive file lock. +// It will wait until it is able to obtain the exclusive file lock. +// It's recommended that TryLock() be used over this function. +// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already exclusive-locked, +// this function short-circuits and returns immediately assuming it can take the mutex lock. +// +// If the *Flock has a shared lock (RLock), +// this may transparently replace the shared lock with an exclusive lock on some UNIX-like operating systems. +// Be careful when using exclusive locks in conjunction with shared locks (RLock()), +// because calling Unlock() may accidentally release the exclusive lock that was once a shared lock. +func (f *Flock) Lock() error { + return f.lock(&f.l, unix.LOCK_EX) +} + +// RLock is a blocking call to try and take a shared file lock. +// It will wait until it is able to obtain the shared file lock. +// It's recommended that TryRLock() be used over this function. +// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already shared-locked, +// this function short-circuits and returns immediately assuming it can take the mutex lock. +func (f *Flock) RLock() error { + return f.lock(&f.r, unix.LOCK_SH) +} + +func (f *Flock) lock(locked *bool, flag int) error { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return nil + } + + if f.fh == nil { + if err := f.setFh(f.flag); err != nil { + return err + } + + defer f.ensureFhState() + } + + err := unix.Flock(int(f.fh.Fd()), flag) + if err != nil { + shouldRetry, reopenErr := f.reopenFDOnError(err) + if reopenErr != nil { + return reopenErr + } + + if !shouldRetry { + return err + } + + err = unix.Flock(int(f.fh.Fd()), flag) + if err != nil { + return err + } + } + + *locked = true + + return nil +} + +// Unlock is a function to unlock the file. +// This file takes a RW-mutex lock, +// so while it is running the Locked() and RLocked() functions will be blocked. +// +// This function short-circuits if we are unlocked already. +// If not, it calls unix.LOCK_UN on the file and closes the file descriptor. +// It does not remove the file from disk. It's up to your application to do. +// +// Please note, +// if your shared lock became an exclusive lock, +// this may unintentionally drop the exclusive lock if called by the consumer that believes they have a shared lock. +// Please see Lock() for more details. +func (f *Flock) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + // If we aren't locked or if the lockfile instance is nil + // just return a nil error because we are unlocked. + if (!f.l && !f.r) || f.fh == nil { + return nil + } + + // Mark the file as unlocked. + err := unix.Flock(int(f.fh.Fd()), unix.LOCK_UN) + if err != nil { + return err + } + + f.reset() + + return nil +} + +// TryLock is the preferred function for taking an exclusive file lock. +// This function takes an RW-mutex lock before it tries to lock the file, +// so there is the possibility that this function may block for a short time +// if another goroutine is trying to take any action. +// +// The actual file lock is non-blocking. +// If we are unable to get the exclusive file lock, +// the function will return false instead of waiting for the lock. +// If we get the lock, we also set the *Flock instance as being exclusive-locked. +func (f *Flock) TryLock() (bool, error) { + return f.try(&f.l, unix.LOCK_EX) +} + +// TryRLock is the preferred function for taking a shared file lock. +// This function takes an RW-mutex lock before it tries to lock the file, +// so there is the possibility that this function may block for a short time +// if another goroutine is trying to take any action. +// +// The actual file lock is non-blocking. +// If we are unable to get the shared file lock, +// the function will return false instead of waiting for the lock. +// If we get the lock, we also set the *Flock instance as being share-locked. +func (f *Flock) TryRLock() (bool, error) { + return f.try(&f.r, unix.LOCK_SH) +} + +func (f *Flock) try(locked *bool, flag int) (bool, error) { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return true, nil + } + + if f.fh == nil { + if err := f.setFh(f.flag); err != nil { + return false, err + } + + defer f.ensureFhState() + } + + var retried bool + +retry: + err := unix.Flock(int(f.fh.Fd()), flag|unix.LOCK_NB) + + switch { + case errors.Is(err, unix.EWOULDBLOCK): + return false, nil + case err == nil: + *locked = true + return true, nil + } + + if !retried { + shouldRetry, reopenErr := f.reopenFDOnError(err) + if reopenErr != nil { + return false, reopenErr + } else if shouldRetry { + retried = true + goto retry + } + } + + return false, err +} + +// reopenFDOnError determines whether we should reopen the file handle in readwrite mode and try again. +// This comes from `util-linux/sys-utils/flock.c`: +// > Since Linux 3.4 (commit 55725513) +// > Probably NFSv4 where flock() is emulated by fcntl(). +// > https://github.com/util-linux/util-linux/blob/198e920aa24743ef6ace4e07cf6237de527f9261/sys-utils/flock.c#L374-L390 +func (f *Flock) reopenFDOnError(err error) (bool, error) { + if !errors.Is(err, unix.EIO) && !errors.Is(err, unix.EBADF) { + return false, nil + } + + st, err := f.fh.Stat() + if err != nil { + return false, nil + } + + if st.Mode()&f.perm != f.perm { + return false, nil + } + + f.resetFh() + + // reopen in read-write mode and set the file handle + err = f.setFh(f.flag | os.O_RDWR) + if err != nil { + return false, err + } + + return true, nil +} diff --git a/vendor/github.com/gofrs/flock/flock_unix_fcntl.go b/vendor/github.com/gofrs/flock/flock_unix_fcntl.go new file mode 100644 index 00000000000..05c2f88c65b --- /dev/null +++ b/vendor/github.com/gofrs/flock/flock_unix_fcntl.go @@ -0,0 +1,393 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code implements the filelock API using POSIX 'fcntl' locks, +// which attach to an (inode, process) pair rather than a file descriptor. +// To avoid unlocking files prematurely when the same file is opened through different descriptors, +// we allow only one read-lock at a time. +// +// This code is adapted from the Go package (go.22): +// https://github.com/golang/go/blob/release-branch.go1.22/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go + +//go:build aix || (solaris && !illumos) + +package flock + +import ( + "errors" + "io" + "io/fs" + "math/rand" + "sync" + "syscall" + "time" + + "golang.org/x/sys/unix" +) + +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L28 +type lockType int16 + +// String returns the name of the function corresponding to lt +// (Lock, RLock, or Unlock). +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go#L67 +func (lt lockType) String() string { + switch lt { + case readLock: + return "RLock" + case writeLock: + return "Lock" + default: + return "Unlock" + } +} + +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L30-L33 +const ( + readLock lockType = unix.F_RDLCK + writeLock lockType = unix.F_WRLCK +) + +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L35 +type inode = uint64 + +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L37-L40 +type inodeLock struct { + owner *Flock + queue []<-chan *Flock +} + +type cmdType int + +const ( + tryLock cmdType = unix.F_SETLK + waitLock cmdType = unix.F_SETLKW +) + +var ( + mu sync.Mutex + inodes = map[*Flock]inode{} + locks = map[inode]inodeLock{} +) + +// Lock is a blocking call to try and take an exclusive file lock. +// It will wait until it is able to obtain the exclusive file lock. +// It's recommended that TryLock() be used over this function. +// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already exclusive-locked, this function short-circuits and +// returns immediately assuming it can take the mutex lock. +// +// If the *Flock has a shared lock (RLock), +// this may transparently replace the shared lock with an exclusive lock on some UNIX-like operating systems. +// Be careful when using exclusive locks in conjunction with shared locks (RLock()), +// because calling Unlock() may accidentally release the exclusive lock that was once a shared lock. +func (f *Flock) Lock() error { + return f.lock(&f.l, writeLock) +} + +// RLock is a blocking call to try and take a shared file lock. +// It will wait until it is able to obtain the shared file lock. +// It's recommended that TryRLock() be used over this function. +// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already shared-locked, this function short-circuits and +// returns immediately assuming it can take the mutex lock. +func (f *Flock) RLock() error { + return f.lock(&f.r, readLock) +} + +func (f *Flock) lock(locked *bool, flag lockType) error { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return nil + } + + if f.fh == nil { + if err := f.setFh(f.flag); err != nil { + return err + } + + defer f.ensureFhState() + } + + _, err := f.doLock(waitLock, flag, true) + if err != nil { + return err + } + + *locked = true + + return nil +} + +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L48 +func (f *Flock) doLock(cmd cmdType, lt lockType, blocking bool) (bool, error) { + // POSIX locks apply per inode and process, + // and the lock for an inode is released when *any* descriptor for that inode is closed. + // So we need to synchronize access to each inode internally, + // and must serialize lock and unlock calls that refer to the same inode through different descriptors. + fi, err := f.fh.Stat() + if err != nil { + return false, err + } + + // Note(ldez): don't replace `syscall.Stat_t` by `unix.Stat_t` because `FileInfo.Sys()` returns `syscall.Stat_t` + ino := fi.Sys().(*syscall.Stat_t).Ino + + mu.Lock() + + if i, dup := inodes[f]; dup && i != ino { + mu.Unlock() + return false, &fs.PathError{ + Op: lt.String(), + Path: f.Path(), + Err: errors.New("inode for file changed since last Lock or RLock"), + } + } + + inodes[f] = ino + + var wait chan *Flock + + l := locks[ino] + + switch { + case l.owner == f: + // This file already owns the lock, but the call may change its lock type. + case l.owner == nil: + // No owner: it's ours now. + l.owner = f + + case !blocking: + // Already owned: cannot take the lock. + mu.Unlock() + return false, nil + + default: + // Already owned: add a channel to wait on. + wait = make(chan *Flock) + l.queue = append(l.queue, wait) + } + + locks[ino] = l + + mu.Unlock() + + if wait != nil { + wait <- f + } + + // Spurious EDEADLK errors arise on platforms that compute deadlock graphs at + // the process, rather than thread, level. Consider processes P and Q, with + // threads P.1, P.2, and Q.3. The following trace is NOT a deadlock, but will be + // reported as a deadlock on systems that consider only process granularity: + // + // P.1 locks file A. + // Q.3 locks file B. + // Q.3 blocks on file A. + // P.2 blocks on file B. (This is erroneously reported as a deadlock.) + // P.1 unlocks file A. + // Q.3 unblocks and locks file A. + // Q.3 unlocks files A and B. + // P.2 unblocks and locks file B. + // P.2 unlocks file B. + // + // These spurious errors were observed in practice on AIX and Solaris in + // cmd/go: see https://golang.org/issue/32817. + // + // We work around this bug by treating EDEADLK as always spurious. If there + // really is a lock-ordering bug between the interacting processes, it will + // become a livelock instead, but that's not appreciably worse than if we had + // a proper flock implementation (which generally does not even attempt to + // diagnose deadlocks). + // + // In the above example, that changes the trace to: + // + // P.1 locks file A. + // Q.3 locks file B. + // Q.3 blocks on file A. + // P.2 spuriously fails to lock file B and goes to sleep. + // P.1 unlocks file A. + // Q.3 unblocks and locks file A. + // Q.3 unlocks files A and B. + // P.2 wakes up and locks file B. + // P.2 unlocks file B. + // + // We know that the retry loop will not introduce a *spurious* livelock + // because, according to the POSIX specification, EDEADLK is only to be + // returned when “the lock is blocked by a lock from another process”. + // If that process is blocked on some lock that we are holding, then the + // resulting livelock is due to a real deadlock (and would manifest as such + // when using, for example, the flock implementation of this package). + // If the other process is *not* blocked on some other lock that we are + // holding, then it will eventually release the requested lock. + + nextSleep := 1 * time.Millisecond + const maxSleep = 500 * time.Millisecond + for { + err = setlkw(f.fh.Fd(), cmd, lt) + if !errors.Is(err, unix.EDEADLK) { + break + } + + time.Sleep(nextSleep) + + nextSleep += nextSleep + if nextSleep > maxSleep { + nextSleep = maxSleep + } + // Apply 10% jitter to avoid synchronizing collisions when we finally unblock. + nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep)) + } + + if err != nil { + f.doUnlock() + + if cmd == tryLock && errors.Is(err, unix.EACCES) { + return false, nil + } + + return false, &fs.PathError{ + Op: lt.String(), + Path: f.Path(), + Err: err, + } + } + + return true, nil +} + +func (f *Flock) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + // If we aren't locked or if the lockfile instance is nil + // just return a nil error because we are unlocked. + if (!f.l && !f.r) || f.fh == nil { + return nil + } + + if err := f.doUnlock(); err != nil { + return err + } + + f.reset() + + return nil +} + +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L163 +func (f *Flock) doUnlock() (err error) { + var owner *Flock + + mu.Lock() + + ino, ok := inodes[f] + if ok { + owner = locks[ino].owner + } + + mu.Unlock() + + if owner == f { + err = setlkw(f.fh.Fd(), waitLock, unix.F_UNLCK) + } + + mu.Lock() + + l := locks[ino] + + if len(l.queue) == 0 { + // No waiters: remove the map entry. + delete(locks, ino) + } else { + // The first waiter is sending us their file now. + // Receive it and update the queue. + l.owner = <-l.queue[0] + l.queue = l.queue[1:] + locks[ino] = l + } + + delete(inodes, f) + + mu.Unlock() + + return err +} + +// TryLock is the preferred function for taking an exclusive file lock. +// This function takes an RW-mutex lock before it tries to lock the file, +// so there is the possibility that this function may block for a short time +// if another goroutine is trying to take any action. +// +// The actual file lock is non-blocking. +// If we are unable to get the exclusive file lock, +// the function will return false instead of waiting for the lock. +// If we get the lock, we also set the *Flock instance as being exclusive-locked. +func (f *Flock) TryLock() (bool, error) { + return f.try(&f.l, writeLock) +} + +// TryRLock is the preferred function for taking a shared file lock. +// This function takes an RW-mutex lock before it tries to lock the file, +// so there is the possibility that this function may block for a short time +// if another goroutine is trying to take any action. +// +// The actual file lock is non-blocking. +// If we are unable to get the shared file lock, +// the function will return false instead of waiting for the lock. +// If we get the lock, we also set the *Flock instance as being share-locked. +func (f *Flock) TryRLock() (bool, error) { + return f.try(&f.r, readLock) +} + +func (f *Flock) try(locked *bool, flag lockType) (bool, error) { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return true, nil + } + + if f.fh == nil { + if err := f.setFh(f.flag); err != nil { + return false, err + } + + defer f.ensureFhState() + } + + hasLock, err := f.doLock(tryLock, flag, false) + if err != nil { + return false, err + } + + *locked = hasLock + + return hasLock, nil +} + +// setlkw calls FcntlFlock with cmd for the entire file indicated by fd. +// https://github.com/golang/go/blob/09aeb6e33ab426eff4676a3baf694d5a3019e9fc/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go#L198 +func setlkw(fd uintptr, cmd cmdType, lt lockType) error { + for { + err := unix.FcntlFlock(fd, int(cmd), &unix.Flock_t{ + Type: int16(lt), + Whence: io.SeekStart, + Start: 0, + Len: 0, // All bytes. + }) + if !errors.Is(err, unix.EINTR) { + return err + } + } +} diff --git a/vendor/github.com/gofrs/flock/flock_windows.go b/vendor/github.com/gofrs/flock/flock_windows.go new file mode 100644 index 00000000000..aa144f156e9 --- /dev/null +++ b/vendor/github.com/gofrs/flock/flock_windows.go @@ -0,0 +1,160 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Copyright 2018-2025 The Gofrs. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +//go:build windows + +package flock + +import ( + "errors" + + "golang.org/x/sys/windows" +) + +// Use of 0x00000000 for the shared lock is a guess based on some the MS Windows `LockFileEX` docs, +// which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as: +// +// > The function requests an exclusive lock. Otherwise, it requests a shared lock. +// +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx +const winLockfileSharedLock = 0x00000000 + +// ErrorLockViolation is the error code returned from the Windows syscall when a lock would block, +// and you ask to fail immediately. +// +//nolint:errname // It should be renamed to `ErrLockViolation`. +const ErrorLockViolation windows.Errno = 0x21 // 33 + +// Lock is a blocking call to try and take an exclusive file lock. +// It will wait until it is able to obtain the exclusive file lock. +// It's recommended that TryLock() be used over this function. +// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already locked, this function short-circuits and +// returns immediately assuming it can take the mutex lock. +func (f *Flock) Lock() error { + return f.lock(&f.l, windows.LOCKFILE_EXCLUSIVE_LOCK) +} + +// RLock is a blocking call to try and take a shared file lock. +// It will wait until it is able to obtain the shared file lock. +// It's recommended that TryRLock() be used over this function. +// This function may block the ability to query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already locked, this function short-circuits and +// returns immediately assuming it can take the mutex lock. +func (f *Flock) RLock() error { + return f.lock(&f.r, winLockfileSharedLock) +} + +func (f *Flock) lock(locked *bool, flag uint32) error { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return nil + } + + if f.fh == nil { + if err := f.setFh(f.flag); err != nil { + return err + } + + defer f.ensureFhState() + } + + err := windows.LockFileEx(windows.Handle(f.fh.Fd()), flag, 0, 1, 0, &windows.Overlapped{}) + if err != nil && !errors.Is(err, windows.Errno(0)) { + return err + } + + *locked = true + + return nil +} + +// Unlock is a function to unlock the file. +// This file takes a RW-mutex lock, +// so while it is running the Locked() and RLocked() functions will be blocked. +// +// This function short-circuits if we are unlocked already. +// If not, it calls UnlockFileEx() on the file and closes the file descriptor. +// It does not remove the file from disk. +// It's up to your application to do. +func (f *Flock) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + // if we aren't locked or if the lockfile instance is nil + // just return a nil error because we are unlocked + if (!f.l && !f.r) || f.fh == nil { + return nil + } + + // mark the file as unlocked + err := windows.UnlockFileEx(windows.Handle(f.fh.Fd()), 0, 1, 0, &windows.Overlapped{}) + if err != nil && !errors.Is(err, windows.Errno(0)) { + return err + } + + f.reset() + + return nil +} + +// TryLock is the preferred function for taking an exclusive file lock. +// This function does take a RW-mutex lock before it tries to lock the file, +// so there is the possibility that this function may block for a short time +// if another goroutine is trying to take any action. +// +// The actual file lock is non-blocking. +// If we are unable to get the exclusive file lock, +// the function will return false instead of waiting for the lock. +// If we get the lock, we also set the *Flock instance as being exclusive-locked. +func (f *Flock) TryLock() (bool, error) { + return f.try(&f.l, windows.LOCKFILE_EXCLUSIVE_LOCK) +} + +// TryRLock is the preferred function for taking a shared file lock. +// This function does take a RW-mutex lock before it tries to lock the file, +// so there is the possibility that this function may block for a short time if another goroutine is trying to take any action. +// +// The actual file lock is non-blocking. +// If we are unable to get the shared file lock, +// the function will return false instead of waiting for the lock. +// If we get the lock, we also set the *Flock instance as being shared-locked. +func (f *Flock) TryRLock() (bool, error) { + return f.try(&f.r, winLockfileSharedLock) +} + +func (f *Flock) try(locked *bool, flag uint32) (bool, error) { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return true, nil + } + + if f.fh == nil { + if err := f.setFh(f.flag); err != nil { + return false, err + } + + defer f.ensureFhState() + } + + err := windows.LockFileEx(windows.Handle(f.fh.Fd()), flag|windows.LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &windows.Overlapped{}) + if err != nil && !errors.Is(err, windows.Errno(0)) { + if errors.Is(err, ErrorLockViolation) || errors.Is(err, windows.ERROR_IO_PENDING) { + return false, nil + } + + return false, err + } + + *locked = true + + return true, nil +} diff --git a/vendor/github.com/google/go-querystring/LICENSE b/vendor/github.com/google/go-querystring/LICENSE new file mode 100644 index 00000000000..ae121a1e46d --- /dev/null +++ b/vendor/github.com/google/go-querystring/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013 Google. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/go-querystring/query/encode.go b/vendor/github.com/google/go-querystring/query/encode.go new file mode 100644 index 00000000000..91198f819a7 --- /dev/null +++ b/vendor/github.com/google/go-querystring/query/encode.go @@ -0,0 +1,357 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package query implements encoding of structs into URL query parameters. +// +// As a simple example: +// +// type Options struct { +// Query string `url:"q"` +// ShowAll bool `url:"all"` +// Page int `url:"page"` +// } +// +// opt := Options{ "foo", true, 2 } +// v, _ := query.Values(opt) +// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2" +// +// The exact mapping between Go values and url.Values is described in the +// documentation for the Values() function. +package query + +import ( + "bytes" + "fmt" + "net/url" + "reflect" + "strconv" + "strings" + "time" +) + +var timeType = reflect.TypeOf(time.Time{}) + +var encoderType = reflect.TypeOf(new(Encoder)).Elem() + +// Encoder is an interface implemented by any type that wishes to encode +// itself into URL values in a non-standard way. +type Encoder interface { + EncodeValues(key string, v *url.Values) error +} + +// Values returns the url.Values encoding of v. +// +// Values expects to be passed a struct, and traverses it recursively using the +// following encoding rules. +// +// Each exported struct field is encoded as a URL parameter unless +// +// - the field's tag is "-", or +// - the field is empty and its tag specifies the "omitempty" option +// +// The empty values are false, 0, any nil pointer or interface value, any array +// slice, map, or string of length zero, and any type (such as time.Time) that +// returns true for IsZero(). +// +// The URL parameter name defaults to the struct field name but can be +// specified in the struct field's tag value. The "url" key in the struct +// field's tag value is the key name, followed by an optional comma and +// options. For example: +// +// // Field is ignored by this package. +// Field int `url:"-"` +// +// // Field appears as URL parameter "myName". +// Field int `url:"myName"` +// +// // Field appears as URL parameter "myName" and the field is omitted if +// // its value is empty +// Field int `url:"myName,omitempty"` +// +// // Field appears as URL parameter "Field" (the default), but the field +// // is skipped if empty. Note the leading comma. +// Field int `url:",omitempty"` +// +// For encoding individual field values, the following type-dependent rules +// apply: +// +// Boolean values default to encoding as the strings "true" or "false". +// Including the "int" option signals that the field should be encoded as the +// strings "1" or "0". +// +// time.Time values default to encoding as RFC3339 timestamps. Including the +// "unix" option signals that the field should be encoded as a Unix time (see +// time.Unix()). The "unixmilli" and "unixnano" options will encode the number +// of milliseconds and nanoseconds, respectively, since January 1, 1970 (see +// time.UnixNano()). Including the "layout" struct tag (separate from the +// "url" tag) will use the value of the "layout" tag as a layout passed to +// time.Format. For example: +// +// // Encode a time.Time as YYYY-MM-DD +// Field time.Time `layout:"2006-01-02"` +// +// Slice and Array values default to encoding as multiple URL values of the +// same name. Including the "comma" option signals that the field should be +// encoded as a single comma-delimited value. Including the "space" option +// similarly encodes the value as a single space-delimited string. Including +// the "semicolon" option will encode the value as a semicolon-delimited string. +// Including the "brackets" option signals that the multiple URL values should +// have "[]" appended to the value name. "numbered" will append a number to +// the end of each incidence of the value name, example: +// name0=value0&name1=value1, etc. Including the "del" struct tag (separate +// from the "url" tag) will use the value of the "del" tag as the delimiter. +// For example: +// +// // Encode a slice of bools as ints ("1" for true, "0" for false), +// // separated by exclamation points "!". +// Field []bool `url:",int" del:"!"` +// +// Anonymous struct fields are usually encoded as if their inner exported +// fields were fields in the outer struct, subject to the standard Go +// visibility rules. An anonymous struct field with a name given in its URL +// tag is treated as having that name, rather than being anonymous. +// +// Non-nil pointer values are encoded as the value pointed to. +// +// Nested structs are encoded including parent fields in value names for +// scoping. e.g: +// +// "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO" +// +// All other values are encoded using their default string representation. +// +// Multiple fields that encode to the same URL parameter name will be included +// as multiple URL values of the same name. +func Values(v interface{}) (url.Values, error) { + values := make(url.Values) + val := reflect.ValueOf(v) + for val.Kind() == reflect.Ptr { + if val.IsNil() { + return values, nil + } + val = val.Elem() + } + + if v == nil { + return values, nil + } + + if val.Kind() != reflect.Struct { + return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind()) + } + + err := reflectValue(values, val, "") + return values, err +} + +// reflectValue populates the values parameter from the struct fields in val. +// Embedded structs are followed recursively (using the rules defined in the +// Values function documentation) breadth-first. +func reflectValue(values url.Values, val reflect.Value, scope string) error { + var embedded []reflect.Value + + typ := val.Type() + for i := 0; i < typ.NumField(); i++ { + sf := typ.Field(i) + if sf.PkgPath != "" && !sf.Anonymous { // unexported + continue + } + + sv := val.Field(i) + tag := sf.Tag.Get("url") + if tag == "-" { + continue + } + name, opts := parseTag(tag) + + if name == "" { + if sf.Anonymous { + v := reflect.Indirect(sv) + if v.IsValid() && v.Kind() == reflect.Struct { + // save embedded struct for later processing + embedded = append(embedded, v) + continue + } + } + + name = sf.Name + } + + if scope != "" { + name = scope + "[" + name + "]" + } + + if opts.Contains("omitempty") && isEmptyValue(sv) { + continue + } + + if sv.Type().Implements(encoderType) { + // if sv is a nil pointer and the custom encoder is defined on a non-pointer + // method receiver, set sv to the zero value of the underlying type + if !reflect.Indirect(sv).IsValid() && sv.Type().Elem().Implements(encoderType) { + sv = reflect.New(sv.Type().Elem()) + } + + m := sv.Interface().(Encoder) + if err := m.EncodeValues(name, &values); err != nil { + return err + } + continue + } + + // recursively dereference pointers. break on nil pointers + for sv.Kind() == reflect.Ptr { + if sv.IsNil() { + break + } + sv = sv.Elem() + } + + if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array { + var del string + if opts.Contains("comma") { + del = "," + } else if opts.Contains("space") { + del = " " + } else if opts.Contains("semicolon") { + del = ";" + } else if opts.Contains("brackets") { + name = name + "[]" + } else { + del = sf.Tag.Get("del") + } + + if del != "" { + s := new(bytes.Buffer) + first := true + for i := 0; i < sv.Len(); i++ { + if first { + first = false + } else { + s.WriteString(del) + } + s.WriteString(valueString(sv.Index(i), opts, sf)) + } + values.Add(name, s.String()) + } else { + for i := 0; i < sv.Len(); i++ { + k := name + if opts.Contains("numbered") { + k = fmt.Sprintf("%s%d", name, i) + } + values.Add(k, valueString(sv.Index(i), opts, sf)) + } + } + continue + } + + if sv.Type() == timeType { + values.Add(name, valueString(sv, opts, sf)) + continue + } + + if sv.Kind() == reflect.Struct { + if err := reflectValue(values, sv, name); err != nil { + return err + } + continue + } + + values.Add(name, valueString(sv, opts, sf)) + } + + for _, f := range embedded { + if err := reflectValue(values, f, scope); err != nil { + return err + } + } + + return nil +} + +// valueString returns the string representation of a value. +func valueString(v reflect.Value, opts tagOptions, sf reflect.StructField) string { + for v.Kind() == reflect.Ptr { + if v.IsNil() { + return "" + } + v = v.Elem() + } + + if v.Kind() == reflect.Bool && opts.Contains("int") { + if v.Bool() { + return "1" + } + return "0" + } + + if v.Type() == timeType { + t := v.Interface().(time.Time) + if opts.Contains("unix") { + return strconv.FormatInt(t.Unix(), 10) + } + if opts.Contains("unixmilli") { + return strconv.FormatInt((t.UnixNano() / 1e6), 10) + } + if opts.Contains("unixnano") { + return strconv.FormatInt(t.UnixNano(), 10) + } + if layout := sf.Tag.Get("layout"); layout != "" { + return t.Format(layout) + } + return t.Format(time.RFC3339) + } + + return fmt.Sprint(v.Interface()) +} + +// isEmptyValue checks if a value should be considered empty for the purposes +// of omitting fields with the "omitempty" option. +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + + type zeroable interface { + IsZero() bool + } + + if z, ok := v.Interface().(zeroable); ok { + return z.IsZero() + } + + return false +} + +// tagOptions is the string following a comma in a struct field's "url" tag, or +// the empty string. It does not include the leading comma. +type tagOptions []string + +// parseTag splits a struct field's url tag into its name and comma-separated +// options. +func parseTag(tag string) (string, tagOptions) { + s := strings.Split(tag, ",") + return s[0], s[1:] +} + +// Contains checks whether the tagOptions contains the specified option. +func (o tagOptions) Contains(option string) bool { + for _, s := range o { + if s == option { + return true + } + } + return false +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/LICENSE b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/LICENSE new file mode 100644 index 00000000000..9d509be21a7 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/auth.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/auth.go new file mode 100644 index 00000000000..8a964d5d2e8 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/auth.go @@ -0,0 +1,347 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "fmt" + "net/url" + "sort" + "strings" + "time" +) + +func setURLWithPolicy(bucketName, canonicalizedUrl string) string { + if strings.HasPrefix(canonicalizedUrl, "/"+bucketName+"/") { + canonicalizedUrl = canonicalizedUrl[len("/"+bucketName+"/"):] + } else if strings.HasPrefix(canonicalizedUrl, "/"+bucketName) { + canonicalizedUrl = canonicalizedUrl[len("/"+bucketName):] + } + return canonicalizedUrl +} + +func (obsClient ObsClient) doAuthTemporary(method, bucketName, objectKey string, policy string, params map[string]string, + headers map[string][]string, expires int64) (requestURL string, err error) { + sh := obsClient.getSecurity() + isAkSkEmpty := sh.ak == "" || sh.sk == "" + if isAkSkEmpty == false && sh.securityToken != "" { + if obsClient.conf.signature == SignatureObs { + params[HEADER_STS_TOKEN_OBS] = sh.securityToken + } else { + params[HEADER_STS_TOKEN_AMZ] = sh.securityToken + } + } + + if policy != "" { + objectKey = "" + } + + requestURL, canonicalizedURL := obsClient.conf.formatUrls(bucketName, objectKey, params, true) + parsedRequestURL, err := url.Parse(requestURL) + if err != nil { + return "", err + } + encodeHeaders(headers) + hostName := parsedRequestURL.Host + + isV4 := obsClient.conf.signature == SignatureV4 + prepareHostAndDate(headers, hostName, isV4) + + if isAkSkEmpty { + doLog(LEVEL_WARN, "No ak/sk provided, skip to construct authorization") + } else { + if isV4 { + date, parseDateErr := time.Parse(RFC1123_FORMAT, headers[HEADER_DATE_CAMEL][0]) + if parseDateErr != nil { + doLog(LEVEL_WARN, "Failed to parse date with reason: %v", parseDateErr) + return "", parseDateErr + } + delete(headers, HEADER_DATE_CAMEL) + shortDate := date.Format(SHORT_DATE_FORMAT) + longDate := date.Format(LONG_DATE_FORMAT) + if len(headers[HEADER_HOST_CAMEL]) != 0 { + index := strings.LastIndex(headers[HEADER_HOST_CAMEL][0], ":") + if index != -1 { + port := headers[HEADER_HOST_CAMEL][0][index+1:] + if port == "80" || port == "443" { + headers[HEADER_HOST_CAMEL] = []string{headers[HEADER_HOST_CAMEL][0][:index]} + } + } + + } + + signedHeaders, _headers := getSignedHeaders(headers) + + credential, scope := getCredential(sh.ak, obsClient.conf.region, shortDate) + params[PARAM_ALGORITHM_AMZ_CAMEL] = V4_HASH_PREFIX + params[PARAM_CREDENTIAL_AMZ_CAMEL] = credential + params[PARAM_DATE_AMZ_CAMEL] = longDate + params[PARAM_EXPIRES_AMZ_CAMEL] = Int64ToString(expires) + params[PARAM_SIGNEDHEADERS_AMZ_CAMEL] = strings.Join(signedHeaders, ";") + + requestURL, canonicalizedURL = obsClient.conf.formatUrls(bucketName, objectKey, params, true) + parsedRequestURL, _err := url.Parse(requestURL) + if _err != nil { + return "", _err + } + + stringToSign := getV4StringToSign(method, canonicalizedURL, parsedRequestURL.RawQuery, scope, longDate, UNSIGNED_PAYLOAD, signedHeaders, _headers) + signature := getSignature(stringToSign, sh.sk, obsClient.conf.region, shortDate) + + requestURL += fmt.Sprintf("&%s=%s", PARAM_SIGNATURE_AMZ_CAMEL, UrlEncode(signature, false)) + + } else { + originDate := headers[HEADER_DATE_CAMEL][0] + date, parseDateErr := time.Parse(RFC1123_FORMAT, originDate) + if parseDateErr != nil { + doLog(LEVEL_WARN, "Failed to parse date with reason: %v", parseDateErr) + return "", parseDateErr + } + expires += date.Unix() + if policy == "" { + headers[HEADER_DATE_CAMEL] = []string{Int64ToString(expires)} + } else { + policy = Base64Encode([]byte(policy)) + headers[HEADER_DATE_CAMEL] = []string{policy} + canonicalizedURL = setURLWithPolicy(bucketName, canonicalizedURL) + } + + stringToSign := getV2StringToSign(method, canonicalizedURL, headers, obsClient.conf.signature == SignatureObs) + signature := UrlEncode(Base64Encode(HmacSha1([]byte(sh.sk), []byte(stringToSign))), false) + if strings.Index(requestURL, "?") < 0 { + requestURL += "?" + } else { + requestURL += "&" + } + delete(headers, HEADER_DATE_CAMEL) + + if obsClient.conf.signature != SignatureObs { + requestURL += "AWS" + } + if policy == "" { + requestURL += fmt.Sprintf("AccessKeyId=%s&Expires=%d&Signature=%s", UrlEncode(sh.ak, false), + expires, signature) + return + + } + requestURL += fmt.Sprintf("AccessKeyId=%s&Policy=%s&Signature=%s", UrlEncode(sh.ak, false), + UrlEncode(policy, false), signature) + } + } + + return +} + +func (obsClient ObsClient) doAuth(method, bucketName, objectKey string, params map[string]string, + headers map[string][]string, hostName string) (requestURL string, err error) { + sh := obsClient.getSecurity() + isAkSkEmpty := sh.ak == "" || sh.sk == "" + if isAkSkEmpty == false && sh.securityToken != "" { + if obsClient.conf.signature == SignatureObs { + headers[HEADER_STS_TOKEN_OBS] = []string{sh.securityToken} + } else { + headers[HEADER_STS_TOKEN_AMZ] = []string{sh.securityToken} + } + } + isObs := obsClient.conf.signature == SignatureObs + requestURL, canonicalizedURL := obsClient.conf.formatUrls(bucketName, objectKey, params, true) + parsedRequestURL, err := url.Parse(requestURL) + if err != nil { + return "", err + } + encodeHeaders(headers) + + if hostName == "" { + hostName = parsedRequestURL.Host + } + + isV4 := obsClient.conf.signature == SignatureV4 + prepareHostAndDate(headers, hostName, isV4) + + if isAkSkEmpty { + doLog(LEVEL_WARN, "No ak/sk provided, skip to construct authorization") + } else { + ak := sh.ak + sk := sh.sk + var authorization string + if isV4 { + headers[HEADER_CONTENT_SHA256_AMZ] = []string{UNSIGNED_PAYLOAD} + ret := v4Auth(ak, sk, obsClient.conf.region, method, canonicalizedURL, parsedRequestURL.RawQuery, headers) + authorization = fmt.Sprintf("%s Credential=%s,SignedHeaders=%s,Signature=%s", V4_HASH_PREFIX, ret["Credential"], ret["SignedHeaders"], ret["Signature"]) + } else { + ret := v2Auth(ak, sk, method, canonicalizedURL, headers, isObs) + hashPrefix := V2_HASH_PREFIX + if isObs { + hashPrefix = OBS_HASH_PREFIX + } + authorization = fmt.Sprintf("%s %s:%s", hashPrefix, ak, ret["Signature"]) + } + headers[HEADER_AUTH_CAMEL] = []string{authorization} + } + return +} + +func prepareHostAndDate(headers map[string][]string, hostName string, isV4 bool) { + headers[HEADER_HOST_CAMEL] = []string{hostName} + if date, ok := headers[HEADER_DATE_AMZ]; ok { + flag := false + if len(date) == 1 { + if isV4 { + if t, err := time.Parse(LONG_DATE_FORMAT, date[0]); err == nil { + headers[HEADER_DATE_CAMEL] = []string{FormatUtcToRfc1123(t)} + flag = true + } + } else { + if strings.HasSuffix(date[0], "GMT") { + headers[HEADER_DATE_CAMEL] = []string{date[0]} + flag = true + } + } + } + if !flag { + delete(headers, HEADER_DATE_AMZ) + } + } + if _, ok := headers[HEADER_DATE_CAMEL]; !ok { + headers[HEADER_DATE_CAMEL] = []string{FormatUtcToRfc1123(time.Now().UTC())} + } + +} + +func encodeHeaders(headers map[string][]string) { + for key, values := range headers { + for index, value := range values { + values[index] = UrlEncode(value, true) + } + headers[key] = values + } +} + +func prepareDateHeader(dataHeader, dateCamelHeader string, headers, _headers map[string][]string) { + if _, ok := _headers[HEADER_DATE_CAMEL]; ok { + if _, ok := _headers[dataHeader]; ok { + _headers[HEADER_DATE_CAMEL] = []string{""} + } else if _, ok := headers[dateCamelHeader]; ok { + _headers[HEADER_DATE_CAMEL] = []string{""} + } + } else if _, ok := _headers[strings.ToLower(HEADER_DATE_CAMEL)]; ok { + if _, ok := _headers[dataHeader]; ok { + _headers[HEADER_DATE_CAMEL] = []string{""} + } else if _, ok := headers[dateCamelHeader]; ok { + _headers[HEADER_DATE_CAMEL] = []string{""} + } + } +} + +func getStringToSign(keys []string, isObs bool, _headers map[string][]string) []string { + stringToSign := make([]string, 0, len(keys)) + for _, key := range keys { + var value string + prefixHeader := HEADER_PREFIX + prefixMetaHeader := HEADER_PREFIX_META + if isObs { + prefixHeader = HEADER_PREFIX_OBS + prefixMetaHeader = HEADER_PREFIX_META_OBS + } + if strings.HasPrefix(key, prefixHeader) { + if strings.HasPrefix(key, prefixMetaHeader) { + for index, v := range _headers[key] { + value += strings.TrimSpace(v) + if index != len(_headers[key])-1 { + value += "," + } + } + } else { + value = strings.Join(_headers[key], ",") + } + value = fmt.Sprintf("%s:%s", key, value) + } else { + value = strings.Join(_headers[key], ",") + } + stringToSign = append(stringToSign, value) + } + return stringToSign +} + +func attachHeaders(headers map[string][]string, isObs bool) string { + length := len(headers) + _headers := make(map[string][]string, length) + keys := make([]string, 0, length) + + for key, value := range headers { + _key := strings.ToLower(strings.TrimSpace(key)) + if _key != "" { + prefixheader := HEADER_PREFIX + if isObs { + prefixheader = HEADER_PREFIX_OBS + } + if _key == "content-md5" || _key == "content-type" || _key == "date" || strings.HasPrefix(_key, prefixheader) { + keys = append(keys, _key) + _headers[_key] = value + } + } else { + delete(headers, key) + } + } + + for _, interestedHeader := range interestedHeaders { + if _, ok := _headers[interestedHeader]; !ok { + _headers[interestedHeader] = []string{""} + keys = append(keys, interestedHeader) + } + } + dateCamelHeader := PARAM_DATE_AMZ_CAMEL + dataHeader := HEADER_DATE_AMZ + if isObs { + dateCamelHeader = PARAM_DATE_OBS_CAMEL + dataHeader = HEADER_DATE_OBS + } + prepareDateHeader(dataHeader, dateCamelHeader, headers, _headers) + + sort.Strings(keys) + stringToSign := getStringToSign(keys, isObs, _headers) + return strings.Join(stringToSign, "\n") +} + +func getScope(region, shortDate string) string { + return fmt.Sprintf("%s/%s/%s/%s", shortDate, region, V4_SERVICE_NAME, V4_SERVICE_SUFFIX) +} + +func getCredential(ak, region, shortDate string) (string, string) { + scope := getScope(region, shortDate) + return fmt.Sprintf("%s/%s", ak, scope), scope +} + +func getSignedHeaders(headers map[string][]string) ([]string, map[string][]string) { + length := len(headers) + _headers := make(map[string][]string, length) + signedHeaders := make([]string, 0, length) + for key, value := range headers { + _key := strings.ToLower(strings.TrimSpace(key)) + if _key != "" { + signedHeaders = append(signedHeaders, _key) + _headers[_key] = value + } else { + delete(headers, key) + } + } + sort.Strings(signedHeaders) + return signedHeaders, _headers +} + +func getSignature(stringToSign, sk, region, shortDate string) string { + key := HmacSha256([]byte(V4_HASH_PRE+sk), []byte(shortDate)) + key = HmacSha256(key, []byte(region)) + key = HmacSha256(key, []byte(V4_SERVICE_NAME)) + key = HmacSha256(key, []byte(V4_SERVICE_SUFFIX)) + return Hex(HmacSha256(key, []byte(stringToSign))) +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV2.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV2.go new file mode 100644 index 00000000000..1812061f027 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV2.go @@ -0,0 +1,55 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "strings" +) + +func getV2StringToSign(method, canonicalizedURL string, headers map[string][]string, isObs bool) string { + stringToSign := strings.Join([]string{method, "\n", attachHeaders(headers, isObs), "\n", canonicalizedURL}, "") + + var isSecurityToken bool + var securityToken []string + if isObs { + securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_OBS] + } else { + securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_AMZ] + } + var query []string + if !isSecurityToken { + parmas := strings.Split(canonicalizedURL, "?") + if len(parmas) > 1 { + query = strings.Split(parmas[1], "&") + for _, value := range query { + if strings.HasPrefix(value, HEADER_STS_TOKEN_AMZ+"=") || strings.HasPrefix(value, HEADER_STS_TOKEN_OBS+"=") { + if value[len(HEADER_STS_TOKEN_AMZ)+1:] != "" { + securityToken = []string{value[len(HEADER_STS_TOKEN_AMZ)+1:]} + isSecurityToken = true + } + } + } + } + } + logStringToSign := stringToSign + if isSecurityToken && len(securityToken) > 0 { + logStringToSign = strings.Replace(logStringToSign, securityToken[0], "******", -1) + } + doLog(LEVEL_DEBUG, "The v2 auth stringToSign:\n%s", logStringToSign) + return stringToSign +} + +func v2Auth(ak, sk, method, canonicalizedURL string, headers map[string][]string, isObs bool) map[string]string { + stringToSign := getV2StringToSign(method, canonicalizedURL, headers, isObs) + return map[string]string{"Signature": Base64Encode(HmacSha1([]byte(sk), []byte(stringToSign)))} +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV4.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV4.go new file mode 100644 index 00000000000..258b342ba45 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/authV4.go @@ -0,0 +1,136 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "strings" + "time" +) + +func getV4StringToSign(method, canonicalizedURL, queryURL, scope, longDate, payload string, signedHeaders []string, headers map[string][]string) string { + canonicalRequest := make([]string, 0, 10+len(signedHeaders)*4) + canonicalRequest = append(canonicalRequest, method) + canonicalRequest = append(canonicalRequest, "\n") + canonicalRequest = append(canonicalRequest, canonicalizedURL) + canonicalRequest = append(canonicalRequest, "\n") + canonicalRequest = append(canonicalRequest, queryURL) + canonicalRequest = append(canonicalRequest, "\n") + + for _, signedHeader := range signedHeaders { + values, _ := headers[signedHeader] + for _, value := range values { + canonicalRequest = append(canonicalRequest, signedHeader) + canonicalRequest = append(canonicalRequest, ":") + canonicalRequest = append(canonicalRequest, value) + canonicalRequest = append(canonicalRequest, "\n") + } + } + canonicalRequest = append(canonicalRequest, "\n") + canonicalRequest = append(canonicalRequest, strings.Join(signedHeaders, ";")) + canonicalRequest = append(canonicalRequest, "\n") + canonicalRequest = append(canonicalRequest, payload) + + _canonicalRequest := strings.Join(canonicalRequest, "") + + var isSecurityToken bool + var securityToken []string + if securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_OBS]; !isSecurityToken { + securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_AMZ] + } + var query []string + if !isSecurityToken { + query = strings.Split(queryURL, "&") + for _, value := range query { + if strings.HasPrefix(value, HEADER_STS_TOKEN_AMZ+"=") || strings.HasPrefix(value, HEADER_STS_TOKEN_OBS+"=") { + if value[len(HEADER_STS_TOKEN_AMZ)+1:] != "" { + securityToken = []string{value[len(HEADER_STS_TOKEN_AMZ)+1:]} + isSecurityToken = true + } + } + } + } + logCanonicalRequest := _canonicalRequest + if isSecurityToken && len(securityToken) > 0 { + logCanonicalRequest = strings.Replace(logCanonicalRequest, securityToken[0], "******", -1) + } + doLog(LEVEL_DEBUG, "The v4 auth canonicalRequest:\n%s", logCanonicalRequest) + + stringToSign := make([]string, 0, 7) + stringToSign = append(stringToSign, V4_HASH_PREFIX) + stringToSign = append(stringToSign, "\n") + stringToSign = append(stringToSign, longDate) + stringToSign = append(stringToSign, "\n") + stringToSign = append(stringToSign, scope) + stringToSign = append(stringToSign, "\n") + stringToSign = append(stringToSign, HexSha256([]byte(_canonicalRequest))) + + _stringToSign := strings.Join(stringToSign, "") + + return _stringToSign +} + +// V4Auth is a wrapper for v4Auth +func V4Auth(ak, sk, region, method, canonicalizedURL, queryURL string, headers map[string][]string) map[string]string { + return v4Auth(ak, sk, region, method, canonicalizedURL, queryURL, headers) +} + +func v4Auth(ak, sk, region, method, canonicalizedURL, queryURL string, headers map[string][]string) map[string]string { + var t time.Time + if val, ok := headers[HEADER_DATE_AMZ]; ok { + var err error + t, err = time.Parse(LONG_DATE_FORMAT, val[0]) + if err != nil { + t = time.Now().UTC() + } + } else if val, ok := headers[PARAM_DATE_AMZ_CAMEL]; ok { + var err error + t, err = time.Parse(LONG_DATE_FORMAT, val[0]) + if err != nil { + t = time.Now().UTC() + } + } else if val, ok := headers[HEADER_DATE_CAMEL]; ok { + var err error + t, err = time.Parse(RFC1123_FORMAT, val[0]) + if err != nil { + t = time.Now().UTC() + } + } else if val, ok := headers[strings.ToLower(HEADER_DATE_CAMEL)]; ok { + var err error + t, err = time.Parse(RFC1123_FORMAT, val[0]) + if err != nil { + t = time.Now().UTC() + } + } else { + t = time.Now().UTC() + } + shortDate := t.Format(SHORT_DATE_FORMAT) + longDate := t.Format(LONG_DATE_FORMAT) + + signedHeaders, _headers := getSignedHeaders(headers) + + credential, scope := getCredential(ak, region, shortDate) + + payload := UNSIGNED_PAYLOAD + if val, ok := headers[HEADER_CONTENT_SHA256_AMZ]; ok { + payload = val[0] + } + stringToSign := getV4StringToSign(method, canonicalizedURL, queryURL, scope, longDate, payload, signedHeaders, _headers) + + signature := getSignature(stringToSign, sk, region, shortDate) + + ret := make(map[string]string, 3) + ret["Credential"] = credential + ret["SignedHeaders"] = strings.Join(signedHeaders, ";") + ret["Signature"] = signature + return ret +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/callback.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/callback.go new file mode 100644 index 00000000000..1358e785ac8 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/callback.go @@ -0,0 +1,49 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "errors" + "io" +) + +type ICallbackReadCloser interface { + setCallbackReadCloser(body io.ReadCloser) +} + +func (output *PutObjectOutput) setCallbackReadCloser(body io.ReadCloser) { + output.CallbackBody.data = body +} + +func (output *CompleteMultipartUploadOutput) setCallbackReadCloser(body io.ReadCloser) { + output.CallbackBody.data = body +} + +// define CallbackBody +type CallbackBody struct { + data io.ReadCloser +} + +func (output CallbackBody) ReadCallbackBody(p []byte) (int, error) { + if output.data == nil { + return 0, errors.New("have no callback data") + } + return output.data.Read(p) +} + +func (output CallbackBody) CloseCallbackBody() error { + if output.data == nil { + return errors.New("have no callback data") + } + return output.data.Close() +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_base.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_base.go new file mode 100644 index 00000000000..aaa20738942 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_base.go @@ -0,0 +1,68 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "fmt" + "net/http" + "strings" +) + +// ObsClient defines OBS client. +type ObsClient struct { + conf *config + httpClient *http.Client +} + +// New creates a new ObsClient instance. +func New(ak, sk, endpoint string, configurers ...configurer) (*ObsClient, error) { + conf := &config{endpoint: endpoint} + conf.securityProviders = make([]securityProvider, 0, 3) + conf.securityProviders = append(conf.securityProviders, NewBasicSecurityProvider(ak, sk, "")) + + conf.maxRetryCount = -1 + conf.maxRedirectCount = -1 + for _, configurer := range configurers { + configurer(conf) + } + + if err := conf.initConfigWithDefault(); err != nil { + return nil, err + } + err := conf.getTransport() + if err != nil { + return nil, err + } + + if isWarnLogEnabled() { + info := make([]string, 3) + info[0] = fmt.Sprintf("[OBS SDK Version=%s", OBS_SDK_VERSION) + info[1] = fmt.Sprintf("Endpoint=%s", conf.endpoint) + accessMode := "Virtual Hosting" + if conf.pathStyle { + accessMode = "Path" + } + info[2] = fmt.Sprintf("Access Mode=%s]", accessMode) + doLog(LEVEL_WARN, strings.Join(info, "];[")) + } + + if conf.httpClient != nil { + doLog(LEVEL_DEBUG, "Create obsclient with config:\n%s\n", conf) + obsClient := &ObsClient{conf: conf, httpClient: conf.httpClient} + return obsClient, nil + } + + doLog(LEVEL_DEBUG, "Create obsclient with config:\n%s\n", conf) + obsClient := &ObsClient{conf: conf, httpClient: &http.Client{Transport: conf.transport, CheckRedirect: checkRedirectFunc}} + return obsClient, nil +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_bucket.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_bucket.go new file mode 100644 index 00000000000..2ee7a2fdaf7 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_bucket.go @@ -0,0 +1,869 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "errors" + "fmt" + "strings" +) + +func (obsClient ObsClient) DeleteBucketCustomDomain(input *DeleteBucketCustomDomainInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("DeleteBucketCustomDomainInput is nil") + } + + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketCustomDomain", HTTP_DELETE, input.Bucket, newSubResourceSerialV2(SubResourceCustomDomain, input.CustomDomain), output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) SetBucketCustomDomain(input *SetBucketCustomDomainInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketCustomDomainInput is nil") + } + + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketCustomDomain", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) GetBucketCustomDomain(bucketName string, extensions ...extensionOptions) (output *GetBucketCustomDomainOutput, err error) { + output = &GetBucketCustomDomainOutput{} + err = obsClient.doActionWithBucket("GetBucketCustomDomain", HTTP_GET, bucketName, newSubResourceSerial(SubResourceCustomDomain), output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) SetBucketMirrorBackToSource(input *SetBucketMirrorBackToSourceInput, extensions ...extensionOptions) (output *BaseModel, err error) { + + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketMirrorBackToSource", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) DeleteBucketMirrorBackToSource(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucketV2("DeleteBucketMirrorBackToSource", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourceMirrorBackToSource), output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) GetBucketMirrorBackToSource(bucketName string, extensions ...extensionOptions) (output *GetBucketMirrorBackToSourceOutput, err error) { + output = &GetBucketMirrorBackToSourceOutput{} + err = obsClient.doActionWithBucketV2("GetBucketMirrorBackToSource", HTTP_GET, bucketName, newSubResourceSerial(SubResourceMirrorBackToSource), output, extensions) + if err != nil { + output = nil + } + return +} + +// ListBuckets lists buckets. +// +// You can use this API to obtain the bucket list. In the list, bucket names are displayed in lexicographical order. +func (obsClient ObsClient) ListBuckets(input *ListBucketsInput, extensions ...extensionOptions) (output *ListBucketsOutput, err error) { + if input == nil { + input = &ListBucketsInput{} + } + output = &ListBucketsOutput{} + err = obsClient.doActionWithoutBucket("ListBuckets", HTTP_GET, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// CreateBucket creates a bucket. +// +// You can use this API to create a bucket and name it as you specify. The created bucket name must be unique in OBS. +func (obsClient ObsClient) CreateBucket(input *CreateBucketInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("CreateBucketInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("CreateBucket", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucket deletes a bucket. +// +// You can use this API to delete a bucket. The bucket to be deleted must be empty +// (containing no objects, noncurrent object versions, or part fragments). +func (obsClient ObsClient) DeleteBucket(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucket", HTTP_DELETE, bucketName, defaultSerializable, output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketStoragePolicy sets bucket storage class. +// +// You can use this API to set storage class for bucket. +func (obsClient ObsClient) SetBucketStoragePolicy(input *SetBucketStoragePolicyInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketStoragePolicyInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketStoragePolicy", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} +func (obsClient ObsClient) getBucketStoragePolicyS3(bucketName string, extensions []extensionOptions) (output *GetBucketStoragePolicyOutput, err error) { + output = &GetBucketStoragePolicyOutput{} + var outputS3 *getBucketStoragePolicyOutputS3 + outputS3 = &getBucketStoragePolicyOutputS3{} + err = obsClient.doActionWithBucket("GetBucketStoragePolicy", HTTP_GET, bucketName, newSubResourceSerial(SubResourceStoragePolicy), outputS3, extensions) + if err != nil { + output = nil + return + } + output.BaseModel = outputS3.BaseModel + output.StorageClass = fmt.Sprintf("%s", outputS3.StorageClass) + return +} + +func (obsClient ObsClient) getBucketStoragePolicyObs(bucketName string, extensions []extensionOptions) (output *GetBucketStoragePolicyOutput, err error) { + output = &GetBucketStoragePolicyOutput{} + var outputObs *getBucketStoragePolicyOutputObs + outputObs = &getBucketStoragePolicyOutputObs{} + err = obsClient.doActionWithBucket("GetBucketStoragePolicy", HTTP_GET, bucketName, newSubResourceSerial(SubResourceStorageClass), outputObs, extensions) + if err != nil { + output = nil + return + } + output.BaseModel = outputObs.BaseModel + output.StorageClass = outputObs.StorageClass + return +} + +// GetBucketStoragePolicy gets bucket storage class. +// +// You can use this API to obtain the storage class of a bucket. +func (obsClient ObsClient) GetBucketStoragePolicy(bucketName string, extensions ...extensionOptions) (output *GetBucketStoragePolicyOutput, err error) { + if obsClient.conf.signature == SignatureObs { + return obsClient.getBucketStoragePolicyObs(bucketName, extensions) + } + return obsClient.getBucketStoragePolicyS3(bucketName, extensions) +} + +// SetBucketQuota sets the bucket quota. +// +// You can use this API to set the bucket quota. A bucket quota must be expressed in bytes and the maximum value is 2^63-1. +func (obsClient ObsClient) SetBucketQuota(input *SetBucketQuotaInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketQuotaInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketQuota", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketQuota gets the bucket quota. +// +// You can use this API to obtain the bucket quota. Value 0 indicates that no upper limit is set for the bucket quota. +func (obsClient ObsClient) GetBucketQuota(bucketName string, extensions ...extensionOptions) (output *GetBucketQuotaOutput, err error) { + output = &GetBucketQuotaOutput{} + err = obsClient.doActionWithBucket("GetBucketQuota", HTTP_GET, bucketName, newSubResourceSerial(SubResourceQuota), output, extensions) + if err != nil { + output = nil + } + return +} + +// HeadBucket checks whether a bucket exists. +// +// You can use this API to check whether a bucket exists. +func (obsClient ObsClient) HeadBucket(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("HeadBucket", HTTP_HEAD, bucketName, defaultSerializable, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketMetadata gets the metadata of a bucket. +// +// You can use this API to send a HEAD request to a bucket to obtain the bucket +// metadata such as the storage class and CORS rules (if set). +func (obsClient ObsClient) GetBucketMetadata(input *GetBucketMetadataInput, extensions ...extensionOptions) (output *GetBucketMetadataOutput, err error) { + output = &GetBucketMetadataOutput{} + err = obsClient.doActionWithBucket("GetBucketMetadata", HTTP_HEAD, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } else { + ParseGetBucketMetadataOutput(output) + } + return +} + +func (obsClient ObsClient) GetBucketFSStatus(input *GetBucketFSStatusInput, extensions ...extensionOptions) (output *GetBucketFSStatusOutput, err error) { + output = &GetBucketFSStatusOutput{} + err = obsClient.doActionWithBucket("GetBucketFSStatus", HTTP_HEAD, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } else { + ParseGetBucketFSStatusOutput(output) + } + return +} + +// GetBucketStorageInfo gets storage information about a bucket. +// +// You can use this API to obtain storage information about a bucket, including the +// bucket size and number of objects in the bucket. +func (obsClient ObsClient) GetBucketStorageInfo(bucketName string, extensions ...extensionOptions) (output *GetBucketStorageInfoOutput, err error) { + output = &GetBucketStorageInfoOutput{} + err = obsClient.doActionWithBucket("GetBucketStorageInfo", HTTP_GET, bucketName, newSubResourceSerial(SubResourceStorageInfo), output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) getBucketLocationS3(bucketName string, extensions []extensionOptions) (output *GetBucketLocationOutput, err error) { + output = &GetBucketLocationOutput{} + var outputS3 *getBucketLocationOutputS3 + outputS3 = &getBucketLocationOutputS3{} + err = obsClient.doActionWithBucket("GetBucketLocation", HTTP_GET, bucketName, newSubResourceSerial(SubResourceLocation), outputS3, extensions) + if err != nil { + output = nil + } else { + output.BaseModel = outputS3.BaseModel + output.Location = outputS3.Location + } + return +} +func (obsClient ObsClient) getBucketLocationObs(bucketName string, extensions []extensionOptions) (output *GetBucketLocationOutput, err error) { + output = &GetBucketLocationOutput{} + var outputObs *getBucketLocationOutputObs + outputObs = &getBucketLocationOutputObs{} + err = obsClient.doActionWithBucket("GetBucketLocation", HTTP_GET, bucketName, newSubResourceSerial(SubResourceLocation), outputObs, extensions) + if err != nil { + output = nil + } else { + output.BaseModel = outputObs.BaseModel + output.Location = outputObs.Location + } + return +} + +// GetBucketLocation gets the location of a bucket. +// +// You can use this API to obtain the bucket location. +func (obsClient ObsClient) GetBucketLocation(bucketName string, extensions ...extensionOptions) (output *GetBucketLocationOutput, err error) { + if obsClient.conf.signature == SignatureObs { + return obsClient.getBucketLocationObs(bucketName, extensions) + } + return obsClient.getBucketLocationS3(bucketName, extensions) +} + +// SetBucketAcl sets the bucket ACL. +// +// You can use this API to set the ACL for a bucket. +func (obsClient ObsClient) SetBucketAcl(input *SetBucketAclInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketAclInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketAcl", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} +func (obsClient ObsClient) getBucketACLObs(bucketName string, extensions []extensionOptions) (output *GetBucketAclOutput, err error) { + output = &GetBucketAclOutput{} + var outputObs *getBucketACLOutputObs + outputObs = &getBucketACLOutputObs{} + err = obsClient.doActionWithBucket("GetBucketAcl", HTTP_GET, bucketName, newSubResourceSerial(SubResourceAcl), outputObs, extensions) + if err != nil { + output = nil + } else { + output.BaseModel = outputObs.BaseModel + output.Owner = outputObs.Owner + output.Grants = make([]Grant, 0, len(outputObs.Grants)) + for _, valGrant := range outputObs.Grants { + tempOutput := Grant{} + tempOutput.Delivered = valGrant.Delivered + tempOutput.Permission = valGrant.Permission + tempOutput.Grantee.DisplayName = valGrant.Grantee.DisplayName + tempOutput.Grantee.ID = valGrant.Grantee.ID + tempOutput.Grantee.Type = valGrant.Grantee.Type + if valGrant.Grantee.Canned == "Everyone" { + tempOutput.Grantee.URI = GroupAllUsers + } + output.Grants = append(output.Grants, tempOutput) + } + } + return +} + +// GetBucketAcl gets the bucket ACL. +// +// You can use this API to obtain a bucket ACL. +func (obsClient ObsClient) GetBucketAcl(bucketName string, extensions ...extensionOptions) (output *GetBucketAclOutput, err error) { + output = &GetBucketAclOutput{} + if obsClient.conf.signature == SignatureObs { + return obsClient.getBucketACLObs(bucketName, extensions) + } + err = obsClient.doActionWithBucket("GetBucketAcl", HTTP_GET, bucketName, newSubResourceSerial(SubResourceAcl), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketPolicy sets the bucket policy. +// +// You can use this API to set a bucket policy. If the bucket already has a policy, the +// policy will be overwritten by the one specified in this request. +func (obsClient ObsClient) SetBucketPolicy(input *SetBucketPolicyInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketPolicy is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketPolicy", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketPolicy gets the bucket policy. +// +// You can use this API to obtain the policy of a bucket. +func (obsClient ObsClient) GetBucketPolicy(bucketName string, extensions ...extensionOptions) (output *GetBucketPolicyOutput, err error) { + output = &GetBucketPolicyOutput{} + err = obsClient.doActionWithBucketV2("GetBucketPolicy", HTTP_GET, bucketName, newSubResourceSerial(SubResourcePolicy), output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketPolicy deletes the bucket policy. +// +// You can use this API to delete the policy of a bucket. +func (obsClient ObsClient) DeleteBucketPolicy(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketPolicy", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourcePolicy), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketCors sets CORS rules for a bucket. +// +// You can use this API to set CORS rules for a bucket to allow client browsers to send cross-origin requests. +func (obsClient ObsClient) SetBucketCors(input *SetBucketCorsInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketCorsInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketCors", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketCors gets CORS rules of a bucket. +// +// You can use this API to obtain the CORS rules of a specified bucket. +func (obsClient ObsClient) GetBucketCors(bucketName string, extensions ...extensionOptions) (output *GetBucketCorsOutput, err error) { + output = &GetBucketCorsOutput{} + err = obsClient.doActionWithBucket("GetBucketCors", HTTP_GET, bucketName, newSubResourceSerial(SubResourceCors), output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketCors deletes CORS rules of a bucket. +// +// You can use this API to delete the CORS rules of a specified bucket. +func (obsClient ObsClient) DeleteBucketCors(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketCors", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourceCors), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketVersioning sets the versioning status for a bucket. +// +// You can use this API to set the versioning status for a bucket. +func (obsClient ObsClient) SetBucketVersioning(input *SetBucketVersioningInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketVersioningInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketVersioning", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketVersioning gets the versioning status of a bucket. +// +// You can use this API to obtain the versioning status of a bucket. +func (obsClient ObsClient) GetBucketVersioning(bucketName string, extensions ...extensionOptions) (output *GetBucketVersioningOutput, err error) { + output = &GetBucketVersioningOutput{} + err = obsClient.doActionWithBucket("GetBucketVersioning", HTTP_GET, bucketName, newSubResourceSerial(SubResourceVersioning), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketWebsiteConfiguration sets website hosting for a bucket. +// +// You can use this API to set website hosting for a bucket. +func (obsClient ObsClient) SetBucketWebsiteConfiguration(input *SetBucketWebsiteConfigurationInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketWebsiteConfigurationInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketWebsiteConfiguration", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketWebsiteConfiguration gets the website hosting settings of a bucket. +// +// You can use this API to obtain the website hosting settings of a bucket. +func (obsClient ObsClient) GetBucketWebsiteConfiguration(bucketName string, extensions ...extensionOptions) (output *GetBucketWebsiteConfigurationOutput, err error) { + output = &GetBucketWebsiteConfigurationOutput{} + err = obsClient.doActionWithBucket("GetBucketWebsiteConfiguration", HTTP_GET, bucketName, newSubResourceSerial(SubResourceWebsite), output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketWebsiteConfiguration deletes the website hosting settings of a bucket. +// +// You can use this API to delete the website hosting settings of a bucket. +func (obsClient ObsClient) DeleteBucketWebsiteConfiguration(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketWebsiteConfiguration", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourceWebsite), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketLoggingConfiguration sets the bucket logging. +// +// You can use this API to configure access logging for a bucket. +func (obsClient ObsClient) SetBucketLoggingConfiguration(input *SetBucketLoggingConfigurationInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketLoggingConfigurationInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketLoggingConfiguration", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketLoggingConfiguration gets the logging settings of a bucket. +// +// You can use this API to obtain the access logging settings of a bucket. +func (obsClient ObsClient) GetBucketLoggingConfiguration(bucketName string, extensions ...extensionOptions) (output *GetBucketLoggingConfigurationOutput, err error) { + output = &GetBucketLoggingConfigurationOutput{} + err = obsClient.doActionWithBucket("GetBucketLoggingConfiguration", HTTP_GET, bucketName, newSubResourceSerial(SubResourceLogging), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketLifecycleConfiguration sets lifecycle rules for a bucket. +// +// You can use this API to set lifecycle rules for a bucket, to periodically transit +// storage classes of objects and delete objects in the bucket. +func (obsClient ObsClient) SetBucketLifecycleConfiguration(input *SetBucketLifecycleConfigurationInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketLifecycleConfigurationInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketLifecycleConfiguration", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketLifecycleConfiguration gets lifecycle rules of a bucket. +// +// You can use this API to obtain the lifecycle rules of a bucket. +func (obsClient ObsClient) GetBucketLifecycleConfiguration(bucketName string, extensions ...extensionOptions) (output *GetBucketLifecycleConfigurationOutput, err error) { + output = &GetBucketLifecycleConfigurationOutput{} + err = obsClient.doActionWithBucket("GetBucketLifecycleConfiguration", HTTP_GET, bucketName, newSubResourceSerial(SubResourceLifecycle), output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketLifecycleConfiguration deletes lifecycle rules of a bucket. +// +// You can use this API to delete all lifecycle rules of a bucket. +func (obsClient ObsClient) DeleteBucketLifecycleConfiguration(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketLifecycleConfiguration", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourceLifecycle), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketEncryption sets the default server-side encryption for a bucket. +// +// You can use this API to create or update the default server-side encryption for a bucket. +func (obsClient ObsClient) SetBucketEncryption(input *SetBucketEncryptionInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketEncryptionInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketEncryption", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketEncryption gets the encryption configuration of a bucket. +// +// You can use this API to obtain obtain the encryption configuration of a bucket. +func (obsClient ObsClient) GetBucketEncryption(bucketName string, extensions ...extensionOptions) (output *GetBucketEncryptionOutput, err error) { + output = &GetBucketEncryptionOutput{} + err = obsClient.doActionWithBucket("GetBucketEncryption", HTTP_GET, bucketName, newSubResourceSerial(SubResourceEncryption), output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketEncryption deletes the encryption configuration of a bucket. +// +// You can use this API to delete the encryption configuration of a bucket. +func (obsClient ObsClient) DeleteBucketEncryption(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketEncryption", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourceEncryption), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketTagging sets bucket tags. +// +// You can use this API to set bucket tags. +func (obsClient ObsClient) SetBucketTagging(input *SetBucketTaggingInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketTaggingInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketTagging", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketTagging gets bucket tags. +// +// You can use this API to obtain the tags of a specified bucket. +func (obsClient ObsClient) GetBucketTagging(bucketName string, extensions ...extensionOptions) (output *GetBucketTaggingOutput, err error) { + output = &GetBucketTaggingOutput{} + err = obsClient.doActionWithBucket("GetBucketTagging", HTTP_GET, bucketName, newSubResourceSerial(SubResourceTagging), output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketTagging deletes bucket tags. +// +// You can use this API to delete the tags of a specified bucket. +func (obsClient ObsClient) DeleteBucketTagging(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketTagging", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourceTagging), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketNotification sets event notification for a bucket. +// +// You can use this API to configure event notification for a bucket. You will be notified of all +// specified operations performed on the bucket. +func (obsClient ObsClient) SetBucketNotification(input *SetBucketNotificationInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketNotificationInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketNotification", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketNotification gets event notification settings of a bucket. +// +// You can use this API to obtain the event notification configuration of a bucket. +func (obsClient ObsClient) GetBucketNotification(bucketName string, extensions ...extensionOptions) (output *GetBucketNotificationOutput, err error) { + if obsClient.conf.signature != SignatureObs { + return obsClient.getBucketNotificationS3(bucketName, extensions) + } + output = &GetBucketNotificationOutput{} + err = obsClient.doActionWithBucket("GetBucketNotification", HTTP_GET, bucketName, newSubResourceSerial(SubResourceNotification), output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) getBucketNotificationS3(bucketName string, extensions []extensionOptions) (output *GetBucketNotificationOutput, err error) { + outputS3 := &getBucketNotificationOutputS3{} + err = obsClient.doActionWithBucket("GetBucketNotification", HTTP_GET, bucketName, newSubResourceSerial(SubResourceNotification), outputS3, extensions) + if err != nil { + return nil, err + } + + output = &GetBucketNotificationOutput{} + output.BaseModel = outputS3.BaseModel + topicConfigurations := make([]TopicConfiguration, 0, len(outputS3.TopicConfigurations)) + for _, topicConfigurationS3 := range outputS3.TopicConfigurations { + topicConfiguration := TopicConfiguration{} + topicConfiguration.ID = topicConfigurationS3.ID + topicConfiguration.Topic = topicConfigurationS3.Topic + topicConfiguration.FilterRules = topicConfigurationS3.FilterRules + + events := make([]EventType, 0, len(topicConfigurationS3.Events)) + for _, event := range topicConfigurationS3.Events { + events = append(events, ParseStringToEventType(event)) + } + topicConfiguration.Events = events + topicConfigurations = append(topicConfigurations, topicConfiguration) + } + output.TopicConfigurations = topicConfigurations + return +} + +// SetBucketRequestPayment sets requester-pays setting for a bucket. +func (obsClient ObsClient) SetBucketRequestPayment(input *SetBucketRequestPaymentInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketRequestPaymentInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("SetBucketRequestPayment", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketRequestPayment gets requester-pays setting of a bucket. +func (obsClient ObsClient) GetBucketRequestPayment(bucketName string, extensions ...extensionOptions) (output *GetBucketRequestPaymentOutput, err error) { + output = &GetBucketRequestPaymentOutput{} + err = obsClient.doActionWithBucket("GetBucketRequestPayment", HTTP_GET, bucketName, newSubResourceSerial(SubResourceRequestPayment), output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketFetchPolicy sets the bucket fetch policy. +// +// You can use this API to set a bucket fetch policy. +func (obsClient ObsClient) SetBucketFetchPolicy(input *SetBucketFetchPolicyInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetBucketFetchPolicyInput is nil") + } + if strings.TrimSpace(string(input.Status)) == "" { + return nil, errors.New("Fetch policy status is empty") + } + if strings.TrimSpace(input.Agency) == "" { + return nil, errors.New("Fetch policy agency is empty") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKey("SetBucketFetchPolicy", HTTP_PUT, input.Bucket, string(objectKeyExtensionPolicy), input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketFetchPolicy gets the bucket fetch policy. +// +// You can use this API to obtain the fetch policy of a bucket. +func (obsClient ObsClient) GetBucketFetchPolicy(input *GetBucketFetchPolicyInput, extensions ...extensionOptions) (output *GetBucketFetchPolicyOutput, err error) { + if input == nil { + return nil, errors.New("GetBucketFetchPolicyInput is nil") + } + output = &GetBucketFetchPolicyOutput{} + err = obsClient.doActionWithBucketAndKeyV2("GetBucketFetchPolicy", HTTP_GET, input.Bucket, string(objectKeyExtensionPolicy), input, output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketFetchPolicy deletes the bucket fetch policy. +// +// You can use this API to delete the fetch policy of a bucket. +func (obsClient ObsClient) DeleteBucketFetchPolicy(input *DeleteBucketFetchPolicyInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("DeleteBucketFetchPolicyInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKey("DeleteBucketFetchPolicy", HTTP_DELETE, input.Bucket, string(objectKeyExtensionPolicy), input, output, extensions) + if err != nil { + output = nil + } + return +} + +// SetBucketFetchJob sets the bucket fetch job. +// +// You can use this API to set a bucket fetch job. +func (obsClient ObsClient) SetBucketFetchJob(input *SetBucketFetchJobInput, extensions ...extensionOptions) (output *SetBucketFetchJobOutput, err error) { + if input == nil { + return nil, errors.New("SetBucketFetchJobInput is nil") + } + if strings.TrimSpace(input.URL) == "" { + return nil, errors.New("URL is empty") + } + output = &SetBucketFetchJobOutput{} + err = obsClient.doActionWithBucketAndKeyV2("SetBucketFetchJob", HTTP_POST, input.Bucket, string(objectKeyAsyncFetchJob), input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketFetchJob gets the bucket fetch job. +// +// You can use this API to obtain the fetch job of a bucket. +func (obsClient ObsClient) GetBucketFetchJob(input *GetBucketFetchJobInput, extensions ...extensionOptions) (output *GetBucketFetchJobOutput, err error) { + if input == nil { + return nil, errors.New("GetBucketFetchJobInput is nil") + } + if strings.TrimSpace(input.JobID) == "" { + return nil, errors.New("JobID is empty") + } + output = &GetBucketFetchJobOutput{} + err = obsClient.doActionWithBucketAndKeyV2("GetBucketFetchJob", HTTP_GET, input.Bucket, string(objectKeyAsyncFetchJob)+"/"+input.JobID, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// PutBucketPublicAccessBlock sets the bucket Block Public Access. +// +// You can use this API to set a bucket Block Public Access. +func (obsClient ObsClient) PutBucketPublicAccessBlock(input *PutBucketPublicAccessBlockInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("PutBucketPublicAccessBlockInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucket("PutBucketPublicAccessBlock", HTTP_PUT, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketPublicAccessBlock gets the bucket Block Public Access. +// +// You can use this API to get a bucket Block Public Access. +func (obsClient ObsClient) GetBucketPublicAccessBlock(bucketName string, extensions ...extensionOptions) (output *GetBucketPublicAccessBlockOutput, err error) { + output = &GetBucketPublicAccessBlockOutput{} + err = obsClient.doActionWithBucket("GetBucketPublicAccessBlock", HTTP_GET, bucketName, newSubResourceSerial(SubResourcePublicAccessBlock), output, extensions) + if err != nil { + output = nil + } + return +} + +// DeleteBucketPublicAccessBlock deletes the bucket Block Public Access. +// +// You can use this API to delete the Block Public Access of a bucket. +func (obsClient ObsClient) DeleteBucketPublicAccessBlock(bucketName string, extensions ...extensionOptions) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doActionWithBucket("DeleteBucketPublicAccessBlock", HTTP_DELETE, bucketName, newSubResourceSerial(SubResourcePublicAccessBlock), output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketPolicyPublicStatus get the bucket Policy status. +// +// You can use this API to get a bucket Policy status. +func (obsClient ObsClient) GetBucketPolicyPublicStatus(bucketName string, extensions ...extensionOptions) (output *GetBucketPolicyPublicStatusOutput, err error) { + output = &GetBucketPolicyPublicStatusOutput{} + err = obsClient.doActionWithBucket("GetBucketPolicyPublicStatus", HTTP_GET, bucketName, newSubResourceSerial(SubResourceBucketPolicyPublicStatus), output, extensions) + if err != nil { + output = nil + } + return +} + +// GetBucketPublicStatus get the bucket public status. +// +// You can use this API to get a bucket public status. +func (obsClient ObsClient) GetBucketPublicStatus(bucketName string, extensions ...extensionOptions) (output *GetBucketPublicStatusOutput, err error) { + output = &GetBucketPublicStatusOutput{} + err = obsClient.doActionWithBucket("GetBucketPublicStatus", HTTP_GET, bucketName, newSubResourceSerial(SubResourceBucketPublicStatus), output, extensions) + if err != nil { + output = nil + } + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_object.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_object.go new file mode 100644 index 00000000000..b53509b491b --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_object.go @@ -0,0 +1,568 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "errors" + "fmt" + "io" + "os" + "strings" +) + +// ListObjects lists objects in a bucket. +// +// You can use this API to list objects in a bucket. By default, a maximum of 1000 objects are listed. +func (obsClient ObsClient) ListObjects(input *ListObjectsInput, extensions ...extensionOptions) (output *ListObjectsOutput, err error) { + if input == nil { + return nil, errors.New("ListObjectsInput is nil") + } + output = &ListObjectsOutput{} + err = obsClient.doActionWithBucket("ListObjects", HTTP_GET, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } else { + if location, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok { + output.Location = location[0] + } + if output.EncodingType == "url" { + err = decodeListObjectsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListObjectsOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// ListPosixObjects lists objects in a posix. +// +// You can use this API to list objects in a posix. By default, a maximum of 1000 objects are listed. +func (obsClient ObsClient) ListPosixObjects(input *ListPosixObjectsInput, extensions ...extensionOptions) (output *ListPosixObjectsOutput, err error) { + if input == nil { + return nil, errors.New("ListPosixObjects is nil") + } + output = &ListPosixObjectsOutput{} + err = obsClient.doActionWithBucket("ListPosixObjects", HTTP_GET, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } else { + if location, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok { + output.Location = location[0] + } + if output.EncodingType == "url" { + err = decodeListPosixObjectsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListPosixObjectsOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// ListVersions lists versioning objects in a bucket. +// +// You can use this API to list versioning objects in a bucket. By default, a maximum of 1000 versioning objects are listed. +func (obsClient ObsClient) ListVersions(input *ListVersionsInput, extensions ...extensionOptions) (output *ListVersionsOutput, err error) { + if input == nil { + return nil, errors.New("ListVersionsInput is nil") + } + output = &ListVersionsOutput{} + err = obsClient.doActionWithBucket("ListVersions", HTTP_GET, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } else { + if location, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok { + output.Location = location[0] + } + if output.EncodingType == "url" { + err = decodeListVersionsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListVersionsOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// HeadObject checks whether an object exists. +// +// You can use this API to check whether an object exists. +func (obsClient ObsClient) HeadObject(input *HeadObjectInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("HeadObjectInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKey("HeadObject", HTTP_HEAD, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// SetObjectMetadata sets object metadata. +func (obsClient ObsClient) SetObjectMetadata(input *SetObjectMetadataInput, extensions ...extensionOptions) (output *SetObjectMetadataOutput, err error) { + output = &SetObjectMetadataOutput{} + err = obsClient.doActionWithBucketAndKey("SetObjectMetadata", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseSetObjectMetadataOutput(output) + } + return +} + +// DeleteObject deletes an object. +// +// You can use this API to delete an object from a specified bucket. +func (obsClient ObsClient) DeleteObject(input *DeleteObjectInput, extensions ...extensionOptions) (output *DeleteObjectOutput, err error) { + if input == nil { + return nil, errors.New("DeleteObjectInput is nil") + } + output = &DeleteObjectOutput{} + err = obsClient.doActionWithBucketAndKey("DeleteObject", HTTP_DELETE, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseDeleteObjectOutput(output) + } + return +} + +// DeleteObjects deletes objects in a batch. +// +// You can use this API to batch delete objects from a specified bucket. +func (obsClient ObsClient) DeleteObjects(input *DeleteObjectsInput, extensions ...extensionOptions) (output *DeleteObjectsOutput, err error) { + if input == nil { + return nil, errors.New("DeleteObjectsInput is nil") + } + output = &DeleteObjectsOutput{} + err = obsClient.doActionWithBucket("DeleteObjects", HTTP_POST, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } else if output.EncodingType == "url" { + err = decodeDeleteObjectsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get DeleteObjectsOutput with error: %v.", err) + output = nil + } + } + return +} + +// SetObjectAcl sets ACL for an object. +// +// You can use this API to set the ACL for an object in a specified bucket. +func (obsClient ObsClient) SetObjectAcl(input *SetObjectAclInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetObjectAclInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKey("SetObjectAcl", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetObjectAcl gets the ACL of an object. +// +// You can use this API to obtain the ACL of an object in a specified bucket. +func (obsClient ObsClient) GetObjectAcl(input *GetObjectAclInput, extensions ...extensionOptions) (output *GetObjectAclOutput, err error) { + if input == nil { + return nil, errors.New("GetObjectAclInput is nil") + } + output = &GetObjectAclOutput{} + err = obsClient.doActionWithBucketAndKey("GetObjectAcl", HTTP_GET, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + if versionID, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = versionID[0] + } + } + return +} + +// RestoreObject restores an object. +func (obsClient ObsClient) RestoreObject(input *RestoreObjectInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("RestoreObjectInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKey("RestoreObject", HTTP_POST, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// GetObjectMetadata gets object metadata. +// +// You can use this API to send a HEAD request to the object of a specified bucket to obtain its metadata. +func (obsClient ObsClient) GetObjectMetadata(input *GetObjectMetadataInput, extensions ...extensionOptions) (output *GetObjectMetadataOutput, err error) { + if input == nil { + return nil, errors.New("GetObjectMetadataInput is nil") + } + output = &GetObjectMetadataOutput{} + err = obsClient.doActionWithBucketAndKey("GetObjectMetadata", HTTP_HEAD, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseGetObjectMetadataOutput(output) + } + return +} + +func (obsClient ObsClient) GetAttribute(input *GetAttributeInput, extensions ...extensionOptions) (output *GetAttributeOutput, err error) { + if input == nil { + return nil, errors.New("GetAttributeInput is nil") + } + output = &GetAttributeOutput{} + err = obsClient.doActionWithBucketAndKey("GetAttribute", HTTP_HEAD, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseGetAttributeOutput(output) + } + return +} + +// GetObject downloads object. +// +// You can use this API to download an object in a specified bucket. +func (obsClient ObsClient) GetObject(input *GetObjectInput, extensions ...extensionOptions) (output *GetObjectOutput, err error) { + if input == nil { + return nil, errors.New("GetObjectInput is nil") + } + output = &GetObjectOutput{} + err = obsClient.doActionWithBucketAndKeyWithProgress(GET_OBJECT, HTTP_GET, input.Bucket, input.Key, input, output, extensions, nil) + if err != nil { + output = nil + return + } + + ParseGetObjectOutput(output) + listener := obsClient.getProgressListener(extensions) + if listener != nil { + output.Body = TeeReader(output.Body, output.ContentLength, listener, nil) + } + return +} + +func (obsClient ObsClient) GetObjectWithoutProgress(input *GetObjectInput, extensions ...extensionOptions) (output *GetObjectOutput, err error) { + if input == nil { + return nil, errors.New("GetObjectInput is nil") + } + output = &GetObjectOutput{} + err = obsClient.doActionWithBucketAndKeyWithProgress(GET_OBJECT, HTTP_GET, input.Bucket, input.Key, input, output, extensions, nil) + if err != nil { + output = nil + return + } + + ParseGetObjectOutput(output) + return +} + +// PutObject uploads an object to the specified bucket. +func (obsClient ObsClient) PutObject(input *PutObjectInput, extensions ...extensionOptions) (output *PutObjectOutput, err error) { + if input == nil { + return nil, errors.New("PutObjectInput is nil") + } + + if input.ContentType == "" && input.Key != "" { + if contentType, ok := GetContentType(input.Key); ok { + input.ContentType = contentType + } + } + output = &PutObjectOutput{} + var repeatable bool + if input.Body != nil { + if _, ok := input.Body.(*strings.Reader); ok { + repeatable = true + } + if input.ContentLength > 0 { + input.Body = &readerWrapper{reader: input.Body, totalCount: input.ContentLength} + } + } + + listener := obsClient.getProgressListener(extensions) + if repeatable { + err = obsClient.doActionWithBucketAndKeyWithProgress(PUT_OBJECT, HTTP_PUT, input.Bucket, input.Key, input, output, extensions, listener) + } else { + err = obsClient.doActionWithBucketAndKeyUnRepeatableWithProgress(PUT_OBJECT, HTTP_PUT, input.Bucket, input.Key, input, output, extensions, listener) + } + if err != nil { + output = nil + return + } + ParsePutObjectOutput(output) + output.ObjectUrl = fmt.Sprintf("%s/%s/%s", obsClient.conf.endpoint, input.Bucket, input.Key) + return +} + +func (obsClient ObsClient) getContentType(input *PutObjectInput, sourceFile string) (contentType string) { + if contentType, ok := GetContentType(input.Key); ok { + return contentType + } + if contentType, ok := GetContentType(sourceFile); ok { + return contentType + } + return +} + +func (obsClient ObsClient) isGetContentType(input *PutObjectInput) bool { + if input.ContentType == "" && input.Key != "" { + return true + } + return false +} + +func (obsClient ObsClient) NewFolder(input *NewFolderInput, extensions ...extensionOptions) (output *NewFolderOutput, err error) { + if input == nil { + return nil, errors.New("NewFolderInput is nil") + } + + if !strings.HasSuffix(input.Key, "/") { + input.Key += "/" + } + + output = &NewFolderOutput{} + err = obsClient.doActionWithBucketAndKey("NewFolder", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseNewFolderOutput(output) + output.ObjectUrl = fmt.Sprintf("%s/%s/%s", obsClient.conf.endpoint, input.Bucket, input.Key) + } + return +} + +// PutFile uploads a file to the specified bucket. +func (obsClient ObsClient) PutFile(input *PutFileInput, extensions ...extensionOptions) (output *PutObjectOutput, err error) { + if input == nil { + return nil, errors.New("PutFileInput is nil") + } + + var body io.Reader + sourceFile := strings.TrimSpace(input.SourceFile) + if sourceFile != "" { + fd, _err := os.Open(sourceFile) + if _err != nil { + err = _err + return nil, err + } + defer func() { + errMsg := fd.Close() + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", errMsg) + } + }() + + stat, _err := fd.Stat() + if _err != nil { + err = _err + return nil, err + } + fileReaderWrapper := &fileReaderWrapper{filePath: sourceFile} + fileReaderWrapper.reader = fd + if input.ContentLength > 0 { + if input.ContentLength > stat.Size() { + input.ContentLength = stat.Size() + } + fileReaderWrapper.totalCount = input.ContentLength + } else { + fileReaderWrapper.totalCount = stat.Size() + } + body = fileReaderWrapper + } + + _input := &PutObjectInput{} + _input.PutObjectBasicInput = input.PutObjectBasicInput + _input.Body = body + + if obsClient.isGetContentType(_input) { + _input.ContentType = obsClient.getContentType(_input, sourceFile) + } + listener := obsClient.getProgressListener(extensions) + output = &PutObjectOutput{} + err = obsClient.doActionWithBucketAndKeyWithProgress(PUT_FILE, HTTP_PUT, _input.Bucket, _input.Key, _input, output, extensions, listener) + + if err != nil { + output = nil + return + } + + ParsePutObjectOutput(output) + output.ObjectUrl = fmt.Sprintf("%s/%s/%s", obsClient.conf.endpoint, input.Bucket, input.Key) + return +} + +// CopyObject creates a copy for an existing object. +// +// You can use this API to create a copy for an object in a specified bucket. +func (obsClient ObsClient) CopyObject(input *CopyObjectInput, extensions ...extensionOptions) (output *CopyObjectOutput, err error) { + if input == nil { + return nil, errors.New("CopyObjectInput is nil") + } + + if strings.TrimSpace(input.CopySourceBucket) == "" { + return nil, errors.New("Source bucket is empty") + } + if strings.TrimSpace(input.CopySourceKey) == "" { + return nil, errors.New("Source key is empty") + } + + output = &CopyObjectOutput{} + err = obsClient.doActionWithBucketAndKey("CopyObject", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseCopyObjectOutput(output) + } + return +} + +func (obsClient ObsClient) AppendObject(input *AppendObjectInput, extensions ...extensionOptions) (output *AppendObjectOutput, err error) { + if input == nil { + return nil, errors.New("AppendObjectInput is nil") + } + + if input.ContentType == "" && input.Key != "" { + if contentType, ok := mimeTypes[strings.ToLower(input.Key[strings.LastIndex(input.Key, ".")+1:])]; ok { + input.ContentType = contentType + } + } + output = &AppendObjectOutput{} + var repeatable bool + if input.Body != nil { + if _, ok := input.Body.(*strings.Reader); ok { + repeatable = true + } + if input.ContentLength > 0 { + input.Body = &readerWrapper{reader: input.Body, totalCount: input.ContentLength} + } + } + listener := obsClient.getProgressListener(extensions) + + if repeatable { + err = obsClient.doActionWithBucketAndKeyWithProgress(APPEND_OBJECT, HTTP_POST, input.Bucket, input.Key, input, output, extensions, listener) + } else { + err = obsClient.doActionWithBucketAndKeyUnRepeatableWithProgress(APPEND_OBJECT, HTTP_POST, input.Bucket, input.Key, input, output, extensions, listener) + } + + if err != nil || ParseAppendObjectOutput(output) != nil { + output = nil + } + return +} + +func (obsClient ObsClient) ModifyObject(input *ModifyObjectInput, extensions ...extensionOptions) (output *ModifyObjectOutput, err error) { + if input == nil { + return nil, errors.New("ModifyObjectInput is nil") + } + + output = &ModifyObjectOutput{} + var repeatable bool + if input.Body != nil { + if _, ok := input.Body.(*strings.Reader); ok { + repeatable = true + } + if input.ContentLength > 0 { + input.Body = &readerWrapper{reader: input.Body, totalCount: input.ContentLength} + } + } + if repeatable { + err = obsClient.doActionWithBucketAndKey("ModifyObject", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + } else { + err = obsClient.doActionWithBucketAndKeyUnRepeatable("ModifyObject", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + } + if err != nil { + output = nil + } else { + ParseModifyObjectOutput(output) + } + return +} + +func (obsClient ObsClient) RenameFile(input *RenameFileInput, extensions ...extensionOptions) (output *RenameFileOutput, err error) { + if input == nil { + return nil, errors.New("RenameFileInput is nil") + } + + output = &RenameFileOutput{} + err = obsClient.doActionWithBucketAndKey("RenameFile", HTTP_POST, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) RenameFolder(input *RenameFolderInput, extensions ...extensionOptions) (output *RenameFolderOutput, err error) { + if input == nil { + return nil, errors.New("RenameFolderInput is nil") + } + + if !strings.HasSuffix(input.Key, "/") { + input.Key += "/" + } + if !strings.HasSuffix(input.NewObjectKey, "/") { + input.NewObjectKey += "/" + } + output = &RenameFolderOutput{} + err = obsClient.doActionWithBucketAndKey("RenameFolder", HTTP_POST, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) SetDirAccesslabel(input *SetDirAccesslabelInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("SetDirAccesslabelInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKeyV2("SetDirAccesslabel", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) GetDirAccesslabel(input *GetDirAccesslabelInput, extensions ...extensionOptions) (output *GetDirAccesslabelOutput, err error) { + if input == nil { + return nil, errors.New("GetDirAccesslabelInput is nil") + } + output = &GetDirAccesslabelOutput{} + err = obsClient.doActionWithBucketAndKeyV2("GetDirAccesslabel", HTTP_GET, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +func (obsClient ObsClient) DeleteDirAccesslabel(input *DeleteDirAccesslabelInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("DeleteDirAccesslabelInput is nil") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKeyV2("DeleteDirAccesslabel", HTTP_DELETE, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_other.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_other.go new file mode 100644 index 00000000000..7823f6bff05 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_other.go @@ -0,0 +1,49 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "strings" +) + +// Refresh refreshes ak, sk and securityToken for obsClient. +func (obsClient ObsClient) Refresh(ak, sk, securityToken string) { + for _, sp := range obsClient.conf.securityProviders { + if bsp, ok := sp.(*BasicSecurityProvider); ok { + bsp.refresh(strings.TrimSpace(ak), strings.TrimSpace(sk), strings.TrimSpace(securityToken)) + break + } + } +} + +func (obsClient ObsClient) getSecurity() securityHolder { + if obsClient.conf.securityProviders != nil { + for _, sp := range obsClient.conf.securityProviders { + if sp == nil { + continue + } + sh := sp.getSecurity() + if sh.ak != "" && sh.sk != "" { + return sh + } + } + } + return emptySecurityHolder +} + +// Close closes ObsClient. +func (obsClient *ObsClient) Close() { + obsClient.httpClient = nil + obsClient.conf.transport.CloseIdleConnections() + obsClient.conf = nil +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_part.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_part.go new file mode 100644 index 00000000000..98c84d58ce8 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_part.go @@ -0,0 +1,254 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "errors" + "io" + "os" + "sort" + "strings" +) + +// ListMultipartUploads lists the multipart uploads. +// +// You can use this API to list the multipart uploads that are initialized but not combined or aborted in a specified bucket. +func (obsClient ObsClient) ListMultipartUploads(input *ListMultipartUploadsInput, extensions ...extensionOptions) (output *ListMultipartUploadsOutput, err error) { + if input == nil { + return nil, errors.New("ListMultipartUploadsInput is nil") + } + output = &ListMultipartUploadsOutput{} + err = obsClient.doActionWithBucket("ListMultipartUploads", HTTP_GET, input.Bucket, input, output, extensions) + if err != nil { + output = nil + } else if output.EncodingType == "url" { + err = decodeListMultipartUploadsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListMultipartUploadsOutput with error: %v.", err) + output = nil + } + } + return +} + +// AbortMultipartUpload aborts a multipart upload in a specified bucket by using the multipart upload ID. +func (obsClient ObsClient) AbortMultipartUpload(input *AbortMultipartUploadInput, extensions ...extensionOptions) (output *BaseModel, err error) { + if input == nil { + return nil, errors.New("AbortMultipartUploadInput is nil") + } + if input.UploadId == "" { + return nil, errors.New("UploadId is empty") + } + output = &BaseModel{} + err = obsClient.doActionWithBucketAndKey("AbortMultipartUpload", HTTP_DELETE, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } + return +} + +// InitiateMultipartUpload initializes a multipart upload. +func (obsClient ObsClient) InitiateMultipartUpload(input *InitiateMultipartUploadInput, extensions ...extensionOptions) (output *InitiateMultipartUploadOutput, err error) { + if input == nil { + return nil, errors.New("InitiateMultipartUploadInput is nil") + } + + if input.ContentType == "" && input.Key != "" { + if contentType, ok := mimeTypes[strings.ToLower(input.Key[strings.LastIndex(input.Key, ".")+1:])]; ok { + input.ContentType = contentType + } + } + + output = &InitiateMultipartUploadOutput{} + err = obsClient.doActionWithBucketAndKey("InitiateMultipartUpload", HTTP_POST, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseInitiateMultipartUploadOutput(output) + if output.EncodingType == "url" { + err = decodeInitiateMultipartUploadOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get InitiateMultipartUploadOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// UploadPart uploads a part to a specified bucket by using a specified multipart upload ID. +// +// After a multipart upload is initialized, you can use this API to upload a part to a specified bucket +// by using the multipart upload ID. Except for the last uploaded part whose size ranges from 0 to 5 GB, +// sizes of the other parts range from 100 KB to 5 GB. The upload part ID ranges from 1 to 10000. +func (obsClient ObsClient) UploadPart(_input *UploadPartInput, extensions ...extensionOptions) (output *UploadPartOutput, err error) { + if _input == nil { + return nil, errors.New("UploadPartInput is nil") + } + + if _input.UploadId == "" { + return nil, errors.New("UploadId is empty") + } + + input := &UploadPartInput{} + input.Bucket = _input.Bucket + input.Key = _input.Key + input.PartNumber = _input.PartNumber + input.UploadId = _input.UploadId + input.ContentMD5 = _input.ContentMD5 + input.ContentSHA256 = _input.ContentSHA256 + input.SourceFile = _input.SourceFile + input.Offset = _input.Offset + input.PartSize = _input.PartSize + input.SseHeader = _input.SseHeader + input.Body = _input.Body + + output = &UploadPartOutput{} + var repeatable bool + if input.Body != nil { + if _, ok := input.Body.(*strings.Reader); ok { + repeatable = true + } + if _, ok := input.Body.(*readerWrapper); !ok && input.PartSize > 0 { + input.Body = &readerWrapper{reader: input.Body, totalCount: input.PartSize} + } + } else if sourceFile := strings.TrimSpace(input.SourceFile); sourceFile != "" { + fd, _err := os.Open(sourceFile) + if _err != nil { + err = _err + return nil, err + } + defer func() { + errMsg := fd.Close() + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", errMsg) + } + }() + + stat, _err := fd.Stat() + if _err != nil { + err = _err + return nil, err + } + fileSize := stat.Size() + fileReaderWrapper := &fileReaderWrapper{filePath: sourceFile} + fileReaderWrapper.reader = fd + + if input.Offset < 0 || input.Offset > fileSize { + input.Offset = 0 + } + + if input.PartSize <= 0 || input.PartSize > (fileSize-input.Offset) { + input.PartSize = fileSize - input.Offset + } + fileReaderWrapper.totalCount = input.PartSize + fileReaderWrapper.mark = input.Offset + if _, err = fd.Seek(input.Offset, io.SeekStart); err != nil { + return nil, err + } + input.Body = fileReaderWrapper + repeatable = true + } + if repeatable { + err = obsClient.doActionWithBucketAndKey("UploadPart", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + } else { + err = obsClient.doActionWithBucketAndKeyUnRepeatable("UploadPart", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + } + if err != nil { + output = nil + } else { + ParseUploadPartOutput(output) + output.PartNumber = input.PartNumber + } + return +} + +// CompleteMultipartUpload combines the uploaded parts in a specified bucket by using the multipart upload ID. +func (obsClient ObsClient) CompleteMultipartUpload(input *CompleteMultipartUploadInput, extensions ...extensionOptions) (output *CompleteMultipartUploadOutput, err error) { + if input == nil { + return nil, errors.New("CompleteMultipartUploadInput is nil") + } + + if input.UploadId == "" { + return nil, errors.New("UploadId is empty") + } + + var parts partSlice = input.Parts + sort.Sort(parts) + + output = &CompleteMultipartUploadOutput{} + err = obsClient.doActionWithBucketAndKey("CompleteMultipartUpload", HTTP_POST, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseCompleteMultipartUploadOutput(output) + if output.EncodingType == "url" { + err = decodeCompleteMultipartUploadOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get CompleteMultipartUploadOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// ListParts lists the uploaded parts in a bucket by using the multipart upload ID. +func (obsClient ObsClient) ListParts(input *ListPartsInput, extensions ...extensionOptions) (output *ListPartsOutput, err error) { + if input == nil { + return nil, errors.New("ListPartsInput is nil") + } + if input.UploadId == "" { + return nil, errors.New("UploadId is empty") + } + output = &ListPartsOutput{} + err = obsClient.doActionWithBucketAndKey("ListParts", HTTP_GET, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else if output.EncodingType == "url" { + err = decodeListPartsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListPartsOutput with error: %v.", err) + output = nil + } + } + return +} + +// CopyPart copy a part to a specified bucket by using a specified multipart upload ID. +// +// After a multipart upload is initialized, you can use this API to copy a part to a specified bucket by using the multipart upload ID. +func (obsClient ObsClient) CopyPart(input *CopyPartInput, extensions ...extensionOptions) (output *CopyPartOutput, err error) { + if input == nil { + return nil, errors.New("CopyPartInput is nil") + } + if input.UploadId == "" { + return nil, errors.New("UploadId is empty") + } + if strings.TrimSpace(input.CopySourceBucket) == "" { + return nil, errors.New("Source bucket is empty") + } + if strings.TrimSpace(input.CopySourceKey) == "" { + return nil, errors.New("Source key is empty") + } + + output = &CopyPartOutput{} + err = obsClient.doActionWithBucketAndKey("CopyPart", HTTP_PUT, input.Bucket, input.Key, input, output, extensions) + if err != nil { + output = nil + } else { + ParseCopyPartOutput(output) + output.PartNumber = input.PartNumber + } + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_resume.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_resume.go new file mode 100644 index 00000000000..aef1b4ca798 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/client_resume.go @@ -0,0 +1,59 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +// UploadFile resume uploads. +// +// This API is an encapsulated and enhanced version of multipart upload, and aims to eliminate large file +// upload failures caused by poor network conditions and program breakdowns. +func (obsClient ObsClient) UploadFile(input *UploadFileInput, extensions ...extensionOptions) (output *CompleteMultipartUploadOutput, err error) { + if input.EnableCheckpoint && input.CheckpointFile == "" { + input.CheckpointFile = input.UploadFile + ".uploadfile_record" + } + + if input.TaskNum <= 0 { + input.TaskNum = 1 + } + if input.PartSize < MIN_PART_SIZE { + input.PartSize = MIN_PART_SIZE + } else if input.PartSize > MAX_PART_SIZE { + input.PartSize = MAX_PART_SIZE + } + + output, err = obsClient.resumeUpload(input, extensions) + return +} + +// DownloadFile resume downloads. +// +// This API is an encapsulated and enhanced version of partial download, and aims to eliminate large file +// download failures caused by poor network conditions and program breakdowns. +func (obsClient ObsClient) DownloadFile(input *DownloadFileInput, extensions ...extensionOptions) (output *GetObjectMetadataOutput, err error) { + if input.DownloadFile == "" { + input.DownloadFile = input.Key + } + + if input.EnableCheckpoint && input.CheckpointFile == "" { + input.CheckpointFile = input.DownloadFile + ".downloadfile_record" + } + + if input.TaskNum <= 0 { + input.TaskNum = 1 + } + if input.PartSize <= 0 { + input.PartSize = DEFAULT_PART_SIZE + } + + output, err = obsClient.resumeDownload(input, extensions) + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/conf.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/conf.go new file mode 100644 index 00000000000..f5f3a9d57df --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/conf.go @@ -0,0 +1,563 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "context" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "net" + "net/http" + "net/url" + "os" + "sort" + "strconv" + "strings" + "sync" + "time" + + "golang.org/x/net/http/httpproxy" +) + +type urlHolder struct { + scheme string + host string + port int +} + +type config struct { + securityProviders []securityProvider + urlHolder *urlHolder + pathStyle bool + cname bool + sslVerify bool + disableKeepAlive bool + endpoint string + signature SignatureType + region string + connectTimeout int + socketTimeout int + headerTimeout int + idleConnTimeout int + finalTimeout int + maxRetryCount int + proxyURL string + noProxyURL string + proxyFromEnv bool + maxConnsPerHost int + pemCerts []byte + transport *http.Transport + roundTripper http.RoundTripper + httpClient *http.Client + ctx context.Context + maxRedirectCount int + userAgent string + enableCompression bool + progressListener ProgressListener + customProxyOnce sync.Once + customProxyFuncValue func(*url.URL) (*url.URL, error) +} + +func (conf config) String() string { + return fmt.Sprintf("[endpoint:%s, signature:%s, pathStyle:%v, region:%s,"+ + "\nconnectTimeout:%d, socketTimeout:%d, headerTimeout:%d, idleConnTimeout:%d,"+ + "\nmaxRetryCount:%d, maxConnsPerHost:%d, sslVerify:%v, maxRedirectCount:%d,"+ + "\ncname:%v, userAgent:%s, disableKeepAlive:%v, proxyFromEnv:%v]", + conf.endpoint, conf.signature, conf.pathStyle, conf.region, + conf.connectTimeout, conf.socketTimeout, conf.headerTimeout, conf.idleConnTimeout, + conf.maxRetryCount, conf.maxConnsPerHost, conf.sslVerify, conf.maxRedirectCount, + conf.cname, conf.userAgent, conf.disableKeepAlive, conf.proxyFromEnv, + ) +} + +type configurer func(conf *config) + +func WithSecurityProviders(sps ...securityProvider) configurer { + return func(conf *config) { + for _, sp := range sps { + if sp != nil { + conf.securityProviders = append(conf.securityProviders, sp) + } + } + } +} + +// WithSslVerify is a wrapper for WithSslVerifyAndPemCerts. +func WithSslVerify(sslVerify bool) configurer { + return WithSslVerifyAndPemCerts(sslVerify, nil) +} + +// WithSslVerifyAndPemCerts is a configurer for ObsClient to set conf.sslVerify and conf.pemCerts. +func WithSslVerifyAndPemCerts(sslVerify bool, pemCerts []byte) configurer { + return func(conf *config) { + conf.sslVerify = sslVerify + conf.pemCerts = pemCerts + } +} + +// WithHeaderTimeout is a configurer for ObsClient to set the timeout period of obtaining the response headers. +func WithHeaderTimeout(headerTimeout int) configurer { + return func(conf *config) { + conf.headerTimeout = headerTimeout + } +} + +// WithProxyUrl is a configurer for ObsClient to set HTTP proxy. +func WithProxyUrl(proxyURL string) configurer { + return func(conf *config) { + conf.proxyURL = proxyURL + } +} + +// WithNoProxyUrl is a configurer for ObsClient to set HTTP no_proxy. +func WithNoProxyUrl(noProxyURL string) configurer { + return func(conf *config) { + conf.noProxyURL = noProxyURL + } +} + +// WithProxyFromEnv is a configurer for ObsClient to get proxy from evironment. +func WithProxyFromEnv(proxyFromEnv bool) configurer { + return func(conf *config) { + conf.proxyFromEnv = proxyFromEnv + } +} + +// WithMaxConnections is a configurer for ObsClient to set the maximum number of idle HTTP connections. +func WithMaxConnections(maxConnsPerHost int) configurer { + return func(conf *config) { + conf.maxConnsPerHost = maxConnsPerHost + } +} + +// WithPathStyle is a configurer for ObsClient. +func WithPathStyle(pathStyle bool) configurer { + return func(conf *config) { + conf.pathStyle = pathStyle + } +} + +// WithSignature is a configurer for ObsClient. +func WithSignature(signature SignatureType) configurer { + return func(conf *config) { + conf.signature = signature + } +} + +// WithRegion is a configurer for ObsClient. +func WithRegion(region string) configurer { + return func(conf *config) { + conf.region = region + } +} + +// WithConnectTimeout is a configurer for ObsClient to set timeout period for establishing +// an http/https connection, in seconds. +func WithConnectTimeout(connectTimeout int) configurer { + return func(conf *config) { + conf.connectTimeout = connectTimeout + } +} + +// WithSocketTimeout is a configurer for ObsClient to set the timeout duration for transmitting data at +// the socket layer, in seconds. +func WithSocketTimeout(socketTimeout int) configurer { + return func(conf *config) { + conf.socketTimeout = socketTimeout + } +} + +// WithIdleConnTimeout is a configurer for ObsClient to set the timeout period of an idle HTTP connection +// in the connection pool, in seconds. +func WithIdleConnTimeout(idleConnTimeout int) configurer { + return func(conf *config) { + conf.idleConnTimeout = idleConnTimeout + } +} + +// WithMaxRetryCount is a configurer for ObsClient to set the maximum number of retries when an HTTP/HTTPS connection is abnormal. +func WithMaxRetryCount(maxRetryCount int) configurer { + return func(conf *config) { + conf.maxRetryCount = maxRetryCount + } +} + +// WithSecurityToken is a configurer for ObsClient to set the security token in the temporary access keys. +func WithSecurityToken(securityToken string) configurer { + return func(conf *config) { + for _, sp := range conf.securityProviders { + if bsp, ok := sp.(*BasicSecurityProvider); ok { + sh := bsp.getSecurity() + bsp.refresh(sh.ak, sh.sk, securityToken) + break + } + } + } +} + +// WithHttpTransport is a configurer for ObsClient to set the customized http Transport. +func WithHttpTransport(transport *http.Transport) configurer { + return func(conf *config) { + conf.transport = transport + } +} + +func WithHttpClient(httpClient *http.Client) configurer { + return func(conf *config) { + conf.httpClient = httpClient + } +} + +// WithRequestContext is a configurer for ObsClient to set the context for each HTTP request. +func WithRequestContext(ctx context.Context) configurer { + return func(conf *config) { + conf.ctx = ctx + } +} + +// WithCustomDomainName is a configurer for ObsClient. +func WithCustomDomainName(cname bool) configurer { + return func(conf *config) { + conf.cname = cname + } +} + +// WithDisableKeepAlive is a configurer for ObsClient to disable the keep-alive for http. +func WithDisableKeepAlive(disableKeepAlive bool) configurer { + return func(conf *config) { + conf.disableKeepAlive = disableKeepAlive + } +} + +// WithMaxRedirectCount is a configurer for ObsClient to set the maximum number of times that the request is redirected. +func WithMaxRedirectCount(maxRedirectCount int) configurer { + return func(conf *config) { + conf.maxRedirectCount = maxRedirectCount + } +} + +// WithUserAgent is a configurer for ObsClient to set the User-Agent. +func WithUserAgent(userAgent string) configurer { + return func(conf *config) { + conf.userAgent = userAgent + } +} + +// WithEnableCompression is a configurer for ObsClient to set the Transport.DisableCompression. +func WithEnableCompression(enableCompression bool) configurer { + return func(conf *config) { + conf.enableCompression = enableCompression + } +} + +func (conf *config) prepareConfig() { + if conf.connectTimeout <= 0 { + conf.connectTimeout = DEFAULT_CONNECT_TIMEOUT + } + + if conf.socketTimeout <= 0 { + conf.socketTimeout = DEFAULT_SOCKET_TIMEOUT + } + + conf.finalTimeout = conf.socketTimeout * 10 + + if conf.headerTimeout <= 0 { + conf.headerTimeout = DEFAULT_HEADER_TIMEOUT + } + + if conf.idleConnTimeout < 0 { + conf.idleConnTimeout = DEFAULT_IDLE_CONN_TIMEOUT + } + + if conf.maxRetryCount < 0 { + conf.maxRetryCount = DEFAULT_MAX_RETRY_COUNT + } + + if conf.maxConnsPerHost <= 0 { + conf.maxConnsPerHost = DEFAULT_MAX_CONN_PER_HOST + } + + if conf.maxRedirectCount < 0 { + conf.maxRedirectCount = DEFAULT_MAX_REDIRECT_COUNT + } + + if conf.pathStyle && conf.signature == SignatureObs { + conf.signature = SignatureV2 + } +} + +func (conf *config) initConfigWithDefault() error { + conf.endpoint = strings.TrimSpace(conf.endpoint) + if conf.endpoint == "" { + return errors.New("endpoint is not set") + } + + if index := strings.Index(conf.endpoint, "?"); index > 0 { + conf.endpoint = conf.endpoint[:index] + } + + for strings.LastIndex(conf.endpoint, "/") == len(conf.endpoint)-1 { + conf.endpoint = conf.endpoint[:len(conf.endpoint)-1] + } + + if conf.signature == "" { + conf.signature = DEFAULT_SIGNATURE + } + + urlHolder := &urlHolder{} + var address string + if strings.HasPrefix(conf.endpoint, "https://") { + urlHolder.scheme = "https" + address = conf.endpoint[len("https://"):] + } else if strings.HasPrefix(conf.endpoint, "http://") { + urlHolder.scheme = "http" + address = conf.endpoint[len("http://"):] + } else { + urlHolder.scheme = "https" + address = conf.endpoint + } + + addr := strings.Split(address, ":") + if len(addr) == 2 { + if port, err := strconv.Atoi(addr[1]); err == nil { + urlHolder.port = port + } + } + urlHolder.host = addr[0] + if urlHolder.port == 0 { + if urlHolder.scheme == "https" { + urlHolder.port = 443 + } else { + urlHolder.port = 80 + } + } + + if IsIP(urlHolder.host) { + conf.pathStyle = true + } + + conf.urlHolder = urlHolder + + conf.region = strings.TrimSpace(conf.region) + if conf.region == "" { + conf.region = DEFAULT_REGION + } + + conf.prepareConfig() + conf.proxyURL = strings.TrimSpace(conf.proxyURL) + return nil +} + +func (conf *config) getTransport() error { + if conf.transport == nil { + conf.transport = &http.Transport{ + Dial: func(network, addr string) (net.Conn, error) { + conn, err := net.DialTimeout(network, addr, time.Second*time.Duration(conf.connectTimeout)) + if err != nil { + return nil, err + } + return getConnDelegate(conn, conf.socketTimeout, conf.finalTimeout), nil + }, + MaxIdleConns: conf.maxConnsPerHost, + MaxIdleConnsPerHost: conf.maxConnsPerHost, + ResponseHeaderTimeout: time.Second * time.Duration(conf.headerTimeout), + IdleConnTimeout: time.Second * time.Duration(conf.idleConnTimeout), + DisableKeepAlives: conf.disableKeepAlive, + } + if conf.proxyURL != "" { + conf.transport.Proxy = conf.customProxyFromEnvironment + } else if conf.proxyFromEnv { + conf.transport.Proxy = http.ProxyFromEnvironment + } + + tlsConfig := &tls.Config{InsecureSkipVerify: !conf.sslVerify} + if conf.sslVerify && conf.pemCerts != nil { + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(conf.pemCerts) + tlsConfig.RootCAs = pool + } + + conf.transport.TLSClientConfig = tlsConfig + conf.transport.DisableCompression = !conf.enableCompression + } + + return nil +} + +func (conf *config) customProxyFromEnvironment(req *http.Request) (*url.URL, error) { + url, err := conf.customProxyFunc()(req.URL) + return url, err +} + +func (conf *config) customProxyFunc() func(*url.URL) (*url.URL, error) { + conf.customProxyOnce.Do(func() { + customhttpproxy := &httpproxy.Config{ + HTTPProxy: conf.proxyURL, + HTTPSProxy: conf.proxyURL, + NoProxy: conf.noProxyURL, + CGI: os.Getenv("REQUEST_METHOD") != "", + } + conf.customProxyFuncValue = customhttpproxy.ProxyFunc() + }) + return conf.customProxyFuncValue +} + +func checkRedirectFunc(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse +} + +// DummyQueryEscape return the input string. +func DummyQueryEscape(s string) string { + return s +} + +func (conf *config) prepareBaseURL(bucketName string) (requestURL string, canonicalizedURL string) { + urlHolder := conf.urlHolder + if conf.cname { + requestURL = fmt.Sprintf("%s://%s:%d", urlHolder.scheme, urlHolder.host, urlHolder.port) + if conf.signature == "v4" { + canonicalizedURL = "/" + } else { + canonicalizedURL = "/" + urlHolder.host + "/" + } + } else { + if bucketName == "" { + requestURL = fmt.Sprintf("%s://%s:%d", urlHolder.scheme, urlHolder.host, urlHolder.port) + canonicalizedURL = "/" + } else { + if conf.pathStyle { + requestURL = fmt.Sprintf("%s://%s:%d/%s", urlHolder.scheme, urlHolder.host, urlHolder.port, bucketName) + canonicalizedURL = "/" + bucketName + } else { + requestURL = fmt.Sprintf("%s://%s.%s:%d", urlHolder.scheme, bucketName, urlHolder.host, urlHolder.port) + if conf.signature == "v2" || conf.signature == "OBS" { + canonicalizedURL = "/" + bucketName + "/" + } else { + canonicalizedURL = "/" + } + } + } + } + return +} + +func (conf *config) prepareObjectKey(escape bool, objectKey string, escapeFunc func(s string) string) (encodeObjectKey string) { + if escape { + tempKey := []rune(objectKey) + result := make([]string, 0, len(tempKey)) + for _, value := range tempKey { + if string(value) == "/" { + result = append(result, string(value)) + } else { + if string(value) == " " { + result = append(result, url.PathEscape(string(value))) + } else { + result = append(result, url.QueryEscape(string(value))) + } + } + } + encodeObjectKey = strings.Join(result, "") + } else { + encodeObjectKey = escapeFunc(objectKey) + } + return +} + +func (conf *config) prepareEscapeFunc(escape bool) (escapeFunc func(s string) string) { + if escape { + return url.QueryEscape + } + return DummyQueryEscape +} + +func (conf *config) formatUrls(bucketName, objectKey string, params map[string]string, escape bool) (requestURL string, canonicalizedURL string) { + + requestURL, canonicalizedURL = conf.prepareBaseURL(bucketName) + var escapeFunc func(s string) string + escapeFunc = conf.prepareEscapeFunc(escape) + + if objectKey != "" { + var encodeObjectKey string + encodeObjectKey = conf.prepareObjectKey(escape, objectKey, escapeFunc) + requestURL += "/" + encodeObjectKey + if !strings.HasSuffix(canonicalizedURL, "/") { + canonicalizedURL += "/" + } + canonicalizedURL += encodeObjectKey + } + + keys := make([]string, 0, len(params)) + for key := range params { + keys = append(keys, strings.TrimSpace(key)) + } + sort.Strings(keys) + i := 0 + + for index, key := range keys { + if index == 0 { + requestURL += "?" + } else { + requestURL += "&" + } + _key := url.QueryEscape(key) + requestURL += _key + + _value := params[key] + if conf.signature == "v4" { + requestURL += "=" + url.QueryEscape(_value) + } else { + if _value != "" { + requestURL += "=" + url.QueryEscape(_value) + _value = "=" + _value + } else { + _value = "" + } + lowerKey := strings.ToLower(key) + _, ok := allowedResourceParameterNames[lowerKey] + prefixHeader := HEADER_PREFIX + isObs := conf.signature == SignatureObs + if isObs { + prefixHeader = HEADER_PREFIX_OBS + } + ok = ok || strings.HasPrefix(lowerKey, prefixHeader) + if ok { + if i == 0 { + canonicalizedURL += "?" + } else { + canonicalizedURL += "&" + } + canonicalizedURL += getQueryURL(_key, _value) + i++ + } + } + } + return +} + +func getQueryURL(key, value string) string { + queryURL := "" + queryURL += key + queryURL += value + return queryURL +} + +func (obsClient ObsClient) getProgressListener(extensions []extensionOptions) ProgressListener { + for _, extension := range extensions { + if configure, ok := extension.(extensionProgressListener); ok { + return configure() + } + } + return nil +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/const.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/const.go new file mode 100644 index 00000000000..28fd769d8ef --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/const.go @@ -0,0 +1,327 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +const ( + OBS_SDK_VERSION = "3.25.4" + USER_AGENT = "obs-sdk-go/" + OBS_SDK_VERSION + HEADER_PREFIX = "x-amz-" + HEADER_PREFIX_META = "x-amz-meta-" + HEADER_PREFIX_OBS = "x-obs-" + HEADER_PREFIX_META_OBS = "x-obs-meta-" + HEADER_DATE_AMZ = "x-amz-date" + HEADER_DATE_OBS = "x-obs-date" + HEADER_STS_TOKEN_AMZ = "x-amz-security-token" + HEADER_STS_TOKEN_OBS = "x-obs-security-token" + HEADER_ACCESSS_KEY_AMZ = "AWSAccessKeyId" + PREFIX_META = "meta-" + + HEADER_CONTENT_SHA256_AMZ = "x-amz-content-sha256" + HEADER_ACL_AMZ = "x-amz-acl" + HEADER_ACL_OBS = "x-obs-acl" + HEADER_ACL = "acl" + HEADER_LOCATION_AMZ = "location" + HEADER_BUCKET_LOCATION_OBS = "bucket-location" + HEADER_COPY_SOURCE = "copy-source" + HEADER_COPY_SOURCE_RANGE = "copy-source-range" + HEADER_RANGE = "Range" + HEADER_STORAGE_CLASS = "x-default-storage-class" + HEADER_STORAGE_CLASS_OBS = "x-obs-storage-class" + HEADER_FS_FILE_INTERFACE_OBS = "x-obs-fs-file-interface" + HEADER_MODE = "mode" + HEADER_VERSION_OBS = "version" + HEADER_REQUEST_PAYER = "x-amz-request-payer" + HEADER_GRANT_READ_OBS = "grant-read" + HEADER_GRANT_WRITE_OBS = "grant-write" + HEADER_GRANT_READ_ACP_OBS = "grant-read-acp" + HEADER_GRANT_WRITE_ACP_OBS = "grant-write-acp" + HEADER_GRANT_FULL_CONTROL_OBS = "grant-full-control" + HEADER_GRANT_READ_DELIVERED_OBS = "grant-read-delivered" + HEADER_GRANT_FULL_CONTROL_DELIVERED_OBS = "grant-full-control-delivered" + HEADER_REQUEST_ID = "request-id" + HEADER_ERROR_CODE = "error-code" + HEADER_ERROR_INDICATOR = "x-reserved-indicator" + HEADER_ERROR_MESSAGE = "error-message" + HEADER_BUCKET_REGION = "bucket-region" + HEADER_ACCESS_CONRTOL_ALLOW_ORIGIN = "access-control-allow-origin" + HEADER_ACCESS_CONRTOL_ALLOW_HEADERS = "access-control-allow-headers" + HEADER_ACCESS_CONRTOL_MAX_AGE = "access-control-max-age" + HEADER_ACCESS_CONRTOL_ALLOW_METHODS = "access-control-allow-methods" + HEADER_ACCESS_CONRTOL_EXPOSE_HEADERS = "access-control-expose-headers" + HEADER_EPID_HEADERS = "epid" + HEADER_VERSION_ID = "version-id" + HEADER_COPY_SOURCE_VERSION_ID = "copy-source-version-id" + HEADER_DELETE_MARKER = "delete-marker" + HEADER_WEBSITE_REDIRECT_LOCATION = "website-redirect-location" + HEADER_METADATA_DIRECTIVE = "metadata-directive" + HEADER_EXPIRATION = "expiration" + HEADER_EXPIRES_OBS = "x-obs-expires" + HEADER_RESTORE = "restore" + HEADER_OBJECT_TYPE = "object-type" + HEADER_NEXT_APPEND_POSITION = "next-append-position" + HEADER_STORAGE_CLASS2 = "storage-class" + HEADER_CONTENT_LENGTH = "content-length" + HEADER_CONTENT_TYPE = "content-type" + HEADER_CONTENT_LANGUAGE = "content-language" + HEADER_EXPIRES = "expires" + HEADER_CACHE_CONTROL = "cache-control" + HEADER_CONTENT_DISPOSITION = "content-disposition" + HEADER_CONTENT_ENCODING = "content-encoding" + HEADER_AZ_REDUNDANCY = "az-redundancy" + HEADER_BUCKET_TYPE = "bucket-type" + HEADER_BUCKET_REDUNDANCY = "bucket-redundancy" + HEADER_FUSION_ALLOW_UPGRADE = "fusion-allow-upgrade" + HEADER_FUSION_ALLOW_ALT = "fusion-allow-alternative" + headerOefMarker = "oef-marker" + + HEADER_ETAG = "etag" + HEADER_LASTMODIFIED = "last-modified" + + HEADER_COPY_SOURCE_IF_MATCH = "copy-source-if-match" + HEADER_COPY_SOURCE_IF_NONE_MATCH = "copy-source-if-none-match" + HEADER_COPY_SOURCE_IF_MODIFIED_SINCE = "copy-source-if-modified-since" + HEADER_COPY_SOURCE_IF_UNMODIFIED_SINCE = "copy-source-if-unmodified-since" + + HEADER_IF_MATCH = "If-Match" + HEADER_IF_NONE_MATCH = "If-None-Match" + HEADER_IF_MODIFIED_SINCE = "If-Modified-Since" + HEADER_IF_UNMODIFIED_SINCE = "If-Unmodified-Since" + + HEADER_SSEC_ENCRYPTION = "server-side-encryption-customer-algorithm" + HEADER_SSEC_KEY = "server-side-encryption-customer-key" + HEADER_SSEC_KEY_MD5 = "server-side-encryption-customer-key-MD5" + + HEADER_SSEKMS_ENCRYPTION = "server-side-encryption" + HEADER_SSEKMS_KEY = "server-side-encryption-aws-kms-key-id" + HEADER_SSEKMS_ENCRYPT_KEY_OBS = "server-side-encryption-kms-key-id" + + HEADER_SSEC_COPY_SOURCE_ENCRYPTION = "copy-source-server-side-encryption-customer-algorithm" + HEADER_SSEC_COPY_SOURCE_KEY = "copy-source-server-side-encryption-customer-key" + HEADER_SSEC_COPY_SOURCE_KEY_MD5 = "copy-source-server-side-encryption-customer-key-MD5" + + HEADER_SSEKMS_KEY_AMZ = "x-amz-server-side-encryption-aws-kms-key-id" + + HEADER_SSEKMS_KEY_OBS = "x-obs-server-side-encryption-kms-key-id" + + HEADER_SUCCESS_ACTION_REDIRECT = "success_action_redirect" + + headerFSFileInterface = "fs-file-interface" + + HEADER_DATE_CAMEL = "Date" + HEADER_HOST_CAMEL = "Host" + HEADER_HOST = "host" + HEADER_AUTH_CAMEL = "Authorization" + HEADER_MD5_CAMEL = "Content-MD5" + HEADER_SHA256_CAMEL = "Content-SHA256" + HEADER_SHA256 = "content-sha256" + HEADER_LOCATION_CAMEL = "Location" + HEADER_CONTENT_LENGTH_CAMEL = "Content-Length" + HEADER_CONTENT_TYPE_CAML = "Content-Type" + HEADER_USER_AGENT_CAMEL = "User-Agent" + HEADER_ORIGIN_CAMEL = "Origin" + HEADER_ACCESS_CONTROL_REQUEST_HEADER_CAMEL = "Access-Control-Request-Headers" + HEADER_CACHE_CONTROL_CAMEL = "Cache-Control" + HEADER_CONTENT_DISPOSITION_CAMEL = "Content-Disposition" + HEADER_CONTENT_ENCODING_CAMEL = "Content-Encoding" + HEADER_CONTENT_LANGUAGE_CAMEL = "Content-Language" + HEADER_EXPIRES_CAMEL = "Expires" + HEADER_ACCEPT_ENCODING = "Accept-Encoding" + + PARAM_VERSION_ID = "versionId" + PARAM_RESPONSE_CONTENT_TYPE = "response-content-type" + PARAM_RESPONSE_CONTENT_LANGUAGE = "response-content-language" + PARAM_RESPONSE_EXPIRES = "response-expires" + PARAM_RESPONSE_CACHE_CONTROL = "response-cache-control" + PARAM_RESPONSE_CONTENT_DISPOSITION = "response-content-disposition" + PARAM_RESPONSE_CONTENT_ENCODING = "response-content-encoding" + PARAM_IMAGE_PROCESS = "x-image-process" + + PARAM_ALGORITHM_AMZ_CAMEL = "X-Amz-Algorithm" + PARAM_CREDENTIAL_AMZ_CAMEL = "X-Amz-Credential" + PARAM_DATE_AMZ_CAMEL = "X-Amz-Date" + PARAM_DATE_OBS_CAMEL = "X-Obs-Date" + PARAM_EXPIRES_AMZ_CAMEL = "X-Amz-Expires" + PARAM_SIGNEDHEADERS_AMZ_CAMEL = "X-Amz-SignedHeaders" + PARAM_SIGNATURE_AMZ_CAMEL = "X-Amz-Signature" + + DEFAULT_SIGNATURE = SignatureV2 + DEFAULT_REGION = "region" + DEFAULT_CONNECT_TIMEOUT = 60 + DEFAULT_SOCKET_TIMEOUT = 60 + DEFAULT_HEADER_TIMEOUT = 60 + DEFAULT_IDLE_CONN_TIMEOUT = 30 + DEFAULT_MAX_RETRY_COUNT = 3 + DEFAULT_MAX_REDIRECT_COUNT = 3 + DEFAULT_MAX_CONN_PER_HOST = 1000 + UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD" + LONG_DATE_FORMAT = "20060102T150405Z" + SHORT_DATE_FORMAT = "20060102" + ISO8601_DATE_FORMAT = "2006-01-02T15:04:05Z" + ISO8601_MIDNIGHT_DATE_FORMAT = "2006-01-02T00:00:00Z" + RFC1123_FORMAT = "Mon, 02 Jan 2006 15:04:05 GMT" + + V4_SERVICE_NAME = "s3" + V4_SERVICE_SUFFIX = "aws4_request" + + V2_HASH_PREFIX = "AWS" + OBS_HASH_PREFIX = "OBS" + + V4_HASH_PREFIX = "AWS4-HMAC-SHA256" + V4_HASH_PRE = "AWS4" + + DEFAULT_SSE_KMS_ENCRYPTION = "aws:kms" + DEFAULT_SSE_KMS_ENCRYPTION_OBS = "kms" + + DEFAULT_SSE_C_ENCRYPTION = "AES256" + + HTTP_GET = "GET" + HTTP_POST = "POST" + HTTP_PUT = "PUT" + HTTP_DELETE = "DELETE" + HTTP_HEAD = "HEAD" + HTTP_OPTIONS = "OPTIONS" + + REQUEST_PAYER = "request-payer" + TRAFFIC_LIMIT = "traffic-limit" + CALLBACK = "callback" + MULTI_AZ = "3az" + + MAX_PART_SIZE = 5 * 1024 * 1024 * 1024 + MIN_PART_SIZE = 100 * 1024 + DEFAULT_PART_SIZE = 9 * 1024 * 1024 + MAX_PART_NUM = 10000 + + GET_OBJECT = "GetObject" + PUT_OBJECT = "PutObject" + PUT_FILE = "PutFile" + APPEND_OBJECT = "AppendObject" + MAX_CERT_XML_BODY_SIZE = 40 * 1024 + CERT_ID_SIZE = 16 + MAX_CERTIFICATE_NAME_LENGTH = 63 + MIN_CERTIFICATE_NAME_LENGTH = 3 + CERTIFICATE_FIELD_NAME = "CERTIFICATE ID SIZE" + NAME_LENGTH = "Name Length" + XML_SIZE = "XML SIZE" +) + +var ( + interestedHeaders = []string{"content-md5", "content-type", "date"} + + allowedRequestHTTPHeaderMetadataNames = map[string]bool{ + "content-type": true, + "content-md5": true, + "content-sha256": true, + "content-length": true, + "content-language": true, + "expires": true, + "origin": true, + "cache-control": true, + "content-disposition": true, + "content-encoding": true, + "access-control-request-method": true, + "access-control-request-headers": true, + "x-default-storage-class": true, + "location": true, + "date": true, + "etag": true, + "range": true, + "host": true, + "if-modified-since": true, + "if-unmodified-since": true, + "if-match": true, + "if-none-match": true, + "last-modified": true, + "content-range": true, + "accept-encoding": true, + } + + allowedLogResponseHTTPHeaderNames = map[string]bool{ + "content-type": true, + "etag": true, + "connection": true, + "content-length": true, + "date": true, + "server": true, + "x-reserved-indicator": true, + } + + allowedResourceParameterNames = map[string]bool{ + "acl": true, + "backtosource": true, + "metadata": true, + "policy": true, + "torrent": true, + "logging": true, + "location": true, + "storageinfo": true, + "quota": true, + "storageclass": true, + "storagepolicy": true, + "requestpayment": true, + "versions": true, + "versioning": true, + "versionid": true, + "uploads": true, + "uploadid": true, + "partnumber": true, + "website": true, + "notification": true, + "lifecycle": true, + "deletebucket": true, + "delete": true, + "cors": true, + "restore": true, + "encryption": true, + "tagging": true, + "append": true, + "modify": true, + "position": true, + "replication": true, + "response-content-type": true, + "response-content-language": true, + "response-expires": true, + "response-cache-control": true, + "response-content-disposition": true, + "response-content-encoding": true, + "x-image-process": true, + "x-oss-process": true, + "x-image-save-bucket": true, + "x-image-save-object": true, + "ignore-sign-in-query": true, + "name": true, + "rename": true, + "customdomain": true, + "mirrorbacktosource": true, + "x-obs-accesslabel": true, + "object-lock": true, + "retention": true, + "x-obs-security-token": true, + "truncate": true, + "length": true, + "inventory": true, + "directcoldaccess": true, + "attname": true, + "cdnnotifyconfiguration": true, + "publicaccessblock": true, + "bucketstatus": true, + "policystatus": true, + } + + obsStorageClasses = []string{ + string(StorageClassStandard), + string(StorageClassWarm), + string(StorageClassCold), + string(StorageClassDeepArchive), + string(StorageClassIntelligentTiering), + } +) diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/convert.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/convert.go new file mode 100644 index 00000000000..87b8c6be572 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/convert.go @@ -0,0 +1,1313 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "strconv" + "strings" + "time" +) + +func cleanHeaderPrefix(header http.Header, isObs bool) map[string][]string { + responseHeaders := make(map[string][]string) + for key, value := range header { + if len(value) > 0 { + key = strings.ToLower(key) + + if !isObs && strings.HasSuffix(key, HEADER_EXPIRES_OBS) { + responseHeaders[key] = value + continue + } + if strings.HasPrefix(key, HEADER_PREFIX) || strings.HasPrefix(key, HEADER_PREFIX_OBS) { + key = key[len(HEADER_PREFIX):] + } + responseHeaders[key] = value + } + } + return responseHeaders +} + +// ParseStringToEventType converts string value to EventType value and returns it +func ParseStringToEventType(value string) (ret EventType) { + switch value { + case "ObjectCreated:*", "s3:ObjectCreated:*": + ret = ObjectCreatedAll + case "ObjectCreated:Put", "s3:ObjectCreated:Put": + ret = ObjectCreatedPut + case "ObjectCreated:Post", "s3:ObjectCreated:Post": + ret = ObjectCreatedPost + case "ObjectCreated:Copy", "s3:ObjectCreated:Copy": + ret = ObjectCreatedCopy + case "ObjectCreated:CompleteMultipartUpload", "s3:ObjectCreated:CompleteMultipartUpload": + ret = ObjectCreatedCompleteMultipartUpload + case "ObjectRemoved:*", "s3:ObjectRemoved:*": + ret = ObjectRemovedAll + case "ObjectRemoved:Delete", "s3:ObjectRemoved:Delete": + ret = ObjectRemovedDelete + case "ObjectRemoved:DeleteMarkerCreated", "s3:ObjectRemoved:DeleteMarkerCreated": + ret = ObjectRemovedDeleteMarkerCreated + default: + ret = "" + } + return +} + +// ParseStringToStorageClassType converts string value to StorageClassType value and returns it +func ParseStringToStorageClassType(value string) (ret StorageClassType) { + switch value { + case string(StorageClassStandard): + ret = StorageClassStandard + case string(storageClassStandardIA), string(StorageClassWarm): + ret = StorageClassWarm + case string(storageClassGlacier), string(StorageClassCold): + ret = StorageClassCold + case string(StorageClassDeepArchive): + ret = StorageClassDeepArchive + case string(StorageClassIntelligentTiering): + ret = StorageClassIntelligentTiering + default: + ret = "" + } + return +} + +func ParseStringToFSStatusType(value string) (ret FSStatusType) { + switch value { + case "Enabled": + ret = FSStatusEnabled + case "Disabled": + ret = FSStatusDisabled + default: + ret = "" + } + return +} + +func prepareGrantURI(grantUri GroupUriType) string { + if grantUri == GroupAllUsers || grantUri == GroupAuthenticatedUsers { + return fmt.Sprintf("%s%s", "http://acs.amazonaws.com/groups/global/", grantUri) + } + if grantUri == GroupLogDelivery { + return fmt.Sprintf("%s%s", "http://acs.amazonaws.com/groups/s3/", grantUri) + } + return fmt.Sprintf("%s", grantUri) +} + +func convertGrantToXML(grant Grant, isObs bool, isBucket bool) string { + xml := make([]string, 0, 4) + + if grant.Grantee.ID != "" && + grant.Grantee.URI == "" && + grant.Grantee.Type == "" { + grant.Grantee.Type = GranteeUser + } + + if grant.Grantee.URI != "" && + grant.Grantee.ID == "" && + grant.Grantee.Type == "" { + grant.Grantee.Type = GranteeGroup + } + + if grant.Grantee.Type == GranteeUser { + if isObs { + xml = append(xml, "") + } else { + xml = append(xml, fmt.Sprintf("", grant.Grantee.Type)) + } + if grant.Grantee.ID != "" { + granteeID := XmlTranscoding(grant.Grantee.ID) + xml = append(xml, fmt.Sprintf("%s", granteeID)) + } + if !isObs && grant.Grantee.DisplayName != "" { + granteeDisplayName := XmlTranscoding(grant.Grantee.DisplayName) + xml = append(xml, fmt.Sprintf("%s", granteeDisplayName)) + } + xml = append(xml, "") + } else { + if !isObs { + xml = append(xml, fmt.Sprintf("", grant.Grantee.Type)) + xml = append(xml, prepareGrantURI(grant.Grantee.URI)) + xml = append(xml, "") + } else if grant.Grantee.URI == GroupAllUsers { + xml = append(xml, "") + xml = append(xml, fmt.Sprintf("Everyone")) + xml = append(xml, "") + } else { + return strings.Join(xml, "") + } + } + + xml = append(xml, fmt.Sprintf("%s", grant.Permission)) + if isObs && isBucket { + xml = append(xml, fmt.Sprintf("%t", grant.Delivered)) + } + xml = append(xml, fmt.Sprintf("")) + return strings.Join(xml, "") +} + +func hasLoggingTarget(input BucketLoggingStatus) bool { + if input.TargetBucket != "" || input.TargetPrefix != "" || len(input.TargetGrants) > 0 { + return true + } + return false +} + +// ConvertLoggingStatusToXml converts BucketLoggingStatus value to XML data and returns it +func ConvertLoggingStatusToXml(input BucketLoggingStatus, returnMd5 bool, isObs bool) (data string, md5 string) { + grantsLength := len(input.TargetGrants) + xml := make([]string, 0, 8+grantsLength) + + if isObs { + xml = append(xml, "") + } else { + xml = append(xml, ``) + } + if isObs && input.Agency != "" { + agency := XmlTranscoding(input.Agency) + xml = append(xml, fmt.Sprintf("%s", agency)) + } + if hasLoggingTarget(input) { + xml = append(xml, "") + if input.TargetBucket != "" { + xml = append(xml, fmt.Sprintf("%s", input.TargetBucket)) + } + if input.TargetPrefix != "" { + targetPrefix := XmlTranscoding(input.TargetPrefix) + xml = append(xml, fmt.Sprintf("%s", targetPrefix)) + } + if grantsLength > 0 { + xml = append(xml, "") + for _, grant := range input.TargetGrants { + xml = append(xml, convertGrantToXML(grant, isObs, false)) + } + xml = append(xml, "") + } + + xml = append(xml, "") + } + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5 = Base64Md5([]byte(data)) + } + return +} + +// ConvertAclToXml converts AccessControlPolicy value to XML data and returns it +func ConvertAclToXml(input AccessControlPolicy, returnMd5 bool, isObs bool) (data string, md5 string) { + xml := make([]string, 0, 4+len(input.Grants)) + ownerID := XmlTranscoding(input.Owner.ID) + xml = append(xml, fmt.Sprintf("%s", ownerID)) + if !isObs && input.Owner.DisplayName != "" { + ownerDisplayName := XmlTranscoding(input.Owner.DisplayName) + xml = append(xml, fmt.Sprintf("%s", ownerDisplayName)) + } + if isObs && input.Delivered != "" { + objectDelivered := XmlTranscoding(input.Delivered) + xml = append(xml, fmt.Sprintf("%s", objectDelivered)) + } else { + xml = append(xml, "") + } + for _, grant := range input.Grants { + xml = append(xml, convertGrantToXML(grant, isObs, false)) + } + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5 = Base64Md5([]byte(data)) + } + return +} + +func convertBucketACLToXML(input AccessControlPolicy, returnMd5 bool, isObs bool) (data string, md5 string) { + xml := make([]string, 0, 4+len(input.Grants)) + ownerID := XmlTranscoding(input.Owner.ID) + xml = append(xml, fmt.Sprintf("%s", ownerID)) + if !isObs && input.Owner.DisplayName != "" { + ownerDisplayName := XmlTranscoding(input.Owner.DisplayName) + xml = append(xml, fmt.Sprintf("%s", ownerDisplayName)) + } + + xml = append(xml, "") + + for _, grant := range input.Grants { + xml = append(xml, convertGrantToXML(grant, isObs, true)) + } + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5 = Base64Md5([]byte(data)) + } + return +} + +func convertConditionToXML(condition Condition) string { + xml := make([]string, 0, 2) + if condition.KeyPrefixEquals != "" { + keyPrefixEquals := XmlTranscoding(condition.KeyPrefixEquals) + xml = append(xml, fmt.Sprintf("%s", keyPrefixEquals)) + } + if condition.HttpErrorCodeReturnedEquals != "" { + xml = append(xml, fmt.Sprintf("%s", condition.HttpErrorCodeReturnedEquals)) + } + if len(xml) > 0 { + return fmt.Sprintf("%s", strings.Join(xml, "")) + } + return "" +} + +func prepareRoutingRule(input BucketWebsiteConfiguration) string { + xml := make([]string, 0, len(input.RoutingRules)*10) + for _, routingRule := range input.RoutingRules { + xml = append(xml, "") + xml = append(xml, "") + if routingRule.Redirect.Protocol != "" { + xml = append(xml, fmt.Sprintf("%s", routingRule.Redirect.Protocol)) + } + if routingRule.Redirect.HostName != "" { + xml = append(xml, fmt.Sprintf("%s", routingRule.Redirect.HostName)) + } + if routingRule.Redirect.ReplaceKeyPrefixWith != "" { + replaceKeyPrefixWith := XmlTranscoding(routingRule.Redirect.ReplaceKeyPrefixWith) + xml = append(xml, fmt.Sprintf("%s", replaceKeyPrefixWith)) + } + + if routingRule.Redirect.ReplaceKeyWith != "" { + replaceKeyWith := XmlTranscoding(routingRule.Redirect.ReplaceKeyWith) + xml = append(xml, fmt.Sprintf("%s", replaceKeyWith)) + } + if routingRule.Redirect.HttpRedirectCode != "" { + xml = append(xml, fmt.Sprintf("%s", routingRule.Redirect.HttpRedirectCode)) + } + xml = append(xml, "") + + if ret := convertConditionToXML(routingRule.Condition); ret != "" { + xml = append(xml, ret) + } + xml = append(xml, "") + } + return strings.Join(xml, "") +} + +// ConvertWebsiteConfigurationToXml converts BucketWebsiteConfiguration value to XML data and returns it +func ConvertWebsiteConfigurationToXml(input BucketWebsiteConfiguration, returnMd5 bool) (data string, md5 string) { + routingRuleLength := len(input.RoutingRules) + xml := make([]string, 0, 6+routingRuleLength*10) + xml = append(xml, "") + + if input.RedirectAllRequestsTo.HostName != "" { + xml = append(xml, fmt.Sprintf("%s", input.RedirectAllRequestsTo.HostName)) + if input.RedirectAllRequestsTo.Protocol != "" { + xml = append(xml, fmt.Sprintf("%s", input.RedirectAllRequestsTo.Protocol)) + } + xml = append(xml, "") + } else { + if input.IndexDocument.Suffix != "" { + indexDocumentSuffix := XmlTranscoding(input.IndexDocument.Suffix) + xml = append(xml, fmt.Sprintf("%s", indexDocumentSuffix)) + } + if input.ErrorDocument.Key != "" { + errorDocumentKey := XmlTranscoding(input.ErrorDocument.Key) + xml = append(xml, fmt.Sprintf("%s", errorDocumentKey)) + } + if routingRuleLength > 0 { + xml = append(xml, "") + xml = append(xml, prepareRoutingRule(input)) + xml = append(xml, "") + } + } + + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5 = Base64Md5([]byte(data)) + } + return +} + +func convertTransitionsToXML(transitions []Transition, isObs bool) string { + if length := len(transitions); length > 0 { + xml := make([]string, 0, length) + for _, transition := range transitions { + var temp string + if transition.Days > 0 { + temp = fmt.Sprintf("%d", transition.Days) + } else if !transition.Date.IsZero() { + temp = fmt.Sprintf("%s", transition.Date.UTC().Format(ISO8601_MIDNIGHT_DATE_FORMAT)) + } + if temp != "" { + if !isObs { + storageClass := string(transition.StorageClass) + if transition.StorageClass == StorageClassWarm { + storageClass = string(storageClassStandardIA) + } else if transition.StorageClass == StorageClassCold { + storageClass = string(storageClassGlacier) + } + xml = append(xml, fmt.Sprintf("%s%s", temp, storageClass)) + } else { + xml = append(xml, fmt.Sprintf("%s%s", temp, transition.StorageClass)) + } + } + } + return strings.Join(xml, "") + } + return "" +} + +func convertLifeCycleFilterToXML(filter LifecycleFilter) string { + if filter.Prefix == "" && len(filter.Tags) == 0 { + return "" + } + data, err := TransToXml(filter) + if err != nil { + return "" + } + return string(data) +} + +func convertExpirationToXML(expiration Expiration) string { + if expiration.Days > 0 { + return fmt.Sprintf("%d", expiration.Days) + } else if !expiration.Date.IsZero() { + return fmt.Sprintf("%s", expiration.Date.UTC().Format(ISO8601_MIDNIGHT_DATE_FORMAT)) + } else if expiration.ExpiredObjectDeleteMarker != "" { + return fmt.Sprintf("%s", expiration.ExpiredObjectDeleteMarker) + } + return "" +} + +func convertNoncurrentVersionTransitionsToXML(noncurrentVersionTransitions []NoncurrentVersionTransition, isObs bool) string { + if length := len(noncurrentVersionTransitions); length > 0 { + xml := make([]string, 0, length) + for _, noncurrentVersionTransition := range noncurrentVersionTransitions { + if noncurrentVersionTransition.NoncurrentDays > 0 { + storageClass := string(noncurrentVersionTransition.StorageClass) + if !isObs { + if storageClass == string(StorageClassWarm) { + storageClass = string(storageClassStandardIA) + } else if storageClass == string(StorageClassCold) { + storageClass = string(storageClassGlacier) + } + } + xml = append(xml, fmt.Sprintf("%d"+ + "%s", + noncurrentVersionTransition.NoncurrentDays, storageClass)) + } + } + return strings.Join(xml, "") + } + return "" +} +func convertNoncurrentVersionExpirationToXML(noncurrentVersionExpiration NoncurrentVersionExpiration) string { + if noncurrentVersionExpiration.NoncurrentDays > 0 { + return fmt.Sprintf("%d", noncurrentVersionExpiration.NoncurrentDays) + } + return "" +} + +func convertAbortIncompleteMultipartUploadToXML(abortIncompleteMultipartUpload AbortIncompleteMultipartUpload) string { + if abortIncompleteMultipartUpload.DaysAfterInitiation > 0 { + return fmt.Sprintf("%d", abortIncompleteMultipartUpload.DaysAfterInitiation) + } + return "" +} + +// ConvertLifecycleConfigurationToXml converts BucketLifecycleConfiguration value to XML data and returns it +func ConvertLifecycleConfigurationToXml(input BucketLifecycleConfiguration, returnMd5, isObs, enableSha256 bool) (data string, md5OrSha256 string) { + xml := make([]string, 0, 2+len(input.LifecycleRules)*9) + xml = append(xml, "") + for _, lifecycleRule := range input.LifecycleRules { + xml = append(xml, "") + if lifecycleRule.ID != "" { + lifecycleRuleID := XmlTranscoding(lifecycleRule.ID) + xml = append(xml, fmt.Sprintf("%s", lifecycleRuleID)) + } + lifecycleRulePrefix := XmlTranscoding(lifecycleRule.Prefix) + lifecycleRuleFilter := convertLifeCycleFilterToXML(lifecycleRule.Filter) + if lifecycleRulePrefix != "" || (lifecycleRulePrefix == "" && lifecycleRuleFilter == "") { + xml = append(xml, fmt.Sprintf("%s", lifecycleRulePrefix)) + } + if lifecycleRuleFilter != "" { + xml = append(xml, lifecycleRuleFilter) + } + xml = append(xml, fmt.Sprintf("%s", lifecycleRule.Status)) + if ret := convertTransitionsToXML(lifecycleRule.Transitions, isObs); ret != "" { + xml = append(xml, ret) + } + if ret := convertExpirationToXML(lifecycleRule.Expiration); ret != "" { + xml = append(xml, ret) + } + if ret := convertNoncurrentVersionTransitionsToXML(lifecycleRule.NoncurrentVersionTransitions, isObs); ret != "" { + xml = append(xml, ret) + } + if ret := convertNoncurrentVersionExpirationToXML(lifecycleRule.NoncurrentVersionExpiration); ret != "" { + xml = append(xml, ret) + } + if ret := convertAbortIncompleteMultipartUploadToXML(lifecycleRule.AbortIncompleteMultipartUpload); ret != "" { + xml = append(xml, ret) + } + xml = append(xml, "") + } + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5OrSha256 = Base64Md5OrSha256([]byte(data), enableSha256) + } + return +} + +// ConvertEncryptionConfigurationToXml converts BucketEncryptionConfiguration value to XML data and returns it +func ConvertEncryptionConfigurationToXml(input BucketEncryptionConfiguration, returnMd5 bool, isObs bool) (data string, md5 string) { + xml := make([]string, 0, 5) + xml = append(xml, "") + + algorithm := XmlTranscoding(input.SSEAlgorithm) + xml = append(xml, fmt.Sprintf("%s", algorithm)) + + if input.KMSMasterKeyID != "" { + kmsKeyID := XmlTranscoding(input.KMSMasterKeyID) + xml = append(xml, fmt.Sprintf("%s", kmsKeyID)) + } + if input.ProjectID != "" { + projectID := XmlTranscoding(input.ProjectID) + xml = append(xml, fmt.Sprintf("%s", projectID)) + } + + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5 = Base64Md5([]byte(data)) + } + return +} + +func converntFilterRulesToXML(filterRules []FilterRule, isObs bool) string { + if length := len(filterRules); length > 0 { + xml := make([]string, 0, length*4) + for _, filterRule := range filterRules { + xml = append(xml, "") + if filterRule.Name != "" { + filterRuleName := XmlTranscoding(filterRule.Name) + xml = append(xml, fmt.Sprintf("%s", filterRuleName)) + } + if filterRule.Value != "" { + filterRuleValue := XmlTranscoding(filterRule.Value) + xml = append(xml, fmt.Sprintf("%s", filterRuleValue)) + } + xml = append(xml, "") + } + if !isObs { + return fmt.Sprintf("%s", strings.Join(xml, "")) + } + return fmt.Sprintf("%s", strings.Join(xml, "")) + } + return "" +} + +func converntEventsToXML(events []EventType, isObs bool) string { + if length := len(events); length > 0 { + xml := make([]string, 0, length) + if !isObs { + for _, event := range events { + xml = append(xml, fmt.Sprintf("%s%s", "s3:", event)) + } + } else { + for _, event := range events { + xml = append(xml, fmt.Sprintf("%s", event)) + } + } + return strings.Join(xml, "") + } + return "" +} + +func converntConfigureToXML(topicConfiguration TopicConfiguration, xmlElem string, isObs bool) string { + xml := make([]string, 0, 6) + xml = append(xml, xmlElem) + if topicConfiguration.ID != "" { + topicConfigurationID := XmlTranscoding(topicConfiguration.ID) + xml = append(xml, fmt.Sprintf("%s", topicConfigurationID)) + } + topicConfigurationTopic := XmlTranscoding(topicConfiguration.Topic) + xml = append(xml, fmt.Sprintf("%s", topicConfigurationTopic)) + + if ret := converntEventsToXML(topicConfiguration.Events, isObs); ret != "" { + xml = append(xml, ret) + } + if ret := converntFilterRulesToXML(topicConfiguration.FilterRules, isObs); ret != "" { + xml = append(xml, ret) + } + tempElem := xmlElem[0:1] + "/" + xmlElem[1:] + xml = append(xml, tempElem) + return strings.Join(xml, "") +} + +// ConventObsRestoreToXml converts RestoreObjectInput value to XML data and returns it +func ConventObsRestoreToXml(restoreObjectInput RestoreObjectInput) string { + xml := make([]string, 0, 2) + xml = append(xml, fmt.Sprintf("%d", restoreObjectInput.Days)) + if restoreObjectInput.Tier != "Bulk" { + xml = append(xml, fmt.Sprintf("%s", restoreObjectInput.Tier)) + } + xml = append(xml, fmt.Sprintf("")) + data := strings.Join(xml, "") + return data +} + +// ConvertNotificationToXml converts BucketNotification value to XML data and returns it +func ConvertNotificationToXml(input BucketNotification, returnMd5 bool, isObs bool) (data string, md5 string) { + xml := make([]string, 0, 2+len(input.TopicConfigurations)*6) + xml = append(xml, "") + for _, topicConfiguration := range input.TopicConfigurations { + ret := converntConfigureToXML(topicConfiguration, "", isObs) + xml = append(xml, ret) + } + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5 = Base64Md5([]byte(data)) + } + return +} + +// ConvertCompleteMultipartUploadInputToXml converts CompleteMultipartUploadInput value to XML data and returns it +func ConvertCompleteMultipartUploadInputToXml(input CompleteMultipartUploadInput, returnMd5 bool) (data string, md5 string) { + xml := make([]string, 0, 2+len(input.Parts)*4) + xml = append(xml, "") + for _, part := range input.Parts { + xml = append(xml, "") + xml = append(xml, fmt.Sprintf("%d", part.PartNumber)) + xml = append(xml, fmt.Sprintf("%s", part.ETag)) + xml = append(xml, "") + } + xml = append(xml, "") + data = strings.Join(xml, "") + if returnMd5 { + md5 = Base64Md5([]byte(data)) + } + return +} + +func convertDeleteObjectsToXML(input DeleteObjectsInput) (data string, md5 string) { + xml := make([]string, 0, 4+len(input.Objects)*4) + xml = append(xml, "") + if input.Quiet { + xml = append(xml, fmt.Sprintf("%t", input.Quiet)) + } + if input.EncodingType != "" { + encodingType := XmlTranscoding(input.EncodingType) + xml = append(xml, fmt.Sprintf("%s", encodingType)) + } + for _, obj := range input.Objects { + xml = append(xml, "") + key := XmlTranscoding(obj.Key) + xml = append(xml, fmt.Sprintf("%s", key)) + if obj.VersionId != "" { + xml = append(xml, fmt.Sprintf("%s", obj.VersionId)) + } + xml = append(xml, "") + } + xml = append(xml, "") + data = strings.Join(xml, "") + md5 = Base64Md5([]byte(data)) + return +} + +func parseSseHeader(responseHeaders map[string][]string) (sseHeader ISseHeader) { + if ret, ok := responseHeaders[HEADER_SSEC_ENCRYPTION]; ok { + sseCHeader := SseCHeader{Encryption: ret[0]} + if ret, ok = responseHeaders[HEADER_SSEC_KEY_MD5]; ok { + sseCHeader.KeyMD5 = ret[0] + } + sseHeader = sseCHeader + } else if ret, ok := responseHeaders[HEADER_SSEKMS_ENCRYPTION]; ok { + sseKmsHeader := SseKmsHeader{Encryption: ret[0]} + if ret, ok = responseHeaders[HEADER_SSEKMS_KEY]; ok { + sseKmsHeader.Key = ret[0] + } else if ret, ok = responseHeaders[HEADER_SSEKMS_ENCRYPT_KEY_OBS]; ok { + sseKmsHeader.Key = ret[0] + } + sseHeader = sseKmsHeader + } + return +} + +func parseCorsHeader(output BaseModel) (AllowOrigin, AllowHeader, AllowMethod, ExposeHeader string, MaxAgeSeconds int) { + if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_ORIGIN]; ok { + AllowOrigin = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_HEADERS]; ok { + AllowHeader = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_MAX_AGE]; ok { + MaxAgeSeconds = StringToInt(ret[0], 0) + } + if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_ALLOW_METHODS]; ok { + AllowMethod = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_ACCESS_CONRTOL_EXPOSE_HEADERS]; ok { + ExposeHeader = ret[0] + } + return +} + +func parseUnCommonHeader(output *GetObjectMetadataOutput) { + if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_WEBSITE_REDIRECT_LOCATION]; ok { + output.WebsiteRedirectLocation = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_EXPIRATION]; ok { + output.Expiration = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_RESTORE]; ok { + output.Restore = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_OBJECT_TYPE]; ok { + output.ObjectType = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_NEXT_APPEND_POSITION]; ok { + output.NextAppendPosition = ret[0] + } +} + +func parseStandardMetadataHeader(output *GetObjectMetadataOutput) { + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok { + output.ContentType = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok { + output.ContentEncoding = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok { + output.CacheControl = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok { + output.ContentDisposition = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok { + output.ContentLanguage = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok { + output.HttpExpires = ret[0] + } +} + +// ParseGetObjectMetadataOutput sets GetObjectMetadataOutput field values with response headers +func ParseGetObjectMetadataOutput(output *GetObjectMetadataOutput) { + output.AllowOrigin, output.AllowHeader, output.AllowMethod, output.ExposeHeader, output.MaxAgeSeconds = parseCorsHeader(output.BaseModel) + parseUnCommonHeader(output) + parseStandardMetadataHeader(output) + if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok { + output.StorageClass = ParseStringToStorageClassType(ret[0]) + } + if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok { + output.ETag = ret[0] + } + + output.SseHeader = parseSseHeader(output.ResponseHeaders) + if ret, ok := output.ResponseHeaders[HEADER_LASTMODIFIED]; ok { + ret, err := time.Parse(time.RFC1123, ret[0]) + if err == nil { + output.LastModified = ret + } + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LENGTH]; ok { + output.ContentLength = StringToInt64(ret[0], 0) + } + + output.Metadata = make(map[string]string) + + for key, value := range output.ResponseHeaders { + if strings.HasPrefix(key, PREFIX_META) { + _key := key[len(PREFIX_META):] + output.ResponseHeaders[_key] = value + output.Metadata[_key] = value[0] + delete(output.ResponseHeaders, key) + } + } + +} + +// ParseCopyObjectOutput sets CopyObjectOutput field values with response headers +func ParseCopyObjectOutput(output *CopyObjectOutput) { + if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = ret[0] + } + output.SseHeader = parseSseHeader(output.ResponseHeaders) + if ret, ok := output.ResponseHeaders[HEADER_COPY_SOURCE_VERSION_ID]; ok { + output.CopySourceVersionId = ret[0] + } +} + +// ParsePutObjectOutput sets PutObjectOutput field values with response headers +func ParsePutObjectOutput(output *PutObjectOutput) { + if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = ret[0] + } + output.SseHeader = parseSseHeader(output.ResponseHeaders) + if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok { + output.StorageClass = ParseStringToStorageClassType(ret[0]) + } + if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok { + output.ETag = ret[0] + } +} + +// ParseInitiateMultipartUploadOutput sets InitiateMultipartUploadOutput field values with response headers +func ParseInitiateMultipartUploadOutput(output *InitiateMultipartUploadOutput) { + output.SseHeader = parseSseHeader(output.ResponseHeaders) +} + +// ParseUploadPartOutput sets UploadPartOutput field values with response headers +func ParseUploadPartOutput(output *UploadPartOutput) { + output.SseHeader = parseSseHeader(output.ResponseHeaders) + if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok { + output.ETag = ret[0] + } +} + +// ParseCompleteMultipartUploadOutput sets CompleteMultipartUploadOutput field values with response headers +func ParseCompleteMultipartUploadOutput(output *CompleteMultipartUploadOutput) { + output.SseHeader = parseSseHeader(output.ResponseHeaders) + if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = ret[0] + } +} + +// ParseCopyPartOutput sets CopyPartOutput field values with response headers +func ParseCopyPartOutput(output *CopyPartOutput) { + output.SseHeader = parseSseHeader(output.ResponseHeaders) +} + +// ParseStringToAvailableZoneType converts string value to AvailableZoneType value and returns it +func ParseStringToAvailableZoneType(value string) (ret AvailableZoneType) { + switch value { + case "3az": + ret = AvailableZoneMultiAz + default: + ret = "" + } + return +} + +// ParseGetBucketMetadataOutput sets GetBucketMetadataOutput field values with response headers +func ParseGetBucketMetadataOutput(output *GetBucketMetadataOutput) { + output.AllowOrigin, output.AllowHeader, output.AllowMethod, output.ExposeHeader, output.MaxAgeSeconds = parseCorsHeader(output.BaseModel) + if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS]; ok { + output.StorageClass = ParseStringToStorageClassType(ret[0]) + } else if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok { + output.StorageClass = ParseStringToStorageClassType(ret[0]) + } + if ret, ok := output.ResponseHeaders[HEADER_VERSION_OBS]; ok { + output.Version = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok { + output.Location = ret[0] + } else if ret, ok := output.ResponseHeaders[HEADER_BUCKET_LOCATION_OBS]; ok { + output.Location = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_EPID_HEADERS]; ok { + output.Epid = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_AZ_REDUNDANCY]; ok { + output.AZRedundancy = ParseStringToAvailableZoneType(ret[0]) + } + if ret, ok := output.ResponseHeaders[HEADER_BUCKET_REDUNDANCY]; ok { + output.BucketRedundancy = parseStringToBucketRedundancy(ret[0]) + } + if ret, ok := output.ResponseHeaders[headerFSFileInterface]; ok { + output.FSStatus = parseStringToFSStatusType(ret[0]) + } else { + output.FSStatus = FSStatusDisabled + } +} + +func parseContentHeader(output *SetObjectMetadataOutput) { + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok { + output.ContentDisposition = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok { + output.ContentEncoding = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok { + output.ContentLanguage = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok { + output.ContentType = ret[0] + } +} + +// ParseSetObjectMetadataOutput sets SetObjectMetadataOutput field values with response headers +func ParseSetObjectMetadataOutput(output *SetObjectMetadataOutput) { + if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS]; ok { + output.StorageClass = ParseStringToStorageClassType(ret[0]) + } else if ret, ok := output.ResponseHeaders[HEADER_STORAGE_CLASS2]; ok { + output.StorageClass = ParseStringToStorageClassType(ret[0]) + } + if ret, ok := output.ResponseHeaders[HEADER_METADATA_DIRECTIVE]; ok { + output.MetadataDirective = MetadataDirectiveType(ret[0]) + } + if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok { + output.CacheControl = ret[0] + } + parseContentHeader(output) + if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok { + output.Expires = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_WEBSITE_REDIRECT_LOCATION]; ok { + output.WebsiteRedirectLocation = ret[0] + } + output.Metadata = make(map[string]string) + + for key, value := range output.ResponseHeaders { + if strings.HasPrefix(key, PREFIX_META) { + _key := key[len(PREFIX_META):] + output.ResponseHeaders[_key] = value + output.Metadata[_key] = value[0] + delete(output.ResponseHeaders, key) + } + } +} + +// ParseDeleteObjectOutput sets DeleteObjectOutput field values with response headers +func ParseDeleteObjectOutput(output *DeleteObjectOutput) { + if versionID, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = versionID[0] + } + + if deleteMarker, ok := output.ResponseHeaders[HEADER_DELETE_MARKER]; ok { + output.DeleteMarker = deleteMarker[0] == "true" + } +} + +// ParseGetObjectOutput sets GetObjectOutput field values with response headers +func ParseGetObjectOutput(output *GetObjectOutput) { + ParseGetObjectMetadataOutput(&output.GetObjectMetadataOutput) + if ret, ok := output.ResponseHeaders[HEADER_DELETE_MARKER]; ok { + output.DeleteMarker = ret[0] == "true" + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_TYPE]; ok { + output.ContentType = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CACHE_CONTROL]; ok { + output.CacheControl = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_DISPOSITION]; ok { + output.ContentDisposition = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_ENCODING]; ok { + output.ContentEncoding = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_CONTENT_LANGUAGE]; ok { + output.ContentLanguage = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_EXPIRES]; ok { + output.Expires = ret[0] + output.HttpExpires = ret[0] + } +} + +// ConvertRequestToIoReaderV2 converts req to XML data +func ConvertRequestToIoReaderV2(req interface{}, enableSha256 bool) (io.Reader, string, error) { + data, err := TransToXml(req) + md5OrSha256 := Base64Md5OrSha256(data, enableSha256) + if err == nil { + return bytes.NewReader(data), md5OrSha256, nil + } + return nil, "", err +} + +// ConvertRequestToIoReader converts req to XML data +func ConvertRequestToIoReader(req interface{}) (io.Reader, error) { + body, err := TransToXml(req) + if err == nil { + return bytes.NewReader(body), nil + } + return nil, err +} + +func parseResponseBodyOutput(s reflect.Type, baseModel IBaseModel, body []byte) { + for i := 0; i < s.NumField(); i++ { + if s.Field(i).Tag == "json:\"body\"" { + reflect.ValueOf(baseModel).Elem().FieldByName(s.Field(i).Name).SetString(string(body)) + break + } + } +} + +// ParseCallbackResponseToBaseModel gets response from Callback Service +func ParseCallbackResponseToBaseModel(resp *http.Response, baseModel IBaseModel, isObs bool) error { + baseModel.setStatusCode(resp.StatusCode) + responseHeaders := cleanHeaderPrefix(resp.Header, isObs) + baseModel.setResponseHeaders(responseHeaders) + if values, ok := responseHeaders[HEADER_REQUEST_ID]; ok { + baseModel.setRequestID(values[0]) + } + readCloser, ok := baseModel.(ICallbackReadCloser) + if !ok { + return errors.New("Failed to set CallbackBody with resp's body.") + } + readCloser.setCallbackReadCloser(resp.Body) + return nil +} + +// ParseResponseToBaseModel gets response from OBS +func ParseResponseToBaseModel(resp *http.Response, baseModel IBaseModel, xmlResult bool, isObs bool) (err error) { + readCloser, ok := baseModel.(IReadCloser) + if !ok { + defer func() { + errMsg := resp.Body.Close() + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close response body") + } + }() + var body []byte + body, err = ioutil.ReadAll(resp.Body) + if err == nil && len(body) > 0 { + + name := reflect.TypeOf(baseModel).Elem().Name() + if xmlResult { + err = ParseXml(body, baseModel) + } else { + s := reflect.TypeOf(baseModel).Elem() + if name == "GetBucketPolicyOutput" || name == "GetBucketMirrorBackToSourceOuput" { + parseResponseBodyOutput(s, baseModel, body) + } else { + err = parseJSON(body, baseModel) + } + } + if err != nil { + doLog(LEVEL_ERROR, "body: %s", body) + if _, ok := baseModel.(*ObsError); !ok && name == "CopyObjectOutput" { + doLog(LEVEL_ERROR, "Unmarshal error: %v, try parse response to ObsError", err) + err = ParseResponseToObsError(resp, isObs) + } else { + doLog(LEVEL_ERROR, "Unmarshal error: %v", err) + } + } + } + } else { + readCloser.setReadCloser(resp.Body) + } + + baseModel.setStatusCode(resp.StatusCode) + responseHeaders := cleanHeaderPrefix(resp.Header, isObs) + baseModel.setResponseHeaders(responseHeaders) + if values, ok := responseHeaders[HEADER_REQUEST_ID]; ok { + baseModel.setRequestID(values[0]) + } + return +} + +// ParseResponseToObsError gets obsError from OBS +func ParseResponseToObsError(resp *http.Response, isObs bool) error { + isJson := false + if contentType, ok := resp.Header[HEADER_CONTENT_TYPE_CAML]; ok { + jsonType, _ := mimeTypes["json"] + isJson = contentType[0] == jsonType + } + obsError := ObsError{} + respError := ParseResponseToBaseModel(resp, &obsError, !isJson, isObs) + if respError != nil { + doLog(LEVEL_WARN, "Parse response to BaseModel with error: %v", respError) + } + obsError.Status = resp.Status + responseHeaders := cleanHeaderPrefix(resp.Header, isObs) + if values, ok := responseHeaders[HEADER_ERROR_MESSAGE]; ok { + obsError.Message = values[0] + } + if values, ok := responseHeaders[HEADER_ERROR_CODE]; ok { + obsError.Code = values[0] + } + if values, ok := responseHeaders[HEADER_ERROR_INDICATOR]; ok { + obsError.Indicator = values[0] + } + return obsError +} + +// convertFetchPolicyToJSON converts SetBucketFetchPolicyInput into json format +func convertFetchPolicyToJSON(input SetBucketFetchPolicyInput) (data string, err error) { + fetch := map[string]SetBucketFetchPolicyInput{"fetch": input} + json, err := json.Marshal(fetch) + if err != nil { + return "", err + } + data = string(json) + return +} + +// convertFetchJobToJSON converts SetBucketFetchJobInput into json format +func convertFetchJobToJSON(input SetBucketFetchJobInput) (data string, err error) { + objectHeaders := make(map[string]string) + for key, value := range input.ObjectHeaders { + if value != "" { + _key := strings.ToLower(key) + if !strings.HasPrefix(key, HEADER_PREFIX_OBS) { + _key = HEADER_PREFIX_META_OBS + _key + } + objectHeaders[_key] = value + } + } + input.ObjectHeaders = objectHeaders + json, err := json.Marshal(input) + if err != nil { + return "", err + } + data = string(json) + return +} + +func parseStringToFSStatusType(value string) (ret FSStatusType) { + switch value { + case "Enabled": + ret = FSStatusEnabled + case "Disabled": + ret = FSStatusDisabled + default: + ret = "" + } + return +} + +func parseStringToBucketRedundancy(value string) (ret BucketRedundancyType) { + switch value { + case "FUSION": + ret = BucketRedundancyFusion + case "CLASSIC": + ret = BucketRedundancyClassic + default: + ret = "" + } + return +} + +func decodeListObjectsOutput(output *ListObjectsOutput) (err error) { + output.Delimiter, err = url.QueryUnescape(output.Delimiter) + if err != nil { + return + } + output.Marker, err = url.QueryUnescape(output.Marker) + if err != nil { + return + } + output.NextMarker, err = url.QueryUnescape(output.NextMarker) + if err != nil { + return + } + output.Prefix, err = url.QueryUnescape(output.Prefix) + if err != nil { + return + } + for index, value := range output.CommonPrefixes { + output.CommonPrefixes[index], err = url.QueryUnescape(value) + if err != nil { + return + } + } + for index, content := range output.Contents { + output.Contents[index].Key, err = url.QueryUnescape(content.Key) + if err != nil { + return + } + } + return +} + +func decodeListPosixObjectsOutput(output *ListPosixObjectsOutput) (err error) { + output.Delimiter, err = url.QueryUnescape(output.Delimiter) + if err != nil { + return + } + output.Marker, err = url.QueryUnescape(output.Marker) + if err != nil { + return + } + output.NextMarker, err = url.QueryUnescape(output.NextMarker) + if err != nil { + return + } + output.Prefix, err = url.QueryUnescape(output.Prefix) + if err != nil { + return + } + for index, value := range output.CommonPrefixes { + output.CommonPrefixes[index].Prefix, err = url.QueryUnescape(value.Prefix) + if err != nil { + return + } + } + for index, content := range output.Contents { + output.Contents[index].Key, err = url.QueryUnescape(content.Key) + if err != nil { + return + } + } + return +} + +func decodeListVersionsOutput(output *ListVersionsOutput) (err error) { + output.Delimiter, err = url.QueryUnescape(output.Delimiter) + if err != nil { + return + } + output.KeyMarker, err = url.QueryUnescape(output.KeyMarker) + if err != nil { + return + } + output.NextKeyMarker, err = url.QueryUnescape(output.NextKeyMarker) + if err != nil { + return + } + output.Prefix, err = url.QueryUnescape(output.Prefix) + if err != nil { + return + } + for index, version := range output.Versions { + output.Versions[index].Key, err = url.QueryUnescape(version.Key) + if err != nil { + return + } + } + for index, deleteMarker := range output.DeleteMarkers { + output.DeleteMarkers[index].Key, err = url.QueryUnescape(deleteMarker.Key) + if err != nil { + return + } + } + for index, value := range output.CommonPrefixes { + output.CommonPrefixes[index], err = url.QueryUnescape(value) + if err != nil { + return + } + } + return +} + +func decodeDeleteObjectsOutput(output *DeleteObjectsOutput) (err error) { + for index, object := range output.Deleteds { + output.Deleteds[index].Key, err = url.QueryUnescape(object.Key) + if err != nil { + return + } + } + for index, object := range output.Errors { + output.Errors[index].Key, err = url.QueryUnescape(object.Key) + if err != nil { + return + } + } + return +} + +func decodeListMultipartUploadsOutput(output *ListMultipartUploadsOutput) (err error) { + output.Delimiter, err = url.QueryUnescape(output.Delimiter) + if err != nil { + return + } + output.Prefix, err = url.QueryUnescape(output.Prefix) + if err != nil { + return + } + output.KeyMarker, err = url.QueryUnescape(output.KeyMarker) + if err != nil { + return + } + output.NextKeyMarker, err = url.QueryUnescape(output.NextKeyMarker) + if err != nil { + return + } + for index, value := range output.CommonPrefixes { + output.CommonPrefixes[index], err = url.QueryUnescape(value) + if err != nil { + return + } + } + for index, upload := range output.Uploads { + output.Uploads[index].Key, err = url.QueryUnescape(upload.Key) + if err != nil { + return + } + } + return +} + +func decodeListPartsOutput(output *ListPartsOutput) (err error) { + output.Key, err = url.QueryUnescape(output.Key) + return +} + +func decodeInitiateMultipartUploadOutput(output *InitiateMultipartUploadOutput) (err error) { + output.Key, err = url.QueryUnescape(output.Key) + return +} + +func decodeCompleteMultipartUploadOutput(output *CompleteMultipartUploadOutput) (err error) { + output.Key, err = url.QueryUnescape(output.Key) + return +} + +// ParseAppendObjectOutput sets AppendObjectOutput field values with response headers +func ParseAppendObjectOutput(output *AppendObjectOutput) (err error) { + if ret, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = ret[0] + } + output.SseHeader = parseSseHeader(output.ResponseHeaders) + if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok { + output.ETag = ret[0] + } + if ret, ok := output.ResponseHeaders[HEADER_NEXT_APPEND_POSITION]; ok { + output.NextAppendPosition, err = strconv.ParseInt(ret[0], 10, 64) + if err != nil { + err = fmt.Errorf("failed to parse next append position with error [%v]", err) + } + } + return +} + +// ParseModifyObjectOutput sets ModifyObjectOutput field values with response headers +func ParseModifyObjectOutput(output *ModifyObjectOutput) { + if ret, ok := output.ResponseHeaders[HEADER_ETAG]; ok { + output.ETag = ret[0] + } +} + +func ParseGetBucketFSStatusOutput(output *GetBucketFSStatusOutput) { + ParseGetBucketMetadataOutput(&output.GetBucketMetadataOutput) + + if ret, ok := output.ResponseHeaders[HEADER_FS_FILE_INTERFACE_OBS]; ok { + output.FSStatus = ParseStringToFSStatusType(ret[0]) + } +} + +func ParseGetAttributeOutput(output *GetAttributeOutput) { + ParseGetObjectMetadataOutput(&output.GetObjectMetadataOutput) + if ret, ok := output.ResponseHeaders[HEADER_MODE]; ok { + output.Mode = StringToInt(ret[0], -1) + } else { + output.Mode = -1 + } +} + +func ParseNewFolderOutput(output *NewFolderOutput) { + ParsePutObjectOutput(&output.PutObjectOutput) +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/error.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/error.go new file mode 100644 index 00000000000..f0742884844 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/error.go @@ -0,0 +1,36 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "encoding/xml" + "fmt" +) + +// ObsError defines error response from OBS +type ObsError struct { + BaseModel + Status string + XMLName xml.Name `xml:"Error"` + Code string `xml:"Code" json:"code"` + Message string `xml:"Message" json:"message"` + Resource string `xml:"Resource"` + HostId string `xml:"HostId"` + Indicator string +} + +// Format print obs error's log +func (err ObsError) Error() string { + return fmt.Sprintf("obs: service returned error: Status=%s, Code=%s, Message=%s, RequestId=%s, Indicator=%s.", + err.Status, err.Code, err.Message, err.RequestId, err.Indicator) +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/extension.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/extension.go new file mode 100644 index 00000000000..84ea974cd52 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/extension.go @@ -0,0 +1,103 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "bytes" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "strconv" + "strings" +) + +type extensionOptions interface{} +type extensionHeaders func(headers map[string][]string, isObs bool) error +type extensionProgressListener func() ProgressListener + +func WithProgress(progressListener ProgressListener) extensionProgressListener { + return func() ProgressListener { + return progressListener + } +} + +func setHeaderPrefix(key string, value string) extensionHeaders { + return func(headers map[string][]string, isObs bool) error { + if strings.TrimSpace(value) == "" { + return fmt.Errorf("set header %s with empty value", key) + } + setHeaders(headers, key, []string{value}, isObs) + return nil + } +} + +// WithReqPaymentHeader sets header for requester-pays +func WithReqPaymentHeader(requester PayerType) extensionHeaders { + return setHeaderPrefix(REQUEST_PAYER, string(requester)) +} + +func WithTrafficLimitHeader(trafficLimit int64) extensionHeaders { + return setHeaderPrefix(TRAFFIC_LIMIT, strconv.FormatInt(trafficLimit, 10)) +} + +func WithCallbackHeader(callback string) extensionHeaders { + return setHeaderPrefix(CALLBACK, string(callback)) +} + +func WithCustomHeader(key string, value string) extensionHeaders { + return func(headers map[string][]string, isObs bool) error { + if strings.TrimSpace(value) == "" { + return fmt.Errorf("set header %s with empty value", key) + } + headers[key] = []string{value} + return nil + } +} + +func PreprocessCallbackInputToSHA256(callbackInput *CallbackInput) (output string, err error) { + + if callbackInput == nil { + return "", fmt.Errorf("the parameter can not be nil") + } + + if callbackInput.CallbackUrl == "" { + return "", fmt.Errorf("the parameter [CallbackUrl] can not be empty") + } + + if callbackInput.CallbackBody == "" { + return "", fmt.Errorf("the parameter [CallbackBody] can not be empty") + } + + callbackBuffer := bytes.NewBuffer([]byte{}) + callbackEncoder := json.NewEncoder(callbackBuffer) + // 避免HTML字符转义 + callbackEncoder.SetEscapeHTML(false) + err = callbackEncoder.Encode(callbackInput) + if err != nil { + return "", err + } + callbackVal := base64.StdEncoding.EncodeToString(removeEndNewlineCharacter(callbackBuffer)) + // 计算SHA256哈希 + hash := sha256.Sum256([]byte(callbackVal)) + + // 将哈希转换为十六进制字符串 + return hex.EncodeToString(hash[:]), nil + +} + +// Encode函数会默认在json结尾增加换行符,导致base64转码结果与其他方式不一致,需要去掉末尾的换行符 +func removeEndNewlineCharacter(callbackBuffer *bytes.Buffer) []byte { + return callbackBuffer.Bytes()[:callbackBuffer.Len()-1] +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/http.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/http.go new file mode 100644 index 00000000000..1bdb964b3f5 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/http.go @@ -0,0 +1,683 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net" + "net/http" + "net/url" + "os" + "strconv" + "strings" + "time" +) + +func prepareHeaders(headers map[string][]string, meta bool, isObs bool) map[string][]string { + _headers := make(map[string][]string, len(headers)) + for key, value := range headers { + key = strings.TrimSpace(key) + if key == "" { + continue + } + _key := strings.ToLower(key) + if _, ok := allowedRequestHTTPHeaderMetadataNames[_key]; !ok && !strings.HasPrefix(key, HEADER_PREFIX) && !strings.HasPrefix(key, HEADER_PREFIX_OBS) { + if !meta { + continue + } + if !isObs { + _key = HEADER_PREFIX_META + _key + } else { + _key = HEADER_PREFIX_META_OBS + _key + } + } else { + _key = key + } + _headers[_key] = value + } + return _headers +} + +func (obsClient ObsClient) checkParamsWithBucketName(bucketName string) bool { + return strings.TrimSpace(bucketName) == "" && !obsClient.conf.cname +} + +func (obsClient ObsClient) checkParamsWithObjectKey(objectKey string) bool { + return strings.TrimSpace(objectKey) == "" +} + +func (obsClient ObsClient) doActionWithoutBucket(action, method string, input ISerializable, output IBaseModel, extensions []extensionOptions) error { + return obsClient.doAction(action, method, "", "", input, output, true, true, extensions, nil) +} + +func (obsClient ObsClient) doActionWithBucketV2(action, method, bucketName string, input ISerializable, output IBaseModel, extensions []extensionOptions) error { + if obsClient.checkParamsWithBucketName(bucketName) { + return errors.New("Bucket is empty") + } + return obsClient.doAction(action, method, bucketName, "", input, output, false, true, extensions, nil) +} + +func (obsClient ObsClient) doActionWithBucket(action, method, bucketName string, input ISerializable, output IBaseModel, extensions []extensionOptions) error { + if obsClient.checkParamsWithBucketName(bucketName) { + return errors.New("Bucket is empty") + } + return obsClient.doAction(action, method, bucketName, "", input, output, true, true, extensions, nil) +} + +func (obsClient ObsClient) doActionWithBucketAndKey(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, extensions []extensionOptions) error { + if obsClient.checkParamsWithBucketName(bucketName) { + return errors.New("Bucket is empty") + } + if obsClient.checkParamsWithObjectKey(objectKey) { + return errors.New("Key is empty") + } + return obsClient.doAction(action, method, bucketName, objectKey, input, output, true, true, extensions, nil) +} + +func (obsClient ObsClient) doActionWithBucketAndKeyWithProgress(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, extensions []extensionOptions, listener ProgressListener) error { + if obsClient.checkParamsWithBucketName(bucketName) { + return errors.New("Bucket is empty") + } + if obsClient.checkParamsWithObjectKey(objectKey) { + return errors.New("Key is empty") + } + return obsClient.doAction(action, method, bucketName, objectKey, input, output, true, true, extensions, listener) +} + +func (obsClient ObsClient) doActionWithBucketAndKeyV2(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, extensions []extensionOptions) error { + if obsClient.checkParamsWithBucketName(bucketName) { + return errors.New("Bucket is empty") + } + if obsClient.checkParamsWithObjectKey(objectKey) { + return errors.New("Key is empty") + } + return obsClient.doAction(action, method, bucketName, objectKey, input, output, false, true, extensions, nil) +} + +func (obsClient ObsClient) doActionWithBucketAndKeyUnRepeatable(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, extensions []extensionOptions) error { + if obsClient.checkParamsWithBucketName(bucketName) { + return errors.New("Bucket is empty") + } + if obsClient.checkParamsWithObjectKey(objectKey) { + return errors.New("Key is empty") + } + return obsClient.doAction(action, method, bucketName, objectKey, input, output, true, false, extensions, nil) +} + +func (obsClient ObsClient) doActionWithBucketAndKeyUnRepeatableWithProgress(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, extensions []extensionOptions, listener ProgressListener) error { + if obsClient.checkParamsWithBucketName(bucketName) { + return errors.New("Bucket is empty") + } + if obsClient.checkParamsWithObjectKey(objectKey) { + return errors.New("Key is empty") + } + return obsClient.doAction(action, method, bucketName, objectKey, input, output, true, false, extensions, listener) +} + +func (obsClient ObsClient) doAction(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, xmlResult bool, repeatable bool, extensions []extensionOptions, listener ProgressListener) error { + + var resp *http.Response + var respError error + doLog(LEVEL_INFO, "Enter method %s...", action) + start := GetCurrentTimestamp() + isObs := obsClient.conf.signature == SignatureObs + + params, headers, data, err := input.trans(isObs) + if err != nil { + return err + } + + if params == nil { + params = make(map[string]string) + } + + if headers == nil { + headers = make(map[string][]string) + } + + for _, extension := range extensions { + if extensionHeader, ok := extension.(extensionHeaders); ok { + if _err := extensionHeader(headers, isObs); _err != nil { + doLog(LEVEL_INFO, fmt.Sprintf("set header with error: %v", _err)) + } + } else { + doLog(LEVEL_INFO, "Unsupported extensionOptions") + } + } + + resp, respError = obsClient.doHTTPRequest(method, bucketName, objectKey, params, headers, data, repeatable, listener) + + if respError == nil && output != nil { + respError = HandleHttpResponse(action, headers, output, resp, xmlResult, isObs) + } else { + doLog(LEVEL_WARN, "Do http request with error: %v", respError) + } + + if isDebugLogEnabled() { + doLog(LEVEL_DEBUG, "End method %s, obsclient cost %d ms", action, (GetCurrentTimestamp() - start)) + } + + return respError +} + +func (obsClient ObsClient) doHTTPRequest(method, bucketName, objectKey string, params map[string]string, + headers map[string][]string, data interface{}, repeatable bool, listener ProgressListener) (*http.Response, error) { + return obsClient.doHTTP(method, bucketName, objectKey, params, prepareHeaders(headers, false, obsClient.conf.signature == SignatureObs), data, repeatable, listener) +} + +func prepareAgentHeader(clientUserAgent string) string { + userAgent := USER_AGENT + if clientUserAgent != "" { + userAgent = clientUserAgent + } + return userAgent +} + +func (obsClient ObsClient) getSignedURLResponse(action string, output IBaseModel, xmlResult bool, resp *http.Response, err error, start int64) (respError error) { + var msg interface{} + isObs := obsClient.conf.signature == SignatureObs + if err != nil { + respError = err + resp = nil + } else { + doLog(LEVEL_DEBUG, "Response headers: %s", logResponseHeader(resp.Header)) + if resp.StatusCode >= 300 { + respError = ParseResponseToObsError(resp, isObs) + msg = resp.Status + resp = nil + } else { + if output != nil { + respError = ParseResponseToBaseModel(resp, output, xmlResult, isObs) + } + if respError != nil { + doLog(LEVEL_WARN, "Parse response to BaseModel with error: %v", respError) + } + } + } + + if msg != nil { + doLog(LEVEL_ERROR, "Failed to send request with reason:%v", msg) + } + + if isDebugLogEnabled() { + doLog(LEVEL_DEBUG, "End method %s, obsclient cost %d ms", action, (GetCurrentTimestamp() - start)) + } + return +} + +func (obsClient ObsClient) doHTTPWithSignedURL(action, method string, signedURL string, actualSignedRequestHeaders http.Header, data io.Reader, output IBaseModel, xmlResult bool) (respError error) { + req, err := http.NewRequest(method, signedURL, data) + if err != nil { + return err + } + if obsClient.conf.ctx != nil { + req = req.WithContext(obsClient.conf.ctx) + } + var resp *http.Response + + var isSecurityToken bool + var securityToken string + var query []string + parmas := strings.Split(signedURL, "?") + if len(parmas) > 1 { + query = strings.Split(parmas[1], "&") + for _, value := range query { + if strings.HasPrefix(value, HEADER_STS_TOKEN_AMZ+"=") || strings.HasPrefix(value, HEADER_STS_TOKEN_OBS+"=") { + if value[len(HEADER_STS_TOKEN_AMZ)+1:] != "" { + securityToken = value[len(HEADER_STS_TOKEN_AMZ)+1:] + isSecurityToken = true + } + } + } + } + logSignedURL := signedURL + if isSecurityToken { + logSignedURL = strings.Replace(logSignedURL, securityToken, "******", -1) + } + doLog(LEVEL_INFO, "Do %s with signedUrl %s...", action, logSignedURL) + + req.Header = actualSignedRequestHeaders + if value, ok := req.Header[HEADER_HOST_CAMEL]; ok { + req.Host = value[0] + delete(req.Header, HEADER_HOST_CAMEL) + } else if value, ok := req.Header[HEADER_HOST]; ok { + req.Host = value[0] + delete(req.Header, HEADER_HOST) + } + + if value, ok := req.Header[HEADER_CONTENT_LENGTH_CAMEL]; ok { + req.ContentLength = StringToInt64(value[0], -1) + delete(req.Header, HEADER_CONTENT_LENGTH_CAMEL) + } else if value, ok := req.Header[HEADER_CONTENT_LENGTH]; ok { + req.ContentLength = StringToInt64(value[0], -1) + delete(req.Header, HEADER_CONTENT_LENGTH) + } + + userAgent := prepareAgentHeader(obsClient.conf.userAgent) + req.Header[HEADER_USER_AGENT_CAMEL] = []string{userAgent} + start := GetCurrentTimestamp() + resp, err = obsClient.httpClient.Do(req) + if isInfoLogEnabled() { + doLog(LEVEL_INFO, "Do http request cost %d ms", (GetCurrentTimestamp() - start)) + } + + respError = obsClient.getSignedURLResponse(action, output, xmlResult, resp, err, start) + + return +} + +func prepareData(headers map[string][]string, data interface{}) (io.Reader, error) { + var _data io.Reader + if data != nil { + if dataStr, ok := data.(string); ok { + doLog(LEVEL_DEBUG, "Do http request with string") + headers[HEADER_CONTENT_LENGTH_CAMEL] = []string{IntToString(len(dataStr))} + _data = strings.NewReader(dataStr) + } else if dataByte, ok := data.([]byte); ok { + doLog(LEVEL_DEBUG, "Do http request with byte array") + headers[HEADER_CONTENT_LENGTH_CAMEL] = []string{IntToString(len(dataByte))} + _data = bytes.NewReader(dataByte) + } else if dataReader, ok := data.(io.Reader); ok { + _data = dataReader + } else { + doLog(LEVEL_WARN, "Data is not a valid io.Reader") + return nil, errors.New("Data is not a valid io.Reader") + } + } + return _data, nil +} + +func (obsClient ObsClient) getRequest(redirectURL, requestURL string, redirectFlag bool, _data io.Reader, method, + bucketName, objectKey string, params map[string]string, headers map[string][]string) (*http.Request, error) { + if redirectURL != "" { + if !redirectFlag { + parsedRedirectURL, err := url.Parse(redirectURL) + if err != nil { + return nil, err + } + requestURL, err = obsClient.doAuth(method, bucketName, objectKey, params, headers, parsedRedirectURL.Host) + if err != nil { + return nil, err + } + if parsedRequestURL, err := url.Parse(requestURL); err != nil { + return nil, err + } else if parsedRequestURL.RawQuery != "" && parsedRedirectURL.RawQuery == "" { + redirectURL += "?" + parsedRequestURL.RawQuery + } + } + requestURL = redirectURL + } else { + var err error + requestURL, err = obsClient.doAuth(method, bucketName, objectKey, params, headers, "") + if err != nil { + return nil, err + } + } + + req, err := http.NewRequest(method, requestURL, _data) + if obsClient.conf.ctx != nil { + req = req.WithContext(obsClient.conf.ctx) + } + if err != nil { + return nil, err + } + doLog(LEVEL_DEBUG, "Do request with url [%s] and method [%s]", requestURL, method) + return req, nil +} + +func logHeaders(headers map[string][]string, signature SignatureType) { + if isDebugLogEnabled() { + auth := headers[HEADER_AUTH_CAMEL] + delete(headers, HEADER_AUTH_CAMEL) + + var isSecurityToken bool + var securityToken []string + if securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_AMZ]; isSecurityToken { + headers[HEADER_STS_TOKEN_AMZ] = []string{"******"} + } else if securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_OBS]; isSecurityToken { + headers[HEADER_STS_TOKEN_OBS] = []string{"******"} + } + doLog(LEVEL_DEBUG, "Request headers: %s", logRequestHeader(headers)) + headers[HEADER_AUTH_CAMEL] = auth + if isSecurityToken { + if signature == SignatureObs { + headers[HEADER_STS_TOKEN_OBS] = securityToken + } else { + headers[HEADER_STS_TOKEN_AMZ] = securityToken + } + } + } +} + +func prepareReq(headers map[string][]string, req, lastRequest *http.Request, clientUserAgent string) *http.Request { + for key, value := range headers { + if key == HEADER_HOST_CAMEL { + req.Host = value[0] + delete(headers, key) + } else if key == HEADER_CONTENT_LENGTH_CAMEL { + req.ContentLength = StringToInt64(value[0], -1) + delete(headers, key) + } else { + req.Header[key] = value + } + } + + lastRequest = req + + userAgent := prepareAgentHeader(clientUserAgent) + req.Header[HEADER_USER_AGENT_CAMEL] = []string{userAgent} + + if lastRequest != nil { + req.Host = lastRequest.Host + req.ContentLength = lastRequest.ContentLength + } + return lastRequest +} + +func canNotRetry(repeatable bool, statusCode int) bool { + if !repeatable || (statusCode >= 400 && statusCode < 500) || statusCode == 304 { + return true + } + return false +} + +func isRedirectErr(location string, redirectCount, maxRedirectCount int) bool { + if location != "" && redirectCount < maxRedirectCount { + return true + } + return false +} + +func setRedirectFlag(statusCode int, method string) (redirectFlag bool) { + if statusCode == 302 && method == HTTP_GET { + redirectFlag = true + } else { + redirectFlag = false + } + return +} + +func prepareRetry(resp *http.Response, headers map[string][]string, _data io.Reader, msg interface{}) (io.Reader, *http.Response, error) { + if resp != nil { + _err := resp.Body.Close() + checkAndLogErr(_err, LEVEL_WARN, "Failed to close resp body") + resp = nil + } + + if _, ok := headers[HEADER_DATE_CAMEL]; ok { + headers[HEADER_DATE_CAMEL] = []string{FormatUtcToRfc1123(time.Now().UTC())} + } + + if _, ok := headers[HEADER_DATE_AMZ]; ok { + headers[HEADER_DATE_AMZ] = []string{FormatUtcToRfc1123(time.Now().UTC())} + } + + if _, ok := headers[HEADER_AUTH_CAMEL]; ok { + delete(headers, HEADER_AUTH_CAMEL) + } + doLog(LEVEL_WARN, "Failed to send request with reason:%v, will try again", msg) + if r, ok := _data.(*strings.Reader); ok { + _, err := r.Seek(0, 0) + if err != nil { + return nil, nil, err + } + } else if r, ok := _data.(*bytes.Reader); ok { + _, err := r.Seek(0, 0) + if err != nil { + return nil, nil, err + } + } else if r, ok := _data.(*fileReaderWrapper); ok { + fd, err := os.Open(r.filePath) + if err != nil { + return nil, nil, err + } + fileReaderWrapper := &fileReaderWrapper{filePath: r.filePath} + fileReaderWrapper.mark = r.mark + fileReaderWrapper.reader = fd + fileReaderWrapper.totalCount = r.totalCount + _data = fileReaderWrapper + _, err = fd.Seek(r.mark, 0) + if err != nil { + errMsg := fd.Close() + checkAndLogErr(errMsg, LEVEL_WARN, "Failed to close with reason: %v", errMsg) + return nil, nil, err + } + } else if r, ok := _data.(*readerWrapper); ok { + _, err := r.seek(0, 0) + if err != nil { + return nil, nil, err + } + r.readedCount = 0 + } + return _data, resp, nil +} + +// handleBody handles request body +func handleBody(req *http.Request, body io.Reader, listener ProgressListener, tracker *readerTracker) { + reader := body + if ret, ok := req.Header[HEADER_CONTENT_LENGTH_CAMEL]; !ok { + readerLen, err := GetReaderLen(reader) + if err == nil { + req.ContentLength = readerLen + } + if req.ContentLength > 0 { + req.Header.Set(HEADER_CONTENT_LENGTH_CAMEL, strconv.FormatInt(req.ContentLength, 10)) + } + } else { + req.ContentLength = StringToInt64(ret[0], 0) + } + + if reader != nil { + reader = TeeReader(reader, req.ContentLength, listener, tracker) + } + + // HTTP body + rc, ok := reader.(io.ReadCloser) + if !ok && reader != nil { + rc = ioutil.NopCloser(reader) + } + + req.Body = rc +} + +func (obsClient ObsClient) doHTTP(method, bucketName, objectKey string, params map[string]string, + headers map[string][]string, data interface{}, repeatable bool, listener ProgressListener) (resp *http.Response, respError error) { + defer func() { + _ = recover() + }() + bucketName = strings.TrimSpace(bucketName) + + method = strings.ToUpper(method) + + var redirectURL string + var requestURL string + maxRetryCount := obsClient.conf.maxRetryCount + maxRedirectCount := obsClient.conf.maxRedirectCount + + _data, _err := prepareData(headers, data) + if _err != nil { + return nil, _err + } + + var lastRequest *http.Request + redirectFlag := false + + tracker := &readerTracker{completedBytes: 0} + + for i, redirectCount := 0, 0; i <= maxRetryCount; i++ { + req, err := obsClient.getRequest(redirectURL, requestURL, redirectFlag, _data, + method, bucketName, objectKey, params, headers) + if err != nil { + return nil, err + } + + handleBody(req, _data, listener, tracker) + + logHeaders(headers, obsClient.conf.signature) + + lastRequest = prepareReq(headers, req, lastRequest, obsClient.conf.userAgent) + + // Transfer started + event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength) + publishProgress(listener, event) + + start := GetCurrentTimestamp() + isObs := obsClient.conf.signature == SignatureObs + resp, err = obsClient.httpClient.Do(req) + doLog(LEVEL_INFO, "Do http request cost %d ms", (GetCurrentTimestamp() - start)) + + var msg interface{} + if err != nil { + msg = err + respError = err + resp = nil + if !repeatable { + break + } + } else { + doLog(LEVEL_DEBUG, "Response headers: %s", logResponseHeader(resp.Header)) + if resp.StatusCode < 300 { + event := newProgressEvent(TransferCompletedEvent, tracker.completedBytes, req.ContentLength) + publishProgress(listener, event) + respError = nil + break + } else if canNotRetry(repeatable, resp.StatusCode) { + event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength) + publishProgress(listener, event) + + respError = ParseResponseToObsError(resp, isObs) + resp = nil + break + } else if resp.StatusCode >= 300 && resp.StatusCode < 400 { + location := resp.Header.Get(HEADER_LOCATION_CAMEL) + if isRedirectErr(location, redirectCount, maxRedirectCount) { + redirectURL = location + doLog(LEVEL_WARN, "Redirect request to %s", redirectURL) + msg = resp.Status + maxRetryCount++ + redirectCount++ + redirectFlag = setRedirectFlag(resp.StatusCode, method) + } else { + respError = ParseResponseToObsError(resp, isObs) + resp = nil + break + } + } else { + msg = resp.Status + } + } + if i != maxRetryCount { + _data, resp, err = prepareRetry(resp, headers, _data, msg) + if err != nil { + return nil, err + } + if r, ok := _data.(*fileReaderWrapper); ok { + if _fd, _ok := r.reader.(*os.File); _ok { + defer func() { + errMsg := _fd.Close() + checkAndLogErr(errMsg, LEVEL_WARN, "Failed to close with reason: %v", errMsg) + }() + } + } + time.Sleep(time.Duration(float64(i+2) * rand.Float64() * float64(time.Second))) + } else { + doLog(LEVEL_ERROR, "Failed to send request with reason:%v", msg) + if resp != nil { + respError = ParseResponseToObsError(resp, isObs) + resp = nil + } + event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength) + publishProgress(listener, event) + } + } + return +} + +type connDelegate struct { + conn net.Conn + socketTimeout time.Duration + finalTimeout time.Duration +} + +func getConnDelegate(conn net.Conn, socketTimeout int, finalTimeout int) *connDelegate { + return &connDelegate{ + conn: conn, + socketTimeout: time.Second * time.Duration(socketTimeout), + finalTimeout: time.Second * time.Duration(finalTimeout), + } +} + +func (delegate *connDelegate) Read(b []byte) (n int, err error) { + setReadDeadlineErr := delegate.SetReadDeadline(time.Now().Add(delegate.socketTimeout)) + flag := isDebugLogEnabled() + + if setReadDeadlineErr != nil && flag { + doLog(LEVEL_DEBUG, "Failed to set read deadline with reason: %v, but it's ok", setReadDeadlineErr) + } + + n, err = delegate.conn.Read(b) + setReadDeadlineErr = delegate.SetReadDeadline(time.Now().Add(delegate.finalTimeout)) + if setReadDeadlineErr != nil && flag { + doLog(LEVEL_DEBUG, "Failed to set read deadline with reason: %v, but it's ok", setReadDeadlineErr) + } + return n, err +} + +func (delegate *connDelegate) Write(b []byte) (n int, err error) { + setWriteDeadlineErr := delegate.SetWriteDeadline(time.Now().Add(delegate.socketTimeout)) + flag := isDebugLogEnabled() + if setWriteDeadlineErr != nil && flag { + doLog(LEVEL_DEBUG, "Failed to set write deadline with reason: %v, but it's ok", setWriteDeadlineErr) + } + + n, err = delegate.conn.Write(b) + finalTimeout := time.Now().Add(delegate.finalTimeout) + setWriteDeadlineErr = delegate.SetWriteDeadline(finalTimeout) + if setWriteDeadlineErr != nil && flag { + doLog(LEVEL_DEBUG, "Failed to set write deadline with reason: %v, but it's ok", setWriteDeadlineErr) + } + setReadDeadlineErr := delegate.SetReadDeadline(finalTimeout) + if setReadDeadlineErr != nil && flag { + doLog(LEVEL_DEBUG, "Failed to set read deadline with reason: %v, but it's ok", setReadDeadlineErr) + } + return n, err +} + +func (delegate *connDelegate) Close() error { + return delegate.conn.Close() +} + +func (delegate *connDelegate) LocalAddr() net.Addr { + return delegate.conn.LocalAddr() +} + +func (delegate *connDelegate) RemoteAddr() net.Addr { + return delegate.conn.RemoteAddr() +} + +func (delegate *connDelegate) SetDeadline(t time.Time) error { + return delegate.conn.SetDeadline(t) +} + +func (delegate *connDelegate) SetReadDeadline(t time.Time) error { + return delegate.conn.SetReadDeadline(t) +} + +func (delegate *connDelegate) SetWriteDeadline(t time.Time) error { + return delegate.conn.SetWriteDeadline(t) +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/log.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/log.go new file mode 100644 index 00000000000..bb46a900361 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/log.go @@ -0,0 +1,394 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "fmt" + "log" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + "time" +) + +// Level defines the level of the log +type Level int + +const ( + LEVEL_OFF Level = 500 + LEVEL_ERROR Level = 400 + LEVEL_WARN Level = 300 + LEVEL_INFO Level = 200 + LEVEL_DEBUG Level = 100 +) + +var logLevelMap = map[Level]string{ + LEVEL_OFF: "[OFF]: ", + LEVEL_ERROR: "[ERROR]: ", + LEVEL_WARN: "[WARN]: ", + LEVEL_INFO: "[INFO]: ", + LEVEL_DEBUG: "[DEBUG]: ", +} + +type logConfType struct { + level Level + logToConsole bool + logFullPath string + maxLogSize int64 + backups int +} + +func getDefaultLogConf() logConfType { + return logConfType{ + level: LEVEL_WARN, + logToConsole: false, + logFullPath: "", + maxLogSize: 1024 * 1024 * 30, //30MB + backups: 10, + } +} + +var logConf logConfType + +type loggerWrapper struct { + fullPath string + fd *os.File + ch chan string + wg sync.WaitGroup + queue []string + logger *log.Logger + index int + cacheCount int + closed bool + loc *time.Location +} + +func (lw *loggerWrapper) doInit() { + lw.queue = make([]string, 0, lw.cacheCount) + lw.logger = log.New(lw.fd, "", 0) + lw.ch = make(chan string, lw.cacheCount) + if lw.loc == nil { + lw.loc = time.FixedZone("UTC", 0) + } + lw.wg.Add(1) + go lw.doWrite() +} + +func (lw *loggerWrapper) rotate() { + stat, err := lw.fd.Stat() + if err != nil { + _err := lw.fd.Close() + if _err != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", _err) + } + panic(err) + } + if stat.Size() >= logConf.maxLogSize { + _err := lw.fd.Sync() + if _err != nil { + panic(_err) + } + _err = lw.fd.Close() + if _err != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", _err) + } + if lw.index > logConf.backups { + lw.index = 1 + } + _err = os.Rename(lw.fullPath, lw.fullPath+"."+IntToString(lw.index)) + if _err != nil { + panic(_err) + } + lw.index++ + + fd, err := os.OpenFile(lw.fullPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + panic(err) + } + lw.fd = fd + lw.logger.SetOutput(lw.fd) + } +} + +func (lw *loggerWrapper) doFlush() { + lw.rotate() + for _, m := range lw.queue { + lw.logger.Println(m) + } + err := lw.fd.Sync() + if err != nil { + panic(err) + } +} + +func (lw *loggerWrapper) doClose() { + lw.closed = true + close(lw.ch) + lw.wg.Wait() +} + +func (lw *loggerWrapper) doWrite() { + defer lw.wg.Done() + for { + msg, ok := <-lw.ch + if !ok { + lw.doFlush() + _err := lw.fd.Close() + if _err != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", _err) + } + break + } + if len(lw.queue) >= lw.cacheCount { + lw.doFlush() + lw.queue = make([]string, 0, lw.cacheCount) + } + lw.queue = append(lw.queue, msg) + } + +} + +func (lw *loggerWrapper) Printf(format string, v ...interface{}) { + if !lw.closed { + msg := fmt.Sprintf(format, v...) + lw.ch <- msg + } +} + +var consoleLogger *log.Logger +var fileLogger *loggerWrapper +var lock = new(sync.RWMutex) + +func isDebugLogEnabled() bool { + return logConf.level <= LEVEL_DEBUG +} + +func isErrorLogEnabled() bool { + return logConf.level <= LEVEL_ERROR +} + +func isWarnLogEnabled() bool { + return logConf.level <= LEVEL_WARN +} + +func isInfoLogEnabled() bool { + return logConf.level <= LEVEL_INFO +} + +func reset() { + if fileLogger != nil { + fileLogger.doClose() + fileLogger = nil + } + consoleLogger = nil + logConf = getDefaultLogConf() +} + +type logConfig func(lw *loggerWrapper) + +func WithLoggerTimeLoc(loc *time.Location) logConfig { + return func(lw *loggerWrapper) { + lw.loc = loc + } +} + +// InitLog enable logging function with default cacheCnt +func InitLog(logFullPath string, maxLogSize int64, backups int, level Level, logToConsole bool, logConfigs ...logConfig) error { + + return InitLogWithCacheCnt(logFullPath, maxLogSize, backups, level, logToConsole, 50, logConfigs...) +} + +// InitLogWithCacheCnt enable logging function +func InitLogWithCacheCnt(logFullPath string, maxLogSize int64, backups int, level Level, logToConsole bool, cacheCnt int, logConfigs ...logConfig) error { + lock.Lock() + defer lock.Unlock() + if cacheCnt <= 0 { + cacheCnt = 50 + } + reset() + if fullPath := strings.TrimSpace(logFullPath); fullPath != "" { + _fullPath, err := filepath.Abs(fullPath) + if err != nil { + return err + } + + if !strings.HasSuffix(_fullPath, ".log") { + _fullPath += ".log" + } + + stat, fd, err := initLogFile(_fullPath) + if err != nil { + return err + } + + prefix := stat.Name() + "." + index := 1 + var timeIndex int64 = 0 + walkFunc := func(path string, info os.FileInfo, err error) error { + if err == nil { + if name := info.Name(); strings.HasPrefix(name, prefix) { + if i := StringToInt(name[len(prefix):], 0); i >= index && info.ModTime().Unix() >= timeIndex { + timeIndex = info.ModTime().Unix() + index = i + 1 + } + } + } + return err + } + + if err = filepath.Walk(filepath.Dir(_fullPath), walkFunc); err != nil { + _err := fd.Close() + if _err != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", _err) + } + return err + } + + fileLogger = &loggerWrapper{fullPath: _fullPath, fd: fd, index: index, cacheCount: cacheCnt, closed: false} + for _, logConfig := range logConfigs { + logConfig(fileLogger) + } + fileLogger.doInit() + } + if maxLogSize > 0 { + logConf.maxLogSize = maxLogSize + } + if backups > 0 { + logConf.backups = backups + } + logConf.level = level + if logToConsole { + consoleLogger = log.New(os.Stdout, "", log.LstdFlags) + } + return nil +} + +func initLogFile(_fullPath string) (os.FileInfo, *os.File, error) { + stat, err := os.Stat(_fullPath) + if err == nil && stat.IsDir() { + return nil, nil, fmt.Errorf("logFullPath:[%s] is a directory", _fullPath) + } else if err = os.MkdirAll(filepath.Dir(_fullPath), os.ModePerm); err != nil { + return nil, nil, err + } + + fd, err := os.OpenFile(_fullPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + _err := fd.Close() + if _err != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", _err) + } + return nil, nil, err + } + + if stat == nil { + stat, err = os.Stat(_fullPath) + if err != nil { + _err := fd.Close() + if _err != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", _err) + } + return nil, nil, err + } + } + + return stat, fd, nil +} + +// CloseLog disable logging and synchronize cache data to log files +func CloseLog() { + if logEnabled() { + lock.Lock() + defer lock.Unlock() + reset() + } +} + +func logEnabled() bool { + return consoleLogger != nil || fileLogger != nil +} + +// DoLog writes log messages to the logger +func DoLog(level Level, format string, v ...interface{}) { + doLog(level, format, v...) +} + +func doLog(level Level, format string, v ...interface{}) { + if logEnabled() && logConf.level <= level { + msg := fmt.Sprintf(format, v...) + if _, file, line, ok := runtime.Caller(1); ok { + index := strings.LastIndex(file, "/") + if index >= 0 { + file = file[index+1:] + } + msg = fmt.Sprintf("%s:%d|%s", file, line, msg) + } + prefix := logLevelMap[level] + defer func() { + _ = recover() + // ignore ch closed error + }() + nowDate := FormatNowWithLoc("2006-01-02T15:04:05.000ZZ", fileLogger.loc) + + if consoleLogger != nil { + consoleLogger.Printf("%s%s", prefix, msg) + } + if fileLogger != nil { + fileLogger.Printf("%s %s%s", nowDate, prefix, msg) + } + } +} + +func checkAndLogErr(err error, level Level, format string, v ...interface{}) { + if err != nil { + doLog(level, format, v...) + } +} + +func logResponseHeader(respHeader http.Header) string { + resp := make([]string, 0, len(respHeader)+1) + for key, value := range respHeader { + key = strings.TrimSpace(key) + if key == "" { + continue + } + _key := strings.ToLower(key) + if strings.HasPrefix(_key, HEADER_PREFIX) || strings.HasPrefix(_key, HEADER_PREFIX_OBS) { + _key = _key[len(HEADER_PREFIX):] + } + if _, ok := allowedLogResponseHTTPHeaderNames[_key]; ok { + resp = append(resp, fmt.Sprintf("%s: [%s]", key, value[0])) + } + if _key == HEADER_REQUEST_ID { + resp = append(resp, fmt.Sprintf("%s: [%s]", key, value[0])) + } + } + return strings.Join(resp, " ") +} + +func logRequestHeader(reqHeader http.Header) string { + resp := make([]string, 0, len(reqHeader)+1) + for key, value := range reqHeader { + key = strings.TrimSpace(key) + if key == "" { + continue + } + _key := strings.ToLower(key) + if _, ok := allowedRequestHTTPHeaderMetadataNames[_key]; ok { + resp = append(resp, fmt.Sprintf("%s: [%s]", key, value[0])) + } + } + return strings.Join(resp, " ") +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/mime.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/mime.go new file mode 100644 index 00000000000..2546e686e74 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/mime.go @@ -0,0 +1,404 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +var mimeTypes = map[string]string{ + "001": "application/x-001", + "301": "application/x-301", + "323": "text/h323", + "7z": "application/x-7z-compressed", + "906": "application/x-906", + "907": "drawing/907", + "IVF": "video/x-ivf", + "a11": "application/x-a11", + "aac": "audio/x-aac", + "acp": "audio/x-mei-aac", + "ai": "application/postscript", + "aif": "audio/aiff", + "aifc": "audio/aiff", + "aiff": "audio/aiff", + "anv": "application/x-anv", + "apk": "application/vnd.android.package-archive", + "asa": "text/asa", + "asf": "video/x-ms-asf", + "asp": "text/asp", + "asx": "video/x-ms-asf", + "atom": "application/atom+xml", + "au": "audio/basic", + "avi": "video/avi", + "awf": "application/vnd.adobe.workflow", + "biz": "text/xml", + "bmp": "application/x-bmp", + "bot": "application/x-bot", + "bz2": "application/x-bzip2", + "c4t": "application/x-c4t", + "c90": "application/x-c90", + "cal": "application/x-cals", + "cat": "application/vnd.ms-pki.seccat", + "cdf": "application/x-netcdf", + "cdr": "application/x-cdr", + "cel": "application/x-cel", + "cer": "application/x-x509-ca-cert", + "cg4": "application/x-g4", + "cgm": "application/x-cgm", + "cit": "application/x-cit", + "class": "java/*", + "cml": "text/xml", + "cmp": "application/x-cmp", + "cmx": "application/x-cmx", + "cot": "application/x-cot", + "crl": "application/pkix-crl", + "crt": "application/x-x509-ca-cert", + "csi": "application/x-csi", + "css": "text/css", + "csv": "text/csv", + "cu": "application/cu-seeme", + "cut": "application/x-cut", + "dbf": "application/x-dbf", + "dbm": "application/x-dbm", + "dbx": "application/x-dbx", + "dcd": "text/xml", + "dcx": "application/x-dcx", + "deb": "application/x-debian-package", + "der": "application/x-x509-ca-cert", + "dgn": "application/x-dgn", + "dib": "application/x-dib", + "dll": "application/x-msdownload", + "doc": "application/msword", + "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "dot": "application/msword", + "drw": "application/x-drw", + "dtd": "text/xml", + "dvi": "application/x-dvi", + "dwf": "application/x-dwf", + "dwg": "application/x-dwg", + "dxb": "application/x-dxb", + "dxf": "application/x-dxf", + "edn": "application/vnd.adobe.edn", + "emf": "application/x-emf", + "eml": "message/rfc822", + "ent": "text/xml", + "eot": "application/vnd.ms-fontobject", + "epi": "application/x-epi", + "eps": "application/postscript", + "epub": "application/epub+zip", + "etd": "application/x-ebx", + "etx": "text/x-setext", + "exe": "application/x-msdownload", + "fax": "image/fax", + "fdf": "application/vnd.fdf", + "fif": "application/fractals", + "flac": "audio/flac", + "flv": "video/x-flv", + "fo": "text/xml", + "frm": "application/x-frm", + "g4": "application/x-g4", + "gbr": "application/x-gbr", + "gif": "image/gif", + "gl2": "application/x-gl2", + "gp4": "application/x-gp4", + "gz": "application/gzip", + "hgl": "application/x-hgl", + "hmr": "application/x-hmr", + "hpg": "application/x-hpgl", + "hpl": "application/x-hpl", + "hqx": "application/mac-binhex40", + "hrf": "application/x-hrf", + "hta": "application/hta", + "htc": "text/x-component", + "htm": "text/html", + "html": "text/html", + "htt": "text/webviewhtml", + "htx": "text/html", + "icb": "application/x-icb", + "ico": "application/x-ico", + "ics": "text/calendar", + "iff": "application/x-iff", + "ig4": "application/x-g4", + "igs": "application/x-igs", + "iii": "application/x-iphone", + "img": "application/x-img", + "ini": "text/plain", + "ins": "application/x-internet-signup", + "ipa": "application/vnd.iphone", + "iso": "application/x-iso9660-image", + "isp": "application/x-internet-signup", + "jar": "application/java-archive", + "java": "java/*", + "jfif": "image/jpeg", + "jpe": "image/jpeg", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "js": "application/x-javascript", + "json": "application/json", + "jsp": "text/html", + "la1": "audio/x-liquid-file", + "lar": "application/x-laplayer-reg", + "latex": "application/x-latex", + "lavs": "audio/x-liquid-secure", + "lbm": "application/x-lbm", + "lmsff": "audio/x-la-lms", + "log": "text/plain", + "ls": "application/x-javascript", + "ltr": "application/x-ltr", + "m1v": "video/x-mpeg", + "m2v": "video/x-mpeg", + "m3u": "audio/mpegurl", + "m4a": "audio/mp4", + "m4e": "video/mpeg4", + "m4v": "video/mp4", + "mac": "application/x-mac", + "man": "application/x-troff-man", + "math": "text/xml", + "mdb": "application/msaccess", + "mfp": "application/x-shockwave-flash", + "mht": "message/rfc822", + "mhtml": "message/rfc822", + "mi": "application/x-mi", + "mid": "audio/mid", + "midi": "audio/mid", + "mil": "application/x-mil", + "mml": "text/xml", + "mnd": "audio/x-musicnet-download", + "mns": "audio/x-musicnet-stream", + "mocha": "application/x-javascript", + "mov": "video/quicktime", + "movie": "video/x-sgi-movie", + "mp1": "audio/mp1", + "mp2": "audio/mp2", + "mp2v": "video/mpeg", + "mp3": "audio/mp3", + "mp4": "video/mp4", + "mp4a": "audio/mp4", + "mp4v": "video/mp4", + "mpa": "video/x-mpg", + "mpd": "application/vnd.ms-project", + "mpe": "video/mpeg", + "mpeg": "video/mpeg", + "mpg": "video/mpeg", + "mpg4": "video/mp4", + "mpga": "audio/rn-mpeg", + "mpp": "application/vnd.ms-project", + "mps": "video/x-mpeg", + "mpt": "application/vnd.ms-project", + "mpv": "video/mpg", + "mpv2": "video/mpeg", + "mpw": "application/vnd.ms-project", + "mpx": "application/vnd.ms-project", + "mtx": "text/xml", + "mxp": "application/x-mmxp", + "net": "image/pnetvue", + "nrf": "application/x-nrf", + "nws": "message/rfc822", + "odc": "text/x-ms-odc", + "oga": "audio/ogg", + "ogg": "audio/ogg", + "ogv": "video/ogg", + "ogx": "application/ogg", + "out": "application/x-out", + "p10": "application/pkcs10", + "p12": "application/x-pkcs12", + "p7b": "application/x-pkcs7-certificates", + "p7c": "application/pkcs7-mime", + "p7m": "application/pkcs7-mime", + "p7r": "application/x-pkcs7-certreqresp", + "p7s": "application/pkcs7-signature", + "pbm": "image/x-portable-bitmap", + "pc5": "application/x-pc5", + "pci": "application/x-pci", + "pcl": "application/x-pcl", + "pcx": "application/x-pcx", + "pdf": "application/pdf", + "pdx": "application/vnd.adobe.pdx", + "pfx": "application/x-pkcs12", + "pgl": "application/x-pgl", + "pgm": "image/x-portable-graymap", + "pic": "application/x-pic", + "pko": "application/vnd.ms-pki.pko", + "pl": "application/x-perl", + "plg": "text/html", + "pls": "audio/scpls", + "plt": "application/x-plt", + "png": "image/png", + "pnm": "image/x-portable-anymap", + "pot": "application/vnd.ms-powerpoint", + "ppa": "application/vnd.ms-powerpoint", + "ppm": "application/x-ppm", + "pps": "application/vnd.ms-powerpoint", + "ppt": "application/vnd.ms-powerpoint", + "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "pr": "application/x-pr", + "prf": "application/pics-rules", + "prn": "application/x-prn", + "prt": "application/x-prt", + "ps": "application/postscript", + "ptn": "application/x-ptn", + "pwz": "application/vnd.ms-powerpoint", + "qt": "video/quicktime", + "r3t": "text/vnd.rn-realtext3d", + "ra": "audio/vnd.rn-realaudio", + "ram": "audio/x-pn-realaudio", + "rar": "application/x-rar-compressed", + "ras": "application/x-ras", + "rat": "application/rat-file", + "rdf": "text/xml", + "rec": "application/vnd.rn-recording", + "red": "application/x-red", + "rgb": "application/x-rgb", + "rjs": "application/vnd.rn-realsystem-rjs", + "rjt": "application/vnd.rn-realsystem-rjt", + "rlc": "application/x-rlc", + "rle": "application/x-rle", + "rm": "application/vnd.rn-realmedia", + "rmf": "application/vnd.adobe.rmf", + "rmi": "audio/mid", + "rmj": "application/vnd.rn-realsystem-rmj", + "rmm": "audio/x-pn-realaudio", + "rmp": "application/vnd.rn-rn_music_package", + "rms": "application/vnd.rn-realmedia-secure", + "rmvb": "application/vnd.rn-realmedia-vbr", + "rmx": "application/vnd.rn-realsystem-rmx", + "rnx": "application/vnd.rn-realplayer", + "rp": "image/vnd.rn-realpix", + "rpm": "audio/x-pn-realaudio-plugin", + "rsml": "application/vnd.rn-rsml", + "rss": "application/rss+xml", + "rt": "text/vnd.rn-realtext", + "rtf": "application/x-rtf", + "rv": "video/vnd.rn-realvideo", + "sam": "application/x-sam", + "sat": "application/x-sat", + "sdp": "application/sdp", + "sdw": "application/x-sdw", + "sgm": "text/sgml", + "sgml": "text/sgml", + "sis": "application/vnd.symbian.install", + "sisx": "application/vnd.symbian.install", + "sit": "application/x-stuffit", + "slb": "application/x-slb", + "sld": "application/x-sld", + "slk": "drawing/x-slk", + "smi": "application/smil", + "smil": "application/smil", + "smk": "application/x-smk", + "snd": "audio/basic", + "sol": "text/plain", + "sor": "text/plain", + "spc": "application/x-pkcs7-certificates", + "spl": "application/futuresplash", + "spp": "text/xml", + "ssm": "application/streamingmedia", + "sst": "application/vnd.ms-pki.certstore", + "stl": "application/vnd.ms-pki.stl", + "stm": "text/html", + "sty": "application/x-sty", + "svg": "image/svg+xml", + "swf": "application/x-shockwave-flash", + "tar": "application/x-tar", + "tdf": "application/x-tdf", + "tg4": "application/x-tg4", + "tga": "application/x-tga", + "tif": "image/tiff", + "tiff": "image/tiff", + "tld": "text/xml", + "top": "drawing/x-top", + "torrent": "application/x-bittorrent", + "tsd": "text/xml", + "ttf": "application/x-font-ttf", + "txt": "text/plain", + "uin": "application/x-icq", + "uls": "text/iuls", + "vcf": "text/x-vcard", + "vda": "application/x-vda", + "vdx": "application/vnd.visio", + "vml": "text/xml", + "vpg": "application/x-vpeg005", + "vsd": "application/vnd.visio", + "vss": "application/vnd.visio", + "vst": "application/x-vst", + "vsw": "application/vnd.visio", + "vsx": "application/vnd.visio", + "vtx": "application/vnd.visio", + "vxml": "text/xml", + "wav": "audio/wav", + "wax": "audio/x-ms-wax", + "wb1": "application/x-wb1", + "wb2": "application/x-wb2", + "wb3": "application/x-wb3", + "wbmp": "image/vnd.wap.wbmp", + "webm": "video/webm", + "wiz": "application/msword", + "wk3": "application/x-wk3", + "wk4": "application/x-wk4", + "wkq": "application/x-wkq", + "wks": "application/x-wks", + "wm": "video/x-ms-wm", + "wma": "audio/x-ms-wma", + "wmd": "application/x-ms-wmd", + "wmf": "application/x-wmf", + "wml": "text/vnd.wap.wml", + "wmv": "video/x-ms-wmv", + "wmx": "video/x-ms-wmx", + "wmz": "application/x-ms-wmz", + "woff": "application/x-font-woff", + "wp6": "application/x-wp6", + "wpd": "application/x-wpd", + "wpg": "application/x-wpg", + "wpl": "application/vnd.ms-wpl", + "wq1": "application/x-wq1", + "wr1": "application/x-wr1", + "wri": "application/x-wri", + "wrk": "application/x-wrk", + "ws": "application/x-ws", + "ws2": "application/x-ws", + "wsc": "text/scriptlet", + "wsdl": "text/xml", + "wvx": "video/x-ms-wvx", + "x_b": "application/x-x_b", + "x_t": "application/x-x_t", + "xap": "application/x-silverlight-app", + "xbm": "image/x-xbitmap", + "xdp": "application/vnd.adobe.xdp", + "xdr": "text/xml", + "xfd": "application/vnd.adobe.xfd", + "xfdf": "application/vnd.adobe.xfdf", + "xhtml": "text/html", + "xls": "application/vnd.ms-excel", + "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "xlw": "application/x-xlw", + "xml": "text/xml", + "xpl": "audio/scpls", + "xpm": "image/x-xpixmap", + "xq": "text/xml", + "xql": "text/xml", + "xquery": "text/xml", + "xsd": "text/xml", + "xsl": "text/xml", + "xslt": "text/xml", + "xwd": "application/x-xwd", + "yaml": "text/yaml", + "yml": "text/yaml", + "zip": "application/zip", + "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + "wps": "application/vnd.ms-works", + "wpt": "x-lml/x-gps", + "pptm": "application/vnd.ms-powerpoint.presentation.macroenabled.12", + "heic": "image/heic", + "mkv": "video/x-matroska", + "raw": "image/x-panasonic-raw", + "webp": "image/webp", + "3gp": "audio/3gpp", + "3g2": "audio/3gpp2", + "weba": "audio/webm", + "woff2": "font/woff2", +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_base.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_base.go new file mode 100644 index 00000000000..45a5fd5186b --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_base.go @@ -0,0 +1,407 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "encoding/xml" + "time" +) + +// Bucket defines bucket properties +type Bucket struct { + XMLName xml.Name `xml:"Bucket"` + Name string `xml:"Name"` + CreationDate time.Time `xml:"CreationDate"` + Location string `xml:"Location"` + BucketType string `xml:"BucketType,omitempty"` +} + +// Owner defines owner properties +type Owner struct { + XMLName xml.Name `xml:"Owner"` + ID string `xml:"ID"` + DisplayName string `xml:"DisplayName,omitempty"` +} + +// Initiator defines initiator properties +type Initiator struct { + XMLName xml.Name `xml:"Initiator"` + ID string `xml:"ID"` + DisplayName string `xml:"DisplayName,omitempty"` +} + +type bucketLocationObs struct { + XMLName xml.Name `xml:"Location"` + Location string `xml:",chardata"` +} + +// BucketLocation defines bucket location configuration +type BucketLocation struct { + XMLName xml.Name `xml:"CreateBucketConfiguration"` + Location string `xml:"LocationConstraint,omitempty"` +} + +// BucketStoragePolicy defines the bucket storage class +type BucketStoragePolicy struct { + XMLName xml.Name `xml:"StoragePolicy"` + StorageClass StorageClassType `xml:"DefaultStorageClass"` +} + +type bucketStoragePolicyObs struct { + XMLName xml.Name `xml:"StorageClass"` + StorageClass string `xml:",chardata"` +} + +// Content defines the object content properties +type Content struct { + XMLName xml.Name `xml:"Contents"` + Owner Owner `xml:"Owner"` + ETag string `xml:"ETag"` + Key string `xml:"Key"` + LastModified time.Time `xml:"LastModified"` + Size int64 `xml:"Size"` + StorageClass StorageClassType `xml:"StorageClass"` +} + +// Version defines the properties of versioning objects +type Version struct { + DeleteMarker + XMLName xml.Name `xml:"Version"` + ETag string `xml:"ETag"` + Size int64 `xml:"Size"` +} + +// DeleteMarker defines the properties of versioning delete markers +type DeleteMarker struct { + XMLName xml.Name `xml:"DeleteMarker"` + Key string `xml:"Key"` + VersionId string `xml:"VersionId"` + IsLatest bool `xml:"IsLatest"` + LastModified time.Time `xml:"LastModified"` + Owner Owner `xml:"Owner"` + StorageClass StorageClassType `xml:"StorageClass"` +} + +// Upload defines multipart upload properties +type Upload struct { + XMLName xml.Name `xml:"Upload"` + Key string `xml:"Key"` + UploadId string `xml:"UploadId"` + Initiated time.Time `xml:"Initiated"` + StorageClass StorageClassType `xml:"StorageClass"` + Owner Owner `xml:"Owner"` + Initiator Initiator `xml:"Initiator"` +} + +// BucketQuota defines bucket quota configuration +type BucketQuota struct { + XMLName xml.Name `xml:"Quota"` + Quota int64 `xml:"StorageQuota"` +} + +// Grantee defines grantee properties +type Grantee struct { + XMLName xml.Name `xml:"Grantee"` + Type GranteeType `xml:"type,attr"` + ID string `xml:"ID,omitempty"` + DisplayName string `xml:"DisplayName,omitempty"` + URI GroupUriType `xml:"URI,omitempty"` +} + +type granteeObs struct { + XMLName xml.Name `xml:"Grantee"` + Type GranteeType `xml:"type,attr"` + ID string `xml:"ID,omitempty"` + DisplayName string `xml:"DisplayName,omitempty"` + Canned string `xml:"Canned,omitempty"` +} + +// Grant defines grant properties +type Grant struct { + XMLName xml.Name `xml:"Grant"` + Grantee Grantee `xml:"Grantee"` + Permission PermissionType `xml:"Permission"` + Delivered bool `xml:"Delivered"` +} + +type grantObs struct { + XMLName xml.Name `xml:"Grant"` + Grantee granteeObs `xml:"Grantee"` + Permission PermissionType `xml:"Permission"` + Delivered bool `xml:"Delivered"` +} + +// AccessControlPolicy defines access control policy properties +type AccessControlPolicy struct { + XMLName xml.Name `xml:"AccessControlPolicy"` + Owner Owner `xml:"Owner"` + Grants []Grant `xml:"AccessControlList>Grant"` + Delivered string `xml:"Delivered,omitempty"` +} + +type accessControlPolicyObs struct { + XMLName xml.Name `xml:"AccessControlPolicy"` + Owner Owner `xml:"Owner"` + Grants []grantObs `xml:"AccessControlList>Grant"` +} + +// CorsRule defines the CORS rules +type CorsRule struct { + XMLName xml.Name `xml:"CORSRule"` + ID string `xml:"ID,omitempty"` + AllowedOrigin []string `xml:"AllowedOrigin"` + AllowedMethod []string `xml:"AllowedMethod"` + AllowedHeader []string `xml:"AllowedHeader,omitempty"` + MaxAgeSeconds int `xml:"MaxAgeSeconds"` + ExposeHeader []string `xml:"ExposeHeader,omitempty"` +} + +// BucketCors defines the bucket CORS configuration +type BucketCors struct { + XMLName xml.Name `xml:"CORSConfiguration"` + CorsRules []CorsRule `xml:"CORSRule"` +} + +// BucketVersioningConfiguration defines the versioning configuration +type BucketVersioningConfiguration struct { + XMLName xml.Name `xml:"VersioningConfiguration"` + Status VersioningStatusType `xml:"Status"` +} + +// IndexDocument defines the default page configuration +type IndexDocument struct { + Suffix string `xml:"Suffix"` +} + +// ErrorDocument defines the error page configuration +type ErrorDocument struct { + Key string `xml:"Key,omitempty"` +} + +// Condition defines condition in RoutingRule +type Condition struct { + XMLName xml.Name `xml:"Condition"` + KeyPrefixEquals string `xml:"KeyPrefixEquals,omitempty"` + HttpErrorCodeReturnedEquals string `xml:"HttpErrorCodeReturnedEquals,omitempty"` +} + +// Redirect defines redirect in RoutingRule +type Redirect struct { + XMLName xml.Name `xml:"Redirect"` + Protocol ProtocolType `xml:"Protocol,omitempty"` + HostName string `xml:"HostName,omitempty"` + ReplaceKeyPrefixWith string `xml:"ReplaceKeyPrefixWith,omitempty"` + ReplaceKeyWith string `xml:"ReplaceKeyWith,omitempty"` + HttpRedirectCode string `xml:"HttpRedirectCode,omitempty"` +} + +// RoutingRule defines routing rules +type RoutingRule struct { + XMLName xml.Name `xml:"RoutingRule"` + Condition Condition `xml:"Condition,omitempty"` + Redirect Redirect `xml:"Redirect"` +} + +// RedirectAllRequestsTo defines redirect in BucketWebsiteConfiguration +type RedirectAllRequestsTo struct { + XMLName xml.Name `xml:"RedirectAllRequestsTo"` + Protocol ProtocolType `xml:"Protocol,omitempty"` + HostName string `xml:"HostName"` +} + +// BucketWebsiteConfiguration defines the bucket website configuration +type BucketWebsiteConfiguration struct { + XMLName xml.Name `xml:"WebsiteConfiguration"` + RedirectAllRequestsTo RedirectAllRequestsTo `xml:"RedirectAllRequestsTo,omitempty"` + IndexDocument IndexDocument `xml:"IndexDocument,omitempty"` + ErrorDocument ErrorDocument `xml:"ErrorDocument,omitempty"` + RoutingRules []RoutingRule `xml:"RoutingRules>RoutingRule,omitempty"` +} + +// BucketLoggingStatus defines the bucket logging configuration +type BucketLoggingStatus struct { + XMLName xml.Name `xml:"BucketLoggingStatus"` + Agency string `xml:"Agency,omitempty"` + TargetBucket string `xml:"LoggingEnabled>TargetBucket,omitempty"` + TargetPrefix string `xml:"LoggingEnabled>TargetPrefix,omitempty"` + TargetGrants []Grant `xml:"LoggingEnabled>TargetGrants>Grant,omitempty"` +} + +// Transition defines transition property in LifecycleRule +type Transition struct { + XMLName xml.Name `xml:"Transition" json:"-"` + Date time.Time `xml:"Date,omitempty"` + Days int `xml:"Days,omitempty"` + StorageClass StorageClassType `xml:"StorageClass"` +} + +// Expiration defines expiration property in LifecycleRule +type Expiration struct { + XMLName xml.Name `xml:"Expiration" json:"-"` + Date time.Time `xml:"Date,omitempty"` + Days int `xml:"Days,omitempty"` + ExpiredObjectDeleteMarker string `xml:"ExpiredObjectDeleteMarker,omitempty"` +} + +// NoncurrentVersionTransition defines noncurrentVersion transition property in LifecycleRule +type NoncurrentVersionTransition struct { + XMLName xml.Name `xml:"NoncurrentVersionTransition" json:"-"` + NoncurrentDays int `xml:"NoncurrentDays"` + StorageClass StorageClassType `xml:"StorageClass"` +} + +// NoncurrentVersionExpiration defines noncurrentVersion expiration property in LifecycleRule +type NoncurrentVersionExpiration struct { + XMLName xml.Name `xml:"NoncurrentVersionExpiration" json:"-"` + NoncurrentDays int `xml:"NoncurrentDays"` +} + +// AbortIncompleteMultipartUpload defines abortIncomplete expiration property in LifecycleRule +type AbortIncompleteMultipartUpload struct { + XMLName xml.Name `xml:"AbortIncompleteMultipartUpload" json:"-"` + DaysAfterInitiation int `xml:"DaysAfterInitiation"` +} + +// LifecycleRule defines lifecycle rule +type LifecycleRule struct { + ID string `xml:"ID,omitempty"` + Prefix string `xml:"Prefix"` + Status RuleStatusType `xml:"Status"` + Transitions []Transition `xml:"Transition,omitempty"` + Expiration Expiration `xml:"Expiration,omitempty"` + NoncurrentVersionTransitions []NoncurrentVersionTransition `xml:"NoncurrentVersionTransition,omitempty"` + NoncurrentVersionExpiration NoncurrentVersionExpiration `xml:"NoncurrentVersionExpiration,omitempty"` + AbortIncompleteMultipartUpload AbortIncompleteMultipartUpload `xml:"AbortIncompleteMultipartUpload,omitempty"` + Filter LifecycleFilter `xml:"Filter,omitempty"` +} + +type LifecycleFilter struct { + XMLName xml.Name `xml:"Filter" json:"-"` + Prefix string `xml:"And>Prefix,omitempty"` + Tags []Tag `xml:"And>Tag,omitempty"` +} + +// BucketEncryptionConfiguration defines the bucket encryption configuration +type BucketEncryptionConfiguration struct { + XMLName xml.Name `xml:"ServerSideEncryptionConfiguration"` + SSEAlgorithm string `xml:"Rule>ApplyServerSideEncryptionByDefault>SSEAlgorithm"` + KMSMasterKeyID string `xml:"Rule>ApplyServerSideEncryptionByDefault>KMSMasterKeyID,omitempty"` + ProjectID string `xml:"Rule>ApplyServerSideEncryptionByDefault>ProjectID,omitempty"` +} + +// Tag defines tag property in BucketTagging +type Tag struct { + XMLName xml.Name `xml:"Tag"` + Key string `xml:"Key"` + Value string `xml:"Value"` +} + +// BucketTagging defines the bucket tag configuration +type BucketTagging struct { + XMLName xml.Name `xml:"Tagging"` + Tags []Tag `xml:"TagSet>Tag"` +} + +// FilterRule defines filter rule in TopicConfiguration +type FilterRule struct { + XMLName xml.Name `xml:"FilterRule"` + Name string `xml:"Name,omitempty"` + Value string `xml:"Value,omitempty"` +} + +// TopicConfiguration defines the topic configuration +type TopicConfiguration struct { + XMLName xml.Name `xml:"TopicConfiguration"` + ID string `xml:"Id,omitempty"` + Topic string `xml:"Topic"` + Events []EventType `xml:"Event"` + FilterRules []FilterRule `xml:"Filter>Object>FilterRule"` +} + +// BucketNotification defines the bucket notification configuration +type BucketNotification struct { + XMLName xml.Name `xml:"NotificationConfiguration"` + TopicConfigurations []TopicConfiguration `xml:"TopicConfiguration"` +} + +type topicConfigurationS3 struct { + XMLName xml.Name `xml:"TopicConfiguration"` + ID string `xml:"Id,omitempty"` + Topic string `xml:"Topic"` + Events []string `xml:"Event"` + FilterRules []FilterRule `xml:"Filter>S3Key>FilterRule"` +} + +type bucketNotificationS3 struct { + XMLName xml.Name `xml:"NotificationConfiguration"` + TopicConfigurations []topicConfigurationS3 `xml:"TopicConfiguration"` +} + +// ObjectToDelete defines the object property in DeleteObjectsInput +type ObjectToDelete struct { + XMLName xml.Name `xml:"Object"` + Key string `xml:"Key"` + VersionId string `xml:"VersionId,omitempty"` +} + +// Deleted defines the deleted property in DeleteObjectsOutput +type Deleted struct { + XMLName xml.Name `xml:"Deleted"` + Key string `xml:"Key"` + VersionId string `xml:"VersionId"` + DeleteMarker bool `xml:"DeleteMarker"` + DeleteMarkerVersionId string `xml:"DeleteMarkerVersionId"` +} + +// Part defines the part properties +type Part struct { + XMLName xml.Name `xml:"Part"` + PartNumber int `xml:"PartNumber"` + ETag string `xml:"ETag"` + LastModified time.Time `xml:"LastModified,omitempty"` + Size int64 `xml:"Size,omitempty"` +} + +// BucketPayer defines the request payment configuration +type BucketPayer struct { + XMLName xml.Name `xml:"RequestPaymentConfiguration"` + Payer PayerType `xml:"Payer"` +} + +type PublicAccessBlockConfiguration struct { + XMLName xml.Name `xml:"PublicAccessBlockConfiguration"` + BlockPublicAcls bool `xml:"BlockPublicAcls"` + IgnorePublicAcls bool `xml:"IgnorePublicAcls"` + BlockPublicPolicy bool `xml:"BlockPublicPolicy"` + RestrictPublicBuckets bool `xml:"RestrictPublicBuckets"` +} + +type PolicyPublicStatus struct { + XMLName xml.Name `xml:"PolicyStatus"` + IsPublic bool `xml:"IsPublic"` +} + +type BucketPublicStatus struct { + XMLName xml.Name `xml:"BucketStatus"` + IsPublic bool `xml:"IsPublic"` +} + +// HttpHeader defines the standard metadata +type HttpHeader struct { + CacheControl string + ContentDisposition string + ContentEncoding string + ContentLanguage string + ContentType string + HttpExpires string +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_bucket.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_bucket.go new file mode 100644 index 00000000000..6882c966d57 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_bucket.go @@ -0,0 +1,437 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "encoding/xml" +) + +// DeleteBucketCustomDomainInput is the input parameter of DeleteBucketCustomDomain function +type DeleteBucketCustomDomainInput struct { + Bucket string + CustomDomain string +} + +// GetBucketCustomDomainOutput is the result of GetBucketCustomDomain function +type GetBucketCustomDomainOutput struct { + BaseModel + Domains []Domain `xml:"Domains"` +} + +type CustomDomainConfiguration struct { + Name string `xml:"Name"` + CertificateId string `xml:"CertificateId,omitempty"` + Certificate string `xml:"Certificate"` + CertificateChain string `xml:"CertificateChain,omitempty"` + PrivateKey string `xml:"PrivateKey"` +} + +type SetBucketCustomDomainInput struct { + Bucket string + CustomDomain string + CustomDomainConfiguration *CustomDomainConfiguration `json:"customDomainConfiguration"` //optional +} + +// GetBucketMirrorBackToSourceOutput is the result of GetBucketMirrorBackToSource function +type GetBucketMirrorBackToSourceOutput struct { + BaseModel + Rules string `json:"body"` +} + +type SetBucketMirrorBackToSourceInput struct { + Bucket string + Rules string `json:"body"` +} + +// Content defines the object content properties +type Domain struct { + DomainName string `xml:"DomainName"` + CreateTime string `xml:"CreateTime"` + CertificateId string `xml:"CertificateId"` +} + +// ListBucketsInput is the input parameter of ListBuckets function +type ListBucketsInput struct { + QueryLocation bool + BucketType BucketType + MaxKeys int + Marker string +} + +// ListBucketsOutput is the result of ListBuckets function +type ListBucketsOutput struct { + BaseModel + XMLName xml.Name `xml:"ListAllMyBucketsResult"` + Owner Owner `xml:"Owner"` + Buckets []Bucket `xml:"Buckets>Bucket"` + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` + NextMarker string `xml:"NextMarker"` + MaxKeys int `xml:"MaxKeys"` +} + +// CreateBucketInput is the input parameter of CreateBucket function +type CreateBucketInput struct { + BucketLocation + Bucket string `xml:"-"` + ACL AclType `xml:"-"` + StorageClass StorageClassType `xml:"-"` + GrantReadId string `xml:"-"` + GrantWriteId string `xml:"-"` + GrantReadAcpId string `xml:"-"` + GrantWriteAcpId string `xml:"-"` + GrantFullControlId string `xml:"-"` + GrantReadDeliveredId string `xml:"-"` + GrantFullControlDeliveredId string `xml:"-"` + Epid string `xml:"-"` + AvailableZone string `xml:"-"` + IsFSFileInterface bool `xml:"-"` + BucketRedundancy BucketRedundancyType `xml:"-"` + IsFusionAllowUpgrade bool `xml:"-"` + IsRedundancyAllowALT bool `xml:"-"` +} + +// SetBucketStoragePolicyInput is the input parameter of SetBucketStoragePolicy function +type SetBucketStoragePolicyInput struct { + Bucket string `xml:"-"` + BucketStoragePolicy +} + +type getBucketStoragePolicyOutputS3 struct { + BaseModel + BucketStoragePolicy +} + +// GetBucketStoragePolicyOutput is the result of GetBucketStoragePolicy function +type GetBucketStoragePolicyOutput struct { + BaseModel + StorageClass string +} + +type getBucketStoragePolicyOutputObs struct { + BaseModel + bucketStoragePolicyObs +} + +// SetBucketQuotaInput is the input parameter of SetBucketQuota function +type SetBucketQuotaInput struct { + Bucket string `xml:"-"` + BucketQuota +} + +// GetBucketQuotaOutput is the result of GetBucketQuota function +type GetBucketQuotaOutput struct { + BaseModel + BucketQuota +} + +// GetBucketStorageInfoOutput is the result of GetBucketStorageInfo function +type GetBucketStorageInfoOutput struct { + BaseModel + XMLName xml.Name `xml:"GetBucketStorageInfoResult"` + Size int64 `xml:"Size"` + ObjectNumber int `xml:"ObjectNumber"` +} + +type getBucketLocationOutputS3 struct { + BaseModel + BucketLocation +} +type getBucketLocationOutputObs struct { + BaseModel + bucketLocationObs +} + +// GetBucketLocationOutput is the result of GetBucketLocation function +type GetBucketLocationOutput struct { + BaseModel + Location string `xml:"-"` +} + +// GetBucketAclOutput is the result of GetBucketAcl function +type GetBucketAclOutput struct { + BaseModel + AccessControlPolicy +} + +type getBucketACLOutputObs struct { + BaseModel + accessControlPolicyObs +} + +// SetBucketAclInput is the input parameter of SetBucketAcl function +type SetBucketAclInput struct { + Bucket string `xml:"-"` + ACL AclType `xml:"-"` + AccessControlPolicy +} + +// SetBucketPolicyInput is the input parameter of SetBucketPolicy function +type SetBucketPolicyInput struct { + Bucket string + Policy string +} + +// GetBucketPolicyOutput is the result of GetBucketPolicy function +type GetBucketPolicyOutput struct { + BaseModel + Policy string `json:"body"` +} + +// SetBucketCorsInput is the input parameter of SetBucketCors function +type SetBucketCorsInput struct { + Bucket string `xml:"-"` + BucketCors + EnableSha256 bool `xml:"-"` +} + +// GetBucketCorsOutput is the result of GetBucketCors function +type GetBucketCorsOutput struct { + BaseModel + BucketCors +} + +// SetBucketVersioningInput is the input parameter of SetBucketVersioning function +type SetBucketVersioningInput struct { + Bucket string `xml:"-"` + BucketVersioningConfiguration +} + +// GetBucketVersioningOutput is the result of GetBucketVersioning function +type GetBucketVersioningOutput struct { + BaseModel + BucketVersioningConfiguration +} + +// SetBucketWebsiteConfigurationInput is the input parameter of SetBucketWebsiteConfiguration function +type SetBucketWebsiteConfigurationInput struct { + Bucket string `xml:"-"` + BucketWebsiteConfiguration +} + +// GetBucketWebsiteConfigurationOutput is the result of GetBucketWebsiteConfiguration function +type GetBucketWebsiteConfigurationOutput struct { + BaseModel + BucketWebsiteConfiguration +} + +// GetBucketMetadataInput is the input parameter of GetBucketMetadata function +type GetBucketMetadataInput struct { + Bucket string + Origin string + RequestHeader string +} + +// GetBucketMetadataOutput is the result of GetBucketMetadata function +type GetBucketMetadataOutput struct { + BaseModel + StorageClass StorageClassType + Location string + Version string + AllowOrigin string + AllowMethod string + AllowHeader string + MaxAgeSeconds int + ExposeHeader string + Epid string + AZRedundancy AvailableZoneType + FSStatus FSStatusType + BucketRedundancy BucketRedundancyType +} + +// SetBucketLoggingConfigurationInput is the input parameter of SetBucketLoggingConfiguration function +type SetBucketLoggingConfigurationInput struct { + Bucket string `xml:"-"` + BucketLoggingStatus +} + +// GetBucketLoggingConfigurationOutput is the result of GetBucketLoggingConfiguration function +type GetBucketLoggingConfigurationOutput struct { + BaseModel + BucketLoggingStatus +} + +// BucketLifecycleConfiguration defines the bucket lifecycle configuration +type BucketLifecycleConfiguration struct { + XMLName xml.Name `xml:"LifecycleConfiguration" json:"-"` + LifecycleRules []LifecycleRule `xml:"Rule"` +} + +// SetBucketLifecycleConfigurationInput is the input parameter of SetBucketLifecycleConfiguration function +type SetBucketLifecycleConfigurationInput struct { + Bucket string `xml:"-"` + BucketLifecycleConfiguration + EnableSha256 bool `xml:"-"` +} + +// GetBucketLifecycleConfigurationOutput is the result of GetBucketLifecycleConfiguration function +type GetBucketLifecycleConfigurationOutput struct { + BaseModel + BucketLifecycleConfiguration +} + +// SetBucketEncryptionInput is the input parameter of SetBucketEncryption function +type SetBucketEncryptionInput struct { + Bucket string `xml:"-"` + BucketEncryptionConfiguration +} + +// GetBucketEncryptionOutput is the result of GetBucketEncryption function +type GetBucketEncryptionOutput struct { + BaseModel + BucketEncryptionConfiguration +} + +// SetBucketTaggingInput is the input parameter of SetBucketTagging function +type SetBucketTaggingInput struct { + Bucket string `xml:"-"` + BucketTagging + EnableSha256 bool `xml:"-"` +} + +// GetBucketTaggingOutput is the result of GetBucketTagging function +type GetBucketTaggingOutput struct { + BaseModel + BucketTagging +} + +// SetBucketNotificationInput is the input parameter of SetBucketNotification function +type SetBucketNotificationInput struct { + Bucket string `xml:"-"` + BucketNotification +} + +type getBucketNotificationOutputS3 struct { + BaseModel + bucketNotificationS3 +} + +// GetBucketNotificationOutput is the result of GetBucketNotification function +type GetBucketNotificationOutput struct { + BaseModel + BucketNotification +} + +// SetBucketFetchPolicyInput is the input parameter of SetBucketFetchPolicy function +type SetBucketFetchPolicyInput struct { + Bucket string + Status FetchPolicyStatusType `json:"status"` + Agency string `json:"agency"` +} + +// GetBucketFetchPolicyInput is the input parameter of GetBucketFetchPolicy function +type GetBucketFetchPolicyInput struct { + Bucket string +} + +// GetBucketFetchPolicyOutput is the result of GetBucketFetchPolicy function +type GetBucketFetchPolicyOutput struct { + BaseModel + FetchResponse `json:"fetch"` +} + +// DeleteBucketFetchPolicyInput is the input parameter of DeleteBucketFetchPolicy function +type DeleteBucketFetchPolicyInput struct { + Bucket string +} + +// SetBucketFetchJobInput is the input parameter of SetBucketFetchJob function +type SetBucketFetchJobInput struct { + Bucket string `json:"bucket"` + URL string `json:"url"` + Host string `json:"host,omitempty"` + Key string `json:"key,omitempty"` + Md5 string `json:"md5,omitempty"` + CallBackURL string `json:"callbackurl,omitempty"` + CallBackBody string `json:"callbackbody,omitempty"` + CallBackBodyType string `json:"callbackbodytype,omitempty"` + CallBackHost string `json:"callbackhost,omitempty"` + FileType string `json:"file_type,omitempty"` + IgnoreSameKey bool `json:"ignore_same_key,omitempty"` + ObjectHeaders map[string]string `json:"objectheaders,omitempty"` + Etag string `json:"etag,omitempty"` + TrustName string `json:"trustname,omitempty"` +} + +// SetBucketFetchJobOutput is the result of SetBucketFetchJob function +type SetBucketFetchJobOutput struct { + BaseModel + SetBucketFetchJobResponse +} + +// GetBucketFetchJobInput is the input parameter of GetBucketFetchJob function +type GetBucketFetchJobInput struct { + Bucket string + JobID string +} + +// GetBucketFetchJobOutput is the result of GetBucketFetchJob function +type GetBucketFetchJobOutput struct { + BaseModel + GetBucketFetchJobResponse +} + +type GetBucketFSStatusInput struct { + GetBucketMetadataInput +} + +type GetBucketFSStatusOutput struct { + GetBucketMetadataOutput + FSStatus FSStatusType +} + +type SetDirAccesslabelInput struct { + BaseDirAccesslabelInput + Accesslabel []string +} + +type GetDirAccesslabelInput struct { + BaseDirAccesslabelInput +} + +type GetDirAccesslabelOutput struct { + BaseModel + Accesslabel []string +} + +type DeleteDirAccesslabelInput struct { + BaseDirAccesslabelInput + Accesslabel []string +} + +type BaseDirAccesslabelInput struct { + Bucket string + Key string + Accesslabel []string +} + +// PutBucketPublicAccessBlockInput is the input parameter of PutBucketPublicAccessBlock function +type PutBucketPublicAccessBlockInput struct { + Bucket string `xml:"-"` + PublicAccessBlockConfiguration +} + +type GetBucketPublicAccessBlockOutput struct { + BaseModel + PublicAccessBlockConfiguration +} + +type GetBucketPublicStatusOutput struct { + BaseModel + BucketPublicStatus +} + +type GetBucketPolicyPublicStatusOutput struct { + BaseModel + PolicyPublicStatus +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_header.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_header.go new file mode 100644 index 00000000000..65dab04bb4a --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_header.go @@ -0,0 +1,33 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +// ISseHeader defines the sse encryption header +type ISseHeader interface { + GetEncryption() string + GetKey() string +} + +// SseKmsHeader defines the SseKms header +type SseKmsHeader struct { + Encryption string + Key string + isObs bool +} + +// SseCHeader defines the SseC header +type SseCHeader struct { + Encryption string + Key string + KeyMD5 string +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_object.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_object.go new file mode 100644 index 00000000000..a35b1857dda --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_object.go @@ -0,0 +1,432 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "encoding/xml" + "io" + "time" +) + +// ListObjsInput defines parameters for listing objects +type ListObjsInput struct { + Prefix string + MaxKeys int + Delimiter string + Origin string + RequestHeader string + EncodingType string +} + +// ListObjectsInput is the input parameter of ListObjects function +type ListObjectsInput struct { + ListObjsInput + Bucket string + Marker string +} + +type ListPosixObjectsInput struct { + ListObjectsInput +} + +// ListObjectsOutput is the result of ListObjects function +type ListObjectsOutput struct { + BaseModel + XMLName xml.Name `xml:"ListBucketResult"` + Delimiter string `xml:"Delimiter"` + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` + NextMarker string `xml:"NextMarker"` + MaxKeys int `xml:"MaxKeys"` + Name string `xml:"Name"` + Prefix string `xml:"Prefix"` + Contents []Content `xml:"Contents"` + CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` + Location string `xml:"-"` + EncodingType string `xml:"EncodingType,omitempty"` +} + +type ListPosixObjectsOutput struct { + ListObjectsOutput + CommonPrefixes []CommonPrefix `xml:"CommonPrefixes"` +} + +type CommonPrefix struct { + XMLName xml.Name `xml:"CommonPrefixes"` + Prefix string `xml:"Prefix"` + MTime string `xml:"MTime"` + Mode string `xml:"Mode"` + InodeNo string `xml:"InodeNo"` + LastModified time.Time `xml:"LastModified"` +} + +// ListVersionsInput is the input parameter of ListVersions function +type ListVersionsInput struct { + ListObjsInput + Bucket string + KeyMarker string + VersionIdMarker string +} + +// ListVersionsOutput is the result of ListVersions function +type ListVersionsOutput struct { + BaseModel + XMLName xml.Name `xml:"ListVersionsResult"` + Delimiter string `xml:"Delimiter"` + IsTruncated bool `xml:"IsTruncated"` + KeyMarker string `xml:"KeyMarker"` + NextKeyMarker string `xml:"NextKeyMarker"` + VersionIdMarker string `xml:"VersionIdMarker"` + NextVersionIdMarker string `xml:"NextVersionIdMarker"` + MaxKeys int `xml:"MaxKeys"` + Name string `xml:"Name"` + Prefix string `xml:"Prefix"` + Versions []Version `xml:"Version"` + DeleteMarkers []DeleteMarker `xml:"DeleteMarker"` + CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` + Location string `xml:"-"` + EncodingType string `xml:"EncodingType,omitempty"` +} + +// DeleteObjectInput is the input parameter of DeleteObject function +type DeleteObjectInput struct { + Bucket string + Key string + VersionId string +} + +// DeleteObjectOutput is the result of DeleteObject function +type DeleteObjectOutput struct { + BaseModel + VersionId string + DeleteMarker bool +} + +// DeleteObjectsInput is the input parameter of DeleteObjects function +type DeleteObjectsInput struct { + Bucket string `xml:"-"` + XMLName xml.Name `xml:"Delete"` + Quiet bool `xml:"Quiet,omitempty"` + Objects []ObjectToDelete `xml:"Object"` + EncodingType string `xml:"EncodingType"` +} + +// DeleteObjectsOutput is the result of DeleteObjects function +type DeleteObjectsOutput struct { + BaseModel + XMLName xml.Name `xml:"DeleteResult"` + Deleteds []Deleted `xml:"Deleted"` + Errors []Error `xml:"Error"` + EncodingType string `xml:"EncodingType,omitempty"` +} + +// SetObjectAclInput is the input parameter of SetObjectAcl function +type SetObjectAclInput struct { + Bucket string `xml:"-"` + Key string `xml:"-"` + VersionId string `xml:"-"` + ACL AclType `xml:"-"` + AccessControlPolicy +} + +// GetObjectAclInput is the input parameter of GetObjectAcl function +type GetObjectAclInput struct { + Bucket string + Key string + VersionId string +} + +// GetObjectAclOutput is the result of GetObjectAcl function +type GetObjectAclOutput struct { + BaseModel + VersionId string + AccessControlPolicy +} + +// RestoreObjectInput is the input parameter of RestoreObject function +type RestoreObjectInput struct { + Bucket string `xml:"-"` + Key string `xml:"-"` + VersionId string `xml:"-"` + XMLName xml.Name `xml:"RestoreRequest"` + Days int `xml:"Days"` + Tier RestoreTierType `xml:"GlacierJobParameters>Tier,omitempty"` +} + +// GetObjectMetadataInput is the input parameter of GetObjectMetadata function +type GetObjectMetadataInput struct { + Bucket string + Key string + VersionId string + Origin string + RequestHeader string + SseHeader ISseHeader +} + +// GetObjectMetadataOutput is the result of GetObjectMetadata function +type GetObjectMetadataOutput struct { + BaseModel + HttpHeader + VersionId string + WebsiteRedirectLocation string + Expiration string + Restore string + ObjectType string + NextAppendPosition string + StorageClass StorageClassType + ContentLength int64 + ETag string + AllowOrigin string + AllowHeader string + AllowMethod string + ExposeHeader string + MaxAgeSeconds int + LastModified time.Time + SseHeader ISseHeader + Metadata map[string]string +} + +type GetAttributeInput struct { + GetObjectMetadataInput + RequestPayer string +} + +type GetAttributeOutput struct { + GetObjectMetadataOutput + Mode int +} + +// GetObjectInput is the input parameter of GetObject function +type GetObjectInput struct { + GetObjectMetadataInput + IfMatch string + IfNoneMatch string + AcceptEncoding string + IfUnmodifiedSince time.Time + IfModifiedSince time.Time + RangeStart int64 + RangeEnd int64 + ImageProcess string + ResponseCacheControl string + ResponseContentDisposition string + ResponseContentEncoding string + ResponseContentLanguage string + ResponseContentType string + ResponseExpires string +} + +// GetObjectOutput is the result of GetObject function +type GetObjectOutput struct { + GetObjectMetadataOutput + DeleteMarker bool + Expires string + Body io.ReadCloser +} + +// ObjectOperationInput defines the object operation properties +type ObjectOperationInput struct { + Bucket string + Key string + ACL AclType + GrantReadId string + GrantReadAcpId string + GrantWriteAcpId string + GrantFullControlId string + StorageClass StorageClassType + WebsiteRedirectLocation string + Expires int64 + SseHeader ISseHeader + Metadata map[string]string +} + +// PutObjectBasicInput defines the basic object operation properties +type PutObjectBasicInput struct { + ObjectOperationInput + HttpHeader + ContentMD5 string + ContentSHA256 string + ContentLength int64 +} + +// PutObjectInput is the input parameter of PutObject function +type PutObjectInput struct { + PutObjectBasicInput + Body io.Reader +} + +type NewFolderInput struct { + ObjectOperationInput + RequestPayer string +} + +type NewFolderOutput struct { + PutObjectOutput +} + +// PutFileInput is the input parameter of PutFile function +type PutFileInput struct { + PutObjectBasicInput + SourceFile string +} + +// PutObjectOutput is the result of PutObject function +type PutObjectOutput struct { + BaseModel + VersionId string + SseHeader ISseHeader + StorageClass StorageClassType + ETag string + ObjectUrl string + CallbackBody +} + +// CopyObjectInput is the input parameter of CopyObject function +type CopyObjectInput struct { + ObjectOperationInput + CopySourceBucket string + CopySourceKey string + CopySourceVersionId string + CopySourceIfMatch string + CopySourceIfNoneMatch string + CopySourceIfUnmodifiedSince time.Time + CopySourceIfModifiedSince time.Time + SourceSseHeader ISseHeader + Expires string + MetadataDirective MetadataDirectiveType + SuccessActionRedirect string + HttpHeader +} + +// CopyObjectOutput is the result of CopyObject function +type CopyObjectOutput struct { + BaseModel + CopySourceVersionId string `xml:"-"` + VersionId string `xml:"-"` + SseHeader ISseHeader `xml:"-"` + XMLName xml.Name `xml:"CopyObjectResult"` + LastModified time.Time `xml:"LastModified"` + ETag string `xml:"ETag"` +} + +// UploadFileInput is the input parameter of UploadFile function +type UploadFileInput struct { + ObjectOperationInput + UploadFile string + PartSize int64 + TaskNum int + EnableCheckpoint bool + CheckpointFile string + EncodingType string + HttpHeader +} + +// DownloadFileInput is the input parameter of DownloadFile function +type DownloadFileInput struct { + GetObjectMetadataInput + IfMatch string + IfNoneMatch string + IfModifiedSince time.Time + IfUnmodifiedSince time.Time + DownloadFile string + PartSize int64 + TaskNum int + EnableCheckpoint bool + CheckpointFile string +} + +type AppendObjectInput struct { + PutObjectBasicInput + Body io.Reader + Position int64 +} + +type AppendObjectOutput struct { + BaseModel + VersionId string + SseHeader ISseHeader + NextAppendPosition int64 + ETag string +} + +type ModifyObjectInput struct { + Bucket string + Key string + Position int64 + Body io.Reader + ContentLength int64 +} + +type ModifyObjectOutput struct { + BaseModel + ETag string +} + +// HeadObjectInput is the input parameter of HeadObject function +type HeadObjectInput struct { + Bucket string + Key string + VersionId string +} + +type RenameFileInput struct { + Bucket string + Key string + NewObjectKey string + RequestPayer string +} + +type RenameFileOutput struct { + BaseModel +} + +type RenameFolderInput struct { + Bucket string + Key string + NewObjectKey string + RequestPayer string +} + +type RenameFolderOutput struct { + BaseModel +} + +// SetObjectMetadataInput is the input parameter of SetObjectMetadata function +type SetObjectMetadataInput struct { + Bucket string + Key string + VersionId string + MetadataDirective MetadataDirectiveType + Expires string + WebsiteRedirectLocation string + StorageClass StorageClassType + Metadata map[string]string + HttpHeader +} + +// SetObjectMetadataOutput is the result of SetObjectMetadata function +type SetObjectMetadataOutput struct { + BaseModel + MetadataDirective MetadataDirectiveType + HttpHeader + Expires string + WebsiteRedirectLocation string + StorageClass StorageClassType + Metadata map[string]string +} + +type CallbackInput struct { + CallbackUrl string `json:"callbackUrl"` + CallbackHost string `json:"callbackHost,omitempty"` + CallbackBody string `json:"callbackBody"` + CallbackBodyType string `json:"callbackBodyType,omitempty"` +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_other.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_other.go new file mode 100644 index 00000000000..78f426ecd01 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_other.go @@ -0,0 +1,73 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "net/http" +) + +// CreateSignedUrlInput is the input parameter of CreateSignedUrl function +type CreateSignedUrlInput struct { + Method HttpMethodType + Bucket string + Key string + Policy string + SubResource SubResourceType + Expires int + Headers map[string]string + QueryParams map[string]string +} + +// CreateSignedUrlOutput is the result of CreateSignedUrl function +type CreateSignedUrlOutput struct { + SignedUrl string + ActualSignedRequestHeaders http.Header +} + +// ConditionRange the specifying ranges in the conditions +type ConditionRange struct { + RangeName string + Lower int64 + Upper int64 +} + +// CreateBrowserBasedSignatureInput is the input parameter of CreateBrowserBasedSignature function. +type CreateBrowserBasedSignatureInput struct { + Bucket string + Key string + Expires int + FormParams map[string]string + RangeParams []ConditionRange +} + +// CreateBrowserBasedSignatureOutput is the result of CreateBrowserBasedSignature function. +type CreateBrowserBasedSignatureOutput struct { + OriginPolicy string + Policy string + Algorithm string + Credential string + Date string + Signature string +} + +// SetBucketRequestPaymentInput is the input parameter of SetBucketRequestPayment function +type SetBucketRequestPaymentInput struct { + Bucket string `xml:"-"` + BucketPayer +} + +// GetBucketRequestPaymentOutput is the result of GetBucketRequestPayment function +type GetBucketRequestPaymentOutput struct { + BaseModel + BucketPayer +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_part.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_part.go new file mode 100644 index 00000000000..16ef0d52744 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_part.go @@ -0,0 +1,173 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "encoding/xml" + "io" + "time" +) + +// ListMultipartUploadsInput is the input parameter of ListMultipartUploads function +type ListMultipartUploadsInput struct { + Bucket string + Prefix string + MaxUploads int + Delimiter string + KeyMarker string + UploadIdMarker string + EncodingType string +} + +// ListMultipartUploadsOutput is the result of ListMultipartUploads function +type ListMultipartUploadsOutput struct { + BaseModel + XMLName xml.Name `xml:"ListMultipartUploadsResult"` + Bucket string `xml:"Bucket"` + KeyMarker string `xml:"KeyMarker"` + NextKeyMarker string `xml:"NextKeyMarker"` + UploadIdMarker string `xml:"UploadIdMarker"` + NextUploadIdMarker string `xml:"NextUploadIdMarker"` + Delimiter string `xml:"Delimiter"` + IsTruncated bool `xml:"IsTruncated"` + MaxUploads int `xml:"MaxUploads"` + Prefix string `xml:"Prefix"` + Uploads []Upload `xml:"Upload"` + CommonPrefixes []string `xml:"CommonPrefixes>Prefix"` + EncodingType string `xml:"EncodingType,omitempty"` +} + +// AbortMultipartUploadInput is the input parameter of AbortMultipartUpload function +type AbortMultipartUploadInput struct { + Bucket string + Key string + UploadId string +} + +// InitiateMultipartUploadInput is the input parameter of InitiateMultipartUpload function +type InitiateMultipartUploadInput struct { + ObjectOperationInput + HttpHeader + EncodingType string +} + +// InitiateMultipartUploadOutput is the result of InitiateMultipartUpload function +type InitiateMultipartUploadOutput struct { + BaseModel + XMLName xml.Name `xml:"InitiateMultipartUploadResult"` + Bucket string `xml:"Bucket"` + Key string `xml:"Key"` + UploadId string `xml:"UploadId"` + SseHeader ISseHeader + EncodingType string `xml:"EncodingType,omitempty"` +} + +// UploadPartInput is the input parameter of UploadPart function +type UploadPartInput struct { + Bucket string + Key string + PartNumber int + UploadId string + ContentMD5 string + ContentSHA256 string + SseHeader ISseHeader + Body io.Reader + SourceFile string + Offset int64 + PartSize int64 +} + +// UploadPartOutput is the result of UploadPart function +type UploadPartOutput struct { + BaseModel + PartNumber int + ETag string + SseHeader ISseHeader +} + +// CompleteMultipartUploadInput is the input parameter of CompleteMultipartUpload function +type CompleteMultipartUploadInput struct { + Bucket string `xml:"-"` + Key string `xml:"-"` + UploadId string `xml:"-"` + XMLName xml.Name `xml:"CompleteMultipartUpload"` + Parts []Part `xml:"Part"` + EncodingType string `xml:"-"` +} + +// CompleteMultipartUploadOutput is the result of CompleteMultipartUpload function +type CompleteMultipartUploadOutput struct { + BaseModel + VersionId string `xml:"-"` + SseHeader ISseHeader `xml:"-"` + XMLName xml.Name `xml:"CompleteMultipartUploadResult"` + Location string `xml:"Location"` + Bucket string `xml:"Bucket"` + Key string `xml:"Key"` + ETag string `xml:"ETag"` + EncodingType string `xml:"EncodingType,omitempty"` + CallbackBody +} + +// ListPartsInput is the input parameter of ListParts function +type ListPartsInput struct { + Bucket string + Key string + UploadId string + MaxParts int + PartNumberMarker int + EncodingType string +} + +// ListPartsOutput is the result of ListParts function +type ListPartsOutput struct { + BaseModel + XMLName xml.Name `xml:"ListPartsResult"` + Bucket string `xml:"Bucket"` + Key string `xml:"Key"` + UploadId string `xml:"UploadId"` + PartNumberMarker int `xml:"PartNumberMarker"` + NextPartNumberMarker int `xml:"NextPartNumberMarker"` + MaxParts int `xml:"MaxParts"` + IsTruncated bool `xml:"IsTruncated"` + StorageClass StorageClassType `xml:"StorageClass"` + Initiator Initiator `xml:"Initiator"` + Owner Owner `xml:"Owner"` + Parts []Part `xml:"Part"` + EncodingType string `xml:"EncodingType,omitempty"` +} + +// CopyPartInput is the input parameter of CopyPart function +type CopyPartInput struct { + Bucket string + Key string + UploadId string + PartNumber int + CopySourceBucket string + CopySourceKey string + CopySourceVersionId string + CopySourceRangeStart int64 + CopySourceRangeEnd int64 + SseHeader ISseHeader + SourceSseHeader ISseHeader +} + +// CopyPartOutput is the result of CopyPart function +type CopyPartOutput struct { + BaseModel + XMLName xml.Name `xml:"CopyPartResult"` + PartNumber int `xml:"-"` + ETag string `xml:"ETag"` + LastModified time.Time `xml:"LastModified"` + SseHeader ISseHeader `xml:"-"` +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_response.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_response.go new file mode 100644 index 00000000000..ec2536cb46e --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/model_response.go @@ -0,0 +1,68 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "encoding/xml" +) + +// BaseModel defines base model response from OBS +type BaseModel struct { + StatusCode int `xml:"-"` + RequestId string `xml:"RequestId" json:"request_id"` + ResponseHeaders map[string][]string `xml:"-"` +} + +// Error defines the error property in DeleteObjectsOutput +type Error struct { + XMLName xml.Name `xml:"Error"` + Key string `xml:"Key"` + VersionId string `xml:"VersionId"` + Code string `xml:"Code"` + Message string `xml:"Message"` +} + +// FetchResponse defines the response fetch policy configuration +type FetchResponse struct { + Status FetchPolicyStatusType `json:"status"` + Agency string `json:"agency"` +} + +// SetBucketFetchJobResponse defines the response SetBucketFetchJob configuration +type SetBucketFetchJobResponse struct { + ID string `json:"id"` + Wait int `json:"Wait"` +} + +// GetBucketFetchJobResponse defines the response fetch job configuration +type GetBucketFetchJobResponse struct { + Err string `json:"err"` + Code string `json:"code"` + Status string `json:"status"` + Job JobResponse `json:"job"` +} + +// JobResponse defines the response job configuration +type JobResponse struct { + Bucket string `json:"bucket"` + URL string `json:"url"` + Host string `json:"host"` + Key string `json:"key"` + Md5 string `json:"md5"` + CallBackURL string `json:"callbackurl"` + CallBackBody string `json:"callbackbody"` + CallBackBodyType string `json:"callbackbodytype"` + CallBackHost string `json:"callbackhost"` + FileType string `json:"file_type"` + IgnoreSameKey bool `json:"ignore_same_key"` +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/pool.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/pool.go new file mode 100644 index 00000000000..1755c96ac51 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/pool.go @@ -0,0 +1,542 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +//nolint:structcheck, unused +package obs + +import ( + "errors" + "fmt" + "runtime" + "sync" + "sync/atomic" + "time" +) + +// Future defines interface with function: Get +type Future interface { + Get() interface{} +} + +// FutureResult for task result +type FutureResult struct { + result interface{} + resultChan chan interface{} + lock sync.Mutex +} + +type panicResult struct { + presult interface{} +} + +func (f *FutureResult) checkPanic() interface{} { + if r, ok := f.result.(panicResult); ok { + panic(r.presult) + } + return f.result +} + +// Get gets the task result +func (f *FutureResult) Get() interface{} { + if f.resultChan == nil { + return f.checkPanic() + } + f.lock.Lock() + defer f.lock.Unlock() + if f.resultChan == nil { + return f.checkPanic() + } + + f.result = <-f.resultChan + close(f.resultChan) + f.resultChan = nil + return f.checkPanic() +} + +// Task defines interface with function: Run +type Task interface { + Run() interface{} +} + +type funcWrapper struct { + f func() interface{} +} + +func (fw *funcWrapper) Run() interface{} { + if fw.f != nil { + return fw.f() + } + return nil +} + +type taskWrapper struct { + t Task + f *FutureResult +} + +func (tw *taskWrapper) Run() interface{} { + if tw.t != nil { + return tw.t.Run() + } + return nil +} + +type signalTask struct { + id string +} + +func (signalTask) Run() interface{} { + return nil +} + +type worker struct { + name string + taskQueue chan Task + wg *sync.WaitGroup + pool *RoutinePool +} + +func runTask(t Task) { + if tw, ok := t.(*taskWrapper); ok { + defer func() { + if r := recover(); r != nil { + tw.f.resultChan <- panicResult{ + presult: r, + } + } + }() + ret := t.Run() + tw.f.resultChan <- ret + } else { + t.Run() + } +} + +func (*worker) runTask(t Task) { + runTask(t) +} + +func (w *worker) start() { + go func() { + defer func() { + if w.wg != nil { + w.wg.Done() + } + }() + for { + task, ok := <-w.taskQueue + if !ok { + break + } + w.pool.AddCurrentWorkingCnt(1) + w.runTask(task) + w.pool.AddCurrentWorkingCnt(-1) + if w.pool.autoTuneWorker(w) { + break + } + } + }() +} + +func (w *worker) release() { + w.taskQueue = nil + w.wg = nil + w.pool = nil +} + +// Pool defines coroutine pool interface +type Pool interface { + ShutDown() + Submit(t Task) (Future, error) + SubmitFunc(f func() interface{}) (Future, error) + Execute(t Task) + ExecuteFunc(f func() interface{}) + GetMaxWorkerCnt() int64 + AddMaxWorkerCnt(value int64) int64 + GetCurrentWorkingCnt() int64 + AddCurrentWorkingCnt(value int64) int64 + GetWorkerCnt() int64 + AddWorkerCnt(value int64) int64 + EnableAutoTune() +} + +type basicPool struct { + maxWorkerCnt int64 + workerCnt int64 + currentWorkingCnt int64 + isShutDown int32 +} + +// ErrTaskInvalid will be returned if the task is nil +var ErrTaskInvalid = errors.New("Task is nil") + +func (pool *basicPool) GetCurrentWorkingCnt() int64 { + return atomic.LoadInt64(&pool.currentWorkingCnt) +} + +func (pool *basicPool) AddCurrentWorkingCnt(value int64) int64 { + return atomic.AddInt64(&pool.currentWorkingCnt, value) +} + +func (pool *basicPool) GetWorkerCnt() int64 { + return atomic.LoadInt64(&pool.workerCnt) +} + +func (pool *basicPool) AddWorkerCnt(value int64) int64 { + return atomic.AddInt64(&pool.workerCnt, value) +} + +func (pool *basicPool) GetMaxWorkerCnt() int64 { + return atomic.LoadInt64(&pool.maxWorkerCnt) +} + +func (pool *basicPool) AddMaxWorkerCnt(value int64) int64 { + return atomic.AddInt64(&pool.maxWorkerCnt, value) +} + +func (pool *basicPool) CompareAndSwapCurrentWorkingCnt(oldValue, newValue int64) bool { + return atomic.CompareAndSwapInt64(&pool.currentWorkingCnt, oldValue, newValue) +} + +func (pool *basicPool) EnableAutoTune() { + +} + +// RoutinePool defines the coroutine pool struct +type RoutinePool struct { + basicPool + taskQueue chan Task + dispatchQueue chan Task + workers map[string]*worker + cacheCnt int + wg *sync.WaitGroup + lock *sync.Mutex + shutDownWg *sync.WaitGroup + autoTune int32 +} + +// ErrSubmitTimeout will be returned if submit task timeout when calling SubmitWithTimeout function +var ErrSubmitTimeout = errors.New("Submit task timeout") + +// ErrPoolShutDown will be returned if RoutinePool is shutdown +var ErrPoolShutDown = errors.New("RoutinePool is shutdown") + +// ErrTaskReject will be returned if submit task is rejected +var ErrTaskReject = errors.New("Submit task is rejected") + +var closeQueue = signalTask{id: "closeQueue"} + +// NewRoutinePool creates a RoutinePool instance +func NewRoutinePool(maxWorkerCnt, cacheCnt int) Pool { + if maxWorkerCnt <= 0 { + maxWorkerCnt = runtime.NumCPU() + } + + pool := &RoutinePool{ + cacheCnt: cacheCnt, + wg: new(sync.WaitGroup), + lock: new(sync.Mutex), + shutDownWg: new(sync.WaitGroup), + autoTune: 0, + } + pool.isShutDown = 0 + pool.maxWorkerCnt += int64(maxWorkerCnt) + if pool.cacheCnt <= 0 { + pool.taskQueue = make(chan Task) + } else { + pool.taskQueue = make(chan Task, pool.cacheCnt) + } + pool.workers = make(map[string]*worker, pool.maxWorkerCnt) + // dispatchQueue must not have length + pool.dispatchQueue = make(chan Task) + pool.dispatcher() + + return pool +} + +// EnableAutoTune sets the autoTune enabled +func (pool *RoutinePool) EnableAutoTune() { + atomic.StoreInt32(&pool.autoTune, 1) +} + +func (pool *RoutinePool) checkStatus(t Task) error { + if t == nil { + return ErrTaskInvalid + } + + if atomic.LoadInt32(&pool.isShutDown) == 1 { + return ErrPoolShutDown + } + return nil +} + +func (pool *RoutinePool) dispatcher() { + pool.shutDownWg.Add(1) + go func() { + for { + task, ok := <-pool.dispatchQueue + if !ok { + break + } + + if task == closeQueue { + close(pool.taskQueue) + pool.shutDownWg.Done() + continue + } + + if pool.GetWorkerCnt() < pool.GetMaxWorkerCnt() { + pool.addWorker() + } + + pool.taskQueue <- task + } + }() +} + +// AddMaxWorkerCnt sets the maxWorkerCnt field's value and returns it +func (pool *RoutinePool) AddMaxWorkerCnt(value int64) int64 { + if atomic.LoadInt32(&pool.autoTune) == 1 { + return pool.basicPool.AddMaxWorkerCnt(value) + } + return pool.GetMaxWorkerCnt() +} + +func (pool *RoutinePool) addWorker() { + if atomic.LoadInt32(&pool.autoTune) == 1 { + pool.lock.Lock() + defer pool.lock.Unlock() + } + w := &worker{} + w.name = fmt.Sprintf("woker-%d", len(pool.workers)) + w.taskQueue = pool.taskQueue + w.wg = pool.wg + pool.AddWorkerCnt(1) + w.pool = pool + pool.workers[w.name] = w + pool.wg.Add(1) + w.start() +} + +func (pool *RoutinePool) autoTuneWorker(w *worker) bool { + if atomic.LoadInt32(&pool.autoTune) == 0 { + return false + } + + if w == nil { + return false + } + + workerCnt := pool.GetWorkerCnt() + maxWorkerCnt := pool.GetMaxWorkerCnt() + if workerCnt > maxWorkerCnt && atomic.CompareAndSwapInt64(&pool.workerCnt, workerCnt, workerCnt-1) { + pool.lock.Lock() + defer pool.lock.Unlock() + delete(pool.workers, w.name) + w.wg.Done() + w.release() + return true + } + + return false +} + +// ExecuteFunc creates a funcWrapper instance with the specified function and calls the Execute function +func (pool *RoutinePool) ExecuteFunc(f func() interface{}) { + fw := &funcWrapper{ + f: f, + } + pool.Execute(fw) +} + +// Execute pushes the specified task to the dispatchQueue +func (pool *RoutinePool) Execute(t Task) { + if t != nil { + pool.dispatchQueue <- t + } +} + +// SubmitFunc creates a funcWrapper instance with the specified function and calls the Submit function +func (pool *RoutinePool) SubmitFunc(f func() interface{}) (Future, error) { + fw := &funcWrapper{ + f: f, + } + return pool.Submit(fw) +} + +// Submit pushes the specified task to the dispatchQueue, and returns the FutureResult and error info +func (pool *RoutinePool) Submit(t Task) (Future, error) { + if err := pool.checkStatus(t); err != nil { + return nil, err + } + f := &FutureResult{} + f.resultChan = make(chan interface{}, 1) + tw := &taskWrapper{ + t: t, + f: f, + } + pool.dispatchQueue <- tw + return f, nil +} + +// SubmitWithTimeout pushes the specified task to the dispatchQueue, and returns the FutureResult and error info. +// Also takes a timeout value, will return ErrSubmitTimeout if it does't complete within that time. +func (pool *RoutinePool) SubmitWithTimeout(t Task, timeout int64) (Future, error) { + if timeout <= 0 { + return pool.Submit(t) + } + if err := pool.checkStatus(t); err != nil { + return nil, err + } + timeoutChan := make(chan bool, 1) + go func() { + time.Sleep(time.Duration(time.Millisecond * time.Duration(timeout))) + timeoutChan <- true + close(timeoutChan) + }() + + f := &FutureResult{} + f.resultChan = make(chan interface{}, 1) + tw := &taskWrapper{ + t: t, + f: f, + } + select { + case pool.dispatchQueue <- tw: + return f, nil + case _, ok := <-timeoutChan: + if ok { + return nil, ErrSubmitTimeout + } + return nil, ErrSubmitTimeout + } +} + +func (pool *RoutinePool) beforeCloseDispatchQueue() { + if !atomic.CompareAndSwapInt32(&pool.isShutDown, 0, 1) { + return + } + pool.dispatchQueue <- closeQueue + pool.wg.Wait() +} + +func (pool *RoutinePool) doCloseDispatchQueue() { + close(pool.dispatchQueue) + pool.shutDownWg.Wait() +} + +// ShutDown closes the RoutinePool instance +func (pool *RoutinePool) ShutDown() { + pool.beforeCloseDispatchQueue() + pool.doCloseDispatchQueue() + for _, w := range pool.workers { + w.release() + } + pool.workers = nil + pool.taskQueue = nil + pool.dispatchQueue = nil +} + +// NoChanPool defines the coroutine pool struct +type NoChanPool struct { + basicPool + wg *sync.WaitGroup + tokens chan interface{} +} + +// NewNochanPool creates a new NoChanPool instance +func NewNochanPool(maxWorkerCnt int) Pool { + if maxWorkerCnt <= 0 { + maxWorkerCnt = runtime.NumCPU() + } + + pool := &NoChanPool{ + wg: new(sync.WaitGroup), + tokens: make(chan interface{}, maxWorkerCnt), + } + pool.isShutDown = 0 + pool.AddMaxWorkerCnt(int64(maxWorkerCnt)) + + for i := 0; i < maxWorkerCnt; i++ { + pool.tokens <- struct{}{} + } + + return pool +} + +func (pool *NoChanPool) acquire() { + <-pool.tokens +} + +func (pool *NoChanPool) release() { + pool.tokens <- 1 +} + +func (pool *NoChanPool) execute(t Task) { + pool.wg.Add(1) + go func() { + pool.acquire() + defer func() { + pool.release() + pool.wg.Done() + }() + runTask(t) + }() +} + +// ShutDown closes the NoChanPool instance +func (pool *NoChanPool) ShutDown() { + if !atomic.CompareAndSwapInt32(&pool.isShutDown, 0, 1) { + return + } + pool.wg.Wait() +} + +// Execute executes the specified task +func (pool *NoChanPool) Execute(t Task) { + if t != nil { + pool.execute(t) + } +} + +// ExecuteFunc creates a funcWrapper instance with the specified function and calls the Execute function +func (pool *NoChanPool) ExecuteFunc(f func() interface{}) { + fw := &funcWrapper{ + f: f, + } + pool.Execute(fw) +} + +// Submit executes the specified task, and returns the FutureResult and error info +func (pool *NoChanPool) Submit(t Task) (Future, error) { + if t == nil { + return nil, ErrTaskInvalid + } + + f := &FutureResult{} + f.resultChan = make(chan interface{}, 1) + tw := &taskWrapper{ + t: t, + f: f, + } + + pool.execute(tw) + return f, nil +} + +// SubmitFunc creates a funcWrapper instance with the specified function and calls the Submit function +func (pool *NoChanPool) SubmitFunc(f func() interface{}) (Future, error) { + fw := &funcWrapper{ + f: f, + } + return pool.Submit(fw) +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/progress.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/progress.go new file mode 100644 index 00000000000..3eced483a40 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/progress.go @@ -0,0 +1,108 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "io" +) + +type ProgressEventType int + +type ProgressEvent struct { + ConsumedBytes int64 + TotalBytes int64 + EventType ProgressEventType +} + +const ( + TransferStartedEvent ProgressEventType = 1 + iota + TransferDataEvent + TransferCompletedEvent + TransferFailedEvent +) + +func newProgressEvent(eventType ProgressEventType, consumed, total int64) *ProgressEvent { + return &ProgressEvent{ + ConsumedBytes: consumed, + TotalBytes: total, + EventType: eventType, + } +} + +type ProgressListener interface { + ProgressChanged(event *ProgressEvent) +} + +type readerTracker struct { + completedBytes int64 +} + +// publishProgress +func publishProgress(listener ProgressListener, event *ProgressEvent) { + if listener != nil && event != nil { + listener.ProgressChanged(event) + } +} + +type teeReader struct { + reader io.Reader + consumedBytes int64 + totalBytes int64 + tracker *readerTracker + listener ProgressListener +} + +func TeeReader(reader io.Reader, totalBytes int64, listener ProgressListener, tracker *readerTracker) io.ReadCloser { + return &teeReader{ + reader: reader, + consumedBytes: 0, + totalBytes: totalBytes, + tracker: tracker, + listener: listener, + } +} + +func (t *teeReader) Read(p []byte) (n int, err error) { + n, err = t.reader.Read(p) + + if err != nil && err != io.EOF { + event := newProgressEvent(TransferFailedEvent, t.consumedBytes, t.totalBytes) + publishProgress(t.listener, event) + } + + if n > 0 { + t.consumedBytes += int64(n) + + if t.listener != nil { + event := newProgressEvent(TransferDataEvent, t.consumedBytes, t.totalBytes) + publishProgress(t.listener, event) + } + + if t.tracker != nil { + t.tracker.completedBytes = t.consumedBytes + } + } + + return +} + +func (r *teeReader) Size() int64 { + return r.totalBytes +} + +func (t *teeReader) Close() error { + if rc, ok := t.reader.(io.ReadCloser); ok { + return rc.Close() + } + return nil +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/provider.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/provider.go new file mode 100644 index 00000000000..297efa41f79 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/provider.go @@ -0,0 +1,242 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "encoding/json" + "io/ioutil" + "math/rand" + "net" + "net/http" + "os" + "strings" + "sync" + "sync/atomic" + "time" +) + +const ( + accessKeyEnv = "OBS_ACCESS_KEY_ID" + securityKeyEnv = "OBS_SECRET_ACCESS_KEY" + securityTokenEnv = "OBS_SECURITY_TOKEN" + ecsRequestURL = "http://169.254.169.254/openstack/latest/securitykey" +) + +type securityHolder struct { + ak string + sk string + securityToken string +} + +var emptySecurityHolder = securityHolder{} + +type securityProvider interface { + getSecurity() securityHolder +} + +type BasicSecurityProvider struct { + val atomic.Value +} + +func (bsp *BasicSecurityProvider) getSecurity() securityHolder { + if sh, ok := bsp.val.Load().(securityHolder); ok { + return sh + } + return emptySecurityHolder +} + +func (bsp *BasicSecurityProvider) refresh(ak, sk, securityToken string) { + bsp.val.Store(securityHolder{ak: strings.TrimSpace(ak), sk: strings.TrimSpace(sk), securityToken: strings.TrimSpace(securityToken)}) +} + +func NewBasicSecurityProvider(ak, sk, securityToken string) *BasicSecurityProvider { + bsp := &BasicSecurityProvider{} + bsp.refresh(ak, sk, securityToken) + return bsp +} + +type EnvSecurityProvider struct { + sh securityHolder + suffix string + once sync.Once +} + +func (esp *EnvSecurityProvider) getSecurity() securityHolder { + //ensure run only once + esp.once.Do(func() { + esp.sh = securityHolder{ + ak: strings.TrimSpace(os.Getenv(accessKeyEnv + esp.suffix)), + sk: strings.TrimSpace(os.Getenv(securityKeyEnv + esp.suffix)), + securityToken: strings.TrimSpace(os.Getenv(securityTokenEnv + esp.suffix)), + } + }) + + return esp.sh +} + +func NewEnvSecurityProvider(suffix string) *EnvSecurityProvider { + if suffix != "" { + suffix = "_" + suffix + } + esp := &EnvSecurityProvider{ + suffix: suffix, + } + return esp +} + +type TemporarySecurityHolder struct { + securityHolder + expireDate time.Time +} + +var emptyTemporarySecurityHolder = TemporarySecurityHolder{} + +type EcsSecurityProvider struct { + val atomic.Value + lock sync.Mutex + httpClient *http.Client + prefetch int32 + retryCount int +} + +func (ecsSp *EcsSecurityProvider) loadTemporarySecurityHolder() (TemporarySecurityHolder, bool) { + if sh := ecsSp.val.Load(); sh == nil { + return emptyTemporarySecurityHolder, false + } else if _sh, ok := sh.(TemporarySecurityHolder); !ok { + return emptyTemporarySecurityHolder, false + } else { + return _sh, true + } +} + +func (ecsSp *EcsSecurityProvider) getAndSetSecurityWithOutLock() securityHolder { + _sh := TemporarySecurityHolder{} + _sh.expireDate = time.Now().Add(time.Minute * 5) + retryCount := 0 + for { + if req, err := http.NewRequest("GET", ecsRequestURL, nil); err == nil { + start := GetCurrentTimestamp() + res, err := ecsSp.httpClient.Do(req) + if err == nil { + if data, _err := ioutil.ReadAll(res.Body); _err == nil { + temp := &struct { + Credential struct { + AK string `json:"access,omitempty"` + SK string `json:"secret,omitempty"` + SecurityToken string `json:"securitytoken,omitempty"` + ExpireDate time.Time `json:"expires_at,omitempty"` + } `json:"credential"` + }{} + + doLog(LEVEL_DEBUG, "Get the json data from ecs succeed") + + if jsonErr := json.Unmarshal(data, temp); jsonErr == nil { + _sh.ak = temp.Credential.AK + _sh.sk = temp.Credential.SK + _sh.securityToken = temp.Credential.SecurityToken + _sh.expireDate = temp.Credential.ExpireDate.Add(time.Minute * -1) + + doLog(LEVEL_INFO, "Get security from ecs succeed, AK:xxxx, SK:xxxx, SecurityToken:xxxx, ExprireDate %s", _sh.expireDate) + + doLog(LEVEL_INFO, "Get security from ecs succeed, cost %d ms", (GetCurrentTimestamp() - start)) + break + } else { + err = jsonErr + } + } else { + err = _err + } + } + + doLog(LEVEL_WARN, "Try to get security from ecs failed, cost %d ms, err %s", (GetCurrentTimestamp() - start), err.Error()) + } + + if retryCount >= ecsSp.retryCount { + doLog(LEVEL_WARN, "Try to get security from ecs failed and exceed the max retry count") + break + } + sleepTime := float64(retryCount+2) * rand.Float64() + if sleepTime > 10 { + sleepTime = 10 + } + time.Sleep(time.Duration(sleepTime * float64(time.Second))) + retryCount++ + } + + ecsSp.val.Store(_sh) + return _sh.securityHolder +} + +func (ecsSp *EcsSecurityProvider) getAndSetSecurity() securityHolder { + ecsSp.lock.Lock() + defer ecsSp.lock.Unlock() + tsh, succeed := ecsSp.loadTemporarySecurityHolder() + if !succeed || time.Now().After(tsh.expireDate) { + return ecsSp.getAndSetSecurityWithOutLock() + } + return tsh.securityHolder +} + +func (ecsSp *EcsSecurityProvider) getSecurity() securityHolder { + if tsh, succeed := ecsSp.loadTemporarySecurityHolder(); succeed { + if time.Now().Before(tsh.expireDate) { + //not expire + if time.Now().Add(time.Minute*5).After(tsh.expireDate) && atomic.CompareAndSwapInt32(&ecsSp.prefetch, 0, 1) { + //do prefetch + sh := ecsSp.getAndSetSecurityWithOutLock() + atomic.CompareAndSwapInt32(&ecsSp.prefetch, 1, 0) + return sh + } + return tsh.securityHolder + } + return ecsSp.getAndSetSecurity() + } + + return ecsSp.getAndSetSecurity() +} + +func getInternalTransport() *http.Transport { + timeout := 10 + transport := &http.Transport{ + Dial: func(network, addr string) (net.Conn, error) { + start := GetCurrentTimestamp() + conn, err := (&net.Dialer{ + Timeout: time.Second * time.Duration(timeout), + Resolver: net.DefaultResolver, + }).Dial(network, addr) + + if isInfoLogEnabled() { + doLog(LEVEL_INFO, "Do http dial cost %d ms", (GetCurrentTimestamp() - start)) + } + if err != nil { + return nil, err + } + return getConnDelegate(conn, timeout, timeout*10), nil + }, + MaxIdleConns: 10, + MaxIdleConnsPerHost: 10, + ResponseHeaderTimeout: time.Second * time.Duration(timeout), + IdleConnTimeout: time.Second * time.Duration(DEFAULT_IDLE_CONN_TIMEOUT), + DisableCompression: true, + } + + return transport +} + +func NewEcsSecurityProvider(retryCount int) *EcsSecurityProvider { + ecsSp := &EcsSecurityProvider{ + retryCount: retryCount, + } + ecsSp.httpClient = &http.Client{Transport: getInternalTransport(), CheckRedirect: checkRedirectFunc} + return ecsSp +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_createSignedUrl.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_createSignedUrl.go new file mode 100644 index 00000000000..14d7742f02c --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_createSignedUrl.go @@ -0,0 +1,65 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "errors" + "fmt" +) + +// CreateSignedUrl creates signed url with the specified CreateSignedUrlInput, and returns the CreateSignedUrlOutput and error +func (obsClient ObsClient) CreateSignedUrl(input *CreateSignedUrlInput, extensions ...extensionOptions) (output *CreateSignedUrlOutput, err error) { + if input == nil { + return nil, errors.New("CreateSignedUrlInput is nil") + } + + params := make(map[string]string, len(input.QueryParams)) + for key, value := range input.QueryParams { + params[key] = value + } + + if input.SubResource != "" { + params[string(input.SubResource)] = "" + } + + headers := make(map[string][]string, len(input.Headers)) + for key, value := range input.Headers { + headers[key] = []string{value} + } + + for _, extension := range extensions { + if extensionHeader, ok := extension.(extensionHeaders); ok { + _err := extensionHeader(headers, obsClient.conf.signature == SignatureObs) + if _err != nil { + doLog(LEVEL_INFO, fmt.Sprintf("set header with error: %v", _err)) + } + } else { + doLog(LEVEL_INFO, "Unsupported extensionOptions") + } + } + + if input.Expires <= 0 { + input.Expires = 300 + } + + requestURL, err := obsClient.doAuthTemporary(string(input.Method), input.Bucket, input.Key, input.Policy, params, headers, int64(input.Expires)) + if err != nil { + return nil, err + } + + output = &CreateSignedUrlOutput{ + SignedUrl: requestURL, + ActualSignedRequestHeaders: headers, + } + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_other.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_other.go new file mode 100644 index 00000000000..9c86f137def --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_other.go @@ -0,0 +1,120 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "errors" + "fmt" + "strings" + "time" +) + +func (obsClient ObsClient) isSecurityToken(params map[string]string, sh securityHolder) { + if sh.securityToken != "" { + if obsClient.conf.signature == SignatureObs { + params[HEADER_STS_TOKEN_OBS] = sh.securityToken + } else { + params[HEADER_STS_TOKEN_AMZ] = sh.securityToken + } + } +} + +// CreateBrowserBasedSignature gets the browser based signature with the specified CreateBrowserBasedSignatureInput, +// and returns the CreateBrowserBasedSignatureOutput and error +func (obsClient ObsClient) CreateBrowserBasedSignature(input *CreateBrowserBasedSignatureInput) (output *CreateBrowserBasedSignatureOutput, err error) { + if input == nil { + return nil, errors.New("CreateBrowserBasedSignatureInput is nil") + } + + params := make(map[string]string, len(input.FormParams)) + for key, value := range input.FormParams { + params[key] = value + } + + date := time.Now().UTC() + shortDate := date.Format(SHORT_DATE_FORMAT) + longDate := date.Format(LONG_DATE_FORMAT) + sh := obsClient.getSecurity() + + credential, _ := getCredential(sh.ak, obsClient.conf.region, shortDate) + + if input.Expires <= 0 { + input.Expires = 300 + } + + expiration := date.Add(time.Second * time.Duration(input.Expires)).Format(ISO8601_DATE_FORMAT) + if obsClient.conf.signature == SignatureV4 { + params[PARAM_ALGORITHM_AMZ_CAMEL] = V4_HASH_PREFIX + params[PARAM_CREDENTIAL_AMZ_CAMEL] = credential + params[PARAM_DATE_AMZ_CAMEL] = longDate + } + + obsClient.isSecurityToken(params, sh) + + matchAnyBucket := true + matchAnyKey := true + count := 5 + if bucket := strings.TrimSpace(input.Bucket); bucket != "" { + params["bucket"] = bucket + matchAnyBucket = false + count-- + } + + if key := strings.TrimSpace(input.Key); key != "" { + params["key"] = key + matchAnyKey = false + count-- + } + + originPolicySlice := make([]string, 0, len(params)+count) + originPolicySlice = append(originPolicySlice, fmt.Sprintf("{\"expiration\":\"%s\",", expiration)) + originPolicySlice = append(originPolicySlice, "\"conditions\":[") + for key, value := range params { + if _key := strings.TrimSpace(strings.ToLower(key)); _key != "" { + originPolicySlice = append(originPolicySlice, fmt.Sprintf("{\"%s\":\"%s\"},", _key, value)) + } + } + + if matchAnyBucket { + originPolicySlice = append(originPolicySlice, "[\"starts-with\", \"$bucket\", \"\"],") + } + + if matchAnyKey { + originPolicySlice = append(originPolicySlice, "[\"starts-with\", \"$key\", \"\"],") + } + + for _, v := range input.RangeParams { + originPolicySlice = append(originPolicySlice, fmt.Sprintf("[\"%s\", %d, %d],", v.RangeName, v.Lower, v.Upper)) + } + + originPolicySlice = append(originPolicySlice, "]}") + + originPolicy := strings.Join(originPolicySlice, "") + policy := Base64Encode([]byte(originPolicy)) + var signature string + if obsClient.conf.signature == SignatureV4 { + signature = getSignature(policy, sh.sk, obsClient.conf.region, shortDate) + } else { + signature = Base64Encode(HmacSha1([]byte(sh.sk), []byte(policy))) + } + + output = &CreateBrowserBasedSignatureOutput{ + OriginPolicy: originPolicy, + Policy: policy, + Algorithm: params[PARAM_ALGORITHM_AMZ_CAMEL], + Credential: params[PARAM_CREDENTIAL_AMZ_CAMEL], + Date: params[PARAM_DATE_AMZ_CAMEL], + Signature: signature, + } + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_signedUrl.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_signedUrl.go new file mode 100644 index 00000000000..c6d6f6f4d21 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/temporary_signedUrl.go @@ -0,0 +1,758 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "errors" + "io" + "net/http" + "os" + "strings" +) + +// ListBucketsWithSignedUrl lists buckets with the specified signed url and signed request headers +func (obsClient ObsClient) ListBucketsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *ListBucketsOutput, err error) { + output = &ListBucketsOutput{} + err = obsClient.doHTTPWithSignedURL("ListBuckets", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// CreateBucketWithSignedUrl creates bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) CreateBucketWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("CreateBucket", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// DeleteBucketWithSignedUrl deletes bucket with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteBucketWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("DeleteBucket", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketStoragePolicyWithSignedUrl sets bucket storage class with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketStoragePolicyWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketStoragePolicy", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketStoragePolicyWithSignedUrl gets bucket storage class with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketStoragePolicyWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketStoragePolicyOutput, err error) { + output = &GetBucketStoragePolicyOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketStoragePolicy", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// ListObjectsWithSignedUrl lists objects in a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) ListObjectsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *ListObjectsOutput, err error) { + output = &ListObjectsOutput{} + err = obsClient.doHTTPWithSignedURL("ListObjects", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + if location, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok { + output.Location = location[0] + } + if output.EncodingType == "url" { + err = decodeListObjectsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListObjectsOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// ListVersionsWithSignedUrl lists versioning objects in a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) ListVersionsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *ListVersionsOutput, err error) { + output = &ListVersionsOutput{} + err = obsClient.doHTTPWithSignedURL("ListVersions", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + if location, ok := output.ResponseHeaders[HEADER_BUCKET_REGION]; ok { + output.Location = location[0] + } + if output.EncodingType == "url" { + err = decodeListVersionsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListVersionsOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// ListMultipartUploadsWithSignedUrl lists the multipart uploads that are initialized but not combined or aborted in a +// specified bucket with the specified signed url and signed request headers +func (obsClient ObsClient) ListMultipartUploadsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *ListMultipartUploadsOutput, err error) { + output = &ListMultipartUploadsOutput{} + err = obsClient.doHTTPWithSignedURL("ListMultipartUploads", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else if output.EncodingType == "url" { + err = decodeListMultipartUploadsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListMultipartUploadsOutput with error: %v.", err) + output = nil + } + } + return +} + +// SetBucketQuotaWithSignedUrl sets the bucket quota with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketQuotaWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketQuota", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketQuotaWithSignedUrl gets the bucket quota with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketQuotaWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketQuotaOutput, err error) { + output = &GetBucketQuotaOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketQuota", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// HeadBucketWithSignedUrl checks whether a bucket exists with the specified signed url and signed request headers +func (obsClient ObsClient) HeadBucketWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("HeadBucket", HTTP_HEAD, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// HeadObjectWithSignedUrl checks whether an object exists with the specified signed url and signed request headers +func (obsClient ObsClient) HeadObjectWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("HeadObject", HTTP_HEAD, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketMetadataWithSignedUrl gets the metadata of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketMetadataWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketMetadataOutput, err error) { + output = &GetBucketMetadataOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketMetadata", HTTP_HEAD, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + ParseGetBucketMetadataOutput(output) + } + return +} + +// GetBucketStorageInfoWithSignedUrl gets storage information about a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketStorageInfoWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketStorageInfoOutput, err error) { + output = &GetBucketStorageInfoOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketStorageInfo", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketLocationWithSignedUrl gets the location of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketLocationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketLocationOutput, err error) { + output = &GetBucketLocationOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketLocation", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketAclWithSignedUrl sets the bucket ACL with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketAclWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketAcl", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketAclWithSignedUrl gets the bucket ACL with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketAclWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketAclOutput, err error) { + output = &GetBucketAclOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketAcl", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketPolicyWithSignedUrl sets the bucket policy with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketPolicyWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketPolicy", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketPolicyWithSignedUrl gets the bucket policy with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketPolicyWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketPolicyOutput, err error) { + output = &GetBucketPolicyOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketPolicy", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, false) + if err != nil { + output = nil + } + return +} + +// DeleteBucketPolicyWithSignedUrl deletes the bucket policy with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteBucketPolicyWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("DeleteBucketPolicy", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketCorsWithSignedUrl sets CORS rules for a bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketCorsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketCors", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketCorsWithSignedUrl gets CORS rules of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketCorsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketCorsOutput, err error) { + output = &GetBucketCorsOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketCors", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// DeleteBucketCorsWithSignedUrl deletes CORS rules of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteBucketCorsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("DeleteBucketCors", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketVersioningWithSignedUrl sets the versioning status for a bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketVersioningWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketVersioning", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketVersioningWithSignedUrl gets the versioning status of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketVersioningWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketVersioningOutput, err error) { + output = &GetBucketVersioningOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketVersioning", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketWebsiteConfigurationWithSignedUrl sets website hosting for a bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketWebsiteConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketWebsiteConfiguration", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketWebsiteConfigurationWithSignedUrl gets the website hosting settings of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketWebsiteConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketWebsiteConfigurationOutput, err error) { + output = &GetBucketWebsiteConfigurationOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketWebsiteConfiguration", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// DeleteBucketWebsiteConfigurationWithSignedUrl deletes the website hosting settings of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteBucketWebsiteConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("DeleteBucketWebsiteConfiguration", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketLoggingConfigurationWithSignedUrl sets the bucket logging with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketLoggingConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketLoggingConfiguration", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketLoggingConfigurationWithSignedUrl gets the logging settings of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketLoggingConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketLoggingConfigurationOutput, err error) { + output = &GetBucketLoggingConfigurationOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketLoggingConfiguration", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketLifecycleConfigurationWithSignedUrl sets lifecycle rules for a bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketLifecycleConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketLifecycleConfiguration", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketLifecycleConfigurationWithSignedUrl gets lifecycle rules of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketLifecycleConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketLifecycleConfigurationOutput, err error) { + output = &GetBucketLifecycleConfigurationOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketLifecycleConfiguration", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// DeleteBucketLifecycleConfigurationWithSignedUrl deletes lifecycle rules of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteBucketLifecycleConfigurationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("DeleteBucketLifecycleConfiguration", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketTaggingWithSignedUrl sets bucket tags with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketTaggingWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketTagging", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketTaggingWithSignedUrl gets bucket tags with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketTaggingWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketTaggingOutput, err error) { + output = &GetBucketTaggingOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketTagging", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// DeleteBucketTaggingWithSignedUrl deletes bucket tags with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteBucketTaggingWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("DeleteBucketTagging", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketNotificationWithSignedUrl sets event notification for a bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketNotificationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketNotification", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketNotificationWithSignedUrl gets event notification settings of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketNotificationWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketNotificationOutput, err error) { + output = &GetBucketNotificationOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketNotification", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// DeleteObjectWithSignedUrl deletes an object with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteObjectWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *DeleteObjectOutput, err error) { + output = &DeleteObjectOutput{} + err = obsClient.doHTTPWithSignedURL("DeleteObject", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + ParseDeleteObjectOutput(output) + } + return +} + +// DeleteObjectsWithSignedUrl deletes objects in a batch with the specified signed url and signed request headers and data +func (obsClient ObsClient) DeleteObjectsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *DeleteObjectsOutput, err error) { + output = &DeleteObjectsOutput{} + err = obsClient.doHTTPWithSignedURL("DeleteObjects", HTTP_POST, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } else if output.EncodingType == "url" { + err = decodeDeleteObjectsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get DeleteObjectsOutput with error: %v.", err) + output = nil + } + } + return +} + +// SetObjectAclWithSignedUrl sets ACL for an object with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetObjectAclWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetObjectAcl", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetObjectAclWithSignedUrl gets the ACL of an object with the specified signed url and signed request headers +func (obsClient ObsClient) GetObjectAclWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetObjectAclOutput, err error) { + output = &GetObjectAclOutput{} + err = obsClient.doHTTPWithSignedURL("GetObjectAcl", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + if versionID, ok := output.ResponseHeaders[HEADER_VERSION_ID]; ok { + output.VersionId = versionID[0] + } + } + return +} + +// RestoreObjectWithSignedUrl restores an object with the specified signed url and signed request headers and data +func (obsClient ObsClient) RestoreObjectWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("RestoreObject", HTTP_POST, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetObjectMetadataWithSignedUrl gets object metadata with the specified signed url and signed request headers +func (obsClient ObsClient) GetObjectMetadataWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetObjectMetadataOutput, err error) { + output = &GetObjectMetadataOutput{} + err = obsClient.doHTTPWithSignedURL("GetObjectMetadata", HTTP_HEAD, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + ParseGetObjectMetadataOutput(output) + } + return +} + +// GetObjectWithSignedUrl downloads object with the specified signed url and signed request headers +func (obsClient ObsClient) GetObjectWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetObjectOutput, err error) { + output = &GetObjectOutput{} + err = obsClient.doHTTPWithSignedURL(GET_OBJECT, HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + ParseGetObjectOutput(output) + } + return +} + +// PutObjectWithSignedUrl uploads an object to the specified bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) PutObjectWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *PutObjectOutput, err error) { + output = &PutObjectOutput{} + err = obsClient.doHTTPWithSignedURL(PUT_OBJECT, HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } else { + ParsePutObjectOutput(output) + } + return +} + +// PutFileWithSignedUrl uploads a file to the specified bucket with the specified signed url and signed request headers and sourceFile path +func (obsClient ObsClient) PutFileWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, sourceFile string) (output *PutObjectOutput, err error) { + var data io.Reader + sourceFile = strings.TrimSpace(sourceFile) + if sourceFile != "" { + fd, _err := os.Open(sourceFile) + if _err != nil { + err = _err + return nil, err + } + defer func() { + errMsg := fd.Close() + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close file with reason: %v", errMsg) + } + }() + + stat, _err := fd.Stat() + if _err != nil { + err = _err + return nil, err + } + fileReaderWrapper := &fileReaderWrapper{filePath: sourceFile} + fileReaderWrapper.reader = fd + + var contentLength int64 + if value, ok := actualSignedRequestHeaders[HEADER_CONTENT_LENGTH_CAMEL]; ok { + contentLength = StringToInt64(value[0], -1) + } else if value, ok := actualSignedRequestHeaders[HEADER_CONTENT_LENGTH]; ok { + contentLength = StringToInt64(value[0], -1) + } else { + contentLength = stat.Size() + } + if contentLength > stat.Size() { + return nil, errors.New("ContentLength is larger than fileSize") + } + fileReaderWrapper.totalCount = contentLength + data = fileReaderWrapper + } + + output = &PutObjectOutput{} + err = obsClient.doHTTPWithSignedURL(PUT_FILE, HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } else { + ParsePutObjectOutput(output) + } + return +} + +// CopyObjectWithSignedUrl creates a copy for an existing object with the specified signed url and signed request headers +func (obsClient ObsClient) CopyObjectWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *CopyObjectOutput, err error) { + output = &CopyObjectOutput{} + err = obsClient.doHTTPWithSignedURL("CopyObject", HTTP_PUT, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + ParseCopyObjectOutput(output) + } + return +} + +// AbortMultipartUploadWithSignedUrl aborts a multipart upload in a specified bucket by using the multipart upload ID with the specified signed url and signed request headers +func (obsClient ObsClient) AbortMultipartUploadWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("AbortMultipartUpload", HTTP_DELETE, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// InitiateMultipartUploadWithSignedUrl initializes a multipart upload with the specified signed url and signed request headers +func (obsClient ObsClient) InitiateMultipartUploadWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *InitiateMultipartUploadOutput, err error) { + output = &InitiateMultipartUploadOutput{} + err = obsClient.doHTTPWithSignedURL("InitiateMultipartUpload", HTTP_POST, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + ParseInitiateMultipartUploadOutput(output) + if output.EncodingType == "url" { + err = decodeInitiateMultipartUploadOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get InitiateMultipartUploadOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// UploadPartWithSignedUrl uploads a part to a specified bucket by using a specified multipart upload ID +// with the specified signed url and signed request headers and data +func (obsClient ObsClient) UploadPartWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *UploadPartOutput, err error) { + output = &UploadPartOutput{} + err = obsClient.doHTTPWithSignedURL("UploadPart", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } else { + ParseUploadPartOutput(output) + } + return +} + +// CompleteMultipartUploadWithSignedUrl combines the uploaded parts in a specified bucket by using the multipart upload ID +// with the specified signed url and signed request headers and data +func (obsClient ObsClient) CompleteMultipartUploadWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *CompleteMultipartUploadOutput, err error) { + output = &CompleteMultipartUploadOutput{} + err = obsClient.doHTTPWithSignedURL("CompleteMultipartUpload", HTTP_POST, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } else { + ParseCompleteMultipartUploadOutput(output) + if output.EncodingType == "url" { + err = decodeCompleteMultipartUploadOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get CompleteMultipartUploadOutput with error: %v.", err) + output = nil + } + } + } + return +} + +// ListPartsWithSignedUrl lists the uploaded parts in a bucket by using the multipart upload ID with the specified signed url and signed request headers +func (obsClient ObsClient) ListPartsWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *ListPartsOutput, err error) { + output = &ListPartsOutput{} + err = obsClient.doHTTPWithSignedURL("ListParts", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else if output.EncodingType == "url" { + err = decodeListPartsOutput(output) + if err != nil { + doLog(LEVEL_ERROR, "Failed to get ListPartsOutput with error: %v.", err) + output = nil + } + } + return +} + +// CopyPartWithSignedUrl copy a part to a specified bucket by using a specified multipart upload ID with the specified signed url and signed request headers +func (obsClient ObsClient) CopyPartWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *CopyPartOutput, err error) { + output = &CopyPartOutput{} + err = obsClient.doHTTPWithSignedURL("CopyPart", HTTP_PUT, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } else { + ParseCopyPartOutput(output) + } + return +} + +// SetBucketRequestPaymentWithSignedUrl sets requester-pays setting for a bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketRequestPaymentWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketRequestPayment", HTTP_PUT, signedUrl, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketRequestPaymentWithSignedUrl gets requester-pays setting of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketRequestPaymentWithSignedUrl(signedUrl string, actualSignedRequestHeaders http.Header) (output *GetBucketRequestPaymentOutput, err error) { + output = &GetBucketRequestPaymentOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketRequestPayment", HTTP_GET, signedUrl, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// SetBucketEncryptionWithSignedURL sets bucket encryption setting for a bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) SetBucketEncryptionWithSignedURL(signedURL string, actualSignedRequestHeaders http.Header, data io.Reader) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("SetBucketEncryption", HTTP_PUT, signedURL, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } + return +} + +// GetBucketEncryptionWithSignedURL gets bucket encryption setting of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) GetBucketEncryptionWithSignedURL(signedURL string, actualSignedRequestHeaders http.Header) (output *GetBucketEncryptionOutput, err error) { + output = &GetBucketEncryptionOutput{} + err = obsClient.doHTTPWithSignedURL("GetBucketEncryption", HTTP_GET, signedURL, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// DeleteBucketEncryptionWithSignedURL deletes bucket encryption setting of a bucket with the specified signed url and signed request headers +func (obsClient ObsClient) DeleteBucketEncryptionWithSignedURL(signedURL string, actualSignedRequestHeaders http.Header) (output *BaseModel, err error) { + output = &BaseModel{} + err = obsClient.doHTTPWithSignedURL("DeleteBucketEncryption", HTTP_DELETE, signedURL, actualSignedRequestHeaders, nil, output, true) + if err != nil { + output = nil + } + return +} + +// AppendObjectWithSignedUrl uploads an object to the specified bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) AppendObjectWithSignedURL(signedURL string, actualSignedRequestHeaders http.Header, data io.Reader) (output *AppendObjectOutput, err error) { + output = &AppendObjectOutput{} + err = obsClient.doHTTPWithSignedURL(APPEND_OBJECT, HTTP_POST, signedURL, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } else { + if err = ParseAppendObjectOutput(output); err != nil { + output = nil + } + } + return +} + +// ModifyObjectWithSignedUrl uploads an object to the specified bucket with the specified signed url and signed request headers and data +func (obsClient ObsClient) ModifyObjectWithSignedURL(signedURL string, actualSignedRequestHeaders http.Header, data io.Reader) (output *ModifyObjectOutput, err error) { + output = &ModifyObjectOutput{} + err = obsClient.doHTTPWithSignedURL("ModifyObject", HTTP_PUT, signedURL, actualSignedRequestHeaders, data, output, true) + if err != nil { + output = nil + } else { + ParseModifyObjectOutput(output) + } + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_base.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_base.go new file mode 100644 index 00000000000..909c7a0c47d --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_base.go @@ -0,0 +1,154 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "io" +) + +type IRepeatable interface { + Reset() error +} + +// IReadCloser defines interface with function: setReadCloser +type IReadCloser interface { + setReadCloser(body io.ReadCloser) +} + +func setHeaders(headers map[string][]string, header string, headerValue []string, isObs bool) { + if isObs { + header = HEADER_PREFIX_OBS + header + headers[header] = headerValue + } else { + header = HEADER_PREFIX + header + headers[header] = headerValue + } +} + +func setHeadersNext(headers map[string][]string, header string, headerNext string, headerValue []string, isObs bool) { + if isObs { + headers[header] = headerValue + } else { + headers[headerNext] = headerValue + } +} + +// IBaseModel defines interface for base response model +type IBaseModel interface { + setStatusCode(statusCode int) + + setRequestID(requestID string) + + setResponseHeaders(responseHeaders map[string][]string) +} + +// ISerializable defines interface with function: trans +type ISerializable interface { + trans(isObs bool) (map[string]string, map[string][]string, interface{}, error) +} + +// DefaultSerializable defines default serializable struct +type DefaultSerializable struct { + params map[string]string + headers map[string][]string + data interface{} +} + +func (input DefaultSerializable) trans(isObs bool) (map[string]string, map[string][]string, interface{}, error) { + return input.params, input.headers, input.data, nil +} + +var defaultSerializable = &DefaultSerializable{} + +func newSubResourceSerialV2(subResource SubResourceType, value string) *DefaultSerializable { + return &DefaultSerializable{map[string]string{string(subResource): value}, nil, nil} +} + +func newSubResourceSerial(subResource SubResourceType) *DefaultSerializable { + return &DefaultSerializable{map[string]string{string(subResource): ""}, nil, nil} +} + +func trans(subResource SubResourceType, input interface{}) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(subResource): ""} + data, err = ConvertRequestToIoReader(input) + return +} + +func (baseModel *BaseModel) setStatusCode(statusCode int) { + baseModel.StatusCode = statusCode +} + +func (baseModel *BaseModel) setRequestID(requestID string) { + baseModel.RequestId = requestID +} + +func (baseModel *BaseModel) setResponseHeaders(responseHeaders map[string][]string) { + baseModel.ResponseHeaders = responseHeaders +} + +// GetEncryption gets the Encryption field value from SseKmsHeader +func (header SseKmsHeader) GetEncryption() string { + if header.Encryption != "" { + return header.Encryption + } + if !header.isObs { + return DEFAULT_SSE_KMS_ENCRYPTION + } + return DEFAULT_SSE_KMS_ENCRYPTION_OBS +} + +// GetKey gets the Key field value from SseKmsHeader +func (header SseKmsHeader) GetKey() string { + return header.Key +} + +// GetEncryption gets the Encryption field value from SseCHeader +func (header SseCHeader) GetEncryption() string { + if header.Encryption != "" { + return header.Encryption + } + return DEFAULT_SSE_C_ENCRYPTION +} + +// GetKey gets the Key field value from SseCHeader +func (header SseCHeader) GetKey() string { + return header.Key +} + +// GetKeyMD5 gets the KeyMD5 field value from SseCHeader +func (header SseCHeader) GetKeyMD5() string { + if header.KeyMD5 != "" { + return header.KeyMD5 + } + + if ret, err := Base64Decode(header.GetKey()); err == nil { + return Base64Md5(ret) + } + return "" +} + +func setSseHeader(headers map[string][]string, sseHeader ISseHeader, sseCOnly bool, isObs bool) { + if sseHeader != nil { + if sseCHeader, ok := sseHeader.(SseCHeader); ok { + setHeaders(headers, HEADER_SSEC_ENCRYPTION, []string{sseCHeader.GetEncryption()}, isObs) + setHeaders(headers, HEADER_SSEC_KEY, []string{sseCHeader.GetKey()}, isObs) + setHeaders(headers, HEADER_SSEC_KEY_MD5, []string{sseCHeader.GetKeyMD5()}, isObs) + } else if sseKmsHeader, ok := sseHeader.(SseKmsHeader); !sseCOnly && ok { + sseKmsHeader.isObs = isObs + setHeaders(headers, HEADER_SSEKMS_ENCRYPTION, []string{sseKmsHeader.GetEncryption()}, isObs) + if sseKmsHeader.GetKey() != "" { + setHeadersNext(headers, HEADER_SSEKMS_KEY_OBS, HEADER_SSEKMS_KEY_AMZ, []string{sseKmsHeader.GetKey()}, isObs) + } + } + } +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_bucket.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_bucket.go new file mode 100644 index 00000000000..8fd28fa1623 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_bucket.go @@ -0,0 +1,352 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "fmt" + "strings" +) + +func (input ListBucketsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = make(map[string]string) + if input.MaxKeys > 0 { + params["max-keys"] = IntToString(input.MaxKeys) + } + if input.Marker != "" { + params["marker"] = input.Marker + } + headers = make(map[string][]string) + if input.QueryLocation && !isObs { + setHeaders(headers, HEADER_LOCATION_AMZ, []string{"true"}, isObs) + } + if input.BucketType != "" { + setHeaders(headers, HEADER_BUCKET_TYPE, []string{string(input.BucketType)}, true) + } + return +} + +func (input CreateBucketInput) prepareGrantHeaders(headers map[string][]string, isObs bool) { + if grantReadID := input.GrantReadId; grantReadID != "" { + setHeaders(headers, HEADER_GRANT_READ_OBS, []string{grantReadID}, isObs) + } + if grantWriteID := input.GrantWriteId; grantWriteID != "" { + setHeaders(headers, HEADER_GRANT_WRITE_OBS, []string{grantWriteID}, isObs) + } + if grantReadAcpID := input.GrantReadAcpId; grantReadAcpID != "" { + setHeaders(headers, HEADER_GRANT_READ_ACP_OBS, []string{grantReadAcpID}, isObs) + } + if grantWriteAcpID := input.GrantWriteAcpId; grantWriteAcpID != "" { + setHeaders(headers, HEADER_GRANT_WRITE_ACP_OBS, []string{grantWriteAcpID}, isObs) + } + if grantFullControlID := input.GrantFullControlId; grantFullControlID != "" { + setHeaders(headers, HEADER_GRANT_FULL_CONTROL_OBS, []string{grantFullControlID}, isObs) + } + if grantReadDeliveredID := input.GrantReadDeliveredId; grantReadDeliveredID != "" { + setHeaders(headers, HEADER_GRANT_READ_DELIVERED_OBS, []string{grantReadDeliveredID}, true) + } + if grantFullControlDeliveredID := input.GrantFullControlDeliveredId; grantFullControlDeliveredID != "" { + setHeaders(headers, HEADER_GRANT_FULL_CONTROL_DELIVERED_OBS, []string{grantFullControlDeliveredID}, true) + } +} + +func (input CreateBucketInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + headers = make(map[string][]string) + if acl := string(input.ACL); acl != "" { + setHeaders(headers, HEADER_ACL, []string{acl}, isObs) + } + if storageClass := string(input.StorageClass); storageClass != "" { + if !isObs { + if storageClass == string(StorageClassWarm) { + storageClass = string(storageClassStandardIA) + } else if storageClass == string(StorageClassCold) { + storageClass = string(storageClassGlacier) + } else if storageClass == string(StorageClassIntelligentTiering) { + doLog(LEVEL_WARN, "Intelligent tiering supports only OBS signature.") + } + } + setHeadersNext(headers, HEADER_STORAGE_CLASS_OBS, HEADER_STORAGE_CLASS, []string{storageClass}, isObs) + } + if epid := input.Epid; epid != "" { + setHeaders(headers, HEADER_EPID_HEADERS, []string{epid}, isObs) + } + if availableZone := input.AvailableZone; availableZone != "" { + setHeaders(headers, HEADER_AZ_REDUNDANCY, []string{availableZone}, isObs) + } + + input.prepareGrantHeaders(headers, isObs) + if input.IsFSFileInterface { + setHeaders(headers, headerFSFileInterface, []string{"Enabled"}, true) + } + + if location := strings.TrimSpace(input.Location); location != "" { + input.Location = location + + xml := make([]string, 0, 3) + xml = append(xml, "") + if isObs { + xml = append(xml, fmt.Sprintf("%s", input.Location)) + } else { + xml = append(xml, fmt.Sprintf("%s", input.Location)) + } + xml = append(xml, "") + + data = strings.Join(xml, "") + } + + if bucketRedundancy := string(input.BucketRedundancy); bucketRedundancy != "" { + setHeaders(headers, HEADER_BUCKET_REDUNDANCY, []string{bucketRedundancy}, isObs) + } + if input.IsFusionAllowUpgrade { + setHeaders(headers, HEADER_FUSION_ALLOW_UPGRADE, []string{"true"}, isObs) + } + + if input.IsRedundancyAllowALT { + setHeaders(headers, HEADER_FUSION_ALLOW_ALT, []string{"true"}, isObs) + } + + return +} + +func (input SetBucketStoragePolicyInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + xml := make([]string, 0, 1) + if !isObs { + storageClass := input.StorageClass + if storageClass == "" { + storageClass = StorageClassStandard + } else if input.StorageClass == StorageClassWarm { + storageClass = storageClassStandardIA + } else if input.StorageClass == StorageClassCold { + storageClass = storageClassGlacier + } else if storageClass == StorageClassIntelligentTiering { + doLog(LEVEL_WARN, "Intelligent tiering supports only OBS signature.") + } + params = map[string]string{string(SubResourceStoragePolicy): ""} + xml = append(xml, fmt.Sprintf("%s", storageClass)) + } else { + if !IsContain(obsStorageClasses, string(input.StorageClass)) { + input.StorageClass = StorageClassStandard + } + params = map[string]string{string(SubResourceStorageClass): ""} + xml = append(xml, fmt.Sprintf("%s", input.StorageClass)) + } + data = strings.Join(xml, "") + return +} + +func (input SetBucketQuotaInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + return trans(SubResourceQuota, input) +} + +func (input SetBucketAclInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceAcl): ""} + headers = make(map[string][]string) + + if acl := string(input.ACL); acl != "" { + setHeaders(headers, HEADER_ACL, []string{acl}, isObs) + } else { + data, _ = convertBucketACLToXML(input.AccessControlPolicy, false, isObs) + } + return +} + +func (input SetBucketPolicyInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourcePolicy): ""} + data = strings.NewReader(input.Policy) + return +} + +func (input SetBucketCorsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceCors): ""} + data, md5OrSha256, err := ConvertRequestToIoReaderV2(input, input.EnableSha256) + if err != nil { + return + } + + headerCheckAlgorithm := HEADER_MD5_CAMEL + if input.EnableSha256 { + headerCheckAlgorithm = HEADER_SHA256_CAMEL + } + + headers = map[string][]string{headerCheckAlgorithm: {md5OrSha256}} + return +} + +func (input SetBucketVersioningInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + return trans(SubResourceVersioning, input) +} + +func (input SetBucketWebsiteConfigurationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceWebsite): ""} + data, _ = ConvertWebsiteConfigurationToXml(input.BucketWebsiteConfiguration, false) + return +} + +func (input GetBucketMetadataInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + headers = make(map[string][]string) + if origin := strings.TrimSpace(input.Origin); origin != "" { + headers[HEADER_ORIGIN_CAMEL] = []string{origin} + } + if requestHeader := strings.TrimSpace(input.RequestHeader); requestHeader != "" { + headers[HEADER_ACCESS_CONTROL_REQUEST_HEADER_CAMEL] = []string{requestHeader} + } + return +} + +func (input SetBucketLoggingConfigurationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceLogging): ""} + data, _ = ConvertLoggingStatusToXml(input.BucketLoggingStatus, false, isObs) + return +} + +func (input SetBucketLifecycleConfigurationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceLifecycle): ""} + + data, md5OrSha256 := ConvertLifecycleConfigurationToXml(input.BucketLifecycleConfiguration, true, isObs, input.EnableSha256) + + headerCheckAlgorithm := HEADER_MD5_CAMEL + if input.EnableSha256 { + headerCheckAlgorithm = HEADER_SHA256_CAMEL + } + + headers = map[string][]string{headerCheckAlgorithm: {md5OrSha256}} + return +} + +func (input SetBucketEncryptionInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceEncryption): ""} + data, _ = ConvertEncryptionConfigurationToXml(input.BucketEncryptionConfiguration, false, isObs) + return +} + +func (input SetBucketTaggingInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceTagging): ""} + data, md5OrSha256, err := ConvertRequestToIoReaderV2(input, input.EnableSha256) + if err != nil { + return + } + + headerCheckAlgorithm := HEADER_MD5_CAMEL + if input.EnableSha256 { + headerCheckAlgorithm = HEADER_SHA256_CAMEL + } + + headers = map[string][]string{headerCheckAlgorithm: {md5OrSha256}} + return +} + +func (input SetBucketNotificationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceNotification): ""} + data, _ = ConvertNotificationToXml(input.BucketNotification, false, isObs) + return +} + +func (input SetBucketRequestPaymentInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + return trans(SubResourceRequestPayment, input) +} + +func (input SetBucketFetchPolicyInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + contentType, _ := mimeTypes["json"] + headers = make(map[string][]string, 2) + headers[HEADER_CONTENT_TYPE] = []string{contentType} + setHeaders(headers, headerOefMarker, []string{"yes"}, isObs) + data, err = convertFetchPolicyToJSON(input) + return +} + +func (input GetBucketFetchPolicyInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + headers = make(map[string][]string, 1) + setHeaders(headers, headerOefMarker, []string{"yes"}, isObs) + return +} + +func (input DeleteBucketFetchPolicyInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + headers = make(map[string][]string, 1) + setHeaders(headers, headerOefMarker, []string{"yes"}, isObs) + return +} + +func (input SetBucketFetchJobInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + contentType, _ := mimeTypes["json"] + headers = make(map[string][]string, 2) + headers[HEADER_CONTENT_TYPE] = []string{contentType} + setHeaders(headers, headerOefMarker, []string{"yes"}, isObs) + data, err = convertFetchJobToJSON(input) + return +} + +func (input GetBucketFetchJobInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + headers = make(map[string][]string, 1) + setHeaders(headers, headerOefMarker, []string{"yes"}, isObs) + return +} + +func (input SetBucketMirrorBackToSourceInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceMirrorBackToSource): ""} + headers = make(map[string][]string, 1) + headers[HEADER_CONTENT_TYPE] = []string{mimeTypes["json"]} + data = input.Rules + return +} + +func (input DeleteBucketCustomDomainInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + return trans(SubResourceCustomDomain, input) +} + +func handleDomainConfig(customDomainConfiguration CustomDomainConfiguration) (headers map[string][]string, data interface{}, err error) { + + headers = make(map[string][]string) + if customDomainConfiguration.CertificateId != "" { + err = validateLength(len(customDomainConfiguration.CertificateId), CERT_ID_SIZE, CERT_ID_SIZE, CERTIFICATE_FIELD_NAME) + if err != nil { + return headers, nil, err + } + } + + err = validateLength(len(customDomainConfiguration.Name), MIN_CERTIFICATE_NAME_LENGTH, MAX_CERTIFICATE_NAME_LENGTH, NAME_LENGTH) + if err != nil { + return headers, nil, err + } + + reader, md5, convertErr := ConvertRequestToIoReaderV2(customDomainConfiguration, false) + if convertErr != nil { + return headers, nil, convertErr + } + + readerLen, err := GetReaderLen(reader) + if err != nil { + return headers, nil, err + } + + err = validateLength(int(readerLen), 0, MAX_CERT_XML_BODY_SIZE, XML_SIZE) + if err != nil { + return headers, nil, err + } + data = reader + + headers = map[string][]string{HEADER_MD5_CAMEL: {md5}} + return +} + +func (input SetBucketCustomDomainInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceCustomDomain): input.CustomDomain} + headers = make(map[string][]string) + data = nil + if input.CustomDomainConfiguration != nil { + headers, data, err = handleDomainConfig(*input.CustomDomainConfiguration) + } + return +} + +func (input PutBucketPublicAccessBlockInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + return trans(SubResourcePublicAccessBlock, input) +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_object.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_object.go new file mode 100644 index 00000000000..e6478bf268c --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_object.go @@ -0,0 +1,532 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "fmt" + "io" + "net/url" + "strconv" + "strings" +) + +func (output *GetObjectOutput) setReadCloser(body io.ReadCloser) { + output.Body = body +} + +func (input ListObjsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = make(map[string]string) + if input.Prefix != "" { + params["prefix"] = input.Prefix + } + if input.Delimiter != "" { + params["delimiter"] = input.Delimiter + } + if input.MaxKeys > 0 { + params["max-keys"] = IntToString(input.MaxKeys) + } + if input.EncodingType != "" { + params["encoding-type"] = input.EncodingType + } + headers = make(map[string][]string) + if origin := strings.TrimSpace(input.Origin); origin != "" { + headers[HEADER_ORIGIN_CAMEL] = []string{origin} + } + if requestHeader := strings.TrimSpace(input.RequestHeader); requestHeader != "" { + headers[HEADER_ACCESS_CONTROL_REQUEST_HEADER_CAMEL] = []string{requestHeader} + } + return +} + +func (input ListObjectsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.ListObjsInput.trans(isObs) + if err != nil { + return + } + if input.Marker != "" { + params["marker"] = input.Marker + } + return +} + +func (input ListPosixObjectsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.ListObjsInput.trans(isObs) + if err != nil { + return + } + if input.Marker != "" { + params["marker"] = input.Marker + } + return +} + +func (input ListVersionsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.ListObjsInput.trans(isObs) + if err != nil { + return + } + params[string(SubResourceVersions)] = "" + if input.KeyMarker != "" { + params["key-marker"] = input.KeyMarker + } + if input.VersionIdMarker != "" { + params["version-id-marker"] = input.VersionIdMarker + } + return +} + +func (input DeleteObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = make(map[string]string) + if input.VersionId != "" { + params[PARAM_VERSION_ID] = input.VersionId + } + return +} + +func (input DeleteObjectsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceDelete): ""} + if strings.ToLower(input.EncodingType) == "url" { + for index, object := range input.Objects { + input.Objects[index].Key = url.QueryEscape(object.Key) + } + } + data, md5 := convertDeleteObjectsToXML(input) + + headers = map[string][]string{HEADER_MD5_CAMEL: {md5}} + return +} + +func (input SetObjectAclInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceAcl): ""} + if input.VersionId != "" { + params[PARAM_VERSION_ID] = input.VersionId + } + headers = make(map[string][]string) + if acl := string(input.ACL); acl != "" { + setHeaders(headers, HEADER_ACL, []string{acl}, isObs) + } else { + data, _ = ConvertAclToXml(input.AccessControlPolicy, false, isObs) + } + return +} + +func (input GetObjectAclInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceAcl): ""} + if input.VersionId != "" { + params[PARAM_VERSION_ID] = input.VersionId + } + return +} + +func (input RestoreObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceRestore): ""} + if input.VersionId != "" { + params[PARAM_VERSION_ID] = input.VersionId + } + if !isObs { + data, err = ConvertRequestToIoReader(input) + } else { + data = ConventObsRestoreToXml(input) + } + return +} + +func (input GetObjectMetadataInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = make(map[string]string) + if input.VersionId != "" { + params[PARAM_VERSION_ID] = input.VersionId + } + headers = make(map[string][]string) + + if input.Origin != "" { + headers[HEADER_ORIGIN_CAMEL] = []string{input.Origin} + } + + if input.RequestHeader != "" { + headers[HEADER_ACCESS_CONTROL_REQUEST_HEADER_CAMEL] = []string{input.RequestHeader} + } + setSseHeader(headers, input.SseHeader, true, isObs) + return +} + +func (input SetObjectMetadataInput) prepareContentHeaders(headers map[string][]string) { + if input.CacheControl != "" { + headers[HEADER_CACHE_CONTROL_CAMEL] = []string{input.CacheControl} + } + if input.ContentDisposition != "" { + headers[HEADER_CONTENT_DISPOSITION_CAMEL] = []string{input.ContentDisposition} + } + if input.ContentEncoding != "" { + headers[HEADER_CONTENT_ENCODING_CAMEL] = []string{input.ContentEncoding} + } + if input.ContentLanguage != "" { + headers[HEADER_CONTENT_LANGUAGE_CAMEL] = []string{input.ContentLanguage} + } + if input.ContentType != "" { + headers[HEADER_CONTENT_TYPE_CAML] = []string{input.ContentType} + } + // 这里为了兼容老版本,默认以Expire值为准,但如果Expires没有,则以HttpExpires为准。 + if input.Expires != "" { + headers[HEADER_EXPIRES_CAMEL] = []string{input.Expires} + } else if input.HttpExpires != "" { + headers[HEADER_EXPIRES_CAMEL] = []string{input.HttpExpires} + } +} + +func (input SetObjectMetadataInput) prepareStorageClass(headers map[string][]string, isObs bool) { + if storageClass := string(input.StorageClass); storageClass != "" { + if !isObs { + if storageClass == string(StorageClassWarm) { + storageClass = string(storageClassStandardIA) + } else if storageClass == string(StorageClassCold) { + storageClass = string(storageClassGlacier) + } else if storageClass == string(StorageClassIntelligentTiering) { + doLog(LEVEL_WARN, "Intelligent tiering supports only OBS signature.") + } + } + setHeaders(headers, HEADER_STORAGE_CLASS2, []string{storageClass}, isObs) + } +} + +func (input SetObjectMetadataInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceMetadata): ""} + if input.VersionId != "" { + params[PARAM_VERSION_ID] = input.VersionId + } + headers = make(map[string][]string) + + if directive := string(input.MetadataDirective); directive != "" { + setHeaders(headers, HEADER_METADATA_DIRECTIVE, []string{string(input.MetadataDirective)}, isObs) + } else { + setHeaders(headers, HEADER_METADATA_DIRECTIVE, []string{string(ReplaceNew)}, isObs) + } + + input.prepareContentHeaders(headers) + if input.WebsiteRedirectLocation != "" { + setHeaders(headers, HEADER_WEBSITE_REDIRECT_LOCATION, []string{input.WebsiteRedirectLocation}, isObs) + } + input.prepareStorageClass(headers, isObs) + if input.Metadata != nil { + for key, value := range input.Metadata { + key = strings.TrimSpace(key) + setHeadersNext(headers, HEADER_PREFIX_META_OBS+key, HEADER_PREFIX_META+key, []string{value}, isObs) + } + } + return +} + +func (input GetObjectInput) prepareResponseParams(params map[string]string) { + if input.ResponseCacheControl != "" { + params[PARAM_RESPONSE_CACHE_CONTROL] = input.ResponseCacheControl + } + if input.ResponseContentDisposition != "" { + params[PARAM_RESPONSE_CONTENT_DISPOSITION] = input.ResponseContentDisposition + } + if input.ResponseContentEncoding != "" { + params[PARAM_RESPONSE_CONTENT_ENCODING] = input.ResponseContentEncoding + } + if input.ResponseContentLanguage != "" { + params[PARAM_RESPONSE_CONTENT_LANGUAGE] = input.ResponseContentLanguage + } + if input.ResponseContentType != "" { + params[PARAM_RESPONSE_CONTENT_TYPE] = input.ResponseContentType + } + if input.ResponseExpires != "" { + params[PARAM_RESPONSE_EXPIRES] = input.ResponseExpires + } +} + +func (input GetObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.GetObjectMetadataInput.trans(isObs) + if err != nil { + return + } + input.prepareResponseParams(params) + if input.ImageProcess != "" { + params[PARAM_IMAGE_PROCESS] = input.ImageProcess + } + if input.RangeStart >= 0 && input.RangeEnd > input.RangeStart { + headers[HEADER_RANGE] = []string{fmt.Sprintf("bytes=%d-%d", input.RangeStart, input.RangeEnd)} + } + if input.AcceptEncoding != "" { + headers[HEADER_ACCEPT_ENCODING] = []string{input.AcceptEncoding} + } + if input.IfMatch != "" { + headers[HEADER_IF_MATCH] = []string{input.IfMatch} + } + if input.IfNoneMatch != "" { + headers[HEADER_IF_NONE_MATCH] = []string{input.IfNoneMatch} + } + if !input.IfModifiedSince.IsZero() { + headers[HEADER_IF_MODIFIED_SINCE] = []string{FormatUtcToRfc1123(input.IfModifiedSince)} + } + if !input.IfUnmodifiedSince.IsZero() { + headers[HEADER_IF_UNMODIFIED_SINCE] = []string{FormatUtcToRfc1123(input.IfUnmodifiedSince)} + } + return +} + +func (input ObjectOperationInput) prepareGrantHeaders(headers map[string][]string, isObs bool) { + if GrantReadID := input.GrantReadId; GrantReadID != "" { + setHeaders(headers, HEADER_GRANT_READ_OBS, []string{GrantReadID}, isObs) + } + if GrantReadAcpID := input.GrantReadAcpId; GrantReadAcpID != "" { + setHeaders(headers, HEADER_GRANT_READ_ACP_OBS, []string{GrantReadAcpID}, isObs) + } + if GrantWriteAcpID := input.GrantWriteAcpId; GrantWriteAcpID != "" { + setHeaders(headers, HEADER_GRANT_WRITE_ACP_OBS, []string{GrantWriteAcpID}, isObs) + } + if GrantFullControlID := input.GrantFullControlId; GrantFullControlID != "" { + setHeaders(headers, HEADER_GRANT_FULL_CONTROL_OBS, []string{GrantFullControlID}, isObs) + } +} + +func (input ObjectOperationInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + headers = make(map[string][]string) + params = make(map[string]string) + if acl := string(input.ACL); acl != "" { + setHeaders(headers, HEADER_ACL, []string{acl}, isObs) + } + input.prepareGrantHeaders(headers, isObs) + if storageClass := string(input.StorageClass); storageClass != "" { + if !isObs { + if storageClass == string(StorageClassWarm) { + storageClass = string(storageClassStandardIA) + } else if storageClass == string(StorageClassCold) { + storageClass = string(storageClassGlacier) + } else if storageClass == string(StorageClassIntelligentTiering) { + doLog(LEVEL_WARN, "Intelligent tiering supports only OBS signature.") + } + } + setHeaders(headers, HEADER_STORAGE_CLASS2, []string{storageClass}, isObs) + } + if input.WebsiteRedirectLocation != "" { + setHeaders(headers, HEADER_WEBSITE_REDIRECT_LOCATION, []string{input.WebsiteRedirectLocation}, isObs) + + } + setSseHeader(headers, input.SseHeader, false, isObs) + if input.Expires != 0 { + setHeaders(headers, HEADER_EXPIRES, []string{Int64ToString(input.Expires)}, true) + } + if input.Metadata != nil { + for key, value := range input.Metadata { + key = strings.TrimSpace(key) + setHeadersNext(headers, HEADER_PREFIX_META_OBS+key, HEADER_PREFIX_META+key, []string{value}, isObs) + } + } + return +} + +func (input PutObjectBasicInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.ObjectOperationInput.trans(isObs) + if err != nil { + return + } + + if input.ContentMD5 != "" { + headers[HEADER_MD5_CAMEL] = []string{input.ContentMD5} + } + + if input.ContentSHA256 != "" { + setHeaders(headers, HEADER_SHA256, []string{input.ContentSHA256}, isObs) + } + + if input.ContentLength > 0 { + headers[HEADER_CONTENT_LENGTH_CAMEL] = []string{Int64ToString(input.ContentLength)} + } + if input.ContentType != "" { + headers[HEADER_CONTENT_TYPE_CAML] = []string{input.ContentType} + } + if input.ContentEncoding != "" { + headers[HEADER_CONTENT_ENCODING_CAMEL] = []string{input.ContentEncoding} + } + if input.CacheControl != "" { + headers[HEADER_CACHE_CONTROL_CAMEL] = []string{input.CacheControl} + } + if input.ContentDisposition != "" { + headers[HEADER_CONTENT_DISPOSITION_CAMEL] = []string{input.ContentDisposition} + } + if input.ContentLanguage != "" { + headers[HEADER_CONTENT_LANGUAGE_CAMEL] = []string{input.ContentLanguage} + } + if input.HttpExpires != "" { + headers[HEADER_EXPIRES_CAMEL] = []string{input.HttpExpires} + } + return +} + +func (input PutObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.PutObjectBasicInput.trans(isObs) + if err != nil { + return + } + if input.Body != nil { + data = input.Body + } + return +} + +func (input AppendObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.PutObjectBasicInput.trans(isObs) + if err != nil { + return + } + params[string(SubResourceAppend)] = "" + params["position"] = strconv.FormatInt(input.Position, 10) + if input.Body != nil { + data = input.Body + } + return +} + +func (input ModifyObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + headers = make(map[string][]string) + params = make(map[string]string) + params[string(SubResourceModify)] = "" + params["position"] = strconv.FormatInt(input.Position, 10) + if input.ContentLength > 0 { + headers[HEADER_CONTENT_LENGTH_CAMEL] = []string{Int64ToString(input.ContentLength)} + } + + if input.Body != nil { + data = input.Body + } + return +} + +func (input CopyObjectInput) prepareReplaceHeaders(headers map[string][]string) { + if input.ContentType != "" { + headers[HEADER_CONTENT_TYPE] = []string{input.ContentType} + } + if input.CacheControl != "" { + headers[HEADER_CACHE_CONTROL] = []string{input.CacheControl} + } + if input.ContentDisposition != "" { + headers[HEADER_CONTENT_DISPOSITION] = []string{input.ContentDisposition} + } + if input.ContentEncoding != "" { + headers[HEADER_CONTENT_ENCODING] = []string{input.ContentEncoding} + } + if input.ContentLanguage != "" { + headers[HEADER_CONTENT_LANGUAGE] = []string{input.ContentLanguage} + } + // 这里为了兼容老版本,默认以Expire值为准,但如果Expires没有,则以HttpExpires为准。 + if input.Expires != "" { + headers[HEADER_EXPIRES_CAMEL] = []string{input.Expires} + } else if input.HttpExpires != "" { + headers[HEADER_EXPIRES_CAMEL] = []string{input.HttpExpires} + } +} + +func (input CopyObjectInput) prepareCopySourceHeaders(headers map[string][]string, isObs bool) { + if input.CopySourceIfMatch != "" { + setHeaders(headers, HEADER_COPY_SOURCE_IF_MATCH, []string{input.CopySourceIfMatch}, isObs) + } + if input.CopySourceIfNoneMatch != "" { + setHeaders(headers, HEADER_COPY_SOURCE_IF_NONE_MATCH, []string{input.CopySourceIfNoneMatch}, isObs) + } + if !input.CopySourceIfModifiedSince.IsZero() { + setHeaders(headers, HEADER_COPY_SOURCE_IF_MODIFIED_SINCE, []string{FormatUtcToRfc1123(input.CopySourceIfModifiedSince)}, isObs) + } + if !input.CopySourceIfUnmodifiedSince.IsZero() { + setHeaders(headers, HEADER_COPY_SOURCE_IF_UNMODIFIED_SINCE, []string{FormatUtcToRfc1123(input.CopySourceIfUnmodifiedSince)}, isObs) + } +} + +func (input CopyObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.ObjectOperationInput.trans(isObs) + if err != nil { + return + } + + var copySource string + if input.CopySourceVersionId != "" { + copySource = fmt.Sprintf("%s/%s?versionId=%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false), input.CopySourceVersionId) + } else { + copySource = fmt.Sprintf("%s/%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false)) + } + setHeaders(headers, HEADER_COPY_SOURCE, []string{copySource}, isObs) + + if directive := string(input.MetadataDirective); directive != "" { + setHeaders(headers, HEADER_METADATA_DIRECTIVE, []string{directive}, isObs) + } + + if input.MetadataDirective == ReplaceMetadata { + input.prepareReplaceHeaders(headers) + } + + input.prepareCopySourceHeaders(headers, isObs) + if input.SourceSseHeader != nil { + if sseCHeader, ok := input.SourceSseHeader.(SseCHeader); ok { + setHeaders(headers, HEADER_SSEC_COPY_SOURCE_ENCRYPTION, []string{sseCHeader.GetEncryption()}, isObs) + setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY, []string{sseCHeader.GetKey()}, isObs) + setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY_MD5, []string{sseCHeader.GetKeyMD5()}, isObs) + } + } + if input.SuccessActionRedirect != "" { + headers[HEADER_SUCCESS_ACTION_REDIRECT] = []string{input.SuccessActionRedirect} + } + return +} + +func (input HeadObjectInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = make(map[string]string) + if input.VersionId != "" { + params[PARAM_VERSION_ID] = input.VersionId + } + return +} + +func (input RenameFileInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceRename): ""} + params["name"] = input.NewObjectKey + headers = make(map[string][]string) + if requestPayer := string(input.RequestPayer); requestPayer != "" { + headers[HEADER_REQUEST_PAYER] = []string{requestPayer} + } + return +} + +func (input RenameFolderInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceRename): ""} + params["name"] = input.NewObjectKey + headers = make(map[string][]string) + if requestPayer := string(input.RequestPayer); requestPayer != "" { + headers[HEADER_REQUEST_PAYER] = []string{requestPayer} + } + return +} + +func (input SetDirAccesslabelInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceAccesslabel): ""} + + accesslabelJson, err := TransToJSON(input.Accesslabel) + if err != nil { + return + } + json := make([]string, 0, 2) + json = append(json, fmt.Sprintf("{\"accesslabel\": %s}", accesslabelJson)) + data = strings.Join(json, "") + + return +} + +func (input GetDirAccesslabelInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceAccesslabel): ""} + return +} + +func (input DeleteDirAccesslabelInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceAccesslabel): ""} + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_other.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_other.go new file mode 100644 index 00000000000..c706e1e25e7 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_other.go @@ -0,0 +1,75 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "bytes" + "io" + "os" + "strings" +) + +type partSlice []Part + +func (parts partSlice) Len() int { + return len(parts) +} + +func (parts partSlice) Less(i, j int) bool { + return parts[i].PartNumber < parts[j].PartNumber +} + +func (parts partSlice) Swap(i, j int) { + parts[i], parts[j] = parts[j], parts[i] +} + +type readerWrapper struct { + reader io.Reader + mark int64 + totalCount int64 + readedCount int64 +} + +func (rw *readerWrapper) seek(offset int64, whence int) (int64, error) { + if r, ok := rw.reader.(*strings.Reader); ok { + return r.Seek(offset, whence) + } else if r, ok := rw.reader.(*bytes.Reader); ok { + return r.Seek(offset, whence) + } else if r, ok := rw.reader.(*os.File); ok { + return r.Seek(offset, whence) + } + return offset, nil +} + +func (rw *readerWrapper) Read(p []byte) (n int, err error) { + if rw.totalCount == 0 { + return 0, io.EOF + } + if rw.totalCount > 0 { + n, err = rw.reader.Read(p) + readedOnce := int64(n) + remainCount := rw.totalCount - rw.readedCount + if remainCount > readedOnce { + rw.readedCount += readedOnce + return n, err + } + rw.readedCount += remainCount + return int(remainCount), io.EOF + } + return rw.reader.Read(p) +} + +type fileReaderWrapper struct { + readerWrapper + filePath string +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_part.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_part.go new file mode 100644 index 00000000000..286dc8a90ea --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/trait_part.go @@ -0,0 +1,140 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "fmt" +) + +func (input ListMultipartUploadsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{string(SubResourceUploads): ""} + if input.Prefix != "" { + params["prefix"] = input.Prefix + } + if input.Delimiter != "" { + params["delimiter"] = input.Delimiter + } + if input.MaxUploads > 0 { + params["max-uploads"] = IntToString(input.MaxUploads) + } + if input.KeyMarker != "" { + params["key-marker"] = input.KeyMarker + } + if input.UploadIdMarker != "" { + params["upload-id-marker"] = input.UploadIdMarker + } + if input.EncodingType != "" { + params["encoding-type"] = input.EncodingType + } + return +} + +func (input AbortMultipartUploadInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{"uploadId": input.UploadId} + return +} + +func (input InitiateMultipartUploadInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params, headers, data, err = input.ObjectOperationInput.trans(isObs) + if err != nil { + return + } + if input.ContentType != "" { + headers[HEADER_CONTENT_TYPE_CAML] = []string{input.ContentType} + } + if input.ContentEncoding != "" { + headers[HEADER_CONTENT_ENCODING_CAMEL] = []string{input.ContentEncoding} + } + if input.CacheControl != "" { + headers[HEADER_CACHE_CONTROL_CAMEL] = []string{input.CacheControl} + } + if input.ContentDisposition != "" { + headers[HEADER_CONTENT_DISPOSITION_CAMEL] = []string{input.ContentDisposition} + } + if input.ContentLanguage != "" { + headers[HEADER_CONTENT_LANGUAGE_CAMEL] = []string{input.ContentLanguage} + } + if input.HttpExpires != "" { + headers[HEADER_EXPIRES_CAMEL] = []string{input.HttpExpires} + } + params[string(SubResourceUploads)] = "" + if input.EncodingType != "" { + params["encoding-type"] = input.EncodingType + } + return +} + +func (input UploadPartInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{"uploadId": input.UploadId, "partNumber": IntToString(input.PartNumber)} + headers = make(map[string][]string) + setSseHeader(headers, input.SseHeader, true, isObs) + if input.ContentMD5 != "" { + headers[HEADER_MD5_CAMEL] = []string{input.ContentMD5} + } + if input.ContentSHA256 != "" { + setHeaders(headers, HEADER_SHA256, []string{input.ContentSHA256}, isObs) + } + if input.Body != nil { + data = input.Body + } + return +} + +func (input CompleteMultipartUploadInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{"uploadId": input.UploadId} + if input.EncodingType != "" { + params["encoding-type"] = input.EncodingType + } + data, _ = ConvertCompleteMultipartUploadInputToXml(input, false) + return +} + +func (input ListPartsInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{"uploadId": input.UploadId} + if input.MaxParts > 0 { + params["max-parts"] = IntToString(input.MaxParts) + } + if input.PartNumberMarker > 0 { + params["part-number-marker"] = IntToString(input.PartNumberMarker) + } + if input.EncodingType != "" { + params["encoding-type"] = input.EncodingType + } + return +} + +func (input CopyPartInput) trans(isObs bool) (params map[string]string, headers map[string][]string, data interface{}, err error) { + params = map[string]string{"uploadId": input.UploadId, "partNumber": IntToString(input.PartNumber)} + headers = make(map[string][]string, 1) + var copySource string + if input.CopySourceVersionId != "" { + copySource = fmt.Sprintf("%s/%s?versionId=%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false), input.CopySourceVersionId) + } else { + copySource = fmt.Sprintf("%s/%s", input.CopySourceBucket, UrlEncode(input.CopySourceKey, false)) + } + setHeaders(headers, HEADER_COPY_SOURCE, []string{copySource}, isObs) + if input.CopySourceRangeStart >= 0 && input.CopySourceRangeEnd > input.CopySourceRangeStart { + setHeaders(headers, HEADER_COPY_SOURCE_RANGE, []string{fmt.Sprintf("bytes=%d-%d", input.CopySourceRangeStart, input.CopySourceRangeEnd)}, isObs) + } + + setSseHeader(headers, input.SseHeader, true, isObs) + if input.SourceSseHeader != nil { + if sseCHeader, ok := input.SourceSseHeader.(SseCHeader); ok { + setHeaders(headers, HEADER_SSEC_COPY_SOURCE_ENCRYPTION, []string{sseCHeader.GetEncryption()}, isObs) + setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY, []string{sseCHeader.GetKey()}, isObs) + setHeaders(headers, HEADER_SSEC_COPY_SOURCE_KEY_MD5, []string{sseCHeader.GetKeyMD5()}, isObs) + } + + } + return +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/transfer.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/transfer.go new file mode 100644 index 00000000000..550db810bee --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/transfer.go @@ -0,0 +1,925 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "bufio" + "encoding/xml" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sync" + "sync/atomic" + "syscall" +) + +var errAbort = errors.New("AbortError") + +// FileStatus defines the upload file properties +type FileStatus struct { + XMLName xml.Name `xml:"FileInfo"` + LastModified int64 `xml:"LastModified"` + Size int64 `xml:"Size"` +} + +// UploadPartInfo defines the upload part properties +type UploadPartInfo struct { + XMLName xml.Name `xml:"UploadPart"` + PartNumber int `xml:"PartNumber"` + Etag string `xml:"Etag"` + PartSize int64 `xml:"PartSize"` + Offset int64 `xml:"Offset"` + IsCompleted bool `xml:"IsCompleted"` +} + +// UploadCheckpoint defines the upload checkpoint file properties +type UploadCheckpoint struct { + XMLName xml.Name `xml:"UploadFileCheckpoint"` + Bucket string `xml:"Bucket"` + Key string `xml:"Key"` + UploadId string `xml:"UploadId,omitempty"` + UploadFile string `xml:"FileUrl"` + FileInfo FileStatus `xml:"FileInfo"` + UploadParts []UploadPartInfo `xml:"UploadParts>UploadPart"` +} + +func (ufc *UploadCheckpoint) isValid(bucket, key, uploadFile string, fileStat os.FileInfo) bool { + if ufc.Bucket != bucket || ufc.Key != key || ufc.UploadFile != uploadFile { + doLog(LEVEL_INFO, "Checkpoint file is invalid, the bucketName or objectKey or uploadFile was changed. clear the record.") + return false + } + + if ufc.FileInfo.Size != fileStat.Size() || ufc.FileInfo.LastModified != fileStat.ModTime().Unix() { + doLog(LEVEL_INFO, "Checkpoint file is invalid, the uploadFile was changed. clear the record.") + return false + } + + if ufc.UploadId == "" { + doLog(LEVEL_INFO, "UploadId is invalid. clear the record.") + return false + } + + return true +} + +type uploadPartTask struct { + UploadPartInput + obsClient *ObsClient + abort *int32 + extensions []extensionOptions + enableCheckpoint bool +} + +func (task *uploadPartTask) Run() interface{} { + if atomic.LoadInt32(task.abort) == 1 { + return errAbort + } + + input := &UploadPartInput{} + input.Bucket = task.Bucket + input.Key = task.Key + input.PartNumber = task.PartNumber + input.UploadId = task.UploadId + input.SseHeader = task.SseHeader + input.SourceFile = task.SourceFile + input.Offset = task.Offset + input.PartSize = task.PartSize + input.ContentMD5 = task.ContentMD5 + input.ContentSHA256 = task.ContentSHA256 + + extensions := task.extensions + + var output *UploadPartOutput + var err error + if len(extensions) != 0 { + output, err = task.obsClient.UploadPart(input, extensions...) + } else { + output, err = task.obsClient.UploadPart(input) + } + + if err == nil { + if output.ETag == "" { + doLog(LEVEL_WARN, "Get invalid etag value after uploading part [%d].", task.PartNumber) + if !task.enableCheckpoint { + atomic.CompareAndSwapInt32(task.abort, 0, 1) + doLog(LEVEL_WARN, "Task is aborted, part number is [%d]", task.PartNumber) + } + return fmt.Errorf("get invalid etag value after uploading part [%d]", task.PartNumber) + } + return output + } else if obsError, ok := err.(ObsError); ok && obsError.StatusCode >= 400 && obsError.StatusCode < 500 { + atomic.CompareAndSwapInt32(task.abort, 0, 1) + doLog(LEVEL_WARN, "Task is aborted, part number is [%d]", task.PartNumber) + } + return err +} + +func loadCheckpointFile(checkpointFile string, result interface{}) error { + ret, err := ioutil.ReadFile(checkpointFile) + if err != nil { + return err + } + if len(ret) == 0 { + return nil + } + return xml.Unmarshal(ret, result) +} + +func updateCheckpointFile(fc interface{}, checkpointFilePath string) error { + result, err := xml.Marshal(fc) + if err != nil { + return err + } + err = ioutil.WriteFile(checkpointFilePath, result, 0640) + return err +} + +func getCheckpointFile(ufc *UploadCheckpoint, uploadFileStat os.FileInfo, input *UploadFileInput, obsClient *ObsClient, extensions []extensionOptions) (needCheckpoint bool, err error) { + checkpointFilePath := input.CheckpointFile + checkpointFileStat, err := os.Stat(checkpointFilePath) + if err != nil { + doLog(LEVEL_DEBUG, fmt.Sprintf("Stat checkpoint file failed with error: [%v].", err)) + return true, nil + } + if checkpointFileStat.IsDir() { + doLog(LEVEL_ERROR, "Checkpoint file can not be a folder.") + return false, errors.New("checkpoint file can not be a folder") + } + err = loadCheckpointFile(checkpointFilePath, ufc) + if err != nil { + doLog(LEVEL_WARN, fmt.Sprintf("Load checkpoint file failed with error: [%v].", err)) + return true, nil + } else if !ufc.isValid(input.Bucket, input.Key, input.UploadFile, uploadFileStat) { + if ufc.Bucket != "" && ufc.Key != "" && ufc.UploadId != "" { + _err := abortTask(ufc.Bucket, ufc.Key, ufc.UploadId, obsClient, extensions) + if _err != nil { + doLog(LEVEL_WARN, "Failed to abort upload task [%s].", ufc.UploadId) + } + } + _err := os.Remove(checkpointFilePath) + if _err != nil { + doLog(LEVEL_WARN, fmt.Sprintf("Failed to remove checkpoint file with error: [%v].", _err)) + } + } else { + return false, nil + } + + return true, nil +} + +func prepareUpload(ufc *UploadCheckpoint, uploadFileStat os.FileInfo, input *UploadFileInput, obsClient *ObsClient, extensions []extensionOptions) error { + initiateInput := &InitiateMultipartUploadInput{} + initiateInput.ObjectOperationInput = input.ObjectOperationInput + initiateInput.HttpHeader = HttpHeader{ + CacheControl: input.CacheControl, + ContentEncoding: input.ContentEncoding, + ContentType: input.ContentType, + ContentDisposition: input.ContentDisposition, + ContentLanguage: input.ContentLanguage, + HttpExpires: input.HttpExpires, + } + initiateInput.EncodingType = input.EncodingType + var output *InitiateMultipartUploadOutput + var err error + if len(extensions) != 0 { + output, err = obsClient.InitiateMultipartUpload(initiateInput, extensions...) + } else { + output, err = obsClient.InitiateMultipartUpload(initiateInput) + } + if err != nil { + return err + } + + ufc.Bucket = input.Bucket + ufc.Key = input.Key + ufc.UploadFile = input.UploadFile + ufc.FileInfo = FileStatus{} + ufc.FileInfo.Size = uploadFileStat.Size() + ufc.FileInfo.LastModified = uploadFileStat.ModTime().Unix() + ufc.UploadId = output.UploadId + + err = sliceFile(input.PartSize, ufc) + return err +} + +func sliceFile(partSize int64, ufc *UploadCheckpoint) error { + fileSize := ufc.FileInfo.Size + cnt := fileSize / partSize + if cnt >= 10000 { + partSize = fileSize / 10000 + if fileSize%10000 != 0 { + partSize++ + } + cnt = fileSize / partSize + } + if fileSize%partSize != 0 { + cnt++ + } + + if partSize > MAX_PART_SIZE { + doLog(LEVEL_ERROR, "The source upload file is too large") + return fmt.Errorf("The source upload file is too large") + } + + if cnt == 0 { + uploadPart := UploadPartInfo{} + uploadPart.PartNumber = 1 + ufc.UploadParts = []UploadPartInfo{uploadPart} + } else { + uploadParts := make([]UploadPartInfo, 0, cnt) + var i int64 + for i = 0; i < cnt; i++ { + uploadPart := UploadPartInfo{} + uploadPart.PartNumber = int(i) + 1 + uploadPart.PartSize = partSize + uploadPart.Offset = i * partSize + uploadParts = append(uploadParts, uploadPart) + } + if value := fileSize % partSize; value != 0 { + uploadParts[cnt-1].PartSize = value + } + ufc.UploadParts = uploadParts + } + return nil +} + +func abortTask(bucket, key, uploadID string, obsClient *ObsClient, extensions []extensionOptions) error { + input := &AbortMultipartUploadInput{} + input.Bucket = bucket + input.Key = key + input.UploadId = uploadID + if len(extensions) != 0 { + _, err := obsClient.AbortMultipartUpload(input, extensions...) + return err + } + _, err := obsClient.AbortMultipartUpload(input) + return err +} + +func handleUploadFileResult(uploadPartError error, ufc *UploadCheckpoint, enableCheckpoint bool, obsClient *ObsClient, extensions []extensionOptions) error { + if uploadPartError != nil { + if enableCheckpoint { + return uploadPartError + } + _err := abortTask(ufc.Bucket, ufc.Key, ufc.UploadId, obsClient, extensions) + if _err != nil { + doLog(LEVEL_WARN, "Failed to abort task [%s].", ufc.UploadId) + } + return uploadPartError + } + return nil +} + +func completeParts(ufc *UploadCheckpoint, enableCheckpoint bool, checkpointFilePath string, obsClient *ObsClient, encodingType string, extensions []extensionOptions) (output *CompleteMultipartUploadOutput, err error) { + completeInput := &CompleteMultipartUploadInput{} + completeInput.Bucket = ufc.Bucket + completeInput.Key = ufc.Key + completeInput.UploadId = ufc.UploadId + completeInput.EncodingType = encodingType + parts := make([]Part, 0, len(ufc.UploadParts)) + for _, uploadPart := range ufc.UploadParts { + part := Part{} + part.PartNumber = uploadPart.PartNumber + part.ETag = uploadPart.Etag + parts = append(parts, part) + } + completeInput.Parts = parts + var completeOutput *CompleteMultipartUploadOutput + if len(extensions) != 0 { + completeOutput, err = obsClient.CompleteMultipartUpload(completeInput, extensions...) + } else { + completeOutput, err = obsClient.CompleteMultipartUpload(completeInput) + } + + if err == nil { + if enableCheckpoint { + _err := os.Remove(checkpointFilePath) + if _err != nil { + doLog(LEVEL_WARN, "Upload file successfully, but remove checkpoint file failed with error [%v].", _err) + } + } + return completeOutput, err + } + if !enableCheckpoint { + _err := abortTask(ufc.Bucket, ufc.Key, ufc.UploadId, obsClient, extensions) + if _err != nil { + doLog(LEVEL_WARN, "Failed to abort task [%s].", ufc.UploadId) + } + } + return completeOutput, err +} + +func (obsClient ObsClient) resumeUpload(input *UploadFileInput, extensions []extensionOptions) (output *CompleteMultipartUploadOutput, err error) { + uploadFileStat, err := os.Stat(input.UploadFile) + if err != nil { + doLog(LEVEL_ERROR, fmt.Sprintf("Failed to stat uploadFile with error: [%v].", err)) + return nil, err + } + if uploadFileStat.IsDir() { + doLog(LEVEL_ERROR, "UploadFile can not be a folder.") + return nil, errors.New("uploadFile can not be a folder") + } + + ufc := &UploadCheckpoint{} + + var needCheckpoint = true + var checkpointFilePath = input.CheckpointFile + var enableCheckpoint = input.EnableCheckpoint + if enableCheckpoint { + needCheckpoint, err = getCheckpointFile(ufc, uploadFileStat, input, &obsClient, extensions) + if err != nil { + return nil, err + } + } + if needCheckpoint { + err = prepareUpload(ufc, uploadFileStat, input, &obsClient, extensions) + if err != nil { + return nil, err + } + + if enableCheckpoint { + err = updateCheckpointFile(ufc, checkpointFilePath) + if err != nil { + doLog(LEVEL_ERROR, "Failed to update checkpoint file with error [%v].", err) + _err := abortTask(ufc.Bucket, ufc.Key, ufc.UploadId, &obsClient, extensions) + if _err != nil { + doLog(LEVEL_WARN, "Failed to abort task [%s].", ufc.UploadId) + } + return nil, err + } + } + } + + uploadPartError := obsClient.uploadPartConcurrent(ufc, checkpointFilePath, input, extensions) + err = handleUploadFileResult(uploadPartError, ufc, enableCheckpoint, &obsClient, extensions) + if err != nil { + return nil, err + } + + completeOutput, err := completeParts(ufc, enableCheckpoint, checkpointFilePath, &obsClient, input.EncodingType, extensions) + + return completeOutput, err +} + +func handleUploadTaskResult(result interface{}, ufc *UploadCheckpoint, partNum int, enableCheckpoint bool, checkpointFilePath string, lock *sync.Mutex, completedBytes *int64, listener ProgressListener) (err error) { + if uploadPartOutput, ok := result.(*UploadPartOutput); ok { + lock.Lock() + defer lock.Unlock() + ufc.UploadParts[partNum-1].Etag = uploadPartOutput.ETag + ufc.UploadParts[partNum-1].IsCompleted = true + + atomic.AddInt64(completedBytes, ufc.UploadParts[partNum-1].PartSize) + + event := newProgressEvent(TransferDataEvent, *completedBytes, ufc.FileInfo.Size) + publishProgress(listener, event) + + if enableCheckpoint { + _err := updateCheckpointFile(ufc, checkpointFilePath) + if _err != nil { + doLog(LEVEL_WARN, "Failed to update checkpoint file with error [%v].", _err) + } + } + } else if result != errAbort { + if _err, ok := result.(error); ok { + err = _err + } + } + return +} + +func (obsClient ObsClient) uploadPartConcurrent(ufc *UploadCheckpoint, checkpointFilePath string, input *UploadFileInput, extensions []extensionOptions) error { + pool := NewRoutinePool(input.TaskNum, MAX_PART_NUM) + var uploadPartError atomic.Value + var errFlag int32 + var abort int32 + lock := new(sync.Mutex) + + var completedBytes int64 + listener := obsClient.getProgressListener(extensions) + totalBytes := ufc.FileInfo.Size + event := newProgressEvent(TransferStartedEvent, 0, totalBytes) + publishProgress(listener, event) + + for _, uploadPart := range ufc.UploadParts { + if atomic.LoadInt32(&abort) == 1 { + break + } + if uploadPart.IsCompleted { + atomic.AddInt64(&completedBytes, uploadPart.PartSize) + event := newProgressEvent(TransferDataEvent, completedBytes, ufc.FileInfo.Size) + publishProgress(listener, event) + continue + } + task := uploadPartTask{ + UploadPartInput: UploadPartInput{ + Bucket: ufc.Bucket, + Key: ufc.Key, + PartNumber: uploadPart.PartNumber, + UploadId: ufc.UploadId, + SseHeader: input.SseHeader, + SourceFile: input.UploadFile, + Offset: uploadPart.Offset, + PartSize: uploadPart.PartSize, + }, + obsClient: &obsClient, + abort: &abort, + extensions: extensions, + enableCheckpoint: input.EnableCheckpoint, + } + pool.ExecuteFunc(func() interface{} { + result := task.Run() + err := handleUploadTaskResult(result, ufc, task.PartNumber, input.EnableCheckpoint, input.CheckpointFile, lock, &completedBytes, listener) + if err != nil && atomic.CompareAndSwapInt32(&errFlag, 0, 1) { + uploadPartError.Store(err) + } + return nil + }) + } + pool.ShutDown() + if err, ok := uploadPartError.Load().(error); ok { + + event := newProgressEvent(TransferFailedEvent, completedBytes, ufc.FileInfo.Size) + publishProgress(listener, event) + + return err + } + event = newProgressEvent(TransferCompletedEvent, completedBytes, ufc.FileInfo.Size) + publishProgress(listener, event) + return nil +} + +// ObjectInfo defines download object info +type ObjectInfo struct { + XMLName xml.Name `xml:"ObjectInfo"` + LastModified int64 `xml:"LastModified"` + Size int64 `xml:"Size"` + ETag string `xml:"ETag"` +} + +// TempFileInfo defines temp download file properties +type TempFileInfo struct { + XMLName xml.Name `xml:"TempFileInfo"` + TempFileUrl string `xml:"TempFileUrl"` + Size int64 `xml:"Size"` +} + +// DownloadPartInfo defines download part properties +type DownloadPartInfo struct { + XMLName xml.Name `xml:"DownloadPart"` + PartNumber int64 `xml:"PartNumber"` + RangeEnd int64 `xml:"RangeEnd"` + Offset int64 `xml:"Offset"` + IsCompleted bool `xml:"IsCompleted"` +} + +// DownloadCheckpoint defines download checkpoint file properties +type DownloadCheckpoint struct { + XMLName xml.Name `xml:"DownloadFileCheckpoint"` + Bucket string `xml:"Bucket"` + Key string `xml:"Key"` + VersionId string `xml:"VersionId,omitempty"` + DownloadFile string `xml:"FileUrl"` + ObjectInfo ObjectInfo `xml:"ObjectInfo"` + TempFileInfo TempFileInfo `xml:"TempFileInfo"` + DownloadParts []DownloadPartInfo `xml:"DownloadParts>DownloadPart"` +} + +func (dfc *DownloadCheckpoint) isValid(input *DownloadFileInput, output *GetObjectMetadataOutput) bool { + if dfc.Bucket != input.Bucket || dfc.Key != input.Key || dfc.VersionId != input.VersionId || dfc.DownloadFile != input.DownloadFile { + doLog(LEVEL_INFO, "Checkpoint file is invalid, the bucketName or objectKey or downloadFile was changed. clear the record.") + return false + } + if dfc.ObjectInfo.LastModified != output.LastModified.Unix() || dfc.ObjectInfo.ETag != output.ETag || dfc.ObjectInfo.Size != output.ContentLength { + doLog(LEVEL_INFO, "Checkpoint file is invalid, the object info was changed. clear the record.") + return false + } + if dfc.TempFileInfo.Size != output.ContentLength { + doLog(LEVEL_INFO, "Checkpoint file is invalid, size was changed. clear the record.") + return false + } + stat, err := os.Stat(dfc.TempFileInfo.TempFileUrl) + if err != nil || stat.Size() != dfc.ObjectInfo.Size { + doLog(LEVEL_INFO, "Checkpoint file is invalid, the temp download file was changed. clear the record.") + return false + } + + return true +} + +type downloadPartTask struct { + GetObjectInput + obsClient *ObsClient + extensions []extensionOptions + abort *int32 + partNumber int64 + tempFileURL string + enableCheckpoint bool +} + +func (task *downloadPartTask) Run() interface{} { + if atomic.LoadInt32(task.abort) == 1 { + return errAbort + } + getObjectInput := &GetObjectInput{} + getObjectInput.GetObjectMetadataInput = task.GetObjectMetadataInput + getObjectInput.IfMatch = task.IfMatch + getObjectInput.IfNoneMatch = task.IfNoneMatch + getObjectInput.IfModifiedSince = task.IfModifiedSince + getObjectInput.IfUnmodifiedSince = task.IfUnmodifiedSince + getObjectInput.RangeStart = task.RangeStart + getObjectInput.RangeEnd = task.RangeEnd + + var output *GetObjectOutput + var err error + if len(task.extensions) != 0 { + output, err = task.obsClient.GetObjectWithoutProgress(getObjectInput, task.extensions...) + } else { + output, err = task.obsClient.GetObjectWithoutProgress(getObjectInput) + } + + if err == nil { + defer func() { + errMsg := output.Body.Close() + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close response body.") + } + }() + _err := updateDownloadFile(task.tempFileURL, task.RangeStart, output) + if _err != nil { + if !task.enableCheckpoint { + atomic.CompareAndSwapInt32(task.abort, 0, 1) + doLog(LEVEL_WARN, "Task is aborted, part number is [%d]", task.partNumber) + } + return _err + } + return output + } else if obsError, ok := err.(ObsError); ok && obsError.StatusCode >= 400 && obsError.StatusCode < 500 { + atomic.CompareAndSwapInt32(task.abort, 0, 1) + doLog(LEVEL_WARN, "Task is aborted, part number is [%d]", task.partNumber) + } + return err +} + +func getObjectInfo(input *DownloadFileInput, obsClient *ObsClient, extensions []extensionOptions) (getObjectmetaOutput *GetObjectMetadataOutput, err error) { + if len(extensions) != 0 { + getObjectmetaOutput, err = obsClient.GetObjectMetadata(&input.GetObjectMetadataInput, extensions...) + } else { + getObjectmetaOutput, err = obsClient.GetObjectMetadata(&input.GetObjectMetadataInput) + } + + return +} + +func getDownloadCheckpointFile(dfc *DownloadCheckpoint, input *DownloadFileInput, output *GetObjectMetadataOutput) (needCheckpoint bool, err error) { + checkpointFilePath := input.CheckpointFile + checkpointFileStat, err := os.Stat(checkpointFilePath) + if err != nil { + doLog(LEVEL_DEBUG, fmt.Sprintf("Stat checkpoint file failed with error: [%v].", err)) + return true, nil + } + if checkpointFileStat.IsDir() { + doLog(LEVEL_ERROR, "Checkpoint file can not be a folder.") + return false, errors.New("checkpoint file can not be a folder") + } + err = loadCheckpointFile(checkpointFilePath, dfc) + if err != nil { + doLog(LEVEL_WARN, fmt.Sprintf("Load checkpoint file failed with error: [%v].", err)) + return true, nil + } else if !dfc.isValid(input, output) { + if dfc.TempFileInfo.TempFileUrl != "" { + _err := os.Remove(dfc.TempFileInfo.TempFileUrl) + if _err != nil { + doLog(LEVEL_WARN, "Failed to remove temp download file with error [%v].", _err) + } + } + _err := os.Remove(checkpointFilePath) + if _err != nil { + doLog(LEVEL_WARN, "Failed to remove checkpoint file with error [%v].", _err) + } + } else { + return false, nil + } + + return true, nil +} + +func sliceObject(objectSize, partSize int64, dfc *DownloadCheckpoint) { + cnt := objectSize / partSize + if objectSize%partSize > 0 { + cnt++ + } + + if cnt == 0 { + downloadPart := DownloadPartInfo{} + downloadPart.PartNumber = 1 + dfc.DownloadParts = []DownloadPartInfo{downloadPart} + } else { + downloadParts := make([]DownloadPartInfo, 0, cnt) + var i int64 + for i = 0; i < cnt; i++ { + downloadPart := DownloadPartInfo{} + downloadPart.PartNumber = i + 1 + downloadPart.Offset = i * partSize + downloadPart.RangeEnd = (i+1)*partSize - 1 + downloadParts = append(downloadParts, downloadPart) + } + dfc.DownloadParts = downloadParts + if value := objectSize % partSize; value > 0 { + dfc.DownloadParts[cnt-1].RangeEnd = dfc.ObjectInfo.Size - 1 + } + } +} + +func createFile(tempFileURL string, fileSize int64) error { + fd, err := syscall.Open(tempFileURL, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) + if err != nil { + doLog(LEVEL_WARN, "Failed to open temp download file [%s].", tempFileURL) + return err + } + defer func() { + errMsg := syscall.Close(fd) + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close file with error [%v].", errMsg) + } + }() + err = syscall.Ftruncate(fd, fileSize) + if err != nil { + doLog(LEVEL_WARN, "Failed to create file with error [%v].", err) + } + return err +} + +func prepareTempFile(tempFileURL string, fileSize int64) error { + parentDir := filepath.Dir(tempFileURL) + stat, err := os.Stat(parentDir) + if err != nil { + doLog(LEVEL_DEBUG, "Failed to stat path with error [%v].", err) + _err := os.MkdirAll(parentDir, os.ModePerm) + if _err != nil { + doLog(LEVEL_ERROR, "Failed to make dir with error [%v].", _err) + return _err + } + } else if !stat.IsDir() { + doLog(LEVEL_ERROR, "Cannot create folder [%s] due to a same file exists.", parentDir) + return fmt.Errorf("cannot create folder [%s] due to a same file exists", parentDir) + } + + err = createFile(tempFileURL, fileSize) + if err == nil { + return nil + } + fd, err := os.OpenFile(tempFileURL, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) + if err != nil { + doLog(LEVEL_ERROR, "Failed to open temp download file [%s].", tempFileURL) + return err + } + defer func() { + errMsg := fd.Close() + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close file with error [%v].", errMsg) + } + }() + if fileSize > 0 { + _, err = fd.WriteAt([]byte("a"), fileSize-1) + if err != nil { + doLog(LEVEL_ERROR, "Failed to create temp download file with error [%v].", err) + return err + } + } + + return nil +} + +func handleDownloadFileResult(tempFileURL string, enableCheckpoint bool, downloadFileError error) error { + if downloadFileError != nil { + if !enableCheckpoint { + _err := os.Remove(tempFileURL) + if _err != nil { + doLog(LEVEL_WARN, "Failed to remove temp download file with error [%v].", _err) + } + } + return downloadFileError + } + return nil +} + +func (obsClient ObsClient) resumeDownload(input *DownloadFileInput, extensions []extensionOptions) (output *GetObjectMetadataOutput, err error) { + getObjectmetaOutput, err := getObjectInfo(input, &obsClient, extensions) + if err != nil { + return nil, err + } + + objectSize := getObjectmetaOutput.ContentLength + partSize := input.PartSize + dfc := &DownloadCheckpoint{} + + var needCheckpoint = true + var checkpointFilePath = input.CheckpointFile + var enableCheckpoint = input.EnableCheckpoint + if enableCheckpoint { + needCheckpoint, err = getDownloadCheckpointFile(dfc, input, getObjectmetaOutput) + if err != nil { + return nil, err + } + } + + if needCheckpoint { + dfc.Bucket = input.Bucket + dfc.Key = input.Key + dfc.VersionId = input.VersionId + dfc.DownloadFile = input.DownloadFile + dfc.ObjectInfo = ObjectInfo{} + dfc.ObjectInfo.LastModified = getObjectmetaOutput.LastModified.Unix() + dfc.ObjectInfo.Size = getObjectmetaOutput.ContentLength + dfc.ObjectInfo.ETag = getObjectmetaOutput.ETag + dfc.TempFileInfo = TempFileInfo{} + dfc.TempFileInfo.TempFileUrl = input.DownloadFile + ".tmp" + dfc.TempFileInfo.Size = getObjectmetaOutput.ContentLength + + sliceObject(objectSize, partSize, dfc) + _err := prepareTempFile(dfc.TempFileInfo.TempFileUrl, dfc.TempFileInfo.Size) + if _err != nil { + return nil, _err + } + + if enableCheckpoint { + _err := updateCheckpointFile(dfc, checkpointFilePath) + if _err != nil { + doLog(LEVEL_ERROR, "Failed to update checkpoint file with error [%v].", _err) + _errMsg := os.Remove(dfc.TempFileInfo.TempFileUrl) + if _errMsg != nil { + doLog(LEVEL_WARN, "Failed to remove temp download file with error [%v].", _errMsg) + } + return nil, _err + } + } + } + + downloadFileError := obsClient.downloadFileConcurrent(input, dfc, extensions) + err = handleDownloadFileResult(dfc.TempFileInfo.TempFileUrl, enableCheckpoint, downloadFileError) + if err != nil { + return nil, err + } + + err = os.Rename(dfc.TempFileInfo.TempFileUrl, input.DownloadFile) + if err != nil { + doLog(LEVEL_ERROR, "Failed to rename temp download file [%s] to download file [%s] with error [%v].", dfc.TempFileInfo.TempFileUrl, input.DownloadFile, err) + return nil, err + } + if enableCheckpoint { + err = os.Remove(checkpointFilePath) + if err != nil { + doLog(LEVEL_WARN, "Download file successfully, but remove checkpoint file failed with error [%v].", err) + } + } + + return getObjectmetaOutput, nil +} + +func updateDownloadFile(filePath string, rangeStart int64, output *GetObjectOutput) error { + fd, err := os.OpenFile(filePath, os.O_WRONLY, 0640) + if err != nil { + doLog(LEVEL_ERROR, "Failed to open file [%s].", filePath) + return err + } + defer func() { + errMsg := fd.Close() + if errMsg != nil { + doLog(LEVEL_WARN, "Failed to close file with error [%v].", errMsg) + } + }() + _, err = fd.Seek(rangeStart, 0) + if err != nil { + doLog(LEVEL_ERROR, "Failed to seek file with error [%v].", err) + return err + } + fileWriter := bufio.NewWriterSize(fd, 65536) + part := make([]byte, 8192) + var readErr error + var readCount int + for { + readCount, readErr = output.Body.Read(part) + if readCount > 0 { + wcnt, werr := fileWriter.Write(part[0:readCount]) + if werr != nil { + doLog(LEVEL_ERROR, "Failed to write to file with error [%v].", werr) + return werr + } + if wcnt != readCount { + doLog(LEVEL_ERROR, "Failed to write to file [%s], expect: [%d], actual: [%d]", filePath, readCount, wcnt) + return fmt.Errorf("Failed to write to file [%s], expect: [%d], actual: [%d]", filePath, readCount, wcnt) + } + } + if readErr != nil { + if readErr != io.EOF { + doLog(LEVEL_ERROR, "Failed to read response body with error [%v].", readErr) + return readErr + } + break + } + } + err = fileWriter.Flush() + if err != nil { + doLog(LEVEL_ERROR, "Failed to flush file with error [%v].", err) + return err + } + return nil +} + +func handleDownloadTaskResult(result interface{}, dfc *DownloadCheckpoint, partNum int64, enableCheckpoint bool, checkpointFile string, lock *sync.Mutex, completedBytes *int64, listener ProgressListener) (err error) { + if output, ok := result.(*GetObjectOutput); ok { + lock.Lock() + defer lock.Unlock() + dfc.DownloadParts[partNum-1].IsCompleted = true + + atomic.AddInt64(completedBytes, output.ContentLength) + + event := newProgressEvent(TransferDataEvent, *completedBytes, dfc.ObjectInfo.Size) + publishProgress(listener, event) + + if enableCheckpoint { + _err := updateCheckpointFile(dfc, checkpointFile) + if _err != nil { + doLog(LEVEL_WARN, "Failed to update checkpoint file with error [%v].", _err) + } + } + } else if result != errAbort { + if _err, ok := result.(error); ok { + err = _err + } + } + return +} + +func (obsClient ObsClient) downloadFileConcurrent(input *DownloadFileInput, dfc *DownloadCheckpoint, extensions []extensionOptions) error { + pool := NewRoutinePool(input.TaskNum, MAX_PART_NUM) + var downloadPartError atomic.Value + var errFlag int32 + var abort int32 + lock := new(sync.Mutex) + + var completedBytes int64 + listener := obsClient.getProgressListener(extensions) + totalBytes := dfc.ObjectInfo.Size + event := newProgressEvent(TransferStartedEvent, 0, totalBytes) + publishProgress(listener, event) + + for _, downloadPart := range dfc.DownloadParts { + if atomic.LoadInt32(&abort) == 1 { + break + } + if downloadPart.IsCompleted { + atomic.AddInt64(&completedBytes, downloadPart.RangeEnd-downloadPart.Offset+1) + event := newProgressEvent(TransferDataEvent, completedBytes, dfc.ObjectInfo.Size) + publishProgress(listener, event) + continue + } + task := downloadPartTask{ + GetObjectInput: GetObjectInput{ + GetObjectMetadataInput: input.GetObjectMetadataInput, + IfMatch: input.IfMatch, + IfNoneMatch: input.IfNoneMatch, + IfUnmodifiedSince: input.IfUnmodifiedSince, + IfModifiedSince: input.IfModifiedSince, + RangeStart: downloadPart.Offset, + RangeEnd: downloadPart.RangeEnd, + }, + obsClient: &obsClient, + extensions: extensions, + abort: &abort, + partNumber: downloadPart.PartNumber, + tempFileURL: dfc.TempFileInfo.TempFileUrl, + enableCheckpoint: input.EnableCheckpoint, + } + pool.ExecuteFunc(func() interface{} { + result := task.Run() + err := handleDownloadTaskResult(result, dfc, task.partNumber, input.EnableCheckpoint, input.CheckpointFile, lock, &completedBytes, listener) + if err != nil && atomic.CompareAndSwapInt32(&errFlag, 0, 1) { + downloadPartError.Store(err) + } + return nil + }) + } + pool.ShutDown() + if err, ok := downloadPartError.Load().(error); ok { + event := newProgressEvent(TransferFailedEvent, completedBytes, dfc.ObjectInfo.Size) + publishProgress(listener, event) + return err + } + event = newProgressEvent(TransferCompletedEvent, completedBytes, dfc.ObjectInfo.Size) + publishProgress(listener, event) + return nil +} diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/type.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/type.go new file mode 100644 index 00000000000..162f4f08c2c --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/type.go @@ -0,0 +1,372 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +// SignatureType defines type of signature +type SignatureType string + +const ( + // SignatureV2 signature type v2 + SignatureV2 SignatureType = "v2" + // SignatureV4 signature type v4 + SignatureV4 SignatureType = "v4" + // SignatureObs signature type OBS + SignatureObs SignatureType = "OBS" +) + +// HttpMethodType defines http method type +type HttpMethodType string + +const ( + HttpMethodGet HttpMethodType = HTTP_GET + HttpMethodPut HttpMethodType = HTTP_PUT + HttpMethodPost HttpMethodType = HTTP_POST + HttpMethodDelete HttpMethodType = HTTP_DELETE + HttpMethodHead HttpMethodType = HTTP_HEAD + HttpMethodOptions HttpMethodType = HTTP_OPTIONS +) + +// SubResourceType defines the subResource value +type SubResourceType string + +const ( + // SubResourceStoragePolicy subResource value: storagePolicy + SubResourceStoragePolicy SubResourceType = "storagePolicy" + + // SubResourceStorageClass subResource value: storageClass + SubResourceStorageClass SubResourceType = "storageClass" + + // SubResourceQuota subResource value: quota + SubResourceQuota SubResourceType = "quota" + + // SubResourceStorageInfo subResource value: storageinfo + SubResourceStorageInfo SubResourceType = "storageinfo" + + // SubResourceLocation subResource value: location + SubResourceLocation SubResourceType = "location" + + // SubResourceAcl subResource value: acl + SubResourceAcl SubResourceType = "acl" + + // SubResourcePolicy subResource value: policy + SubResourcePolicy SubResourceType = "policy" + + // SubResourceCors subResource value: cors + SubResourceCors SubResourceType = "cors" + + // SubResourceVersioning subResource value: versioning + SubResourceVersioning SubResourceType = "versioning" + + // SubResourceWebsite subResource value: website + SubResourceWebsite SubResourceType = "website" + + // SubResourceLogging subResource value: logging + SubResourceLogging SubResourceType = "logging" + + // SubResourceLifecycle subResource value: lifecycle + SubResourceLifecycle SubResourceType = "lifecycle" + + // SubResourceNotification subResource value: notification + SubResourceNotification SubResourceType = "notification" + + // SubResourceEncryption subResource value: encryption + SubResourceEncryption SubResourceType = "encryption" + + // SubResourceTagging subResource value: tagging + SubResourceTagging SubResourceType = "tagging" + + // SubResourceDelete subResource value: delete + SubResourceDelete SubResourceType = "delete" + + // SubResourceVersions subResource value: versions + SubResourceVersions SubResourceType = "versions" + + // SubResourceUploads subResource value: uploads + SubResourceUploads SubResourceType = "uploads" + + // SubResourceRestore subResource value: restore + SubResourceRestore SubResourceType = "restore" + + // SubResourceMetadata subResource value: metadata + SubResourceMetadata SubResourceType = "metadata" + + // SubResourceRequestPayment subResource value: requestPayment + SubResourceRequestPayment SubResourceType = "requestPayment" + + // SubResourceAppend subResource value: append + SubResourceAppend SubResourceType = "append" + + // SubResourceModify subResource value: modify + SubResourceModify SubResourceType = "modify" + + // SubResourceRename subResource value: rename + SubResourceRename SubResourceType = "rename" + + // SubResourceCustomDomain subResource value: customdomain + SubResourceCustomDomain SubResourceType = "customdomain" + + // SubResourceMirrorBackToSource subResource value: mirrorBackToSource + SubResourceMirrorBackToSource SubResourceType = "mirrorBackToSource" + + // SubResourceMirrorBackToSource subResource value: mirrorBackToSource + SubResourceAccesslabel SubResourceType = "x-obs-accesslabel" + + // SubResourceMirrorBackToSource subResource value: publicAccessBlock + SubResourcePublicAccessBlock SubResourceType = "publicAccessBlock" + + // SubResourcePublicBucketStatus subResource value: bucketStatus + SubResourceBucketPublicStatus SubResourceType = "bucketStatus" + + // SubResourcePublicPolicyStatus subResource value: policyStatus + SubResourceBucketPolicyPublicStatus SubResourceType = "policyStatus" +) + +// objectKeyType defines the objectKey value +type objectKeyType string + +const ( + // objectKeyExtensionPolicy objectKey value: v1/extension_policy + objectKeyExtensionPolicy objectKeyType = "v1/extension_policy" + + // objectKeyAsyncFetchJob objectKey value: v1/async-fetch/jobs + objectKeyAsyncFetchJob objectKeyType = "v1/async-fetch/jobs" +) + +// AclType defines bucket/object acl type +type AclType string + +const ( + AclPrivate AclType = "private" + AclPublicRead AclType = "public-read" + AclPublicReadWrite AclType = "public-read-write" + AclAuthenticatedRead AclType = "authenticated-read" + AclBucketOwnerRead AclType = "bucket-owner-read" + AclBucketOwnerFullControl AclType = "bucket-owner-full-control" + AclLogDeliveryWrite AclType = "log-delivery-write" + AclPublicReadDelivery AclType = "public-read-delivered" + AclPublicReadWriteDelivery AclType = "public-read-write-delivered" +) + +// StorageClassType defines bucket storage class +type StorageClassType string + +const ( + //StorageClassStandard storage class: STANDARD + StorageClassStandard StorageClassType = "STANDARD" + + //StorageClassWarm storage class: WARM + StorageClassWarm StorageClassType = "WARM" + + //StorageClassCold storage class: COLD + StorageClassCold StorageClassType = "COLD" + + //StorageClassDeepArchive storage class: DEEP_ARCHIVE + StorageClassDeepArchive StorageClassType = "DEEP_ARCHIVE" + + //StorageClassIntelligentTiering storage class: INTELLIGENT_TIERING + StorageClassIntelligentTiering StorageClassType = "INTELLIGENT_TIERING" + + storageClassStandardIA StorageClassType = "STANDARD_IA" + storageClassGlacier StorageClassType = "GLACIER" +) + +// PermissionType defines permission type +type PermissionType string + +const ( + // PermissionRead permission type: READ + PermissionRead PermissionType = "READ" + + // PermissionWrite permission type: WRITE + PermissionWrite PermissionType = "WRITE" + + // PermissionReadAcp permission type: READ_ACP + PermissionReadAcp PermissionType = "READ_ACP" + + // PermissionWriteAcp permission type: WRITE_ACP + PermissionWriteAcp PermissionType = "WRITE_ACP" + + // PermissionFullControl permission type: FULL_CONTROL + PermissionFullControl PermissionType = "FULL_CONTROL" +) + +// GranteeType defines grantee type +type GranteeType string + +const ( + // GranteeGroup grantee type: Group + GranteeGroup GranteeType = "Group" + + // GranteeUser grantee type: CanonicalUser + GranteeUser GranteeType = "CanonicalUser" +) + +// GroupUriType defines grantee uri type +type GroupUriType string + +const ( + // GroupAllUsers grantee uri type: AllUsers + GroupAllUsers GroupUriType = "AllUsers" + + // GroupAuthenticatedUsers grantee uri type: AuthenticatedUsers + GroupAuthenticatedUsers GroupUriType = "AuthenticatedUsers" + + // GroupLogDelivery grantee uri type: LogDelivery + GroupLogDelivery GroupUriType = "LogDelivery" +) + +// VersioningStatusType defines bucket version status +type VersioningStatusType string + +const ( + // VersioningStatusEnabled version status: Enabled + VersioningStatusEnabled VersioningStatusType = "Enabled" + + // VersioningStatusSuspended version status: Suspended + VersioningStatusSuspended VersioningStatusType = "Suspended" +) + +// ProtocolType defines protocol type +type ProtocolType string + +const ( + // ProtocolHttp prorocol type: http + ProtocolHttp ProtocolType = "http" + + // ProtocolHttps prorocol type: https + ProtocolHttps ProtocolType = "https" +) + +// RuleStatusType defines lifeCycle rule status +type RuleStatusType string + +const ( + // RuleStatusEnabled rule status: Enabled + RuleStatusEnabled RuleStatusType = "Enabled" + + // RuleStatusDisabled rule status: Disabled + RuleStatusDisabled RuleStatusType = "Disabled" +) + +// RestoreTierType defines restore options +type RestoreTierType string + +const ( + // RestoreTierExpedited restore options: Expedited + RestoreTierExpedited RestoreTierType = "Expedited" + + // RestoreTierStandard restore options: Standard + RestoreTierStandard RestoreTierType = "Standard" + + // RestoreTierBulk restore options: Bulk + RestoreTierBulk RestoreTierType = "Bulk" +) + +// MetadataDirectiveType defines metadata operation indicator +type MetadataDirectiveType string + +const ( + // CopyMetadata metadata operation: COPY + CopyMetadata MetadataDirectiveType = "COPY" + + // ReplaceNew metadata operation: REPLACE_NEW + ReplaceNew MetadataDirectiveType = "REPLACE_NEW" + + // ReplaceMetadata metadata operation: REPLACE + ReplaceMetadata MetadataDirectiveType = "REPLACE" +) + +// EventType defines bucket notification type of events +type EventType string + +const ( + // ObjectCreatedAll type of events: ObjectCreated:* + ObjectCreatedAll EventType = "ObjectCreated:*" + + // ObjectCreatedPut type of events: ObjectCreated:Put + ObjectCreatedPut EventType = "ObjectCreated:Put" + + // ObjectCreatedPost type of events: ObjectCreated:Post + ObjectCreatedPost EventType = "ObjectCreated:Post" + + // ObjectCreatedCopy type of events: ObjectCreated:Copy + ObjectCreatedCopy EventType = "ObjectCreated:Copy" + + // ObjectCreatedCompleteMultipartUpload type of events: ObjectCreated:CompleteMultipartUpload + ObjectCreatedCompleteMultipartUpload EventType = "ObjectCreated:CompleteMultipartUpload" + + // ObjectRemovedAll type of events: ObjectRemoved:* + ObjectRemovedAll EventType = "ObjectRemoved:*" + + // ObjectRemovedDelete type of events: ObjectRemoved:Delete + ObjectRemovedDelete EventType = "ObjectRemoved:Delete" + + // ObjectRemovedDeleteMarkerCreated type of events: ObjectRemoved:DeleteMarkerCreated + ObjectRemovedDeleteMarkerCreated EventType = "ObjectRemoved:DeleteMarkerCreated" +) + +// PayerType defines type of payer +type PayerType string + +const ( + // BucketOwnerPayer type of payer: BucketOwner + BucketOwnerPayer PayerType = "BucketOwner" + + // RequesterPayer type of payer: Requester + RequesterPayer PayerType = "Requester" + + // Requester header for requester-Pays + Requester PayerType = "requester" +) + +// FetchPolicyStatusType defines type of fetch policy status +type FetchPolicyStatusType string + +const ( + // FetchStatusOpen type of status: open + FetchStatusOpen FetchPolicyStatusType = "open" + + // FetchStatusClosed type of status: closed + FetchStatusClosed FetchPolicyStatusType = "closed" +) + +// AvailableZoneType defines type of az redundancy +type AvailableZoneType string + +const ( + AvailableZoneMultiAz AvailableZoneType = "3az" +) + +// FSStatusType defines type of file system status +type FSStatusType string + +const ( + FSStatusEnabled FSStatusType = "Enabled" + FSStatusDisabled FSStatusType = "Disabled" +) + +// BucketType defines type of bucket +type BucketType string + +const ( + OBJECT BucketType = "OBJECT" + POSIX BucketType = "POSIX" +) + +// RedundancyType defines type of redundancyType +type BucketRedundancyType string + +const ( + BucketRedundancyClassic BucketRedundancyType = "CLASSIC" + BucketRedundancyFusion BucketRedundancyType = "FUSION" +) diff --git a/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/util.go b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/util.go new file mode 100644 index 00000000000..3119a2b7bf7 --- /dev/null +++ b/vendor/github.com/huaweicloud/huaweicloud-sdk-go-obs/obs/util.go @@ -0,0 +1,661 @@ +// Copyright 2019 Huawei Technologies Co.,Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +package obs + +import ( + "bytes" + "crypto/hmac" + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "net/http" + "net/url" + "os" + "regexp" + "strconv" + "strings" + "time" +) + +var regex = regexp.MustCompile("^[\u4e00-\u9fa5]$") +var ipRegex = regexp.MustCompile("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$") +var v4AuthRegex = regexp.MustCompile("Credential=(.+?),SignedHeaders=(.+?),Signature=.+") +var regionRegex = regexp.MustCompile(".+/\\d+/(.+?)/.+") + +// StringContains replaces subStr in src with subTranscoding and returns the new string +func StringContains(src string, subStr string, subTranscoding string) string { + return strings.Replace(src, subStr, subTranscoding, -1) +} + +// XmlTranscoding replaces special characters with their escaped form +func XmlTranscoding(src string) string { + srcTmp := StringContains(src, "&", "&") + srcTmp = StringContains(srcTmp, "<", "<") + srcTmp = StringContains(srcTmp, ">", ">") + srcTmp = StringContains(srcTmp, "'", "'") + srcTmp = StringContains(srcTmp, "\"", """) + return srcTmp +} + +func HandleHttpResponse(action string, headers map[string][]string, output IBaseModel, resp *http.Response, xmlResult bool, isObs bool) (err error) { + if IsHandleCallbackResponse(action, headers, isObs) { + if err = ParseCallbackResponseToBaseModel(resp, output, isObs); err != nil { + doLog(LEVEL_WARN, "Parse callback response to BaseModel with error: %v", err) + } + } else { + if err = ParseResponseToBaseModel(resp, output, xmlResult, isObs); err != nil { + doLog(LEVEL_WARN, "Parse response to BaseModel with error: %v", err) + } + } + return +} + +func IsHandleCallbackResponse(action string, headers map[string][]string, isObs bool) bool { + var headerPrefix = HEADER_PREFIX + if isObs == true { + headerPrefix = HEADER_PREFIX_OBS + } + supportCallbackActions := []string{PUT_OBJECT, PUT_FILE, "CompleteMultipartUpload"} + return len(headers[headerPrefix+CALLBACK]) != 0 && IsContain(supportCallbackActions, action) +} + +func IsContain(items []string, item string) bool { + for _, eachItem := range items { + if eachItem == item { + return true + } + } + return false +} + +// StringToInt converts string value to int value with default value +func StringToInt(value string, def int) int { + ret, err := strconv.Atoi(value) + if err != nil { + ret = def + } + return ret +} + +// StringToInt64 converts string value to int64 value with default value +func StringToInt64(value string, def int64) int64 { + ret, err := strconv.ParseInt(value, 10, 64) + if err != nil { + ret = def + } + return ret +} + +// IntToString converts int value to string value +func IntToString(value int) string { + return strconv.Itoa(value) +} + +// Int64ToString converts int64 value to string value +func Int64ToString(value int64) string { + return strconv.FormatInt(value, 10) +} + +// GetCurrentTimestamp gets unix time in milliseconds +func GetCurrentTimestamp() int64 { + return time.Now().UnixNano() / 1000000 +} + +// FormatUtcNow gets a textual representation of the UTC format time value +func FormatUtcNow(format string) string { + return time.Now().UTC().Format(format) +} + +// FormatNowWithLoc gets a textual representation of the format time value with loc +func FormatNowWithLoc(format string, loc *time.Location) string { + return time.Now().In(loc).Format(format) +} + +// FormatUtcToRfc1123 gets a textual representation of the RFC1123 format time value +func FormatUtcToRfc1123(t time.Time) string { + ret := t.UTC().Format(time.RFC1123) + return ret[:strings.LastIndex(ret, "UTC")] + "GMT" +} + +// Md5 gets the md5 value of input +func Md5(value []byte) []byte { + m := md5.New() + _, err := m.Write(value) + if err != nil { + doLog(LEVEL_WARN, "MD5 failed to write") + } + return m.Sum(nil) +} + +// HmacSha1 gets hmac sha1 value of input +func HmacSha1(key, value []byte) []byte { + mac := hmac.New(sha1.New, key) + _, err := mac.Write(value) + if err != nil { + doLog(LEVEL_WARN, "HmacSha1 failed to write") + } + return mac.Sum(nil) +} + +// HmacSha256 get hmac sha256 value if input +func HmacSha256(key, value []byte) []byte { + mac := hmac.New(sha256.New, key) + _, err := mac.Write(value) + if err != nil { + doLog(LEVEL_WARN, "HmacSha256 failed to write") + } + return mac.Sum(nil) +} + +// Base64Encode wrapper of base64.StdEncoding.EncodeToString +func Base64Encode(value []byte) string { + return base64.StdEncoding.EncodeToString(value) +} + +// Base64Decode wrapper of base64.StdEncoding.DecodeString +func Base64Decode(value string) ([]byte, error) { + return base64.StdEncoding.DecodeString(value) +} + +// HexMd5 returns the md5 value of input in hexadecimal format +func HexMd5(value []byte) string { + return Hex(Md5(value)) +} + +// Base64Md5 returns the md5 value of input with Base64Encode +func Base64Md5(value []byte) string { + return Base64Encode(Md5(value)) +} + +// Base64Md5OrSha256 returns the md5 or sha256 value of input with Base64Encode +func Base64Md5OrSha256(value []byte, enableSha256 bool) string { + if enableSha256 { + return Base64Sha256(value) + } + return Base64Md5(value) +} + +// Base64Sha256 returns the sha256 value of input with Base64Encode +func Base64Sha256(value []byte) string { + return Base64Encode(Sha256Hash(value)) +} + +// Sha256Hash returns sha256 checksum +func Sha256Hash(value []byte) []byte { + hash := sha256.New() + _, err := hash.Write(value) + if err != nil { + doLog(LEVEL_WARN, "Sha256Hash failed to write") + } + return hash.Sum(nil) +} + +// ParseXml wrapper of xml.Unmarshal +func ParseXml(value []byte, result interface{}) error { + if len(value) == 0 { + return nil + } + return xml.Unmarshal(value, result) +} + +// parseJSON wrapper of json.Unmarshal +func parseJSON(value []byte, result interface{}) error { + if len(value) == 0 { + return nil + } + return json.Unmarshal(value, result) +} + +// TransToXml wrapper of xml.Marshal +func TransToXml(value interface{}) ([]byte, error) { + if value == nil { + return []byte{}, nil + } + return xml.Marshal(value) +} + +// TransToJSON wrapper of json.Marshal +func TransToJSON(value interface{}) ([]byte, error) { + if value == nil { + return []byte{}, nil + } + return json.Marshal(value) +} + +// Hex wrapper of hex.EncodeToString +func Hex(value []byte) string { + return hex.EncodeToString(value) +} + +// HexSha256 returns the Sha256Hash value of input in hexadecimal format +func HexSha256(value []byte) string { + return Hex(Sha256Hash(value)) +} + +// UrlDecode wrapper of url.QueryUnescape +func UrlDecode(value string) (string, error) { + ret, err := url.QueryUnescape(value) + if err == nil { + return ret, nil + } + return "", err +} + +// UrlDecodeWithoutError wrapper of UrlDecode +func UrlDecodeWithoutError(value string) string { + ret, err := UrlDecode(value) + if err == nil { + return ret + } + if isErrorLogEnabled() { + doLog(LEVEL_ERROR, "Url decode error") + } + return "" +} + +// IsIP checks whether the value matches ip address +func IsIP(value string) bool { + return ipRegex.MatchString(value) +} + +// UrlEncode encodes the input value +func UrlEncode(value string, chineseOnly bool) string { + if chineseOnly { + values := make([]string, 0, len(value)) + for _, val := range value { + _value := string(val) + if regex.MatchString(_value) { + _value = url.QueryEscape(_value) + } + values = append(values, _value) + } + return strings.Join(values, "") + } + return url.QueryEscape(value) +} + +func copyHeaders(m map[string][]string) (ret map[string][]string) { + if m != nil { + ret = make(map[string][]string, len(m)) + for key, values := range m { + _values := make([]string, 0, len(values)) + for _, value := range values { + _values = append(_values, value) + } + ret[strings.ToLower(key)] = _values + } + } else { + ret = make(map[string][]string) + } + + return +} + +func parseHeaders(headers map[string][]string) (signature string, region string, signedHeaders string) { + signature = "v2" + if receviedAuthorization, ok := headers[strings.ToLower(HEADER_AUTH_CAMEL)]; ok && len(receviedAuthorization) > 0 { + if strings.HasPrefix(receviedAuthorization[0], V4_HASH_PREFIX) { + signature = "v4" + matches := v4AuthRegex.FindStringSubmatch(receviedAuthorization[0]) + if len(matches) >= 3 { + region = matches[1] + regions := regionRegex.FindStringSubmatch(region) + if len(regions) >= 2 { + region = regions[1] + } + signedHeaders = matches[2] + } + + } else if strings.HasPrefix(receviedAuthorization[0], V2_HASH_PREFIX) { + signature = "v2" + } + } + return +} + +func getTemporaryKeys() []string { + return []string{ + "Signature", + "signature", + "X-Amz-Signature", + "x-amz-signature", + } +} + +func getIsObs(isTemporary bool, querys []string, headers map[string][]string) bool { + isObs := true + if isTemporary { + for _, value := range querys { + keyPrefix := strings.ToLower(value) + if strings.HasPrefix(keyPrefix, HEADER_PREFIX) { + isObs = false + } else if strings.HasPrefix(value, HEADER_ACCESSS_KEY_AMZ) { + isObs = false + } + } + } else { + for key := range headers { + keyPrefix := strings.ToLower(key) + if strings.HasPrefix(keyPrefix, HEADER_PREFIX) { + isObs = false + break + } + } + } + return isObs +} + +func isPathStyle(headers map[string][]string, bucketName string) bool { + if receviedHost, ok := headers[HEADER_HOST]; ok && len(receviedHost) > 0 && !strings.HasPrefix(receviedHost[0], bucketName+".") { + return true + } + return false +} + +// GetV2Authorization v2 Authorization +func GetV2Authorization(ak, sk, method, bucketName, objectKey, queryURL string, headers map[string][]string) (ret map[string]string) { + + if strings.HasPrefix(queryURL, "?") { + queryURL = queryURL[1:] + } + + method = strings.ToUpper(method) + + querys := strings.Split(queryURL, "&") + querysResult := make([]string, 0) + for _, value := range querys { + if value != "=" && len(value) != 0 { + querysResult = append(querysResult, value) + } + } + params := make(map[string]string) + + for _, value := range querysResult { + kv := strings.Split(value, "=") + length := len(kv) + if length == 1 { + key := UrlDecodeWithoutError(kv[0]) + params[key] = "" + } else if length >= 2 { + key := UrlDecodeWithoutError(kv[0]) + vals := make([]string, 0, length-1) + for i := 1; i < length; i++ { + val := UrlDecodeWithoutError(kv[i]) + vals = append(vals, val) + } + params[key] = strings.Join(vals, "=") + } + } + headers = copyHeaders(headers) + pathStyle := isPathStyle(headers, bucketName) + conf := &config{securityProviders: []securityProvider{NewBasicSecurityProvider(ak, sk, "")}, + urlHolder: &urlHolder{scheme: "https", host: "dummy", port: 443}, + pathStyle: pathStyle} + conf.signature = SignatureObs + _, canonicalizedURL := conf.formatUrls(bucketName, objectKey, params, false) + ret = v2Auth(ak, sk, method, canonicalizedURL, headers, true) + v2HashPrefix := OBS_HASH_PREFIX + ret[HEADER_AUTH_CAMEL] = fmt.Sprintf("%s %s:%s", v2HashPrefix, ak, ret["Signature"]) + return +} + +func getQuerysResult(querys []string) []string { + querysResult := make([]string, 0) + for _, value := range querys { + if value != "=" && len(value) != 0 { + querysResult = append(querysResult, value) + } + } + return querysResult +} + +func getParams(querysResult []string) map[string]string { + params := make(map[string]string) + for _, value := range querysResult { + kv := strings.Split(value, "=") + length := len(kv) + if length == 1 { + key := UrlDecodeWithoutError(kv[0]) + params[key] = "" + } else if length >= 2 { + key := UrlDecodeWithoutError(kv[0]) + vals := make([]string, 0, length-1) + for i := 1; i < length; i++ { + val := UrlDecodeWithoutError(kv[i]) + vals = append(vals, val) + } + params[key] = strings.Join(vals, "=") + } + } + return params +} + +func getTemporaryAndSignature(params map[string]string) (bool, string) { + isTemporary := false + signature := "v2" + temporaryKeys := getTemporaryKeys() + for _, key := range temporaryKeys { + if _, ok := params[key]; ok { + isTemporary = true + if strings.ToLower(key) == "signature" { + signature = "v2" + } else if strings.ToLower(key) == "x-amz-signature" { + signature = "v4" + } + break + } + } + return isTemporary, signature +} + +// GetAuthorization Authorization +func GetAuthorization(ak, sk, method, bucketName, objectKey, queryURL string, headers map[string][]string) (ret map[string]string) { + + if strings.HasPrefix(queryURL, "?") { + queryURL = queryURL[1:] + } + + method = strings.ToUpper(method) + + querys := strings.Split(queryURL, "&") + querysResult := getQuerysResult(querys) + params := getParams(querysResult) + + isTemporary, signature := getTemporaryAndSignature(params) + + isObs := getIsObs(isTemporary, querysResult, headers) + headers = copyHeaders(headers) + pathStyle := false + if receviedHost, ok := headers[HEADER_HOST]; ok && len(receviedHost) > 0 && !strings.HasPrefix(receviedHost[0], bucketName+".") { + pathStyle = true + } + conf := &config{securityProviders: []securityProvider{NewBasicSecurityProvider(ak, sk, "")}, + urlHolder: &urlHolder{scheme: "https", host: "dummy", port: 443}, + pathStyle: pathStyle} + + if isTemporary { + return getTemporaryAuthorization(ak, sk, method, bucketName, objectKey, signature, conf, params, headers, isObs) + } + signature, region, signedHeaders := parseHeaders(headers) + if signature == "v4" { + conf.signature = SignatureV4 + requestURL, canonicalizedURL := conf.formatUrls(bucketName, objectKey, params, false) + parsedRequestURL, _err := url.Parse(requestURL) + if _err != nil { + doLog(LEVEL_WARN, "Failed to parse requestURL") + return nil + } + headerKeys := strings.Split(signedHeaders, ";") + _headers := make(map[string][]string, len(headerKeys)) + for _, headerKey := range headerKeys { + _headers[headerKey] = headers[headerKey] + } + ret = v4Auth(ak, sk, region, method, canonicalizedURL, parsedRequestURL.RawQuery, _headers) + ret[HEADER_AUTH_CAMEL] = fmt.Sprintf("%s Credential=%s,SignedHeaders=%s,Signature=%s", V4_HASH_PREFIX, ret["Credential"], ret["SignedHeaders"], ret["Signature"]) + } else if signature == "v2" { + if isObs { + conf.signature = SignatureObs + } else { + conf.signature = SignatureV2 + } + _, canonicalizedURL := conf.formatUrls(bucketName, objectKey, params, false) + ret = v2Auth(ak, sk, method, canonicalizedURL, headers, isObs) + v2HashPrefix := V2_HASH_PREFIX + if isObs { + v2HashPrefix = OBS_HASH_PREFIX + } + ret[HEADER_AUTH_CAMEL] = fmt.Sprintf("%s %s:%s", v2HashPrefix, ak, ret["Signature"]) + } + return + +} + +func getTemporaryAuthorization(ak, sk, method, bucketName, objectKey, signature string, conf *config, params map[string]string, + headers map[string][]string, isObs bool) (ret map[string]string) { + + if signature == "v4" { + conf.signature = SignatureV4 + + longDate, ok := params[PARAM_DATE_AMZ_CAMEL] + if !ok { + longDate = params[HEADER_DATE_AMZ] + } + shortDate := longDate[:8] + + credential, ok := params[PARAM_CREDENTIAL_AMZ_CAMEL] + if !ok { + credential = params[strings.ToLower(PARAM_CREDENTIAL_AMZ_CAMEL)] + } + + _credential := UrlDecodeWithoutError(credential) + + regions := regionRegex.FindStringSubmatch(_credential) + var region string + if len(regions) >= 2 { + region = regions[1] + } + + _, scope := getCredential(ak, region, shortDate) + + expires, ok := params[PARAM_EXPIRES_AMZ_CAMEL] + if !ok { + expires = params[strings.ToLower(PARAM_EXPIRES_AMZ_CAMEL)] + } + + signedHeaders, ok := params[PARAM_SIGNEDHEADERS_AMZ_CAMEL] + if !ok { + signedHeaders = params[strings.ToLower(PARAM_SIGNEDHEADERS_AMZ_CAMEL)] + } + + algorithm, ok := params[PARAM_ALGORITHM_AMZ_CAMEL] + if !ok { + algorithm = params[strings.ToLower(PARAM_ALGORITHM_AMZ_CAMEL)] + } + + if _, ok := params[PARAM_SIGNATURE_AMZ_CAMEL]; ok { + delete(params, PARAM_SIGNATURE_AMZ_CAMEL) + } else if _, ok := params[strings.ToLower(PARAM_SIGNATURE_AMZ_CAMEL)]; ok { + delete(params, strings.ToLower(PARAM_SIGNATURE_AMZ_CAMEL)) + } + + ret = make(map[string]string, 6) + ret[PARAM_ALGORITHM_AMZ_CAMEL] = algorithm + ret[PARAM_CREDENTIAL_AMZ_CAMEL] = credential + ret[PARAM_DATE_AMZ_CAMEL] = longDate + ret[PARAM_EXPIRES_AMZ_CAMEL] = expires + ret[PARAM_SIGNEDHEADERS_AMZ_CAMEL] = signedHeaders + + requestURL, canonicalizedURL := conf.formatUrls(bucketName, objectKey, params, false) + parsedRequestURL, _err := url.Parse(requestURL) + if _err != nil { + doLog(LEVEL_WARN, "Failed to parse requestUrl") + return nil + } + stringToSign := getV4StringToSign(method, canonicalizedURL, parsedRequestURL.RawQuery, scope, longDate, UNSIGNED_PAYLOAD, strings.Split(signedHeaders, ";"), headers) + ret[PARAM_SIGNATURE_AMZ_CAMEL] = UrlEncode(getSignature(stringToSign, sk, region, shortDate), false) + } else if signature == "v2" { + if isObs { + conf.signature = SignatureObs + } else { + conf.signature = SignatureV2 + } + _, canonicalizedURL := conf.formatUrls(bucketName, objectKey, params, false) + expires, ok := params["Expires"] + if !ok { + expires = params["expires"] + } + headers[HEADER_DATE_CAMEL] = []string{expires} + stringToSign := getV2StringToSign(method, canonicalizedURL, headers, isObs) + ret = make(map[string]string, 3) + ret["Signature"] = UrlEncode(Base64Encode(HmacSha1([]byte(sk), []byte(stringToSign))), false) + ret["AWSAccessKeyId"] = UrlEncode(ak, false) + ret["Expires"] = UrlEncode(expires, false) + } + + return +} + +func GetContentType(key string) (string, bool) { + if ct, ok := mimeTypes[strings.ToLower(key[strings.LastIndex(key, ".")+1:])]; ok { + return ct, ok + } + return "", false +} + +func GetReaderLen(reader io.Reader) (int64, error) { + var contentLength int64 + var err error + switch v := reader.(type) { + case *bytes.Buffer: + contentLength = int64(v.Len()) + case *bytes.Reader: + contentLength = int64(v.Len()) + case *strings.Reader: + contentLength = int64(v.Len()) + case *os.File: + fInfo, fError := v.Stat() + if fError != nil { + err = fmt.Errorf("can't get reader content length,%s", fError.Error()) + } else { + contentLength = fInfo.Size() + } + case *io.LimitedReader: + contentLength = int64(v.N) + case *fileReaderWrapper: + contentLength = int64(v.totalCount) + case *readerWrapper: + contentLength = int64(v.totalCount) + default: + err = fmt.Errorf("can't get reader content length,unkown reader type") + } + return contentLength, err +} + +func validateLength(value int, minLen int, maxLen int, fieldName string) error { + if minLen > maxLen { + return fmt.Errorf("Min Value can not be greater than Max Value") + } + if minLen == maxLen && value != minLen { + return fmt.Errorf("%s length must be %d characters. (value len: %d)", fieldName, maxLen, value) + } + if value < minLen || value > maxLen { + return fmt.Errorf("%s length must be between %d and %d characters. (value len: %d)", fieldName, minLen, maxLen, value) + } + return nil +} diff --git a/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md new file mode 100644 index 00000000000..c758234904e --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md @@ -0,0 +1,96 @@ +## 1.5.0 + +* New option `IgnoreUntaggedFields` to ignore decoding to any fields + without `mapstructure` (or the configured tag name) set [GH-277] +* New option `ErrorUnset` which makes it an error if any fields + in a target struct are not set by the decoding process. [GH-225] +* New function `OrComposeDecodeHookFunc` to help compose decode hooks. [GH-240] +* Decoding to slice from array no longer crashes [GH-265] +* Decode nested struct pointers to map [GH-271] +* Fix issue where `,squash` was ignored if `Squash` option was set. [GH-280] +* Fix issue where fields with `,omitempty` would sometimes decode + into a map with an empty string key [GH-281] + +## 1.4.3 + +* Fix cases where `json.Number` didn't decode properly [GH-261] + +## 1.4.2 + +* Custom name matchers to support any sort of casing, formatting, etc. for + field names. [GH-250] +* Fix possible panic in ComposeDecodeHookFunc [GH-251] + +## 1.4.1 + +* Fix regression where `*time.Time` value would be set to empty and not be sent + to decode hooks properly [GH-232] + +## 1.4.0 + +* A new decode hook type `DecodeHookFuncValue` has been added that has + access to the full values. [GH-183] +* Squash is now supported with embedded fields that are struct pointers [GH-205] +* Empty strings will convert to 0 for all numeric types when weakly decoding [GH-206] + +## 1.3.3 + +* Decoding maps from maps creates a settable value for decode hooks [GH-203] + +## 1.3.2 + +* Decode into interface type with a struct value is supported [GH-187] + +## 1.3.1 + +* Squash should only squash embedded structs. [GH-194] + +## 1.3.0 + +* Added `",omitempty"` support. This will ignore zero values in the source + structure when encoding. [GH-145] + +## 1.2.3 + +* Fix duplicate entries in Keys list with pointer values. [GH-185] + +## 1.2.2 + +* Do not add unsettable (unexported) values to the unused metadata key + or "remain" value. [GH-150] + +## 1.2.1 + +* Go modules checksum mismatch fix + +## 1.2.0 + +* Added support to capture unused values in a field using the `",remain"` value + in the mapstructure tag. There is an example to showcase usage. +* Added `DecoderConfig` option to always squash embedded structs +* `json.Number` can decode into `uint` types +* Empty slices are preserved and not replaced with nil slices +* Fix panic that can occur in when decoding a map into a nil slice of structs +* Improved package documentation for godoc + +## 1.1.2 + +* Fix error when decode hook decodes interface implementation into interface + type. [GH-140] + +## 1.1.1 + +* Fix panic that can happen in `decodePtr` + +## 1.1.0 + +* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133] +* Support struct to struct decoding [GH-137] +* If source map value is nil, then destination map value is nil (instead of empty) +* If source slice value is nil, then destination slice value is nil (instead of empty) +* If source pointer is nil, then destination pointer is set to nil (instead of + allocated zero value of type) + +## 1.0.0 + +* Initial tagged stable release. diff --git a/vendor/github.com/mitchellh/mapstructure/LICENSE b/vendor/github.com/mitchellh/mapstructure/LICENSE new file mode 100644 index 00000000000..f9c841a51e0 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md new file mode 100644 index 00000000000..0018dc7d9f9 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/README.md @@ -0,0 +1,46 @@ +# mapstructure [![Godoc](https://godoc.org/github.com/mitchellh/mapstructure?status.svg)](https://godoc.org/github.com/mitchellh/mapstructure) + +mapstructure is a Go library for decoding generic map values to structures +and vice versa, while providing helpful error handling. + +This library is most useful when decoding values from some data stream (JSON, +Gob, etc.) where you don't _quite_ know the structure of the underlying data +until you read a part of it. You can therefore read a `map[string]interface{}` +and use this library to decode it into the proper underlying native Go +structure. + +## Installation + +Standard `go get`: + +``` +$ go get github.com/mitchellh/mapstructure +``` + +## Usage & Example + +For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure). + +The `Decode` function has examples associated with it there. + +## But Why?! + +Go offers fantastic standard libraries for decoding formats such as JSON. +The standard method is to have a struct pre-created, and populate that struct +from the bytes of the encoded format. This is great, but the problem is if +you have configuration or an encoding that changes slightly depending on +specific fields. For example, consider this JSON: + +```json +{ + "type": "person", + "name": "Mitchell" +} +``` + +Perhaps we can't populate a specific structure without first reading +the "type" field from the JSON. We could always do two passes over the +decoding of the JSON (reading the "type" first, and the rest later). +However, it is much simpler to just decode this into a `map[string]interface{}` +structure, read the "type" key, then use something like this library +to decode it into the proper structure. diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go new file mode 100644 index 00000000000..3a754ca7248 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go @@ -0,0 +1,279 @@ +package mapstructure + +import ( + "encoding" + "errors" + "fmt" + "net" + "reflect" + "strconv" + "strings" + "time" +) + +// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// it into the proper DecodeHookFunc type, such as DecodeHookFuncType. +func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { + // Create variables here so we can reference them with the reflect pkg + var f1 DecodeHookFuncType + var f2 DecodeHookFuncKind + var f3 DecodeHookFuncValue + + // Fill in the variables into this interface and the rest is done + // automatically using the reflect package. + potential := []interface{}{f1, f2, f3} + + v := reflect.ValueOf(h) + vt := v.Type() + for _, raw := range potential { + pt := reflect.ValueOf(raw).Type() + if vt.ConvertibleTo(pt) { + return v.Convert(pt).Interface() + } + } + + return nil +} + +// DecodeHookExec executes the given decode hook. This should be used +// since it'll naturally degrade to the older backwards compatible DecodeHookFunc +// that took reflect.Kind instead of reflect.Type. +func DecodeHookExec( + raw DecodeHookFunc, + from reflect.Value, to reflect.Value) (interface{}, error) { + + switch f := typedDecodeHook(raw).(type) { + case DecodeHookFuncType: + return f(from.Type(), to.Type(), from.Interface()) + case DecodeHookFuncKind: + return f(from.Kind(), to.Kind(), from.Interface()) + case DecodeHookFuncValue: + return f(from, to) + default: + return nil, errors.New("invalid decode hook signature") + } +} + +// ComposeDecodeHookFunc creates a single DecodeHookFunc that +// automatically composes multiple DecodeHookFuncs. +// +// The composed funcs are called in order, with the result of the +// previous transformation. +func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { + return func(f reflect.Value, t reflect.Value) (interface{}, error) { + var err error + data := f.Interface() + + newFrom := f + for _, f1 := range fs { + data, err = DecodeHookExec(f1, newFrom, t) + if err != nil { + return nil, err + } + newFrom = reflect.ValueOf(data) + } + + return data, nil + } +} + +// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned. +// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages. +func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc { + return func(a, b reflect.Value) (interface{}, error) { + var allErrs string + var out interface{} + var err error + + for _, f := range ff { + out, err = DecodeHookExec(f, a, b) + if err != nil { + allErrs += err.Error() + "\n" + continue + } + + return out, nil + } + + return nil, errors.New(allErrs) + } +} + +// StringToSliceHookFunc returns a DecodeHookFunc that converts +// string to []string by splitting on the given sep. +func StringToSliceHookFunc(sep string) DecodeHookFunc { + return func( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + if f != reflect.String || t != reflect.Slice { + return data, nil + } + + raw := data.(string) + if raw == "" { + return []string{}, nil + } + + return strings.Split(raw, sep), nil + } +} + +// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts +// strings to time.Duration. +func StringToTimeDurationHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Duration(5)) { + return data, nil + } + + // Convert it by parsing + return time.ParseDuration(data.(string)) + } +} + +// StringToIPHookFunc returns a DecodeHookFunc that converts +// strings to net.IP +func StringToIPHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(net.IP{}) { + return data, nil + } + + // Convert it by parsing + ip := net.ParseIP(data.(string)) + if ip == nil { + return net.IP{}, fmt.Errorf("failed parsing ip %v", data) + } + + return ip, nil + } +} + +// StringToIPNetHookFunc returns a DecodeHookFunc that converts +// strings to net.IPNet +func StringToIPNetHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(net.IPNet{}) { + return data, nil + } + + // Convert it by parsing + _, net, err := net.ParseCIDR(data.(string)) + return net, err + } +} + +// StringToTimeHookFunc returns a DecodeHookFunc that converts +// strings to time.Time. +func StringToTimeHookFunc(layout string) DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Time{}) { + return data, nil + } + + // Convert it by parsing + return time.Parse(layout, data.(string)) + } +} + +// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to +// the decoder. +// +// Note that this is significantly different from the WeaklyTypedInput option +// of the DecoderConfig. +func WeaklyTypedHook( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + dataVal := reflect.ValueOf(data) + switch t { + case reflect.String: + switch f { + case reflect.Bool: + if dataVal.Bool() { + return "1", nil + } + return "0", nil + case reflect.Float32: + return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil + case reflect.Int: + return strconv.FormatInt(dataVal.Int(), 10), nil + case reflect.Slice: + dataType := dataVal.Type() + elemKind := dataType.Elem().Kind() + if elemKind == reflect.Uint8 { + return string(dataVal.Interface().([]uint8)), nil + } + case reflect.Uint: + return strconv.FormatUint(dataVal.Uint(), 10), nil + } + } + + return data, nil +} + +func RecursiveStructToMapHookFunc() DecodeHookFunc { + return func(f reflect.Value, t reflect.Value) (interface{}, error) { + if f.Kind() != reflect.Struct { + return f.Interface(), nil + } + + var i interface{} = struct{}{} + if t.Type() != reflect.TypeOf(&i).Elem() { + return f.Interface(), nil + } + + m := make(map[string]interface{}) + t.Set(reflect.ValueOf(m)) + + return f.Interface(), nil + } +} + +// TextUnmarshallerHookFunc returns a DecodeHookFunc that applies +// strings to the UnmarshalText function, when the target type +// implements the encoding.TextUnmarshaler interface +func TextUnmarshallerHookFunc() DecodeHookFuncType { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + result := reflect.New(t).Interface() + unmarshaller, ok := result.(encoding.TextUnmarshaler) + if !ok { + return data, nil + } + if err := unmarshaller.UnmarshalText([]byte(data.(string))); err != nil { + return nil, err + } + return result, nil + } +} diff --git a/vendor/github.com/mitchellh/mapstructure/error.go b/vendor/github.com/mitchellh/mapstructure/error.go new file mode 100644 index 00000000000..47a99e5af3f --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/error.go @@ -0,0 +1,50 @@ +package mapstructure + +import ( + "errors" + "fmt" + "sort" + "strings" +) + +// Error implements the error interface and can represents multiple +// errors that occur in the course of a single decode. +type Error struct { + Errors []string +} + +func (e *Error) Error() string { + points := make([]string, len(e.Errors)) + for i, err := range e.Errors { + points[i] = fmt.Sprintf("* %s", err) + } + + sort.Strings(points) + return fmt.Sprintf( + "%d error(s) decoding:\n\n%s", + len(e.Errors), strings.Join(points, "\n")) +} + +// WrappedErrors implements the errwrap.Wrapper interface to make this +// return value more useful with the errwrap and go-multierror libraries. +func (e *Error) WrappedErrors() []error { + if e == nil { + return nil + } + + result := make([]error, len(e.Errors)) + for i, e := range e.Errors { + result[i] = errors.New(e) + } + + return result +} + +func appendErrors(errors []string, err error) []string { + switch e := err.(type) { + case *Error: + return append(errors, e.Errors...) + default: + return append(errors, e.Error()) + } +} diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go new file mode 100644 index 00000000000..1efb22ac361 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go @@ -0,0 +1,1540 @@ +// Package mapstructure exposes functionality to convert one arbitrary +// Go type into another, typically to convert a map[string]interface{} +// into a native Go structure. +// +// The Go structure can be arbitrarily complex, containing slices, +// other structs, etc. and the decoder will properly decode nested +// maps and so on into the proper structures in the native Go struct. +// See the examples to see what the decoder is capable of. +// +// The simplest function to start with is Decode. +// +// Field Tags +// +// When decoding to a struct, mapstructure will use the field name by +// default to perform the mapping. For example, if a struct has a field +// "Username" then mapstructure will look for a key in the source value +// of "username" (case insensitive). +// +// type User struct { +// Username string +// } +// +// You can change the behavior of mapstructure by using struct tags. +// The default struct tag that mapstructure looks for is "mapstructure" +// but you can customize it using DecoderConfig. +// +// Renaming Fields +// +// To rename the key that mapstructure looks for, use the "mapstructure" +// tag and set a value directly. For example, to change the "username" example +// above to "user": +// +// type User struct { +// Username string `mapstructure:"user"` +// } +// +// Embedded Structs and Squashing +// +// Embedded structs are treated as if they're another field with that name. +// By default, the two structs below are equivalent when decoding with +// mapstructure: +// +// type Person struct { +// Name string +// } +// +// type Friend struct { +// Person +// } +// +// type Friend struct { +// Person Person +// } +// +// This would require an input that looks like below: +// +// map[string]interface{}{ +// "person": map[string]interface{}{"name": "alice"}, +// } +// +// If your "person" value is NOT nested, then you can append ",squash" to +// your tag value and mapstructure will treat it as if the embedded struct +// were part of the struct directly. Example: +// +// type Friend struct { +// Person `mapstructure:",squash"` +// } +// +// Now the following input would be accepted: +// +// map[string]interface{}{ +// "name": "alice", +// } +// +// When decoding from a struct to a map, the squash tag squashes the struct +// fields into a single map. Using the example structs from above: +// +// Friend{Person: Person{Name: "alice"}} +// +// Will be decoded into a map: +// +// map[string]interface{}{ +// "name": "alice", +// } +// +// DecoderConfig has a field that changes the behavior of mapstructure +// to always squash embedded structs. +// +// Remainder Values +// +// If there are any unmapped keys in the source value, mapstructure by +// default will silently ignore them. You can error by setting ErrorUnused +// in DecoderConfig. If you're using Metadata you can also maintain a slice +// of the unused keys. +// +// You can also use the ",remain" suffix on your tag to collect all unused +// values in a map. The field with this tag MUST be a map type and should +// probably be a "map[string]interface{}" or "map[interface{}]interface{}". +// See example below: +// +// type Friend struct { +// Name string +// Other map[string]interface{} `mapstructure:",remain"` +// } +// +// Given the input below, Other would be populated with the other +// values that weren't used (everything but "name"): +// +// map[string]interface{}{ +// "name": "bob", +// "address": "123 Maple St.", +// } +// +// Omit Empty Values +// +// When decoding from a struct to any other value, you may use the +// ",omitempty" suffix on your tag to omit that value if it equates to +// the zero value. The zero value of all types is specified in the Go +// specification. +// +// For example, the zero type of a numeric type is zero ("0"). If the struct +// field value is zero and a numeric type, the field is empty, and it won't +// be encoded into the destination type. +// +// type Source struct { +// Age int `mapstructure:",omitempty"` +// } +// +// Unexported fields +// +// Since unexported (private) struct fields cannot be set outside the package +// where they are defined, the decoder will simply skip them. +// +// For this output type definition: +// +// type Exported struct { +// private string // this unexported field will be skipped +// Public string +// } +// +// Using this map as input: +// +// map[string]interface{}{ +// "private": "I will be ignored", +// "Public": "I made it through!", +// } +// +// The following struct will be decoded: +// +// type Exported struct { +// private: "" // field is left with an empty string (zero value) +// Public: "I made it through!" +// } +// +// Other Configuration +// +// mapstructure is highly configurable. See the DecoderConfig struct +// for other features and options that are supported. +package mapstructure + +import ( + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" + "strconv" + "strings" +) + +// DecodeHookFunc is the callback function that can be used for +// data transformations. See "DecodeHook" in the DecoderConfig +// struct. +// +// The type must be one of DecodeHookFuncType, DecodeHookFuncKind, or +// DecodeHookFuncValue. +// Values are a superset of Types (Values can return types), and Types are a +// superset of Kinds (Types can return Kinds) and are generally a richer thing +// to use, but Kinds are simpler if you only need those. +// +// The reason DecodeHookFunc is multi-typed is for backwards compatibility: +// we started with Kinds and then realized Types were the better solution, +// but have a promise to not break backwards compat so we now support +// both. +type DecodeHookFunc interface{} + +// DecodeHookFuncType is a DecodeHookFunc which has complete information about +// the source and target types. +type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) + +// DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the +// source and target types. +type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) + +// DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target +// values. +type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error) + +// DecoderConfig is the configuration that is used to create a new decoder +// and allows customization of various aspects of decoding. +type DecoderConfig struct { + // DecodeHook, if set, will be called before any decoding and any + // type conversion (if WeaklyTypedInput is on). This lets you modify + // the values before they're set down onto the resulting struct. The + // DecodeHook is called for every map and value in the input. This means + // that if a struct has embedded fields with squash tags the decode hook + // is called only once with all of the input data, not once for each + // embedded struct. + // + // If an error is returned, the entire decode will fail with that error. + DecodeHook DecodeHookFunc + + // If ErrorUnused is true, then it is an error for there to exist + // keys in the original map that were unused in the decoding process + // (extra keys). + ErrorUnused bool + + // If ErrorUnset is true, then it is an error for there to exist + // fields in the result that were not set in the decoding process + // (extra fields). This only applies to decoding to a struct. This + // will affect all nested structs as well. + ErrorUnset bool + + // ZeroFields, if set to true, will zero fields before writing them. + // For example, a map will be emptied before decoded values are put in + // it. If this is false, a map will be merged. + ZeroFields bool + + // If WeaklyTypedInput is true, the decoder will make the following + // "weak" conversions: + // + // - bools to string (true = "1", false = "0") + // - numbers to string (base 10) + // - bools to int/uint (true = 1, false = 0) + // - strings to int/uint (base implied by prefix) + // - int to bool (true if value != 0) + // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F, + // FALSE, false, False. Anything else is an error) + // - empty array = empty map and vice versa + // - negative numbers to overflowed uint values (base 10) + // - slice of maps to a merged map + // - single values are converted to slices if required. Each + // element is weakly decoded. For example: "4" can become []int{4} + // if the target type is an int slice. + // + WeaklyTypedInput bool + + // Squash will squash embedded structs. A squash tag may also be + // added to an individual struct field using a tag. For example: + // + // type Parent struct { + // Child `mapstructure:",squash"` + // } + Squash bool + + // Metadata is the struct that will contain extra metadata about + // the decoding. If this is nil, then no metadata will be tracked. + Metadata *Metadata + + // Result is a pointer to the struct that will contain the decoded + // value. + Result interface{} + + // The tag name that mapstructure reads for field names. This + // defaults to "mapstructure" + TagName string + + // IgnoreUntaggedFields ignores all struct fields without explicit + // TagName, comparable to `mapstructure:"-"` as default behaviour. + IgnoreUntaggedFields bool + + // MatchName is the function used to match the map key to the struct + // field name or tag. Defaults to `strings.EqualFold`. This can be used + // to implement case-sensitive tag values, support snake casing, etc. + MatchName func(mapKey, fieldName string) bool +} + +// A Decoder takes a raw interface value and turns it into structured +// data, keeping track of rich error information along the way in case +// anything goes wrong. Unlike the basic top-level Decode method, you can +// more finely control how the Decoder behaves using the DecoderConfig +// structure. The top-level Decode method is just a convenience that sets +// up the most basic Decoder. +type Decoder struct { + config *DecoderConfig +} + +// Metadata contains information about decoding a structure that +// is tedious or difficult to get otherwise. +type Metadata struct { + // Keys are the keys of the structure which were successfully decoded + Keys []string + + // Unused is a slice of keys that were found in the raw value but + // weren't decoded since there was no matching field in the result interface + Unused []string + + // Unset is a slice of field names that were found in the result interface + // but weren't set in the decoding process since there was no matching value + // in the input + Unset []string +} + +// Decode takes an input structure and uses reflection to translate it to +// the output structure. output must be a pointer to a map or struct. +func Decode(input interface{}, output interface{}) error { + config := &DecoderConfig{ + Metadata: nil, + Result: output, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// WeakDecode is the same as Decode but is shorthand to enable +// WeaklyTypedInput. See DecoderConfig for more info. +func WeakDecode(input, output interface{}) error { + config := &DecoderConfig{ + Metadata: nil, + Result: output, + WeaklyTypedInput: true, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// DecodeMetadata is the same as Decode, but is shorthand to +// enable metadata collection. See DecoderConfig for more info. +func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { + config := &DecoderConfig{ + Metadata: metadata, + Result: output, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// WeakDecodeMetadata is the same as Decode, but is shorthand to +// enable both WeaklyTypedInput and metadata collection. See +// DecoderConfig for more info. +func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { + config := &DecoderConfig{ + Metadata: metadata, + Result: output, + WeaklyTypedInput: true, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// NewDecoder returns a new decoder for the given configuration. Once +// a decoder has been returned, the same configuration must not be used +// again. +func NewDecoder(config *DecoderConfig) (*Decoder, error) { + val := reflect.ValueOf(config.Result) + if val.Kind() != reflect.Ptr { + return nil, errors.New("result must be a pointer") + } + + val = val.Elem() + if !val.CanAddr() { + return nil, errors.New("result must be addressable (a pointer)") + } + + if config.Metadata != nil { + if config.Metadata.Keys == nil { + config.Metadata.Keys = make([]string, 0) + } + + if config.Metadata.Unused == nil { + config.Metadata.Unused = make([]string, 0) + } + + if config.Metadata.Unset == nil { + config.Metadata.Unset = make([]string, 0) + } + } + + if config.TagName == "" { + config.TagName = "mapstructure" + } + + if config.MatchName == nil { + config.MatchName = strings.EqualFold + } + + result := &Decoder{ + config: config, + } + + return result, nil +} + +// Decode decodes the given raw interface to the target pointer specified +// by the configuration. +func (d *Decoder) Decode(input interface{}) error { + return d.decode("", input, reflect.ValueOf(d.config.Result).Elem()) +} + +// Decodes an unknown data type into a specific reflection value. +func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { + var inputVal reflect.Value + if input != nil { + inputVal = reflect.ValueOf(input) + + // We need to check here if input is a typed nil. Typed nils won't + // match the "input == nil" below so we check that here. + if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() { + input = nil + } + } + + if input == nil { + // If the data is nil, then we don't set anything, unless ZeroFields is set + // to true. + if d.config.ZeroFields { + outVal.Set(reflect.Zero(outVal.Type())) + + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + } + return nil + } + + if !inputVal.IsValid() { + // If the input value is invalid, then we just set the value + // to be the zero value. + outVal.Set(reflect.Zero(outVal.Type())) + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + return nil + } + + if d.config.DecodeHook != nil { + // We have a DecodeHook, so let's pre-process the input. + var err error + input, err = DecodeHookExec(d.config.DecodeHook, inputVal, outVal) + if err != nil { + return fmt.Errorf("error decoding '%s': %s", name, err) + } + } + + var err error + outputKind := getKind(outVal) + addMetaKey := true + switch outputKind { + case reflect.Bool: + err = d.decodeBool(name, input, outVal) + case reflect.Interface: + err = d.decodeBasic(name, input, outVal) + case reflect.String: + err = d.decodeString(name, input, outVal) + case reflect.Int: + err = d.decodeInt(name, input, outVal) + case reflect.Uint: + err = d.decodeUint(name, input, outVal) + case reflect.Float32: + err = d.decodeFloat(name, input, outVal) + case reflect.Struct: + err = d.decodeStruct(name, input, outVal) + case reflect.Map: + err = d.decodeMap(name, input, outVal) + case reflect.Ptr: + addMetaKey, err = d.decodePtr(name, input, outVal) + case reflect.Slice: + err = d.decodeSlice(name, input, outVal) + case reflect.Array: + err = d.decodeArray(name, input, outVal) + case reflect.Func: + err = d.decodeFunc(name, input, outVal) + default: + // If we reached this point then we weren't able to decode it + return fmt.Errorf("%s: unsupported type: %s", name, outputKind) + } + + // If we reached here, then we successfully decoded SOMETHING, so + // mark the key as used if we're tracking metainput. + if addMetaKey && d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + + return err +} + +// This decodes a basic type (bool, int, string, etc.) and sets the +// value to "data" of that type. +func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { + if val.IsValid() && val.Elem().IsValid() { + elem := val.Elem() + + // If we can't address this element, then its not writable. Instead, + // we make a copy of the value (which is a pointer and therefore + // writable), decode into that, and replace the whole value. + copied := false + if !elem.CanAddr() { + copied = true + + // Make *T + copy := reflect.New(elem.Type()) + + // *T = elem + copy.Elem().Set(elem) + + // Set elem so we decode into it + elem = copy + } + + // Decode. If we have an error then return. We also return right + // away if we're not a copy because that means we decoded directly. + if err := d.decode(name, data, elem); err != nil || !copied { + return err + } + + // If we're a copy, we need to set te final result + val.Set(elem.Elem()) + return nil + } + + dataVal := reflect.ValueOf(data) + + // If the input data is a pointer, and the assigned type is the dereference + // of that exact pointer, then indirect it so that we can assign it. + // Example: *string to string + if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() { + dataVal = reflect.Indirect(dataVal) + } + + if !dataVal.IsValid() { + dataVal = reflect.Zero(val.Type()) + } + + dataValType := dataVal.Type() + if !dataValType.AssignableTo(val.Type()) { + return fmt.Errorf( + "'%s' expected type '%s', got '%s'", + name, val.Type(), dataValType) + } + + val.Set(dataVal) + return nil +} + +func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + + converted := true + switch { + case dataKind == reflect.String: + val.SetString(dataVal.String()) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetString("1") + } else { + val.SetString("0") + } + case dataKind == reflect.Int && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatInt(dataVal.Int(), 10)) + case dataKind == reflect.Uint && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) + case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) + case dataKind == reflect.Slice && d.config.WeaklyTypedInput, + dataKind == reflect.Array && d.config.WeaklyTypedInput: + dataType := dataVal.Type() + elemKind := dataType.Elem().Kind() + switch elemKind { + case reflect.Uint8: + var uints []uint8 + if dataKind == reflect.Array { + uints = make([]uint8, dataVal.Len(), dataVal.Len()) + for i := range uints { + uints[i] = dataVal.Index(i).Interface().(uint8) + } + } else { + uints = dataVal.Interface().([]uint8) + } + val.SetString(string(uints)) + default: + converted = false + } + default: + converted = false + } + + if !converted { + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + val.SetInt(dataVal.Int()) + case dataKind == reflect.Uint: + val.SetInt(int64(dataVal.Uint())) + case dataKind == reflect.Float32: + val.SetInt(int64(dataVal.Float())) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetInt(1) + } else { + val.SetInt(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + str := dataVal.String() + if str == "" { + str = "0" + } + + i, err := strconv.ParseInt(str, 0, val.Type().Bits()) + if err == nil { + val.SetInt(i) + } else { + return fmt.Errorf("cannot parse '%s' as int: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := jn.Int64() + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + val.SetInt(i) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + i := dataVal.Int() + if i < 0 && !d.config.WeaklyTypedInput { + return fmt.Errorf("cannot parse '%s', %d overflows uint", + name, i) + } + val.SetUint(uint64(i)) + case dataKind == reflect.Uint: + val.SetUint(dataVal.Uint()) + case dataKind == reflect.Float32: + f := dataVal.Float() + if f < 0 && !d.config.WeaklyTypedInput { + return fmt.Errorf("cannot parse '%s', %f overflows uint", + name, f) + } + val.SetUint(uint64(f)) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetUint(1) + } else { + val.SetUint(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + str := dataVal.String() + if str == "" { + str = "0" + } + + i, err := strconv.ParseUint(str, 0, val.Type().Bits()) + if err == nil { + val.SetUint(i) + } else { + return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := strconv.ParseUint(string(jn), 0, 64) + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + val.SetUint(i) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + + switch { + case dataKind == reflect.Bool: + val.SetBool(dataVal.Bool()) + case dataKind == reflect.Int && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Int() != 0) + case dataKind == reflect.Uint && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Uint() != 0) + case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Float() != 0) + case dataKind == reflect.String && d.config.WeaklyTypedInput: + b, err := strconv.ParseBool(dataVal.String()) + if err == nil { + val.SetBool(b) + } else if dataVal.String() == "" { + val.SetBool(false) + } else { + return fmt.Errorf("cannot parse '%s' as bool: %s", name, err) + } + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + val.SetFloat(float64(dataVal.Int())) + case dataKind == reflect.Uint: + val.SetFloat(float64(dataVal.Uint())) + case dataKind == reflect.Float32: + val.SetFloat(dataVal.Float()) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetFloat(1) + } else { + val.SetFloat(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + str := dataVal.String() + if str == "" { + str = "0" + } + + f, err := strconv.ParseFloat(str, val.Type().Bits()) + if err == nil { + val.SetFloat(f) + } else { + return fmt.Errorf("cannot parse '%s' as float: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := jn.Float64() + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + val.SetFloat(i) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { + valType := val.Type() + valKeyType := valType.Key() + valElemType := valType.Elem() + + // By default we overwrite keys in the current map + valMap := val + + // If the map is nil or we're purposely zeroing fields, make a new map + if valMap.IsNil() || d.config.ZeroFields { + // Make a new map to hold our result + mapType := reflect.MapOf(valKeyType, valElemType) + valMap = reflect.MakeMap(mapType) + } + + // Check input type and based on the input type jump to the proper func + dataVal := reflect.Indirect(reflect.ValueOf(data)) + switch dataVal.Kind() { + case reflect.Map: + return d.decodeMapFromMap(name, dataVal, val, valMap) + + case reflect.Struct: + return d.decodeMapFromStruct(name, dataVal, val, valMap) + + case reflect.Array, reflect.Slice: + if d.config.WeaklyTypedInput { + return d.decodeMapFromSlice(name, dataVal, val, valMap) + } + + fallthrough + + default: + return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + } +} + +func (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + // Special case for BC reasons (covered by tests) + if dataVal.Len() == 0 { + val.Set(valMap) + return nil + } + + for i := 0; i < dataVal.Len(); i++ { + err := d.decode( + name+"["+strconv.Itoa(i)+"]", + dataVal.Index(i).Interface(), val) + if err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + valType := val.Type() + valKeyType := valType.Key() + valElemType := valType.Elem() + + // Accumulate errors + errors := make([]string, 0) + + // If the input data is empty, then we just match what the input data is. + if dataVal.Len() == 0 { + if dataVal.IsNil() { + if !val.IsNil() { + val.Set(dataVal) + } + } else { + // Set to empty allocated value + val.Set(valMap) + } + + return nil + } + + for _, k := range dataVal.MapKeys() { + fieldName := name + "[" + k.String() + "]" + + // First decode the key into the proper type + currentKey := reflect.Indirect(reflect.New(valKeyType)) + if err := d.decode(fieldName, k.Interface(), currentKey); err != nil { + errors = appendErrors(errors, err) + continue + } + + // Next decode the data into the proper type + v := dataVal.MapIndex(k).Interface() + currentVal := reflect.Indirect(reflect.New(valElemType)) + if err := d.decode(fieldName, v, currentVal); err != nil { + errors = appendErrors(errors, err) + continue + } + + valMap.SetMapIndex(currentKey, currentVal) + } + + // Set the built up map to the value + val.Set(valMap) + + // If we had errors, return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + typ := dataVal.Type() + for i := 0; i < typ.NumField(); i++ { + // Get the StructField first since this is a cheap operation. If the + // field is unexported, then ignore it. + f := typ.Field(i) + if f.PkgPath != "" { + continue + } + + // Next get the actual value of this field and verify it is assignable + // to the map value. + v := dataVal.Field(i) + if !v.Type().AssignableTo(valMap.Type().Elem()) { + return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem()) + } + + tagValue := f.Tag.Get(d.config.TagName) + keyName := f.Name + + if tagValue == "" && d.config.IgnoreUntaggedFields { + continue + } + + // If Squash is set in the config, we squash the field down. + squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous + + v = dereferencePtrToStructIfNeeded(v, d.config.TagName) + + // Determine the name of the key in the map + if index := strings.Index(tagValue, ","); index != -1 { + if tagValue[:index] == "-" { + continue + } + // If "omitempty" is specified in the tag, it ignores empty values. + if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) { + continue + } + + // If "squash" is specified in the tag, we squash the field down. + squash = squash || strings.Index(tagValue[index+1:], "squash") != -1 + if squash { + // When squashing, the embedded type can be a pointer to a struct. + if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { + v = v.Elem() + } + + // The final type must be a struct + if v.Kind() != reflect.Struct { + return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) + } + } + if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" { + keyName = keyNameTagValue + } + } else if len(tagValue) > 0 { + if tagValue == "-" { + continue + } + keyName = tagValue + } + + switch v.Kind() { + // this is an embedded struct, so handle it differently + case reflect.Struct: + x := reflect.New(v.Type()) + x.Elem().Set(v) + + vType := valMap.Type() + vKeyType := vType.Key() + vElemType := vType.Elem() + mType := reflect.MapOf(vKeyType, vElemType) + vMap := reflect.MakeMap(mType) + + // Creating a pointer to a map so that other methods can completely + // overwrite the map if need be (looking at you decodeMapFromMap). The + // indirection allows the underlying map to be settable (CanSet() == true) + // where as reflect.MakeMap returns an unsettable map. + addrVal := reflect.New(vMap.Type()) + reflect.Indirect(addrVal).Set(vMap) + + err := d.decode(keyName, x.Interface(), reflect.Indirect(addrVal)) + if err != nil { + return err + } + + // the underlying map may have been completely overwritten so pull + // it indirectly out of the enclosing value. + vMap = reflect.Indirect(addrVal) + + if squash { + for _, k := range vMap.MapKeys() { + valMap.SetMapIndex(k, vMap.MapIndex(k)) + } + } else { + valMap.SetMapIndex(reflect.ValueOf(keyName), vMap) + } + + default: + valMap.SetMapIndex(reflect.ValueOf(keyName), v) + } + } + + if val.CanAddr() { + val.Set(valMap) + } + + return nil +} + +func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (bool, error) { + // If the input data is nil, then we want to just set the output + // pointer to be nil as well. + isNil := data == nil + if !isNil { + switch v := reflect.Indirect(reflect.ValueOf(data)); v.Kind() { + case reflect.Chan, + reflect.Func, + reflect.Interface, + reflect.Map, + reflect.Ptr, + reflect.Slice: + isNil = v.IsNil() + } + } + if isNil { + if !val.IsNil() && val.CanSet() { + nilValue := reflect.New(val.Type()).Elem() + val.Set(nilValue) + } + + return true, nil + } + + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + valType := val.Type() + valElemType := valType.Elem() + if val.CanSet() { + realVal := val + if realVal.IsNil() || d.config.ZeroFields { + realVal = reflect.New(valElemType) + } + + if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { + return false, err + } + + val.Set(realVal) + } else { + if err := d.decode(name, data, reflect.Indirect(val)); err != nil { + return false, err + } + } + return false, nil +} + +func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error { + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + dataVal := reflect.Indirect(reflect.ValueOf(data)) + if val.Type() != dataVal.Type() { + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + val.Set(dataVal) + return nil +} + +func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataValKind := dataVal.Kind() + valType := val.Type() + valElemType := valType.Elem() + sliceType := reflect.SliceOf(valElemType) + + // If we have a non array/slice type then we first attempt to convert. + if dataValKind != reflect.Array && dataValKind != reflect.Slice { + if d.config.WeaklyTypedInput { + switch { + // Slice and array we use the normal logic + case dataValKind == reflect.Slice, dataValKind == reflect.Array: + break + + // Empty maps turn into empty slices + case dataValKind == reflect.Map: + if dataVal.Len() == 0 { + val.Set(reflect.MakeSlice(sliceType, 0, 0)) + return nil + } + // Create slice of maps of other sizes + return d.decodeSlice(name, []interface{}{data}, val) + + case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: + return d.decodeSlice(name, []byte(dataVal.String()), val) + + // All other types we try to convert to the slice type + // and "lift" it into it. i.e. a string becomes a string slice. + default: + // Just re-try this function with data as a slice. + return d.decodeSlice(name, []interface{}{data}, val) + } + } + + return fmt.Errorf( + "'%s': source data must be an array or slice, got %s", name, dataValKind) + } + + // If the input value is nil, then don't allocate since empty != nil + if dataValKind != reflect.Array && dataVal.IsNil() { + return nil + } + + valSlice := val + if valSlice.IsNil() || d.config.ZeroFields { + // Make a new slice to hold our result, same size as the original data. + valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) + } + + // Accumulate any errors + errors := make([]string, 0) + + for i := 0; i < dataVal.Len(); i++ { + currentData := dataVal.Index(i).Interface() + for valSlice.Len() <= i { + valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) + } + currentField := valSlice.Index(i) + + fieldName := name + "[" + strconv.Itoa(i) + "]" + if err := d.decode(fieldName, currentData, currentField); err != nil { + errors = appendErrors(errors, err) + } + } + + // Finally, set the value to the slice we built up + val.Set(valSlice) + + // If there were errors, we return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataValKind := dataVal.Kind() + valType := val.Type() + valElemType := valType.Elem() + arrayType := reflect.ArrayOf(valType.Len(), valElemType) + + valArray := val + + if valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.config.ZeroFields { + // Check input type + if dataValKind != reflect.Array && dataValKind != reflect.Slice { + if d.config.WeaklyTypedInput { + switch { + // Empty maps turn into empty arrays + case dataValKind == reflect.Map: + if dataVal.Len() == 0 { + val.Set(reflect.Zero(arrayType)) + return nil + } + + // All other types we try to convert to the array type + // and "lift" it into it. i.e. a string becomes a string array. + default: + // Just re-try this function with data as a slice. + return d.decodeArray(name, []interface{}{data}, val) + } + } + + return fmt.Errorf( + "'%s': source data must be an array or slice, got %s", name, dataValKind) + + } + if dataVal.Len() > arrayType.Len() { + return fmt.Errorf( + "'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len()) + + } + + // Make a new array to hold our result, same size as the original data. + valArray = reflect.New(arrayType).Elem() + } + + // Accumulate any errors + errors := make([]string, 0) + + for i := 0; i < dataVal.Len(); i++ { + currentData := dataVal.Index(i).Interface() + currentField := valArray.Index(i) + + fieldName := name + "[" + strconv.Itoa(i) + "]" + if err := d.decode(fieldName, currentData, currentField); err != nil { + errors = appendErrors(errors, err) + } + } + + // Finally, set the value to the array we built up + val.Set(valArray) + + // If there were errors, we return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + + // If the type of the value to write to and the data match directly, + // then we just set it directly instead of recursing into the structure. + if dataVal.Type() == val.Type() { + val.Set(dataVal) + return nil + } + + dataValKind := dataVal.Kind() + switch dataValKind { + case reflect.Map: + return d.decodeStructFromMap(name, dataVal, val) + + case reflect.Struct: + // Not the most efficient way to do this but we can optimize later if + // we want to. To convert from struct to struct we go to map first + // as an intermediary. + + // Make a new map to hold our result + mapType := reflect.TypeOf((map[string]interface{})(nil)) + mval := reflect.MakeMap(mapType) + + // Creating a pointer to a map so that other methods can completely + // overwrite the map if need be (looking at you decodeMapFromMap). The + // indirection allows the underlying map to be settable (CanSet() == true) + // where as reflect.MakeMap returns an unsettable map. + addrVal := reflect.New(mval.Type()) + + reflect.Indirect(addrVal).Set(mval) + if err := d.decodeMapFromStruct(name, dataVal, reflect.Indirect(addrVal), mval); err != nil { + return err + } + + result := d.decodeStructFromMap(name, reflect.Indirect(addrVal), val) + return result + + default: + return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + } +} + +func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error { + dataValType := dataVal.Type() + if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { + return fmt.Errorf( + "'%s' needs a map with string keys, has '%s' keys", + name, dataValType.Key().Kind()) + } + + dataValKeys := make(map[reflect.Value]struct{}) + dataValKeysUnused := make(map[interface{}]struct{}) + for _, dataValKey := range dataVal.MapKeys() { + dataValKeys[dataValKey] = struct{}{} + dataValKeysUnused[dataValKey.Interface()] = struct{}{} + } + + targetValKeysUnused := make(map[interface{}]struct{}) + errors := make([]string, 0) + + // This slice will keep track of all the structs we'll be decoding. + // There can be more than one struct if there are embedded structs + // that are squashed. + structs := make([]reflect.Value, 1, 5) + structs[0] = val + + // Compile the list of all the fields that we're going to be decoding + // from all the structs. + type field struct { + field reflect.StructField + val reflect.Value + } + + // remainField is set to a valid field set with the "remain" tag if + // we are keeping track of remaining values. + var remainField *field + + fields := []field{} + for len(structs) > 0 { + structVal := structs[0] + structs = structs[1:] + + structType := structVal.Type() + + for i := 0; i < structType.NumField(); i++ { + fieldType := structType.Field(i) + fieldVal := structVal.Field(i) + if fieldVal.Kind() == reflect.Ptr && fieldVal.Elem().Kind() == reflect.Struct { + // Handle embedded struct pointers as embedded structs. + fieldVal = fieldVal.Elem() + } + + // If "squash" is specified in the tag, we squash the field down. + squash := d.config.Squash && fieldVal.Kind() == reflect.Struct && fieldType.Anonymous + remain := false + + // We always parse the tags cause we're looking for other tags too + tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") + for _, tag := range tagParts[1:] { + if tag == "squash" { + squash = true + break + } + + if tag == "remain" { + remain = true + break + } + } + + if squash { + if fieldVal.Kind() != reflect.Struct { + errors = appendErrors(errors, + fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind())) + } else { + structs = append(structs, fieldVal) + } + continue + } + + // Build our field + if remain { + remainField = &field{fieldType, fieldVal} + } else { + // Normal struct field, store it away + fields = append(fields, field{fieldType, fieldVal}) + } + } + } + + // for fieldType, field := range fields { + for _, f := range fields { + field, fieldValue := f.field, f.val + fieldName := field.Name + + tagValue := field.Tag.Get(d.config.TagName) + tagValue = strings.SplitN(tagValue, ",", 2)[0] + if tagValue != "" { + fieldName = tagValue + } + + rawMapKey := reflect.ValueOf(fieldName) + rawMapVal := dataVal.MapIndex(rawMapKey) + if !rawMapVal.IsValid() { + // Do a slower search by iterating over each key and + // doing case-insensitive search. + for dataValKey := range dataValKeys { + mK, ok := dataValKey.Interface().(string) + if !ok { + // Not a string key + continue + } + + if d.config.MatchName(mK, fieldName) { + rawMapKey = dataValKey + rawMapVal = dataVal.MapIndex(dataValKey) + break + } + } + + if !rawMapVal.IsValid() { + // There was no matching key in the map for the value in + // the struct. Remember it for potential errors and metadata. + targetValKeysUnused[fieldName] = struct{}{} + continue + } + } + + if !fieldValue.IsValid() { + // This should never happen + panic("field is not valid") + } + + // If we can't set the field, then it is unexported or something, + // and we just continue onwards. + if !fieldValue.CanSet() { + continue + } + + // Delete the key we're using from the unused map so we stop tracking + delete(dataValKeysUnused, rawMapKey.Interface()) + + // If the name is empty string, then we're at the root, and we + // don't dot-join the fields. + if name != "" { + fieldName = name + "." + fieldName + } + + if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil { + errors = appendErrors(errors, err) + } + } + + // If we have a "remain"-tagged field and we have unused keys then + // we put the unused keys directly into the remain field. + if remainField != nil && len(dataValKeysUnused) > 0 { + // Build a map of only the unused values + remain := map[interface{}]interface{}{} + for key := range dataValKeysUnused { + remain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface() + } + + // Decode it as-if we were just decoding this map onto our map. + if err := d.decodeMap(name, remain, remainField.val); err != nil { + errors = appendErrors(errors, err) + } + + // Set the map to nil so we have none so that the next check will + // not error (ErrorUnused) + dataValKeysUnused = nil + } + + if d.config.ErrorUnused && len(dataValKeysUnused) > 0 { + keys := make([]string, 0, len(dataValKeysUnused)) + for rawKey := range dataValKeysUnused { + keys = append(keys, rawKey.(string)) + } + sort.Strings(keys) + + err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) + errors = appendErrors(errors, err) + } + + if d.config.ErrorUnset && len(targetValKeysUnused) > 0 { + keys := make([]string, 0, len(targetValKeysUnused)) + for rawKey := range targetValKeysUnused { + keys = append(keys, rawKey.(string)) + } + sort.Strings(keys) + + err := fmt.Errorf("'%s' has unset fields: %s", name, strings.Join(keys, ", ")) + errors = appendErrors(errors, err) + } + + if len(errors) > 0 { + return &Error{errors} + } + + // Add the unused keys to the list of unused keys if we're tracking metadata + if d.config.Metadata != nil { + for rawKey := range dataValKeysUnused { + key := rawKey.(string) + if name != "" { + key = name + "." + key + } + + d.config.Metadata.Unused = append(d.config.Metadata.Unused, key) + } + for rawKey := range targetValKeysUnused { + key := rawKey.(string) + if name != "" { + key = name + "." + key + } + + d.config.Metadata.Unset = append(d.config.Metadata.Unset, key) + } + } + + return nil +} + +func isEmptyValue(v reflect.Value) bool { + switch getKind(v) { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + return false +} + +func getKind(val reflect.Value) reflect.Kind { + kind := val.Kind() + + switch { + case kind >= reflect.Int && kind <= reflect.Int64: + return reflect.Int + case kind >= reflect.Uint && kind <= reflect.Uint64: + return reflect.Uint + case kind >= reflect.Float32 && kind <= reflect.Float64: + return reflect.Float32 + default: + return kind + } +} + +func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, tagName string) bool { + for i := 0; i < typ.NumField(); i++ { + f := typ.Field(i) + if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields + return true + } + if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside + return true + } + } + return false +} + +func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value { + if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { + return v + } + deref := v.Elem() + derefT := deref.Type() + if isStructTypeConvertibleToMap(derefT, true, tagName) { + return deref + } + return v +} diff --git a/vendor/github.com/mozillazg/go-httpheader/.bumpversion.cfg b/vendor/github.com/mozillazg/go-httpheader/.bumpversion.cfg new file mode 100644 index 00000000000..62e4d5feaf2 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/.bumpversion.cfg @@ -0,0 +1,7 @@ +[bumpversion] +commit = True +tag = True +current_version = 0.3.1 + +[bumpversion:file:encode.go] + diff --git a/vendor/github.com/mozillazg/go-httpheader/.gitignore b/vendor/github.com/mozillazg/go-httpheader/.gitignore new file mode 100644 index 00000000000..098e254bc85 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/.gitignore @@ -0,0 +1,27 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +dist/ +cover.html +cover.out diff --git a/vendor/github.com/mozillazg/go-httpheader/CHANGELOG.md b/vendor/github.com/mozillazg/go-httpheader/CHANGELOG.md new file mode 100644 index 00000000000..696478c1d71 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +## [0.4.0] (2023-06-29) + +* decode into embedded structs + + +## [0.3.1] (2022-04-09) + +* fix Decode: don't fill value for struct fields that don't exist in header + + +## [0.3.0] (2021-01-24) + +* add `func Decode(header http.Header, v interface{}) error` to support decoding headers into struct + +## [0.2.1] (2018-11-03) + +* add go.mod file to identify as a module + + +## [0.2.0] (2017-06-24) + +* support http.Header field. + + +## 0.1.0 (2017-06-10) + +* Initial Release + +[0.2.0]: https://github.com/mozillazg/go-httpheader/compare/v0.1.0...v0.2.0 +[0.2.1]: https://github.com/mozillazg/go-httpheader/compare/v0.2.0...v0.2.1 +[0.3.0]: https://github.com/mozillazg/go-httpheader/compare/v0.2.1...v0.3.0 +[0.3.1]: https://github.com/mozillazg/go-httpheader/compare/v0.3.0...v0.3.1 +[0.4.0]: https://github.com/mozillazg/go-httpheader/compare/v0.3.1...v0.4.0 diff --git a/vendor/github.com/mozillazg/go-httpheader/LICENSE b/vendor/github.com/mozillazg/go-httpheader/LICENSE new file mode 100644 index 00000000000..8ff7942e203 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 mozillazg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/mozillazg/go-httpheader/Makefile b/vendor/github.com/mozillazg/go-httpheader/Makefile new file mode 100644 index 00000000000..7ab8078b0b4 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/Makefile @@ -0,0 +1,15 @@ +help: + @echo "test run test" + @echo "lint run lint" + +.PHONY: test +test: + go test -race -v -cover -coverprofile cover.out + go tool cover -html=cover.out -o cover.html + +.PHONY: lint +lint: + gofmt -s -w . + goimports -w . + golint . + go vet diff --git a/vendor/github.com/mozillazg/go-httpheader/README.md b/vendor/github.com/mozillazg/go-httpheader/README.md new file mode 100644 index 00000000000..a297f7fc549 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/README.md @@ -0,0 +1,69 @@ +# go-httpheader + +go-httpheader is a Go library for encoding structs into Header fields. + +[![Build Status](https://github.com/mozillazg/go-httpheader/workflows/CI/badge.svg?branch=master)](https://github.com/mozillazg/go-httpheader/actions) +[![Coverage Status](https://coveralls.io/repos/github/mozillazg/go-httpheader/badge.svg?branch=master)](https://coveralls.io/github/mozillazg/go-httpheader?branch=master) +[![Go Report Card](https://goreportcard.com/badge/github.com/mozillazg/go-httpheader)](https://goreportcard.com/report/github.com/mozillazg/go-httpheader) +[![GoDoc](https://godoc.org/github.com/mozillazg/go-httpheader?status.svg)](https://godoc.org/github.com/mozillazg/go-httpheader) + +## install + +``` +go get github.com/mozillazg/go-httpheader +``` + + +## usage + +```go +package main + +import ( + "fmt" + "net/http" + + "github.com/mozillazg/go-httpheader" +) + +type Options struct { + hide string + ContentType string `header:"Content-Type"` + Length int + XArray []string `header:"X-Array"` + TestHide string `header:"-"` + IgnoreEmpty string `header:"X-Empty,omitempty"` + IgnoreEmptyN string `header:"X-Empty-N,omitempty"` + CustomHeader http.Header +} + +func main() { + opt := Options{ + hide: "hide", + ContentType: "application/json", + Length: 2, + XArray: []string{"test1", "test2"}, + TestHide: "hide", + IgnoreEmptyN: "n", + CustomHeader: http.Header{ + "X-Test-1": []string{"233"}, + "X-Test-2": []string{"666"}, + }, + } + h, _ := httpheader.Header(opt) + fmt.Printf("%#v", h) + // h: + // http.Header{ + // "X-Test-1": []string{"233"}, + // "X-Test-2": []string{"666"}, + // "Content-Type": []string{"application/json"}, + // "Length": []string{"2"}, + // "X-Array": []string{"test1", "test2"}, + // "X-Empty-N": []string{"n"}, + // } + + // decode + var decode Options + httpheader.Decode(h, &decode) +} +``` diff --git a/vendor/github.com/mozillazg/go-httpheader/decode.go b/vendor/github.com/mozillazg/go-httpheader/decode.go new file mode 100644 index 00000000000..19220557d62 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/decode.go @@ -0,0 +1,300 @@ +package httpheader + +import ( + "errors" + "fmt" + "net/http" + "net/textproto" + "reflect" + "strconv" + "time" +) + +// Decoder is an interface implemented by any type that wishes to decode +// itself from Header fields in a non-standard way. +type Decoder interface { + DecodeHeader(header http.Header, key string) error +} + +// Decode expects to be passed an http.Header and a struct, and parses +// header into the struct recursively using the same rules as Header (see above) +func Decode(header http.Header, v interface{}) error { + val := reflect.ValueOf(v) + if val.Kind() != reflect.Ptr || val.IsNil() { + return errors.New("v should be a pointer and should not be nil") + } + + for val.Kind() == reflect.Ptr { + val = val.Elem() + } + + if val.Kind() != reflect.Struct { + return fmt.Errorf("v is not a struct %+v", val.Kind()) + } + return parseValue(header, val) +} + +// parseValue populates the struct fields in val from the header fields. +// Embedded structs are followed recursively (using the rules defined in the +// Values function documentation) breadth-first. +func parseValue(header http.Header, val reflect.Value) error { + var embedded []reflect.Value + + typ := val.Type() + for i := 0; i < typ.NumField(); i++ { + sf := typ.Field(i) + if sf.PkgPath != "" && !sf.Anonymous { // unexported + continue + } + + sv := val.Field(i) + tag := sf.Tag.Get(tagName) + if tag == "-" { + continue + } + name, opts := parseTag(tag) + if name == "" { + if sf.Anonymous && sv.Kind() == reflect.Struct { + // save embedded struct for later processing + embedded = append(embedded, sv) + continue + } + name = sf.Name + } + + if opts.Contains("omitempty") && header.Get(name) == "" { + continue + } + + // Decoder interface + addr := sv + if addr.Kind() != reflect.Ptr && addr.Type().Name() != "" && addr.CanAddr() { + addr = addr.Addr() + } + if addr.Type().NumMethod() > 0 && addr.CanInterface() { + if m, ok := addr.Interface().(Decoder); ok { + if err := m.DecodeHeader(header, name); err != nil { + return err + } + continue + } + } + + if sv.Kind() == reflect.Ptr { + valArr, exist := headerValues(header, name) + if !exist { + continue + } + ve := reflect.New(sv.Type().Elem()) + if err := fillValues(ve, opts, valArr); err != nil { + return err + } + sv.Set(ve) + continue + } + + if sv.Type() == timeType { + valArr, exist := headerValues(header, name) + if !exist { + continue + } + if err := fillValues(sv, opts, valArr); err != nil { + return err + } + continue + } + + if sv.Kind() == reflect.Struct { + if err := parseValue(header, sv); err != nil { + return err + } + continue + } + + if sv.Kind() != reflect.Slice && sv.Kind() != reflect.Array && sv.Kind() != reflect.Interface { + vals, exist := headerValues(header, name) + if !exist { + continue + } + v := vals[0] + vals = vals[1:] + + if err := fillValues(sv, opts, []string{v}); err != nil { + return err + } + + header.Del(name) + for _, v := range vals { + header.Add(name, v) + } + continue + } + + valArr, exist := headerValues(header, name) + if !exist { + continue + } + if err := fillValues(sv, opts, valArr); err != nil { + return err + } + } + + for _, f := range embedded { + if err := parseValue(header, f); err != nil { + return err + } + } + return nil +} + +func fillValues(sv reflect.Value, opts tagOptions, valArr []string) error { + var err error + var value string + if len(valArr) > 0 { + value = valArr[0] + } + for sv.Kind() == reflect.Ptr { + sv = sv.Elem() + } + + switch sv.Kind() { + case reflect.Bool: + var v bool + if opts.Contains("int") { + v = value != "0" + } else { + v = value != "false" + } + sv.SetBool(v) + return nil + case reflect.String: + sv.SetString(value) + return nil + case reflect.Uint, reflect.Uint64: + var v uint64 + if v, err = strconv.ParseUint(value, 10, 64); err != nil { + return err + } + sv.SetUint(v) + return nil + case reflect.Uint8: + var v uint64 + if v, err = strconv.ParseUint(value, 10, 8); err != nil { + return err + } + sv.SetUint(v) + return nil + case reflect.Uint16: + var v uint64 + if v, err = strconv.ParseUint(value, 10, 16); err != nil { + return err + } + sv.SetUint(v) + return nil + case reflect.Uint32: + var v uint64 + if v, err = strconv.ParseUint(value, 10, 32); err != nil { + return err + } + sv.SetUint(v) + return nil + case reflect.Int, reflect.Int64: + var v int64 + if v, err = strconv.ParseInt(value, 10, 64); err != nil { + return err + } + sv.SetInt(v) + return nil + case reflect.Int8: + var v int64 + if v, err = strconv.ParseInt(value, 10, 8); err != nil { + return err + } + sv.SetInt(v) + return nil + case reflect.Int16: + var v int64 + if v, err = strconv.ParseInt(value, 10, 16); err != nil { + return err + } + sv.SetInt(v) + return nil + case reflect.Int32: + var v int64 + if v, err = strconv.ParseInt(value, 10, 32); err != nil { + return err + } + sv.SetInt(v) + return nil + case reflect.Float32: + var v float64 + if v, err = strconv.ParseFloat(value, 32); err != nil { + return err + } + sv.SetFloat(v) + return nil + case reflect.Float64: + var v float64 + if v, err = strconv.ParseFloat(value, 64); err != nil { + return err + } + sv.SetFloat(v) + return nil + case reflect.Slice: + v := reflect.MakeSlice(sv.Type(), len(valArr), len(valArr)) + for i, s := range valArr { + eleV := reflect.New(sv.Type().Elem()).Elem() + if err := fillValues(eleV, opts, []string{s}); err != nil { + return err + } + v.Index(i).Set(eleV) + } + sv.Set(v) + return nil + case reflect.Array: + v := reflect.Indirect(reflect.New(reflect.ArrayOf(sv.Len(), sv.Type().Elem()))) + length := len(valArr) + if sv.Len() < length { + length = sv.Len() + } + for i := 0; i < length; i++ { + eleV := reflect.New(sv.Type().Elem()).Elem() + if err := fillValues(eleV, opts, []string{valArr[i]}); err != nil { + return err + } + v.Index(i).Set(eleV) + } + sv.Set(v) + return nil + case reflect.Interface: + v := reflect.ValueOf(valArr) + sv.Set(v) + return nil + } + + if sv.Type() == timeType { + var v time.Time + if opts.Contains("unix") { + u, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + v = time.Unix(u, 0).UTC() + } else { + v, err = time.Parse(http.TimeFormat, value) + if err != nil { + return err + } + } + sv.Set(reflect.ValueOf(v)) + return nil + } + + // sv.Set(reflect.ValueOf(value)) + return nil +} + +func headerValues(h http.Header, key string) ([]string, bool) { + vs, ok := textproto.MIMEHeader(h)[textproto.CanonicalMIMEHeaderKey(key)] + return vs, ok +} diff --git a/vendor/github.com/mozillazg/go-httpheader/encode.go b/vendor/github.com/mozillazg/go-httpheader/encode.go new file mode 100644 index 00000000000..98c03f5db52 --- /dev/null +++ b/vendor/github.com/mozillazg/go-httpheader/encode.go @@ -0,0 +1,297 @@ +// Package httpheader implements encoding of structs into http.Header fields. +// +// As a simple example: +// +// type Options struct { +// ContentType string `header:"Content-Type"` +// Length int +// } +// +// opt := Options{"application/json", 2} +// h, _ := httpheader.Header(opt) +// fmt.Printf("%#v", h) +// // will output: +// // http.Header{"Content-Type":[]string{"application/json"},"Length":[]string{"2"}} +// +// The exact mapping between Go values and http.Header is described in the +// documentation for the Header() function. +package httpheader + +import ( + "fmt" + "net/http" + "reflect" + "strconv" + "strings" + "time" +) + +const tagName = "header" + +// Version ... +const Version = "0.3.1" + +var timeType = reflect.TypeOf(time.Time{}) +var headerType = reflect.TypeOf(http.Header{}) + +var encoderType = reflect.TypeOf(new(Encoder)).Elem() + +// Encoder is an interface implemented by any type that wishes to encode +// itself into Header fields in a non-standard way. +type Encoder interface { + EncodeHeader(key string, v *http.Header) error +} + +// Header returns the http.Header encoding of v. +// +// Header expects to be passed a struct, and traverses it recursively using the +// following encoding rules. +// +// Each exported struct field is encoded as a Header field unless +// +// - the field's tag is "-", or +// - the field is empty and its tag specifies the "omitempty" option +// +// The empty values are false, 0, any nil pointer or interface value, any array +// slice, map, or string of length zero, and any time.Time that returns true +// for IsZero(). +// +// The Header field name defaults to the struct field name but can be +// specified in the struct field's tag value. The "header" key in the struct +// field's tag value is the key name, followed by an optional comma and +// options. For example: +// +// // Field is ignored by this package. +// Field int `header:"-"` +// +// // Field appears as Header field "X-Name". +// Field int `header:"X-Name"` +// +// // Field appears as Header field "X-Name" and the field is omitted if +// // its value is empty +// Field int `header:"X-Name,omitempty"` +// +// // Field appears as Header field "Field" (the default), but the field +// // is skipped if empty. Note the leading comma. +// Field int `header:",omitempty"` +// +// For encoding individual field values, the following type-dependent rules +// apply: +// +// Boolean values default to encoding as the strings "true" or "false". +// Including the "int" option signals that the field should be encoded as the +// strings "1" or "0". +// +// time.Time values default to encoding as RFC1123("Mon, 02 Jan 2006 15:04:05 GMT") +// timestamps. Including the "unix" option signals that the field should be +// encoded as a Unix time (see time.Unix()) +// +// Slice and Array values default to encoding as multiple Header values of the +// same name. example: +// X-Name: []string{"Tom", "Jim"}, etc. +// +// http.Header values will be used to extend the Header fields. +// +// Anonymous struct fields are usually encoded as if their inner exported +// fields were fields in the outer struct, subject to the standard Go +// visibility rules. An anonymous struct field with a name given in its Header +// tag is treated as having that name, rather than being anonymous. +// +// Non-nil pointer values are encoded as the value pointed to. +// +// All other values are encoded using their default string representation. +// +// Multiple fields that encode to the same Header filed name will be included +// as multiple Header values of the same name. +func Header(v interface{}) (http.Header, error) { + h := make(http.Header) + val := reflect.ValueOf(v) + for val.Kind() == reflect.Ptr { + if val.IsNil() { + return h, nil + } + val = val.Elem() + } + + if v == nil { + return h, nil + } + + if val.Kind() != reflect.Struct { + return nil, fmt.Errorf("httpheader: Header() expects struct input. Got %v", val.Kind()) + } + + err := reflectValue(h, val) + return h, err +} + +// reflectValue populates the header fields from the struct fields in val. +// Embedded structs are followed recursively (using the rules defined in the +// Values function documentation) breadth-first. +func reflectValue(header http.Header, val reflect.Value) error { + var embedded []reflect.Value + + typ := val.Type() + for i := 0; i < typ.NumField(); i++ { + sf := typ.Field(i) + if sf.PkgPath != "" && !sf.Anonymous { // unexported + continue + } + + sv := val.Field(i) + tag := sf.Tag.Get(tagName) + if tag == "-" { + continue + } + name, opts := parseTag(tag) + if name == "" { + if sf.Anonymous && sv.Kind() == reflect.Struct { + // save embedded struct for later processing + embedded = append(embedded, sv) + continue + } + + name = sf.Name + } + + if opts.Contains("omitempty") && isEmptyValue(sv) { + continue + } + + if sv.Type().Implements(encoderType) { + if !reflect.Indirect(sv).IsValid() { + sv = reflect.New(sv.Type().Elem()) + } + + m := sv.Interface().(Encoder) + if err := m.EncodeHeader(name, &header); err != nil { + return err + } + continue + } + + if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array { + for i := 0; i < sv.Len(); i++ { + k := name + header.Add(k, valueString(sv.Index(i), opts)) + } + continue + } + + for sv.Kind() == reflect.Ptr { + if sv.IsNil() { + break + } + sv = sv.Elem() + } + + if sv.Type() == timeType { + header.Add(name, valueString(sv, opts)) + continue + } + if sv.Type() == headerType { + h := sv.Interface().(http.Header) + for k, vs := range h { + for _, v := range vs { + header.Add(k, v) + } + } + continue + } + + if sv.Kind() == reflect.Struct { + if err := reflectValue(header, sv); err != nil { + return err + } + continue + } + + header.Add(name, valueString(sv, opts)) + } + + for _, f := range embedded { + if err := reflectValue(header, f); err != nil { + return err + } + } + + return nil +} + +// valueString returns the string representation of a value. +func valueString(v reflect.Value, opts tagOptions) string { + for v.Kind() == reflect.Ptr { + if v.IsNil() { + return "" + } + v = v.Elem() + } + + if v.Kind() == reflect.Bool && opts.Contains("int") { + if v.Bool() { + return "1" + } + return "0" + } + + if v.Type() == timeType { + t := v.Interface().(time.Time) + if opts.Contains("unix") { + return strconv.FormatInt(t.Unix(), 10) + } + return t.Format(http.TimeFormat) + } + + return fmt.Sprint(v.Interface()) +} + +// isEmptyValue checks if a value should be considered empty for the purposes +// of omitting fields with the "omitempty" option. +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + + if v.Type() == timeType { + return v.Interface().(time.Time).IsZero() + } + + return false +} + +// tagOptions is the string following a comma in a struct field's "header" tag, or +// the empty string. It does not include the leading comma. +type tagOptions []string + +// parseTag splits a struct field's header tag into its name and comma-separated +// options. +func parseTag(tag string) (string, tagOptions) { + s := strings.Split(tag, ",") + return s[0], s[1:] +} + +// Contains checks whether the tagOptions contains the specified option. +func (o tagOptions) Contains(option string) bool { + for _, s := range o { + if s == option { + return true + } + } + return false +} + +// Encode is an alias of Header function +func Encode(v interface{}) (http.Header, error) { + return Header(v) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/LICENSE.txt b/vendor/github.com/oracle/oci-go-sdk/v65/LICENSE.txt new file mode 100644 index 00000000000..a8c3183743c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/LICENSE.txt @@ -0,0 +1,102 @@ +Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. +This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl +or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + ____________________________ +Copyright (c) 2016, 2023 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +The Apache Software License, Version 2.0 +Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); You may not use this product except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. A copy of the license is also reproduced below. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +1. Definitions. +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. +END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/NOTICE.txt b/vendor/github.com/oracle/oci-go-sdk/v65/NOTICE.txt new file mode 100644 index 00000000000..55a68d59ce0 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/NOTICE.txt @@ -0,0 +1 @@ +Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. \ No newline at end of file diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/certificate_retriever.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/certificate_retriever.go new file mode 100644 index 00000000000..23fed45c284 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/certificate_retriever.go @@ -0,0 +1,262 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "bytes" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + "sync" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// x509CertificateRetriever provides an X509 certificate with the RSA private key +type x509CertificateRetriever interface { + Refresh() error + CertificatePemRaw() []byte + Certificate() *x509.Certificate + PrivateKeyPemRaw() []byte + PrivateKey() *rsa.PrivateKey +} + +// urlBasedX509CertificateRetriever retrieves PEM-encoded X509 certificates from the given URLs. +type urlBasedX509CertificateRetriever struct { + certURL string + privateKeyURL string + passphrase string + certificatePemRaw []byte + certificate *x509.Certificate + privateKeyPemRaw []byte + privateKey *rsa.PrivateKey + mux sync.Mutex + dispatcher common.HTTPRequestDispatcher +} + +func newURLBasedX509CertificateRetriever(dispatcher common.HTTPRequestDispatcher, certURL, privateKeyURL, passphrase string) x509CertificateRetriever { + return &urlBasedX509CertificateRetriever{ + certURL: certURL, + privateKeyURL: privateKeyURL, + passphrase: passphrase, + mux: sync.Mutex{}, + dispatcher: dispatcher, + } +} + +// Refresh() is failure atomic, i.e., CertificatePemRaw(), Certificate(), PrivateKeyPemRaw(), and PrivateKey() would +// return their previous values if Refresh() fails. +func (r *urlBasedX509CertificateRetriever) Refresh() error { + common.Debugln("Refreshing certificate") + + r.mux.Lock() + defer r.mux.Unlock() + + var err error + + var certificatePemRaw []byte + var certificate *x509.Certificate + if certificatePemRaw, certificate, err = r.renewCertificate(r.certURL); err != nil { + return fmt.Errorf("failed to renew certificate: %s", err.Error()) + } + + var privateKeyPemRaw []byte + var privateKey *rsa.PrivateKey + if r.privateKeyURL != "" { + if privateKeyPemRaw, privateKey, err = r.renewPrivateKey(r.privateKeyURL, r.passphrase); err != nil { + return fmt.Errorf("failed to renew private key: %s", err.Error()) + } + } + + r.certificatePemRaw = certificatePemRaw + r.certificate = certificate + r.privateKeyPemRaw = privateKeyPemRaw + r.privateKey = privateKey + return nil +} + +func (r *urlBasedX509CertificateRetriever) renewCertificate(url string) (certificatePemRaw []byte, certificate *x509.Certificate, err error) { + var body bytes.Buffer + if body, _, err = httpGet(r.dispatcher, url); err != nil { + return nil, nil, fmt.Errorf("failed to get certificate from %s: %s", url, err.Error()) + } + + certificatePemRaw = body.Bytes() + var block *pem.Block + block, _ = pem.Decode(certificatePemRaw) + if block == nil { + return nil, nil, fmt.Errorf("failed to parse the new certificate, not valid pem data") + } + + if certificate, err = x509.ParseCertificate(block.Bytes); err != nil { + return nil, nil, fmt.Errorf("failed to parse the new certificate: %s", err.Error()) + } + + return certificatePemRaw, certificate, nil +} + +func (r *urlBasedX509CertificateRetriever) renewPrivateKey(url, passphrase string) (privateKeyPemRaw []byte, privateKey *rsa.PrivateKey, err error) { + var body bytes.Buffer + if body, _, err = httpGet(r.dispatcher, url); err != nil { + return nil, nil, fmt.Errorf("failed to get private key from %s: %s", url, err.Error()) + } + + privateKeyPemRaw = body.Bytes() + if privateKey, err = common.PrivateKeyFromBytes(privateKeyPemRaw, &passphrase); err != nil { + return nil, nil, fmt.Errorf("failed to parse the new private key: %s", err.Error()) + } + + return privateKeyPemRaw, privateKey, nil +} + +func (r *urlBasedX509CertificateRetriever) CertificatePemRaw() []byte { + r.mux.Lock() + defer r.mux.Unlock() + + if r.certificatePemRaw == nil { + return nil + } + + c := make([]byte, len(r.certificatePemRaw)) + copy(c, r.certificatePemRaw) + return c +} + +func (r *urlBasedX509CertificateRetriever) Certificate() *x509.Certificate { + r.mux.Lock() + defer r.mux.Unlock() + + if r.certificate == nil { + return nil + } + + c := *r.certificate + return &c +} + +func (r *urlBasedX509CertificateRetriever) PrivateKeyPemRaw() []byte { + r.mux.Lock() + defer r.mux.Unlock() + + if r.privateKeyPemRaw == nil { + return nil + } + + c := make([]byte, len(r.privateKeyPemRaw)) + copy(c, r.privateKeyPemRaw) + return c +} + +func (r *urlBasedX509CertificateRetriever) PrivateKey() *rsa.PrivateKey { + r.mux.Lock() + defer r.mux.Unlock() + + //Nil Private keys are supported as part of a certificate + if r.privateKey == nil { + return nil + } + + c := *r.privateKey + return &c +} + +// staticCertificateRetriever serves certificates from static data +type staticCertificateRetriever struct { + Passphrase []byte + CertificatePem []byte + PrivateKeyPem []byte + certificate *x509.Certificate + privateKey *rsa.PrivateKey + mux sync.Mutex +} + +// Refresh proccess the inputs into appropiate keys and certificates +func (r *staticCertificateRetriever) Refresh() error { + r.mux.Lock() + defer r.mux.Unlock() + + certifcate, err := r.readCertificate() + if err != nil { + r.certificate = nil + return err + } + r.certificate = certifcate + + key, err := r.readPrivateKey() + if err != nil { + r.privateKey = nil + return err + } + r.privateKey = key + + return nil +} + +func (r *staticCertificateRetriever) Certificate() *x509.Certificate { + r.mux.Lock() + defer r.mux.Unlock() + + return r.certificate +} + +func (r *staticCertificateRetriever) PrivateKey() *rsa.PrivateKey { + r.mux.Lock() + defer r.mux.Unlock() + + return r.privateKey +} + +func (r *staticCertificateRetriever) CertificatePemRaw() []byte { + r.mux.Lock() + defer r.mux.Unlock() + + if r.CertificatePem == nil { + return nil + } + + c := make([]byte, len(r.CertificatePem)) + copy(c, r.CertificatePem) + return c +} + +func (r *staticCertificateRetriever) PrivateKeyPemRaw() []byte { + r.mux.Lock() + defer r.mux.Unlock() + + if r.PrivateKeyPem == nil { + return nil + } + + c := make([]byte, len(r.PrivateKeyPem)) + copy(c, r.PrivateKeyPem) + return c +} + +func (r *staticCertificateRetriever) readCertificate() (certificate *x509.Certificate, err error) { + block, _ := pem.Decode(r.CertificatePem) + if block == nil { + return nil, fmt.Errorf("failed to parse the new certificate, not valid pem data") + } + + if certificate, err = x509.ParseCertificate(block.Bytes); err != nil { + return nil, fmt.Errorf("failed to parse the new certificate: %s", err.Error()) + } + return certificate, nil +} + +func (r *staticCertificateRetriever) readPrivateKey() (*rsa.PrivateKey, error) { + if r.PrivateKeyPem == nil { + return nil, nil + } + + var pass *string + if r.Passphrase == nil { + pass = nil + } else { + ss := string(r.Passphrase) + pass = &ss + } + return common.PrivateKeyFromBytes(r.PrivateKeyPem, pass) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/configuration.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/configuration.go new file mode 100644 index 00000000000..37da71796b4 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/configuration.go @@ -0,0 +1,115 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "crypto/rsa" + "fmt" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +type instancePrincipalConfigurationProvider struct { + keyProvider instancePrincipalKeyProvider + region *common.Region +} + +// InstancePrincipalConfigurationProvider returns a configuration for instance principals +func InstancePrincipalConfigurationProvider() (common.ConfigurationProvider, error) { + return newInstancePrincipalConfigurationProvider("", nil) +} + +// InstancePrincipalConfigurationProviderForRegion returns a configuration for instance principals with a given region +func InstancePrincipalConfigurationProviderForRegion(region common.Region) (common.ConfigurationProvider, error) { + return newInstancePrincipalConfigurationProvider(region, nil) +} + +// InstancePrincipalConfigurationProviderWithCustomClient returns a configuration for instance principals using a modifier function to modify the HTTPRequestDispatcher +func InstancePrincipalConfigurationProviderWithCustomClient(modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error)) (common.ConfigurationProvider, error) { + return newInstancePrincipalConfigurationProvider("", modifier) +} + +// InstancePrincipalConfigurationForRegionWithCustomClient returns a configuration for instance principals with a given region using a modifier function to modify the HTTPRequestDispatcher +func InstancePrincipalConfigurationForRegionWithCustomClient(region common.Region, modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error)) (common.ConfigurationProvider, error) { + return newInstancePrincipalConfigurationProvider(region, modifier) +} + +func newInstancePrincipalConfigurationProvider(region common.Region, modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error)) (common.ConfigurationProvider, error) { + var err error + var keyProvider *instancePrincipalKeyProvider + if keyProvider, err = newInstancePrincipalKeyProvider(modifier); err != nil { + return nil, fmt.Errorf("failed to create a new key provider for instance principal: %s", err.Error()) + } + if len(region) > 0 { + return instancePrincipalConfigurationProvider{keyProvider: *keyProvider, region: ®ion}, nil + } + return instancePrincipalConfigurationProvider{keyProvider: *keyProvider, region: nil}, nil +} + +// InstancePrincipalConfigurationWithCerts returns a configuration for instance principals with a given region and hardcoded certificates in lieu of metadata service certs +func InstancePrincipalConfigurationWithCerts(region common.Region, leafCertificate, leafPassphrase, leafPrivateKey []byte, intermediateCertificates [][]byte) (common.ConfigurationProvider, error) { + leafCertificateRetriever := staticCertificateRetriever{Passphrase: leafPassphrase, CertificatePem: leafCertificate, PrivateKeyPem: leafPrivateKey} + + //The .Refresh() call actually reads the certificates from the inputs + err := leafCertificateRetriever.Refresh() + if err != nil { + return nil, err + } + + certificate := leafCertificateRetriever.Certificate() + + tenancyID := extractTenancyIDFromCertificate(certificate) + fedClient, err := newX509FederationClientWithCerts(region, tenancyID, leafCertificate, leafPassphrase, leafPrivateKey, intermediateCertificates, *newDispatcherModifier(nil)) + if err != nil { + return nil, err + } + + provider := instancePrincipalConfigurationProvider{ + keyProvider: instancePrincipalKeyProvider{ + Region: region, + FederationClient: fedClient, + TenancyID: tenancyID, + }, + region: ®ion, + } + return provider, nil + +} + +func (p instancePrincipalConfigurationProvider) PrivateRSAKey() (*rsa.PrivateKey, error) { + return p.keyProvider.PrivateRSAKey() +} + +func (p instancePrincipalConfigurationProvider) KeyID() (string, error) { + return p.keyProvider.KeyID() +} + +func (p instancePrincipalConfigurationProvider) TenancyOCID() (string, error) { + return p.keyProvider.TenancyOCID() +} + +func (p instancePrincipalConfigurationProvider) UserOCID() (string, error) { + return "", nil +} + +func (p instancePrincipalConfigurationProvider) KeyFingerprint() (string, error) { + return "", nil +} + +func (p instancePrincipalConfigurationProvider) Region() (string, error) { + if p.region == nil { + region := p.keyProvider.RegionForFederationClient() + common.Debugf("Region in instance principal configuration provider is nil. Returning federation clients region: %s", region) + return string(region), nil + } + return string(*p.region), nil +} + +func (p instancePrincipalConfigurationProvider) AuthType() (common.AuthConfig, error) { + return common.AuthConfig{common.InstancePrincipal, false, nil}, fmt.Errorf("unsupported, keep the interface") +} + +func (p instancePrincipalConfigurationProvider) Refreshable() bool { + return true +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/dispatcher_modifier.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/dispatcher_modifier.go new file mode 100644 index 00000000000..3ef8a33d5d2 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/dispatcher_modifier.go @@ -0,0 +1,41 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import "github.com/oracle/oci-go-sdk/v65/common" + +// dispatcherModifier gives ability to modify a HTTPRequestDispatcher before use. +type dispatcherModifier struct { + modifiers []func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error) +} + +// newDispatcherModifier creates a new dispatcherModifier with optional initial modifier (may be nil). +func newDispatcherModifier(modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error)) *dispatcherModifier { + dispatcherModifier := &dispatcherModifier{ + modifiers: make([]func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error), 0), + } + if modifier != nil { + dispatcherModifier.QueueModifier(modifier) + } + return dispatcherModifier +} + +// QueueModifier queues up a new modifier +func (c *dispatcherModifier) QueueModifier(modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error)) { + c.modifiers = append(c.modifiers, modifier) +} + +// Modify the provided HTTPRequestDispatcher with this modifier, and return the result, or error if something goes wrong +func (c *dispatcherModifier) Modify(dispatcher common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error) { + if len(c.modifiers) > 0 { + for _, modifier := range c.modifiers { + var err error + if dispatcher, err = modifier(dispatcher); err != nil { + common.Debugf("An error occurred when attempting to modify the dispatcher. Error was: %s", err.Error()) + return nil, err + } + } + } + return dispatcher, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client.go new file mode 100644 index 00000000000..7b3a8940999 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client.go @@ -0,0 +1,583 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +// Package auth provides supporting functions and structs for authentication +package auth + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + "math" + "net/http" + "os" + "strings" + "sync" + "time" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// federationClient is a client to retrieve the security token for an instance principal necessary to sign a request. +// It also provides the private key whose corresponding public key is used to retrieve the security token. +type federationClient interface { + ClaimHolder + PrivateKey() (*rsa.PrivateKey, error) + SecurityToken() (string, error) +} + +// ClaimHolder is implemented by any token interface that provides access to the security claims embedded in the token. +type ClaimHolder interface { + GetClaim(key string) (interface{}, error) +} + +type genericFederationClient struct { + SessionKeySupplier sessionKeySupplier + RefreshSecurityToken func() (securityToken, error) + + securityToken securityToken + mux sync.Mutex +} + +var _ federationClient = &genericFederationClient{} + +func (c *genericFederationClient) PrivateKey() (*rsa.PrivateKey, error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.renewKeyAndSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.SessionKeySupplier.PrivateKey(), nil +} + +func (c *genericFederationClient) SecurityToken() (token string, err error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err = c.renewKeyAndSecurityTokenIfNotValid(); err != nil { + return "", err + } + return c.securityToken.String(), nil +} + +func (c *genericFederationClient) renewKeyAndSecurityTokenIfNotValid() (err error) { + if c.securityToken == nil || !c.securityToken.Valid() { + if err = c.renewKeyAndSecurityToken(); err != nil { + return fmt.Errorf("failed to renew security token: %s", err.Error()) + } + } + return nil +} + +func (c *genericFederationClient) renewKeyAndSecurityToken() (err error) { + common.Logf("Renewing keys for file based security token at: %v\n", time.Now().Format("15:04:05.000")) + if err = c.SessionKeySupplier.Refresh(); err != nil { + return fmt.Errorf("failed to refresh session key: %s", err.Error()) + } + + common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000")) + if c.securityToken, err = c.RefreshSecurityToken(); err != nil { + return fmt.Errorf("failed to refresh security token key: %s", err.Error()) + } + common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000")) + return nil +} + +func (c *genericFederationClient) GetClaim(key string) (interface{}, error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.renewKeyAndSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.securityToken.GetClaim(key) +} + +func newFileBasedFederationClient(securityTokenPath string, supplier sessionKeySupplier) (*genericFederationClient, error) { + return &genericFederationClient{ + SessionKeySupplier: supplier, + RefreshSecurityToken: func() (token securityToken, err error) { + var content []byte + if content, err = ioutil.ReadFile(securityTokenPath); err != nil { + return nil, fmt.Errorf("failed to read security token from :%s. Due to: %s", securityTokenPath, err.Error()) + } + + var newToken securityToken + if newToken, err = newPrincipalToken(string(content)); err != nil { + return nil, fmt.Errorf("failed to read security token from :%s. Due to: %s", securityTokenPath, err.Error()) + } + + return newToken, nil + }, + }, nil +} + +func newStaticFederationClient(sessionToken string, supplier sessionKeySupplier) (*genericFederationClient, error) { + var newToken securityToken + var err error + if newToken, err = newPrincipalToken(string(sessionToken)); err != nil { + return nil, fmt.Errorf("failed to read security token. Due to: %s", err.Error()) + } + + return &genericFederationClient{ + SessionKeySupplier: supplier, + RefreshSecurityToken: func() (token securityToken, err error) { + return newToken, nil + }, + }, nil +} + +// x509FederationClient retrieves a security token from Auth service. +type x509FederationClient struct { + tenancyID string + sessionKeySupplier sessionKeySupplier + leafCertificateRetriever x509CertificateRetriever + intermediateCertificateRetrievers []x509CertificateRetriever + securityToken securityToken + authClient *common.BaseClient + mux sync.Mutex +} + +func newX509FederationClient(region common.Region, tenancyID string, leafCertificateRetriever x509CertificateRetriever, intermediateCertificateRetrievers []x509CertificateRetriever, modifier dispatcherModifier) (federationClient, error) { + client := &x509FederationClient{ + tenancyID: tenancyID, + leafCertificateRetriever: leafCertificateRetriever, + intermediateCertificateRetrievers: intermediateCertificateRetrievers, + } + client.sessionKeySupplier = newSessionKeySupplier() + authClient := newAuthClient(region, client) + + var err error + + if authClient.HTTPClient, err = modifier.Modify(authClient.HTTPClient); err != nil { + err = fmt.Errorf("failed to modify client: %s", err.Error()) + return nil, err + } + + client.authClient = authClient + return client, nil +} + +func newX509FederationClientWithCerts(region common.Region, tenancyID string, leafCertificate, leafPassphrase, leafPrivateKey []byte, intermediateCertificates [][]byte, modifier dispatcherModifier) (federationClient, error) { + intermediateRetrievers := make([]x509CertificateRetriever, len(intermediateCertificates)) + for i, c := range intermediateCertificates { + intermediateRetrievers[i] = &staticCertificateRetriever{Passphrase: []byte(""), CertificatePem: c, PrivateKeyPem: nil} + } + + client := &x509FederationClient{ + tenancyID: tenancyID, + leafCertificateRetriever: &staticCertificateRetriever{Passphrase: leafPassphrase, CertificatePem: leafCertificate, PrivateKeyPem: leafPrivateKey}, + intermediateCertificateRetrievers: intermediateRetrievers, + } + client.sessionKeySupplier = newSessionKeySupplier() + authClient := newAuthClient(region, client) + + var err error + + if authClient.HTTPClient, err = modifier.Modify(authClient.HTTPClient); err != nil { + err = fmt.Errorf("failed to modify client: %s", err.Error()) + return nil, err + } + + client.authClient = authClient + return client, nil +} + +var ( + genericHeaders = []string{"date", "(request-target)"} // "host" is not needed for the federation endpoint. Don't ask me why. + bodyHeaders = []string{"content-length", "content-type", "x-content-sha256"} +) + +func newAuthClient(region common.Region, provider common.KeyProvider) *common.BaseClient { + signer := common.RequestSigner(provider, genericHeaders, bodyHeaders) + client := common.DefaultBaseClientWithSigner(signer) + if regionURL, ok := os.LookupEnv("OCI_SDK_AUTH_CLIENT_REGION_URL"); ok { + client.Host = regionURL + } else { + client.Host = region.Endpoint("auth") + } + client.BasePath = "v1/x509" + + if common.GlobalAuthClientCircuitBreakerSetting != nil { + client.Configuration.CircuitBreaker = common.NewCircuitBreaker(common.GlobalAuthClientCircuitBreakerSetting) + } else if !common.IsEnvVarFalse("OCI_SDK_AUTH_CLIENT_CIRCUIT_BREAKER_ENABLED") { + common.Logf("Configuring DefaultAuthClientCircuitBreakerSetting for federation client") + client.Configuration.CircuitBreaker = common.NewCircuitBreaker(common.DefaultAuthClientCircuitBreakerSetting()) + } + return &client +} + +// For authClient to sign requests to X509 Federation Endpoint +func (c *x509FederationClient) KeyID() (string, error) { + tenancy := c.tenancyID + fingerprint := fingerprint(c.leafCertificateRetriever.Certificate()) + return fmt.Sprintf("%s/fed-x509/%s", tenancy, fingerprint), nil +} + +// For authClient to sign requests to X509 Federation Endpoint +func (c *x509FederationClient) PrivateRSAKey() (*rsa.PrivateKey, error) { + key := c.leafCertificateRetriever.PrivateKey() + if key == nil { + return nil, fmt.Errorf("can not read private key from leaf certificate. Likely an error in the metadata service") + } + + return key, nil +} + +func (c *x509FederationClient) PrivateKey() (*rsa.PrivateKey, error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.renewSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.sessionKeySupplier.PrivateKey(), nil +} + +func (c *x509FederationClient) SecurityToken() (token string, err error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err = c.renewSecurityTokenIfNotValid(); err != nil { + return "", err + } + return c.securityToken.String(), nil +} + +func (c *x509FederationClient) renewSecurityTokenIfNotValid() (err error) { + if c.securityToken == nil || !c.securityToken.Valid() { + if err = c.renewSecurityToken(); err != nil { + return fmt.Errorf("failed to renew security token: %s", err.Error()) + } + } + return nil +} + +func (c *x509FederationClient) renewSecurityToken() (err error) { + if err = c.sessionKeySupplier.Refresh(); err != nil { + return fmt.Errorf("failed to refresh session key: %s", err.Error()) + } + + if err = c.leafCertificateRetriever.Refresh(); err != nil { + return fmt.Errorf("failed to refresh leaf certificate: %s", err.Error()) + } + + updatedTenancyID := extractTenancyIDFromCertificate(c.leafCertificateRetriever.Certificate()) + if c.tenancyID != updatedTenancyID { + err = fmt.Errorf("unexpected update of tenancy OCID in the leaf certificate. Previous tenancy: %s, Updated: %s", c.tenancyID, updatedTenancyID) + return + } + + for _, retriever := range c.intermediateCertificateRetrievers { + if err = retriever.Refresh(); err != nil { + return fmt.Errorf("failed to refresh intermediate certificate: %s", err.Error()) + } + } + + common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000")) + if c.securityToken, err = c.getSecurityToken(); err != nil { + return fmt.Errorf("failed to get security token: %s", err.Error()) + } + common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000")) + + return nil +} + +func (c *x509FederationClient) getSecurityToken() (securityToken, error) { + var err error + var httpRequest http.Request + var httpResponse *http.Response + defer common.CloseBodyIfValid(httpResponse) + + for retry := 0; retry < 3; retry++ { + request := c.makeX509FederationRequest() + + if httpRequest, err = common.MakeDefaultHTTPRequestWithTaggedStruct(http.MethodPost, "", request); err != nil { + return nil, fmt.Errorf("failed to make http request: %s", err.Error()) + } + + if httpResponse, err = c.authClient.Call(context.Background(), &httpRequest); err == nil { + break + } + // Don't retry on 4xx errors + if httpResponse != nil && httpResponse.StatusCode >= 400 && httpResponse.StatusCode <= 499 { + return nil, fmt.Errorf("error %s returned by auth service: %s", httpResponse.Status, err.Error()) + } + nextDuration := time.Duration(1000.0*(math.Pow(2.0, float64(retry)))) * time.Millisecond + time.Sleep(nextDuration) + } + if err != nil { + return nil, fmt.Errorf("failed to call: %s", err.Error()) + } + + response := x509FederationResponse{} + if err = common.UnmarshalResponse(httpResponse, &response); err != nil { + return nil, fmt.Errorf("failed to unmarshal the response: %s", err.Error()) + } + + return newPrincipalToken(response.Token.Token) +} + +func (c *x509FederationClient) GetClaim(key string) (interface{}, error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.renewSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.securityToken.GetClaim(key) +} + +type x509FederationRequest struct { + X509FederationDetails `contributesTo:"body"` +} + +// X509FederationDetails x509 federation details +type X509FederationDetails struct { + Certificate string `mandatory:"true" json:"certificate,omitempty"` + PublicKey string `mandatory:"true" json:"publicKey,omitempty"` + IntermediateCertificates []string `mandatory:"false" json:"intermediateCertificates,omitempty"` +} + +type x509FederationResponse struct { + Token `presentIn:"body"` +} + +// Token token +type Token struct { + Token string `mandatory:"true" json:"token,omitempty"` +} + +func (c *x509FederationClient) makeX509FederationRequest() *x509FederationRequest { + certificate := c.sanitizeCertificateString(string(c.leafCertificateRetriever.CertificatePemRaw())) + publicKey := c.sanitizeCertificateString(string(c.sessionKeySupplier.PublicKeyPemRaw())) + var intermediateCertificates []string + for _, retriever := range c.intermediateCertificateRetrievers { + intermediateCertificates = append(intermediateCertificates, c.sanitizeCertificateString(string(retriever.CertificatePemRaw()))) + } + + details := X509FederationDetails{ + Certificate: certificate, + PublicKey: publicKey, + IntermediateCertificates: intermediateCertificates, + } + return &x509FederationRequest{details} +} + +func (c *x509FederationClient) sanitizeCertificateString(certString string) string { + certString = strings.Replace(certString, "-----BEGIN CERTIFICATE-----", "", -1) + certString = strings.Replace(certString, "-----END CERTIFICATE-----", "", -1) + certString = strings.Replace(certString, "-----BEGIN PUBLIC KEY-----", "", -1) + certString = strings.Replace(certString, "-----END PUBLIC KEY-----", "", -1) + certString = strings.Replace(certString, "\n", "", -1) + return certString +} + +// sessionKeySupplier provides an RSA keypair which can be re-generated by calling Refresh(). +type sessionKeySupplier interface { + Refresh() error + PrivateKey() *rsa.PrivateKey + PublicKeyPemRaw() []byte +} + +// genericKeySupplier implements sessionKeySupplier and provides an arbitrary refresh mechanism +type genericKeySupplier struct { + RefreshFn func() (*rsa.PrivateKey, []byte, error) + + privateKey *rsa.PrivateKey + publicKeyPemRaw []byte +} + +func (s genericKeySupplier) PrivateKey() *rsa.PrivateKey { + if s.privateKey == nil { + return nil + } + + c := *s.privateKey + return &c +} + +func (s genericKeySupplier) PublicKeyPemRaw() []byte { + if s.publicKeyPemRaw == nil { + return nil + } + + c := make([]byte, len(s.publicKeyPemRaw)) + copy(c, s.publicKeyPemRaw) + return c +} + +func (s *genericKeySupplier) Refresh() (err error) { + privateKey, publicPem, err := s.RefreshFn() + if err != nil { + return err + } + + s.privateKey = privateKey + s.publicKeyPemRaw = publicPem + return nil +} + +// create a sessionKeySupplier that reads keys from file every time it refreshes +func newFileBasedKeySessionSupplier(privateKeyPemPath string, passphrasePath *string) (*genericKeySupplier, error) { + return &genericKeySupplier{ + RefreshFn: func() (*rsa.PrivateKey, []byte, error) { + var err error + var passContent []byte + if passphrasePath != nil { + if passContent, err = ioutil.ReadFile(*passphrasePath); err != nil { + return nil, nil, fmt.Errorf("can not read passphrase from file: %s, due to %s", *passphrasePath, err.Error()) + } + } + + var keyPemContent []byte + if keyPemContent, err = ioutil.ReadFile(privateKeyPemPath); err != nil { + return nil, nil, fmt.Errorf("can not read private privateKey pem from file: %s, due to %s", privateKeyPemPath, err.Error()) + } + + var privateKey *rsa.PrivateKey + if privateKey, err = common.PrivateKeyFromBytesWithPassword(keyPemContent, passContent); err != nil { + return nil, nil, fmt.Errorf("can not create private privateKey from contents of: %s, due to: %s", privateKeyPemPath, err.Error()) + } + + var publicKeyAsnBytes []byte + if publicKeyAsnBytes, err = x509.MarshalPKIXPublicKey(privateKey.Public()); err != nil { + return nil, nil, fmt.Errorf("failed to marshal the public part of the new keypair: %s", err.Error()) + } + publicKeyPemRaw := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: publicKeyAsnBytes, + }) + return privateKey, publicKeyPemRaw, nil + }, + }, nil +} + +func newStaticKeySessionSupplier(privateKeyPemContent, passphrase []byte) (*genericKeySupplier, error) { + var err error + var privateKey *rsa.PrivateKey + + if privateKey, err = common.PrivateKeyFromBytesWithPassword(privateKeyPemContent, passphrase); err != nil { + return nil, fmt.Errorf("can not create private privateKey, due to: %s", err.Error()) + } + + var publicKeyAsnBytes []byte + if publicKeyAsnBytes, err = x509.MarshalPKIXPublicKey(privateKey.Public()); err != nil { + return nil, fmt.Errorf("failed to marshal the public part of the new keypair: %s", err.Error()) + } + publicKeyPemRaw := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: publicKeyAsnBytes, + }) + + return &genericKeySupplier{ + RefreshFn: func() (key *rsa.PrivateKey, bytes []byte, err error) { + return privateKey, publicKeyPemRaw, nil + }, + }, nil +} + +// inMemorySessionKeySupplier implements sessionKeySupplier to vend an RSA keypair. +// Refresh() generates a new RSA keypair with a random source, and keeps it in memory. +// +// inMemorySessionKeySupplier is not thread-safe. +type inMemorySessionKeySupplier struct { + keySize int + privateKey *rsa.PrivateKey + publicKeyPemRaw []byte +} + +// newSessionKeySupplier creates and returns a sessionKeySupplier instance which generates key pairs of size 2048. +func newSessionKeySupplier() sessionKeySupplier { + return &inMemorySessionKeySupplier{keySize: 2048} +} + +// Refresh() is failure atomic, i.e., PrivateKey() and PublicKeyPemRaw() would return their previous values +// if Refresh() fails. +func (s *inMemorySessionKeySupplier) Refresh() (err error) { + common.Debugln("Refreshing session key") + + var privateKey *rsa.PrivateKey + privateKey, err = rsa.GenerateKey(rand.Reader, s.keySize) + if err != nil { + return fmt.Errorf("failed to generate a new keypair: %s", err) + } + + var publicKeyAsnBytes []byte + if publicKeyAsnBytes, err = x509.MarshalPKIXPublicKey(privateKey.Public()); err != nil { + return fmt.Errorf("failed to marshal the public part of the new keypair: %s", err.Error()) + } + publicKeyPemRaw := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: publicKeyAsnBytes, + }) + + s.privateKey = privateKey + s.publicKeyPemRaw = publicKeyPemRaw + return nil +} + +func (s *inMemorySessionKeySupplier) PrivateKey() *rsa.PrivateKey { + if s.privateKey == nil { + return nil + } + + c := *s.privateKey + return &c +} + +func (s *inMemorySessionKeySupplier) PublicKeyPemRaw() []byte { + if s.publicKeyPemRaw == nil { + return nil + } + + c := make([]byte, len(s.publicKeyPemRaw)) + copy(c, s.publicKeyPemRaw) + return c +} + +type securityToken interface { + fmt.Stringer + Valid() bool + + ClaimHolder +} + +type principalToken struct { + tokenString string + jwtToken *jwtToken +} + +func newPrincipalToken(tokenString string) (newToken securityToken, err error) { + var jwtToken *jwtToken + if jwtToken, err = parseJwt(tokenString); err != nil { + return nil, fmt.Errorf("failed to parse the token string \"%s\": %s", tokenString, err.Error()) + } + return &principalToken{tokenString, jwtToken}, nil +} + +func (t *principalToken) String() string { + return t.tokenString +} + +func (t *principalToken) Valid() bool { + return !t.jwtToken.expired() +} + +var ( + // ErrNoSuchClaim is returned when a token does not hold the claim sought + ErrNoSuchClaim = errors.New("no such claim") +) + +func (t *principalToken) GetClaim(key string) (interface{}, error) { + if value, ok := t.jwtToken.payload[key]; ok { + return value, nil + } + return nil, ErrNoSuchClaim +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client_oke_workload_identity.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client_oke_workload_identity.go new file mode 100644 index 00000000000..f4f24cec93b --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/federation_client_oke_workload_identity.go @@ -0,0 +1,221 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "bytes" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "sync" + "time" + + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/common/utils" +) + +const ( + rpstValidForRatio float64 = 0.5 +) + +// Workload RPST Issuance Service (WRIS) +// x509FederationClientForOkeWorkloadIdentity retrieves a security token from Auth service. +type x509FederationClientForOkeWorkloadIdentity struct { + tenancyID string + sessionKeySupplier sessionKeySupplier + securityToken securityToken + authClient *common.BaseClient + mux sync.Mutex + proxymuxEndpoint string + saTokenProvider ServiceAccountTokenProvider + kubernetesServiceAccountCert *x509.CertPool +} + +func newX509FederationClientForOkeWorkloadIdentity(endpoint string, saTokenProvider ServiceAccountTokenProvider, + kubernetesServiceAccountCert *x509.CertPool) (federationClient, error) { + client := &x509FederationClientForOkeWorkloadIdentity{ + proxymuxEndpoint: endpoint, + saTokenProvider: saTokenProvider, + kubernetesServiceAccountCert: kubernetesServiceAccountCert, + } + + client.sessionKeySupplier = newSessionKeySupplier() + + return client, nil +} + +func (c *x509FederationClientForOkeWorkloadIdentity) renewSecurityToken() (err error) { + if err = c.sessionKeySupplier.Refresh(); err != nil { + return fmt.Errorf("failed to refresh session key: %s", err.Error()) + } + + common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000")) + if c.securityToken, err = c.getSecurityToken(); err != nil { + return fmt.Errorf("failed to get security token: %s", err.Error()) + } + common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000")) + + return nil +} + +type workloadIdentityRequestPayload struct { + Podkey string `json:"podKey"` +} +type token struct { + Token string +} + +// getSecurityToken get security token from Proxymux +func (c *x509FederationClientForOkeWorkloadIdentity) getSecurityToken() (securityToken, error) { + client := http.Client{ + Timeout: 30 * time.Second, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: c.kubernetesServiceAccountCert, + }, + }, + } + + publicKey := string(c.sessionKeySupplier.PublicKeyPemRaw()) + common.Logf("Public Key for OKE Workload Identity is:", publicKey) + rawPayload := workloadIdentityRequestPayload{Podkey: publicKey} + payload, err := json.Marshal(rawPayload) + if err != nil { + return nil, fmt.Errorf("error getting security token%s", err) + } + + common.Logf("Payload for OKE Workload Identity is:", string(payload)) + request, err := http.NewRequest(http.MethodPost, c.proxymuxEndpoint, bytes.NewBuffer(payload)) + + if err != nil { + common.Logf("error %s", err) + return nil, fmt.Errorf("error getting security token %s", err) + } + + kubernetesServiceAccountToken, err := c.saTokenProvider.ServiceAccountToken() + if err != nil { + common.Logf("error %s", err) + return nil, fmt.Errorf("error getting service account token %s", err) + } + + common.Logf("Service Account Token for OKE Workload Identity is: ", kubernetesServiceAccountToken) + request.Header.Add("Authorization", "Bearer "+kubernetesServiceAccountToken) + request.Header.Set("Content-Type", "application/json") + opcRequestID := utils.GenerateOpcRequestID() + request.Header.Set("opc-request-id", opcRequestID) + + response, err := client.Do(request) + if err != nil { + return nil, fmt.Errorf("error %s", err) + } + + var body bytes.Buffer + defer func(body io.ReadCloser) { + err := body.Close() + if err != nil { + common.Logf("error %s", err) + } + }(response.Body) + + statusCode := response.StatusCode + if statusCode != http.StatusOK { + if statusCode == http.StatusForbidden { + return nil, fmt.Errorf("please ensure the cluster type is enhanced: Status: %s, Message: %s", + response.Status, body.String()) + } else { + return nil, fmt.Errorf("failed to get a RPST token from Proxymux: URL: %s, Status: %s, Message: %s", + c.proxymuxEndpoint, response.Status, body.String()) + } + + } + + if _, err = body.ReadFrom(response.Body); err != nil { + return nil, fmt.Errorf("error reading body from Proxymux response: %s", err) + } + + rawBody := body.String() + rawBody = rawBody[1 : len(rawBody)-1] + decodedBodyStr, err := base64.StdEncoding.DecodeString(rawBody) + if err != nil { + return nil, fmt.Errorf("error decoding Proxymux response using base64 scheme: %s", err) + } + + var parsedBody token + err = json.Unmarshal(decodedBodyStr, &parsedBody) + if err != nil { + return nil, fmt.Errorf("error parsing Proxymux response body: %s", err) + } + + token := parsedBody.Token + if len(token) == 0 { + return nil, fmt.Errorf("invalid (empty) token received from Proxymux") + } + if len(token) < 3 { + return nil, fmt.Errorf("invalid token received from Proxymux") + } + + return newPrincipalToken(token[3:]) +} + +func (c *x509FederationClientForOkeWorkloadIdentity) PrivateKey() (*rsa.PrivateKey, error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.renewSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.sessionKeySupplier.PrivateKey(), nil +} + +func (c *x509FederationClientForOkeWorkloadIdentity) SecurityToken() (token string, err error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err = c.renewSecurityTokenIfNotValid(); err != nil { + return "", err + } + return c.securityToken.String(), nil +} + +func (c *x509FederationClientForOkeWorkloadIdentity) renewSecurityTokenIfNotValid() (err error) { + if c.securityToken == nil || !c.securityToken.Valid() { + if err = c.renewSecurityToken(); err != nil { + return fmt.Errorf("failed to renew security token: %s", err.Error()) + } + } + return nil +} + +type workloadIdentityPrincipalToken struct { + principalToken +} + +func (t *workloadIdentityPrincipalToken) Valid() bool { + // TODO: read rpstValidForRatio from rpst token + issuedAt := int64(t.jwtToken.payload["iat"].(float64)) + expiredAt := int64(t.jwtToken.payload["exp"].(float64)) + softExpiredAt := issuedAt + int64(float64(expiredAt-issuedAt)*rpstValidForRatio) + softExpiredAtTime := time.Unix(softExpiredAt, 0) + now := time.Now().Unix() + int64(bufferTimeBeforeTokenExpiration.Seconds()) + expired := softExpiredAt <= now + if expired { + common.Debugf("Token expired at: %v", softExpiredAtTime.Format("15:04:05.000")) + } + return !expired +} + +func (c *x509FederationClientForOkeWorkloadIdentity) GetClaim(key string) (interface{}, error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.renewSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.securityToken.GetClaim(key) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_delegation_token_provider.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_delegation_token_provider.go new file mode 100644 index 00000000000..fdbdcf19232 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_delegation_token_provider.go @@ -0,0 +1,95 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "crypto/rsa" + "fmt" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +type instancePrincipalDelegationTokenConfigurationProvider struct { + instancePrincipalKeyProvider instancePrincipalKeyProvider + delegationToken string + region *common.Region +} +type instancePrincipalDelegationTokenError struct { + err error +} + +func (ipe instancePrincipalDelegationTokenError) Error() string { + return fmt.Sprintf("%s\nInstance principals delegation token authentication can only be used on specific OCI services. Please confirm this code is running on the correct environment", ipe.err.Error()) +} + +// InstancePrincipalDelegationTokenConfigurationProvider returns a configuration for obo token instance principals +func InstancePrincipalDelegationTokenConfigurationProvider(delegationToken *string) (common.ConfigurationProvider, error) { + if delegationToken == nil || len(*delegationToken) == 0 { + return nil, instancePrincipalDelegationTokenError{err: fmt.Errorf("failed to create a delagationTokenConfigurationProvider: token is a mandatory input parameter")} + } + return newInstancePrincipalDelegationTokenConfigurationProvider(delegationToken, "", nil) +} + +// InstancePrincipalDelegationTokenConfigurationProviderForRegion returns a configuration for obo token instance principals with a given region +func InstancePrincipalDelegationTokenConfigurationProviderForRegion(delegationToken *string, region common.Region) (common.ConfigurationProvider, error) { + if delegationToken == nil || len(*delegationToken) == 0 { + return nil, instancePrincipalDelegationTokenError{err: fmt.Errorf("failed to create a delagationTokenConfigurationProvider: token is a mandatory input parameter")} + } + return newInstancePrincipalDelegationTokenConfigurationProvider(delegationToken, region, nil) +} + +func newInstancePrincipalDelegationTokenConfigurationProvider(delegationToken *string, region common.Region, modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, + error)) (common.ConfigurationProvider, error) { + + keyProvider, err := newInstancePrincipalKeyProvider(modifier) + if err != nil { + return nil, instancePrincipalDelegationTokenError{err: fmt.Errorf("failed to create a new key provider for instance principal: %s", err.Error())} + } + if len(region) > 0 { + return instancePrincipalDelegationTokenConfigurationProvider{*keyProvider, *delegationToken, ®ion}, err + } + return instancePrincipalDelegationTokenConfigurationProvider{*keyProvider, *delegationToken, nil}, err +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) getInstancePrincipalDelegationTokenConfigurationProvider() (instancePrincipalDelegationTokenConfigurationProvider, error) { + return p, nil +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) PrivateRSAKey() (*rsa.PrivateKey, error) { + return p.instancePrincipalKeyProvider.PrivateRSAKey() +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) KeyID() (string, error) { + return p.instancePrincipalKeyProvider.KeyID() +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) TenancyOCID() (string, error) { + return p.instancePrincipalKeyProvider.TenancyOCID() +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) UserOCID() (string, error) { + return "", nil +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) KeyFingerprint() (string, error) { + return "", nil +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) Region() (string, error) { + if p.region == nil { + region := p.instancePrincipalKeyProvider.RegionForFederationClient() + common.Debugf("Region in instance principal delegation token configuration provider is nil. Returning federation clients region: %s", region) + return string(region), nil + } + return string(*p.region), nil +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) AuthType() (common.AuthConfig, error) { + token := p.delegationToken + return common.AuthConfig{common.InstancePrincipalDelegationToken, false, &token}, nil +} + +func (p instancePrincipalDelegationTokenConfigurationProvider) Refreshable() bool { + return true +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_key_provider.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_key_provider.go new file mode 100644 index 00000000000..8b1be2a6cbe --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/instance_principal_key_provider.go @@ -0,0 +1,169 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "bytes" + "crypto/rsa" + "fmt" + "math/rand" + "net/http" + "os" + "time" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +const ( + defaultMetadataBaseURL = `http://169.254.169.254/opc/v2` + metadataBaseURLEnvVar = `OCI_METADATA_BASE_URL` + regionPath = `/instance/region` + leafCertificatePath = `/identity/cert.pem` + leafCertificateKeyPath = `/identity/key.pem` + intermediateCertificatePath = `/identity/intermediate.pem` + + leafCertificateKeyPassphrase = `` // No passphrase for the private key for Compute instances + intermediateCertificateKeyURL = `` + intermediateCertificateKeyPassphrase = `` // No passphrase for the private key for Compute instances +) + +var ( + regionURL, leafCertificateURL, leafCertificateKeyURL, intermediateCertificateURL string +) + +// instancePrincipalKeyProvider implements KeyProvider to provide a key ID and its corresponding private key +// for an instance principal by getting a security token via x509FederationClient. +// +// The region name of the endpoint for x509FederationClient is obtained from the metadata service on the compute +// instance. +type instancePrincipalKeyProvider struct { + Region common.Region + FederationClient federationClient + TenancyID string +} + +type instancePrincipalError struct { + err error +} + +func (ipe instancePrincipalError) Error() string { + return fmt.Sprintf("%s\nInstance principals authentication can only be used on OCI compute instances. Please confirm this code is running on an OCI compute instance and you have set up the policy properly.\nSee https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm for more info", ipe.err.Error()) +} + +// newInstancePrincipalKeyProvider creates and returns an instancePrincipalKeyProvider instance based on +// x509FederationClient. +// +// NOTE: There is a race condition between PrivateRSAKey() and KeyID(). These two pieces are tightly coupled; KeyID +// includes a security token obtained from Auth service by giving a public key which is paired with PrivateRSAKey. +// The x509FederationClient caches the security token in memory until it is expired. Thus, even if a client obtains a +// KeyID that is not expired at the moment, the PrivateRSAKey that the client acquires at a next moment could be +// invalid because the KeyID could be already expired. +func newInstancePrincipalKeyProvider(modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error)) (provider *instancePrincipalKeyProvider, err error) { + updateX509CertRetrieverURLParas(getMetadataBaseURL()) + clientModifier := newDispatcherModifier(modifier) + + client, err := clientModifier.Modify(&http.Client{}) + if err != nil { + err = fmt.Errorf("failed to modify client: %s", err.Error()) + return nil, instancePrincipalError{err: err} + } + + var region common.Region + + if region, err = getRegionForFederationClient(client, regionURL); err != nil { + err = fmt.Errorf("failed to get the region name from %s: %s", regionURL, err.Error()) + common.Logf("%v\n", err) + return nil, instancePrincipalError{err: err} + } + + leafCertificateRetriever := newURLBasedX509CertificateRetriever(client, + leafCertificateURL, leafCertificateKeyURL, leafCertificateKeyPassphrase) + intermediateCertificateRetrievers := []x509CertificateRetriever{ + newURLBasedX509CertificateRetriever( + client, intermediateCertificateURL, intermediateCertificateKeyURL, + intermediateCertificateKeyPassphrase), + } + + if err = leafCertificateRetriever.Refresh(); err != nil { + err = fmt.Errorf("failed to refresh the leaf certificate: %s", err.Error()) + return nil, instancePrincipalError{err: err} + } + tenancyID := extractTenancyIDFromCertificate(leafCertificateRetriever.Certificate()) + + federationClient, err := newX509FederationClient(region, tenancyID, leafCertificateRetriever, intermediateCertificateRetrievers, *clientModifier) + + if err != nil { + err = fmt.Errorf("failed to create federation client: %s", err.Error()) + return nil, instancePrincipalError{err: err} + } + + provider = &instancePrincipalKeyProvider{FederationClient: federationClient, TenancyID: tenancyID, Region: region} + return +} + +func getRegionForFederationClient(dispatcher common.HTTPRequestDispatcher, url string) (r common.Region, err error) { + var body bytes.Buffer + var statusCode int + MaxRetriesFederationClient := 8 + for currTry := 0; currTry < MaxRetriesFederationClient; currTry++ { + body, statusCode, err = httpGet(dispatcher, url) + if err == nil && statusCode == 200 { + return common.StringToRegion(body.String()), nil + } + common.Logf("Error in getting region from url: %s, Status code: %v, Error: %s", url, statusCode, err.Error()) + nextDuration := time.Duration(float64(int(1)< 30*time.Second { + nextDuration = 30*time.Second + time.Duration(rand.Float64())*time.Second + } + common.Logf("Retrying for getRegionForFederationClinet function, current retry count is:%v, sleep after %v", currTry+1, nextDuration) + time.Sleep(nextDuration) + } + return +} + +func updateX509CertRetrieverURLParas(baseURL string) { + regionURL = baseURL + regionPath + leafCertificateURL = baseURL + leafCertificatePath + leafCertificateKeyURL = baseURL + leafCertificateKeyPath + intermediateCertificateURL = baseURL + intermediateCertificatePath +} + +func (p *instancePrincipalKeyProvider) RegionForFederationClient() common.Region { + return p.Region +} + +func (p *instancePrincipalKeyProvider) PrivateRSAKey() (privateKey *rsa.PrivateKey, err error) { + if privateKey, err = p.FederationClient.PrivateKey(); err != nil { + err = fmt.Errorf("failed to get private key: %s", err.Error()) + return nil, instancePrincipalError{err: err} + } + return privateKey, nil +} + +func (p *instancePrincipalKeyProvider) KeyID() (string, error) { + var securityToken string + var err error + if securityToken, err = p.FederationClient.SecurityToken(); err != nil { + err = fmt.Errorf("failed to get security token: %s", err.Error()) + return "", instancePrincipalError{err: err} + } + return fmt.Sprintf("ST$%s", securityToken), nil +} + +func (p *instancePrincipalKeyProvider) TenancyOCID() (string, error) { + return p.TenancyID, nil +} + +func (p *instancePrincipalKeyProvider) Refreshable() bool { + return true +} + +// Gets the Meta Data Base url from the Environment variable SNTL_METADATA_BASE_URL +// If it is not present, returns default value instead +func getMetadataBaseURL() string { + if baseURL := os.Getenv(metadataBaseURLEnvVar); baseURL != "" { + return baseURL + } + return defaultMetadataBaseURL +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/jwt.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/jwt.go new file mode 100644 index 00000000000..8d6485db11c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/jwt.go @@ -0,0 +1,71 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +type jwtToken struct { + raw string + header map[string]interface{} + payload map[string]interface{} +} + +const bufferTimeBeforeTokenExpiration = 5 * time.Minute + +func (t *jwtToken) expired() bool { + exp := int64(t.payload["exp"].(float64)) + expTime := time.Unix(exp, 0) + expired := exp <= time.Now().Unix()+int64(bufferTimeBeforeTokenExpiration.Seconds()) + if expired { + common.Debugf("Token expires at: %v, currently expired due to bufferTime: %v", expTime.Format("15:04:05.000"), expired) + } + return expired +} + +func parseJwt(tokenString string) (*jwtToken, error) { + parts := strings.Split(tokenString, ".") + if len(parts) != 3 { + return nil, fmt.Errorf("the given token string contains an invalid number of parts") + } + + token := &jwtToken{raw: tokenString} + var err error + + // Parse Header part + var headerBytes []byte + if headerBytes, err = decodePart(parts[0]); err != nil { + return nil, fmt.Errorf("failed to decode the header bytes: %s", err.Error()) + } + if err = json.Unmarshal(headerBytes, &token.header); err != nil { + return nil, err + } + + // Parse Payload part + var payloadBytes []byte + if payloadBytes, err = decodePart(parts[1]); err != nil { + return nil, fmt.Errorf("failed to decode the payload bytes: %s", err.Error()) + } + decoder := json.NewDecoder(bytes.NewBuffer(payloadBytes)) + if err = decoder.Decode(&token.payload); err != nil { + return nil, fmt.Errorf("failed to decode the payload json: %s", err.Error()) + } + + return token, nil +} + +func decodePart(partString string) ([]byte, error) { + if l := len(partString) % 4; 0 < l { + partString += strings.Repeat("=", 4-l) + } + return base64.URLEncoding.DecodeString(partString) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_delegation_token_provider.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_delegation_token_provider.go new file mode 100644 index 00000000000..7c04882e9ac --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_delegation_token_provider.go @@ -0,0 +1,90 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "crypto/rsa" + "fmt" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +type resourcePrincipalDelegationTokenConfigurationProvider struct { + resourcePrincipalKeyProvider ConfigurationProviderWithClaimAccess + delegationToken string + region *common.Region +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) PrivateRSAKey() (*rsa.PrivateKey, error) { + return r.resourcePrincipalKeyProvider.PrivateRSAKey() +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) KeyID() (string, error) { + return r.resourcePrincipalKeyProvider.KeyID() +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) TenancyOCID() (string, error) { + return r.resourcePrincipalKeyProvider.TenancyOCID() +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) UserOCID() (string, error) { + return "", nil +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) KeyFingerprint() (string, error) { + return "", nil +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) Region() (string, error) { + if r.region == nil { + common.Debugf("Region in resource principal delegation token configuration provider is nil. Returning configuration provider region: %s", r.region) + return r.resourcePrincipalKeyProvider.Region() + } + return string(*r.region), nil +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) AuthType() (common.AuthConfig, error) { + token := r.delegationToken + return common.AuthConfig{AuthType: common.ResourcePrincipalDelegationToken, OboToken: &token}, nil +} + +func (r resourcePrincipalDelegationTokenConfigurationProvider) GetClaim(key string) (interface{}, error) { + return r.resourcePrincipalKeyProvider.GetClaim(key) +} + +type resourcePrincipalDelegationTokenError struct { + err error +} + +func (rpe resourcePrincipalDelegationTokenError) Error() string { + return fmt.Sprintf("%s\nResource principals delegation token authentication can only be used on specific OCI services. Please confirm this code is running on the correct environment", rpe.err.Error()) +} + +// ResourcePrincipalDelegationTokenConfigurationProvider returns a configuration for obo token resource principals +func ResourcePrincipalDelegationTokenConfigurationProvider(delegationToken *string) (ConfigurationProviderWithClaimAccess, error) { + if delegationToken == nil || len(*delegationToken) == 0 { + return nil, resourcePrincipalDelegationTokenError{err: fmt.Errorf("failed to create a delagationTokenConfigurationProvider: token is a mandatory input parameter")} + } + return newResourcePrincipalDelegationTokenConfigurationProvider(delegationToken, "", nil) +} + +// ResourcePrincipalDelegationTokenConfigurationProviderForRegion returns a configuration for obo token resource principals with a given region +func ResourcePrincipalDelegationTokenConfigurationProviderForRegion(delegationToken *string, region common.Region) (ConfigurationProviderWithClaimAccess, error) { + if delegationToken == nil || len(*delegationToken) == 0 { + return nil, resourcePrincipalDelegationTokenError{err: fmt.Errorf("failed to create a delagationTokenConfigurationProvider: token is a mandatory input parameter")} + } + return newResourcePrincipalDelegationTokenConfigurationProvider(delegationToken, region, nil) +} + +func newResourcePrincipalDelegationTokenConfigurationProvider(delegationToken *string, region common.Region, modifier func(common.HTTPRequestDispatcher) (common.HTTPRequestDispatcher, error)) (ConfigurationProviderWithClaimAccess, error) { + + keyProvider, err := ResourcePrincipalConfigurationProvider() + if err != nil { + return nil, resourcePrincipalDelegationTokenError{err: fmt.Errorf("failed to create a new key provider for resource principal: %s", err.Error())} + } + if len(region) > 0 { + return resourcePrincipalDelegationTokenConfigurationProvider{keyProvider, *delegationToken, ®ion}, err + } + return resourcePrincipalDelegationTokenConfigurationProvider{keyProvider, *delegationToken, nil}, err +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_key_provider.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_key_provider.go new file mode 100644 index 00000000000..e4ae6034eec --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_key_provider.go @@ -0,0 +1,485 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "crypto/rsa" + "crypto/x509" + "errors" + "fmt" + "io/ioutil" + "os" + "path" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +const ( + //ResourcePrincipalVersion2_2 is a supported version for resource principals + ResourcePrincipalVersion2_2 = "2.2" + //ResourcePrincipalVersionEnvVar environment var name for version + ResourcePrincipalVersionEnvVar = "OCI_RESOURCE_PRINCIPAL_VERSION" + //ResourcePrincipalRPSTEnvVar environment var name holding the token or a path to the token + ResourcePrincipalRPSTEnvVar = "OCI_RESOURCE_PRINCIPAL_RPST" + //ResourcePrincipalPrivatePEMEnvVar environment var holding a rsa private key in pem format or a path to one + ResourcePrincipalPrivatePEMEnvVar = "OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM" + //ResourcePrincipalPrivatePEMPassphraseEnvVar environment var holding the passphrase to a key or a path to one + ResourcePrincipalPrivatePEMPassphraseEnvVar = "OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM_PASSPHRASE" + //ResourcePrincipalRegionEnvVar environment variable holding a region + ResourcePrincipalRegionEnvVar = "OCI_RESOURCE_PRINCIPAL_REGION" + + //ResourcePrincipalVersion1_1 is a supported version for resource principals + ResourcePrincipalVersion1_1 = "1.1" + //ResourcePrincipalSessionTokenEndpoint endpoint for retrieving the Resource Principal Session Token + ResourcePrincipalSessionTokenEndpoint = "OCI_RESOURCE_PRINCIPAL_RPST_ENDPOINT" + //ResourcePrincipalTokenEndpoint endpoint for retrieving the Resource Principal Token + ResourcePrincipalTokenEndpoint = "OCI_RESOURCE_PRINCIPAL_RPT_ENDPOINT" + + //ResourcePrincipalVersion3_0 is a supported version for resource principals + ResourcePrincipalVersion3_0 = "3.0" + ResourcePrincipalVersionForLeaf = "OCI_RESOURCE_PRINCIPAL_VERSION_FOR_LEAF_RESOURCE" + ResourcePrincipalRptEndpointForLeaf = "OCI_RESOURCE_PRINCIPAL_RPT_ENDPOINT_FOR_LEAF_RESOURCE" + ResourcePrincipalRptPathForLeaf = "OCI_RESOURCE_PRINCIPAL_RPT_PATH_FOR_LEAF_RESOURCE" + ResourcePrincipalRpstEndpointForLeaf = "OCI_RESOURCE_PRINCIPAL_RPST_ENDPOINT_FOR_LEAF_RESOURCE" + ResourcePrincipalResourceIdForLeaf = "OCI_RESOURCE_PRINCIPAL_RESOURCE_ID_FOR_LEAF_RESOURCE" + ResourcePrincipalPrivatePemForLeaf = "OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM_FOR_LEAF_RESOURCE" + ResourcePrincipalPrivatePemPassphraseForLeaf = "OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM_PASSPHRASE_FOR_LEAF_RESOURCE" + ResourcePrincipalRpstForLeaf = "OCI_RESOURCE_PRINCIPAL_RPST_FOR_LEAF_RESOURCE" + ResourcePrincipalRegionForLeaf = "OCI_RESOURCE_PRINCIPAL_REGION_FOR_LEAF_RESOURCE" + ResourcePrincipalRptURLForParent = "OCI_RESOURCE_PRINCIPAL_RPT_URL_FOR_PARENT_RESOURCE" + ResourcePrincipalRpstEndpointForParent = "OCI_RESOURCE_PRINCIPAL_RPST_ENDPOINT_FOR_PARENT_RESOURCE" + ResourcePrincipalTenancyIDForLeaf = "OCI_RESOURCE_PRINCIPAL_TENANCY_ID_FOR_LEAF_RESOURCE" + OpcParentRptUrlHeader = "opc-parent-rpt-url" + + // KubernetesServiceAccountTokenPath that contains cluster information + KubernetesServiceAccountTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token" + // DefaultKubernetesServiceAccountCertPath that contains cluster information + DefaultKubernetesServiceAccountCertPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + // OciKubernetesServiceAccountCertPath Environment variable for Kubernetes Service Account Cert Path + OciKubernetesServiceAccountCertPath = "OCI_KUBERNETES_SERVICE_ACCOUNT_CERT_PATH" + // KubernetesServiceHostEnvVar environment var holding the kubernetes host + KubernetesServiceHostEnvVar = "KUBERNETES_SERVICE_HOST" + // KubernetesProxymuxServicePort environment var holding the kubernetes port + KubernetesProxymuxServicePort = "12250" + // TenancyOCIDClaimKey is the key used to look up the resource tenancy in an RPST + TenancyOCIDClaimKey = "res_tenant" + // CompartmentOCIDClaimKey is the key used to look up the resource compartment in an RPST + CompartmentOCIDClaimKey = "res_compartment" +) + +// ConfigurationProviderWithClaimAccess mixes in a method to access the claims held on the underlying security token +type ConfigurationProviderWithClaimAccess interface { + common.ConfigurationProvider + ClaimHolder +} + +// ResourcePrincipalConfigurationProvider returns a resource principal configuration provider using well known +// environment variables to look up token information. The environment variables can either paths or contain the material value +// of the keys. However in the case of the keys and tokens paths and values can not be mixed +func ResourcePrincipalConfigurationProvider() (ConfigurationProviderWithClaimAccess, error) { + var version string + var ok bool + if version, ok = os.LookupEnv(ResourcePrincipalVersionEnvVar); !ok { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } + + switch version { + case ResourcePrincipalVersion2_2: + rpst := requireEnv(ResourcePrincipalRPSTEnvVar) + if rpst == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } + private := requireEnv(ResourcePrincipalPrivatePEMEnvVar) + if private == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } + passphrase := requireEnv(ResourcePrincipalPrivatePEMPassphraseEnvVar) + region := requireEnv(ResourcePrincipalRegionEnvVar) + if region == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalRegionEnvVar) + return nil, resourcePrincipalError{err: err} + } + return newResourcePrincipalKeyProvider22( + *rpst, *private, passphrase, *region) + case ResourcePrincipalVersion1_1: + return newResourcePrincipalKeyProvider11(DefaultRptPathProvider{}) + case ResourcePrincipalVersion3_0: + return newResourcePrincipalKeyProvider30() + default: + err := fmt.Errorf("can not create resource principal, environment variable: %s, must be valid", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } +} + +// OkeWorkloadIdentityConfigurationProvider returns a resource principal configuration provider by OKE Workload Identity +func OkeWorkloadIdentityConfigurationProvider() (ConfigurationProviderWithClaimAccess, error) { + return OkeWorkloadIdentityConfigurationProviderWithServiceAccountTokenProvider(NewDefaultServiceAccountTokenProvider()) +} + +// OkeWorkloadIdentityConfigurationProviderWithServiceAccountTokenProvider returns a resource principal configuration provider by OKE Workload Identity +// with service account token provider +func OkeWorkloadIdentityConfigurationProviderWithServiceAccountTokenProvider(saTokenProvider ServiceAccountTokenProvider) (ConfigurationProviderWithClaimAccess, error) { + var version string + var ok bool + if version, ok = os.LookupEnv(ResourcePrincipalVersionEnvVar); !ok { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } + + if version == ResourcePrincipalVersion1_1 || version == ResourcePrincipalVersion2_2 { + + saCertPath := requireEnv(OciKubernetesServiceAccountCertPath) + + if saCertPath == nil { + tmp := DefaultKubernetesServiceAccountCertPath + saCertPath = &tmp + } + + kubernetesServiceAccountCertRaw, err := ioutil.ReadFile(*saCertPath) + if err != nil { + err = fmt.Errorf("can not create resource principal, error getting Kubernetes Service Account Token at %s", *saCertPath) + return nil, resourcePrincipalError{err: err} + } + + kubernetesServiceAccountCert := x509.NewCertPool() + kubernetesServiceAccountCert.AppendCertsFromPEM(kubernetesServiceAccountCertRaw) + + region := requireEnv(ResourcePrincipalRegionEnvVar) + if region == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", + ResourcePrincipalRegionEnvVar) + return nil, resourcePrincipalError{err: err} + } + + k8sServiceHost := requireEnv(KubernetesServiceHostEnvVar) + if k8sServiceHost == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", + KubernetesServiceHostEnvVar) + return nil, resourcePrincipalError{err: err} + } + proxymuxEndpoint := fmt.Sprintf("https://%s:%s/resourcePrincipalSessionTokens", *k8sServiceHost, KubernetesProxymuxServicePort) + + return newOkeWorkloadIdentityProvider(proxymuxEndpoint, saTokenProvider, kubernetesServiceAccountCert, *region) + } + + err := fmt.Errorf("can not create resource principal, environment variable: %s, must be valid", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} +} + +func OkeWorkloadIdentityConfigurationProviderWithServiceAccountTokenProviderK8sService(k8sServiceHost *string, saTokenProvider ServiceAccountTokenProvider, remoteCAbytes []byte) (ConfigurationProviderWithClaimAccess, error) { + saCertPath := requireEnv(OciKubernetesServiceAccountCertPath) + + if saCertPath == nil { + tmp := DefaultKubernetesServiceAccountCertPath + saCertPath = &tmp + } + + kubernetesServiceAccountCertRaw, err := ioutil.ReadFile(*saCertPath) + if err != nil { + err = fmt.Errorf("can not create resource principal, error getting Kubernetes Service Account Token at %s", *saCertPath) + return nil, resourcePrincipalError{err: err} + } + + kubernetesServiceAccountCert := x509.NewCertPool() + kubernetesServiceAccountCert.AppendCertsFromPEM(kubernetesServiceAccountCertRaw) + if ok := kubernetesServiceAccountCert.AppendCertsFromPEM(remoteCAbytes); !ok { + err := fmt.Errorf("failed to load remote CA") + return nil, resourcePrincipalError{err: err} + } + + region := requireEnv(ResourcePrincipalRegionEnvVar) + if region == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", + ResourcePrincipalRegionEnvVar) + return nil, resourcePrincipalError{err: err} + } + + proxymuxEndpoint := fmt.Sprintf("https://%s:%s/resourcePrincipalSessionTokens", *k8sServiceHost, KubernetesProxymuxServicePort) + + return newOkeWorkloadIdentityProvider(proxymuxEndpoint, saTokenProvider, kubernetesServiceAccountCert, *region) + + return nil, resourcePrincipalError{err: err} +} + +// ResourcePrincipalConfigurationProviderForRegion returns a resource principal configuration provider using well known +// environment variables to look up token information, for a given region. The environment variables can either paths or contain the material value +// of the keys. However, in the case of the keys and tokens paths and values can not be mixed +func ResourcePrincipalConfigurationProviderForRegion(region common.Region) (ConfigurationProviderWithClaimAccess, error) { + var version string + var ok bool + if version, ok = os.LookupEnv(ResourcePrincipalVersionEnvVar); !ok { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } + + switch version { + case ResourcePrincipalVersion2_2: + rpst := requireEnv(ResourcePrincipalRPSTEnvVar) + if rpst == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } + private := requireEnv(ResourcePrincipalPrivatePEMEnvVar) + if private == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } + passphrase := requireEnv(ResourcePrincipalPrivatePEMPassphraseEnvVar) + region := string(region) + if region == "" { + err := fmt.Errorf("can not create resource principal, region cannot be empty") + return nil, resourcePrincipalError{err: err} + } + return newResourcePrincipalKeyProvider22( + *rpst, *private, passphrase, region) + case ResourcePrincipalVersion1_1: + return newResourcePrincipalKeyProvider11(DefaultRptPathProvider{}) + default: + err := fmt.Errorf("can not create resource principal, environment variable: %s, must be valid", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } +} + +// ResourcePrincipalConfigurationProviderWithPathProvider returns a resource principal configuration provider using path provider. +func ResourcePrincipalConfigurationProviderWithPathProvider(pathProvider PathProvider) (ConfigurationProviderWithClaimAccess, error) { + var version string + var ok bool + if version, ok = os.LookupEnv(ResourcePrincipalVersionEnvVar); !ok { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionEnvVar) + return nil, resourcePrincipalError{err: err} + } else if version != ResourcePrincipalVersion1_1 { + err := fmt.Errorf("can not create resource principal, environment variable: %s, must be %s", ResourcePrincipalVersionEnvVar, ResourcePrincipalVersion1_1) + return nil, resourcePrincipalError{err: err} + } + return newResourcePrincipalKeyProvider11(pathProvider) +} + +func newResourcePrincipalKeyProvider11(pathProvider PathProvider) (ConfigurationProviderWithClaimAccess, error) { + rptEndpoint := requireEnv(ResourcePrincipalTokenEndpoint) + if rptEndpoint == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalTokenEndpoint) + return nil, resourcePrincipalError{err: err} + } + rptPath, err := pathProvider.Path() + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + resourceID, err := pathProvider.ResourceID() + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + rp, err := resourcePrincipalConfigurationProviderV1(*rptEndpoint+*rptPath, *resourceID) + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + return rp, nil +} + +func requireEnv(key string) *string { + if val, ok := os.LookupEnv(key); ok { + return &val + } + return nil +} + +// resourcePrincipalKeyProvider22 is key provider that reads from specified the specified environment variables +// the environment variables can host the material keys/passphrases or they can be paths to files that need to be read +type resourcePrincipalKeyProvider struct { + FederationClient federationClient + KeyProviderRegion common.Region +} + +func newResourcePrincipalKeyProvider22(sessionTokenLocation, privatePemLocation string, + passphraseLocation *string, region string) (*resourcePrincipalKeyProvider, error) { + + //Check both the passphrase and the key are paths + if passphraseLocation != nil && (!isPath(privatePemLocation) && isPath(*passphraseLocation) || + isPath(privatePemLocation) && !isPath(*passphraseLocation)) { + err := fmt.Errorf("cant not create resource principal: both key and passphrase need to be path or none needs to be path") + return nil, resourcePrincipalError{err: err} + } + + var supplier sessionKeySupplier + var err error + + //File based case + if isPath(privatePemLocation) { + supplier, err = newFileBasedKeySessionSupplier(privatePemLocation, passphraseLocation) + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + } else { + //else the content is in the env vars + var passphrase []byte + if passphraseLocation != nil { + passphrase = []byte(*passphraseLocation) + } + supplier, err = newStaticKeySessionSupplier([]byte(privatePemLocation), passphrase) + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + } + + var fd federationClient + if isPath(sessionTokenLocation) { + fd, _ = newFileBasedFederationClient(sessionTokenLocation, supplier) + } else { + fd, err = newStaticFederationClient(sessionTokenLocation, supplier) + + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + } + + rs := resourcePrincipalKeyProvider{ + FederationClient: fd, + KeyProviderRegion: common.StringToRegion(region), + } + + return &rs, nil +} + +func newResourcePrincipalKeyProvider30() (ConfigurationProviderWithClaimAccess, error) { + rpVersionForLeafResource := requireEnv(ResourcePrincipalVersionForLeaf) + if rpVersionForLeafResource == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalVersionForLeaf) + return nil, resourcePrincipalError{err: err} + } + var leafResourceAuthProvider ConfigurationProviderWithClaimAccess + var err error + switch *rpVersionForLeafResource { + case ResourcePrincipalVersion1_1: + leafResourceAuthProvider, err = newResourcePrincipalKeyProvider11(RptPathProviderForLeafResource{}) + if err != nil { + return nil, err + } + return ResourcePrincipalConfigurationProviderV3(leafResourceAuthProvider) + case ResourcePrincipalVersion2_2: + rpst := requireEnv(ResourcePrincipalRpstForLeaf) + if rpst == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalRpstForLeaf) + return nil, resourcePrincipalError{err: err} + } + private := requireEnv(ResourcePrincipalPrivatePemForLeaf) + if private == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalPrivatePemForLeaf) + return nil, resourcePrincipalError{err: err} + } + passphrase := requireEnv(ResourcePrincipalPrivatePemPassphraseForLeaf) + region := requireEnv(ResourcePrincipalRegionForLeaf) + if region == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", ResourcePrincipalRegionForLeaf) + return nil, resourcePrincipalError{err: err} + } + leafResourceAuthProvider, err = newResourcePrincipalKeyProvider22( + *rpst, *private, passphrase, *region) + if err != nil { + return nil, err + } + return ResourcePrincipalConfigurationProviderV3(leafResourceAuthProvider) + default: + err := fmt.Errorf("can not create resource principal, environment variable: %s, must be valid", ResourcePrincipalVersionForLeaf) + return nil, resourcePrincipalError{err: err} + + } +} + +func newOkeWorkloadIdentityProvider(proxymuxEndpoint string, saTokenProvider ServiceAccountTokenProvider, + kubernetesServiceAccountCert *x509.CertPool, region string) (*resourcePrincipalKeyProvider, error) { + var err error + var fd federationClient + fd, err = newX509FederationClientForOkeWorkloadIdentity(proxymuxEndpoint, saTokenProvider, kubernetesServiceAccountCert) + + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + + rs := resourcePrincipalKeyProvider{ + FederationClient: fd, + KeyProviderRegion: common.StringToRegion(region), + } + + return &rs, nil +} + +func (p *resourcePrincipalKeyProvider) PrivateRSAKey() (privateKey *rsa.PrivateKey, err error) { + if privateKey, err = p.FederationClient.PrivateKey(); err != nil { + err = fmt.Errorf("failed to get private key: %s", err.Error()) + return nil, resourcePrincipalError{err: err} + } + return privateKey, nil +} + +func (p *resourcePrincipalKeyProvider) KeyID() (string, error) { + var securityToken string + var err error + if securityToken, err = p.FederationClient.SecurityToken(); err != nil { + err = fmt.Errorf("failed to get security token: %s", err.Error()) + return "", resourcePrincipalError{err: err} + } + return fmt.Sprintf("ST$%s", securityToken), nil +} + +func (p *resourcePrincipalKeyProvider) Region() (string, error) { + return string(p.KeyProviderRegion), nil +} + +var ( + // ErrNonStringClaim is returned if the token has a claim for a key, but it's not a string value + ErrNonStringClaim = errors.New("claim does not have a string value") +) + +func (p *resourcePrincipalKeyProvider) TenancyOCID() (string, error) { + if claim, err := p.GetClaim(TenancyOCIDClaimKey); err != nil { + return "", err + } else if tenancy, ok := claim.(string); ok { + return tenancy, nil + } else { + return "", ErrNonStringClaim + } +} + +func (p *resourcePrincipalKeyProvider) GetClaim(claim string) (interface{}, error) { + return p.FederationClient.GetClaim(claim) +} + +func (p *resourcePrincipalKeyProvider) KeyFingerprint() (string, error) { + return "", nil +} + +func (p *resourcePrincipalKeyProvider) UserOCID() (string, error) { + return "", nil +} + +func (p *resourcePrincipalKeyProvider) AuthType() (common.AuthConfig, error) { + return common.AuthConfig{common.UnknownAuthenticationType, false, nil}, fmt.Errorf("unsupported, keep the interface") +} + +func (p *resourcePrincipalKeyProvider) Refreshable() bool { + return true +} + +// By contract for the the content of a resource principal to be considered path, it needs to be +// an absolute path. +func isPath(str string) bool { + return path.IsAbs(str) +} + +type resourcePrincipalError struct { + err error +} + +func (ipe resourcePrincipalError) Error() string { + return fmt.Sprintf("%s\nResource principals authentication can only be used in certain OCI services. Please check that the OCI service you're running this code from supports Resource principals.\nSee https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdk_authentication_methods.htm#sdk_authentication_methods_resource_principal for more info.", ipe.err.Error()) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_token_path_provider.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_token_path_provider.go new file mode 100644 index 00000000000..56db98c5208 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principal_token_path_provider.go @@ -0,0 +1,247 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "io/ioutil" + "net/http" + "time" +) + +const ( + imdsPathTemplate = "/20180711/resourcePrincipalToken/{id}" + instanceIDURL = `http://169.254.169.254/opc/v2/instance/id` + + //ResourcePrincipalTokenPath path for retrieving the Resource Principal Token + ResourcePrincipalTokenPath = "OCI_RESOURCE_PRINCIPAL_RPT_PATH" + //ResourceID OCID for the resource for Resource Principal + ResourceID = "OCI_RESOURCE_PRINCIPAL_RPT_ID" +) + +// PathProvider is an interface that returns path and resource ID +type PathProvider interface { + Path() (*string, error) + ResourceID() (*string, error) +} + +// StringRptPathProvider is a simple path provider that takes a string and returns it +type StringRptPathProvider struct { + path string + resourceID string +} + +// Path returns the resource principal token path +func (pp StringRptPathProvider) Path() (*string, error) { + return &pp.path, nil +} + +// ResourceID returns the resource associated with the resource principal +func (pp StringRptPathProvider) ResourceID() (*string, error) { + return &pp.resourceID, nil +} + +// ImdsRptPathProvider sets the path from a default value and the resource ID from instance metadata +type ImdsRptPathProvider struct{} + +// Path returns the resource principal token path +func (pp ImdsRptPathProvider) Path() (*string, error) { + path := imdsPathTemplate + return &path, nil +} + +// ResourceID returns the resource associated with the resource principal +func (pp ImdsRptPathProvider) ResourceID() (*string, error) { + instanceID, err := getInstanceIDFromMetadata() + return &instanceID, err +} + +// EnvRptPathProvider sets the path and resource ID from environment variables +type EnvRptPathProvider struct{} + +// Path returns the resource principal token path +func (pp EnvRptPathProvider) Path() (*string, error) { + path := requireEnv(ResourcePrincipalTokenPath) + if path == nil { + return nil, fmt.Errorf("missing %s env var", ResourcePrincipalTokenPath) + } + return path, nil +} + +// ResourceID returns the resource associated with the resource principal +func (pp EnvRptPathProvider) ResourceID() (*string, error) { + rpID := requireEnv(ResourceID) + if rpID == nil { + return nil, fmt.Errorf("missing %s env var", ResourceID) + } + return rpID, nil +} + +// DefaultRptPathProvider path provider makes sure the behavior happens with the correct fallback. +// +// For the path, +// Use the contents of the OCI_RESOURCE_PRINCIPAL_RPT_PATH environment variable, if set. +// Otherwise, use the current path: "/20180711/resourcePrincipalToken/{id}" +// +// For the resource id, +// Use the contents of the OCI_RESOURCE_PRINCIPAL_RPT_ID environment variable, if set. +// Otherwise, use IMDS to get the instance id +// +// This path provider is used when the caller doesn't provide a specific path provider to the resource principals signer +type DefaultRptPathProvider struct { + path string + resourceID string +} + +// Path returns the resource principal token path +func (pp DefaultRptPathProvider) Path() (*string, error) { + path := requireEnv(ResourcePrincipalTokenPath) + if path == nil { + rpPath := imdsPathTemplate + return &rpPath, nil + } + return path, nil +} + +// ResourceID returns the resource associated with the resource principal +func (pp DefaultRptPathProvider) ResourceID() (*string, error) { + rpID := requireEnv(ResourceID) + if rpID == nil { + instanceID, err := getInstanceIDFromMetadata() + if err != nil { + return nil, err + } + return &instanceID, nil + } + return rpID, nil +} + +type RptPathProviderForLeafResource struct { + path string + resourceID string +} + +func (pp RptPathProviderForLeafResource) Path() (*string, error) { + path := requireEnv(ResourcePrincipalRptPathForLeaf) + if path == nil { + rpPath := imdsPathTemplate + return &rpPath, nil + } + return path, nil +} + +// ResourceID returns the resource associated with the resource principal +func (pp RptPathProviderForLeafResource) ResourceID() (*string, error) { + rpID := requireEnv(ResourcePrincipalResourceIdForLeaf) + if rpID == nil { + instanceID, err := getInstanceIDFromMetadata() + if err != nil { + return nil, err + } + return &instanceID, nil + } + return rpID, nil +} + +func getInstanceIDFromMetadata() (instanceID string, err error) { + client := &http.Client{} + req, err := http.NewRequest("GET", instanceIDURL, nil) + if err != nil { + return "", err + } + req.Header.Set("Authorization", "Bearer Oracle") + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + bodyString := string(bodyBytes) + return bodyString, nil +} + +// ServiceAccountTokenProvider comment +type ServiceAccountTokenProvider interface { + ServiceAccountToken() (string, error) +} + +// DefaultServiceAccountTokenProvider is supplied by user when instantiating +// OkeWorkloadIdentityConfigurationProvider +type DefaultServiceAccountTokenProvider struct { + tokenPath string `mandatory:"false"` +} + +// NewDefaultServiceAccountTokenProvider returns a new instance of defaultServiceAccountTokenProvider +func NewDefaultServiceAccountTokenProvider() DefaultServiceAccountTokenProvider { + return DefaultServiceAccountTokenProvider{ + tokenPath: KubernetesServiceAccountTokenPath, + } +} + +// WithSaTokenPath Builder method to override the to SA ken path +func (d DefaultServiceAccountTokenProvider) WithSaTokenPath(tokenPath string) DefaultServiceAccountTokenProvider { + d.tokenPath = tokenPath + return d +} + +// ServiceAccountToken returns a service account token +func (d DefaultServiceAccountTokenProvider) ServiceAccountToken() (string, error) { + saTokenString, err := ioutil.ReadFile(d.tokenPath) + if err != nil { + common.Logf("error %s", err) + return "", fmt.Errorf("error reading service account token: %s", err) + } + isSaTokenValid, err := isValidSaToken(string(saTokenString)) + if !isSaTokenValid { + common.Logf("error %s", err) + return "", fmt.Errorf("error validating service account token: %s", err) + } + return string(saTokenString), err +} + +// SuppliedServiceAccountTokenProvider is supplied by user when instantiating +// OkeWorkloadIdentityConfigurationProviderWithServiceAccountTokenProvider +type SuppliedServiceAccountTokenProvider struct { + tokenString string `mandatory:"false"` +} + +// NewSuppliedServiceAccountTokenProvider returns a new instance of defaultServiceAccountTokenProvider +func NewSuppliedServiceAccountTokenProvider(tokenString string) SuppliedServiceAccountTokenProvider { + return SuppliedServiceAccountTokenProvider{tokenString: tokenString} +} + +// ServiceAccountToken returns a service account token +func (d SuppliedServiceAccountTokenProvider) ServiceAccountToken() (string, error) { + isSaTokenValid, err := isValidSaToken(d.tokenString) + if !isSaTokenValid { + common.Logf("error %s", err) + return "", fmt.Errorf("error validating service account token %s", err) + } + return d.tokenString, nil +} + +// isValidSaToken returns true is a saTokenString provides a valid service account token +func isValidSaToken(saTokenString string) (bool, error) { + var jwtToken *jwtToken + var err error + if jwtToken, err = parseJwt(saTokenString); err != nil { + return false, fmt.Errorf("failed to parse the default service token string \"%s\": %s", saTokenString, err.Error()) + } + now := time.Now().Unix() + int64(bufferTimeBeforeTokenExpiration.Seconds()) + if jwtToken.payload["exp"] == nil { + return false, fmt.Errorf("service token doesn't have an `exp` field") + } + expiredAt := int64(jwtToken.payload["exp"].(float64)) + expired := expiredAt <= now + if expired { + return false, fmt.Errorf("service token expired at: %v", time.Unix(expiredAt, 0).Format("15:04:05.000")) + } + + return true, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v1.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v1.go new file mode 100644 index 00000000000..6477e47062e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v1.go @@ -0,0 +1,377 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "context" + "crypto/rsa" + "fmt" + + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "net/url" + "sync" + "time" +) + +// resourcePrincipalFederationClient is the client used to to talk acquire resource principals +// No auth client, leaf or intermediate retrievers. We use certificates retrieved by instance principals to sign the operations of +// resource principals +type resourcePrincipalFederationClient struct { + tenancyID string + instanceID string + sessionKeySupplier sessionKeySupplier + mux sync.Mutex + securityToken securityToken + path string + + //instancePrincipalKeyProvider the instance Principal Key container + instancePrincipalKeyProvider instancePrincipalKeyProvider + + //ResourcePrincipalTargetServiceClient client that calls the target service to acquire a resource principal token + ResourcePrincipalTargetServiceClient common.BaseClient + + //ResourcePrincipalSessionTokenClient. The client used to communicate with identity to exchange a resource principal for + // resource principal session token + ResourcePrincipalSessionTokenClient common.BaseClient +} + +type resourcePrincipalTokenRequest struct { + InstanceID string `contributesTo:"path" name:"id"` +} + +type resourcePrincipalTokenResponse struct { + Body struct { + ResourcePrincipalToken string `json:"resourcePrincipalToken"` + ServicePrincipalSessionToken string `json:"servicePrincipalSessionToken"` + } `presentIn:"body"` +} + +type resourcePrincipalSessionTokenRequestBody struct { + ResourcePrincipalToken string `json:"resourcePrincipalToken,omitempty"` + ServicePrincipalSessionToken string `json:"servicePrincipalSessionToken,omitempty"` + SessionPublicKey string `json:"sessionPublicKey,omitempty"` +} +type resourcePrincipalSessionTokenRequest struct { + Body resourcePrincipalSessionTokenRequestBody `contributesTo:"body"` +} + +// acquireResourcePrincipalToken acquires the resource principal from the target service +func (c *resourcePrincipalFederationClient) acquireResourcePrincipalToken() (tokenResponse resourcePrincipalTokenResponse, err error) { + rpServiceClient := c.ResourcePrincipalTargetServiceClient + + //Set the signer of this client to be the instance principal provider + rpServiceClient.Signer = common.DefaultRequestSigner(&c.instancePrincipalKeyProvider) + + //Create a request with the instanceId + request, err := common.MakeDefaultHTTPRequestWithTaggedStruct(http.MethodGet, c.path, resourcePrincipalTokenRequest{InstanceID: c.instanceID}) + if err != nil { + return + } + + //Call the target service + response, err := rpServiceClient.Call(context.Background(), &request) + if err != nil { + return + } + + defer common.CloseBodyIfValid(response) + + tokenResponse = resourcePrincipalTokenResponse{} + err = common.UnmarshalResponse(response, &tokenResponse) + return +} + +// exchangeToken exchanges a resource principal token from the target service with a session token from identity +func (c *resourcePrincipalFederationClient) exchangeToken(publicKeyBase64 string, tokenResponse resourcePrincipalTokenResponse) (sessionToken string, err error) { + rpServiceClient := c.ResourcePrincipalSessionTokenClient + + //Set the signer of this client to be the instance principal provider + rpServiceClient.Signer = common.DefaultRequestSigner(&c.instancePrincipalKeyProvider) + + // Call identity service to get resource principal session token + sessionTokenReq := resourcePrincipalSessionTokenRequest{ + resourcePrincipalSessionTokenRequestBody{ + ServicePrincipalSessionToken: tokenResponse.Body.ServicePrincipalSessionToken, + ResourcePrincipalToken: tokenResponse.Body.ResourcePrincipalToken, + SessionPublicKey: publicKeyBase64, + }, + } + + sessionTokenHTTPReq, err := common.MakeDefaultHTTPRequestWithTaggedStruct(http.MethodPost, + "", sessionTokenReq) + if err != nil { + return + } + + sessionTokenHTTPRes, err := rpServiceClient.Call(context.Background(), &sessionTokenHTTPReq) + if err != nil { + return + } + defer common.CloseBodyIfValid(sessionTokenHTTPRes) + + sessionTokenRes := x509FederationResponse{} + err = common.UnmarshalResponse(sessionTokenHTTPRes, &sessionTokenRes) + if err != nil { + return + } + + sessionToken = sessionTokenRes.Token.Token + return +} + +// getSecurityToken makes the appropiate calls to acquire a resource principal security token +func (c *resourcePrincipalFederationClient) getSecurityToken() (securityToken, error) { + var err error + ipFederationClient := c.instancePrincipalKeyProvider.FederationClient + + common.Debugf("Refreshing instance principal token") + //Refresh instance principal token + if refreshable, ok := ipFederationClient.(*x509FederationClient); ok { + err = refreshable.renewSecurityTokenIfNotValid() + if err != nil { + return nil, err + } + } + + //Acquire resource principal token from target service + common.Debugf("Acquiring resource principal token from target service") + tokenResponse, err := c.acquireResourcePrincipalToken() + if err != nil { + return nil, err + } + + //Read the public key from the session supplier. + pem := c.sessionKeySupplier.PublicKeyPemRaw() + pemSanitized := sanitizeCertificateString(string(pem)) + + //Exchange resource principal token for session token from identity + common.Debugf("Exchanging resource principal token for resource principal session token") + sessionToken, err := c.exchangeToken(pemSanitized, tokenResponse) + if err != nil { + return nil, err + } + + return newPrincipalToken(sessionToken) // should be a resource principal token +} + +func (c *resourcePrincipalFederationClient) renewSecurityToken() (err error) { + if err = c.sessionKeySupplier.Refresh(); err != nil { + return fmt.Errorf("failed to refresh session key: %s", err.Error()) + } + common.Logf("Renewing resource principal security token at: %v\n", time.Now().Format("15:04:05.000")) + if c.securityToken, err = c.getSecurityToken(); err != nil { + return fmt.Errorf("failed to get security token: %s", err.Error()) + } + common.Logf("Resource principal security token renewed at: %v\n", time.Now().Format("15:04:05.000")) + + return nil +} + +// ResourcePrincipal Key provider in charge of resource principal acquiring tokens +type resourcePrincipalKeyProviderV1 struct { + ResourcePrincipalClient resourcePrincipalFederationClient +} + +func (c *resourcePrincipalFederationClient) renewSecurityTokenIfNotValid() (err error) { + if c.securityToken == nil || !c.securityToken.Valid() { + if err = c.renewSecurityToken(); err != nil { + return fmt.Errorf("failed to renew resource prinicipal security token: %s", err.Error()) + } + } + return nil +} + +func (c *resourcePrincipalFederationClient) PrivateKey() (*rsa.PrivateKey, error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.renewSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.sessionKeySupplier.PrivateKey(), nil +} + +func (c *resourcePrincipalFederationClient) SecurityToken() (token string, err error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err = c.renewSecurityTokenIfNotValid(); err != nil { + return "", err + } + return c.securityToken.String(), nil +} + +func (p *resourcePrincipalConfigurationProvider) PrivateRSAKey() (privateKey *rsa.PrivateKey, err error) { + if privateKey, err = p.keyProvider.ResourcePrincipalClient.PrivateKey(); err != nil { + err = fmt.Errorf("failed to get resource principal private key: %s", err.Error()) + return nil, err + } + return privateKey, nil +} + +func (p *resourcePrincipalConfigurationProvider) KeyID() (string, error) { + var securityToken string + var err error + if securityToken, err = p.keyProvider.ResourcePrincipalClient.SecurityToken(); err != nil { + return "", fmt.Errorf("failed to get resource principal security token: %s", err.Error()) + } + return fmt.Sprintf("ST$%s", securityToken), nil +} + +func (p *resourcePrincipalConfigurationProvider) TenancyOCID() (string, error) { + return p.keyProvider.ResourcePrincipalClient.instancePrincipalKeyProvider.TenancyOCID() +} + +// todo what is this +func (p *resourcePrincipalConfigurationProvider) GetClaim(key string) (interface{}, error) { + return nil, nil +} + +// Resource Principals +type resourcePrincipalConfigurationProvider struct { + keyProvider resourcePrincipalKeyProviderV1 + region *common.Region +} + +func newResourcePrincipalKeyProvider(ipKeyProvider instancePrincipalKeyProvider, rpTokenTargetServiceClient, rpSessionTokenClient common.BaseClient, instanceID, path string) (keyProvider resourcePrincipalKeyProviderV1, err error) { + rpFedClient := resourcePrincipalFederationClient{} + rpFedClient.tenancyID = ipKeyProvider.TenancyID + rpFedClient.instanceID = instanceID + rpFedClient.sessionKeySupplier = newSessionKeySupplier() + rpFedClient.ResourcePrincipalTargetServiceClient = rpTokenTargetServiceClient + rpFedClient.ResourcePrincipalSessionTokenClient = rpSessionTokenClient + rpFedClient.instancePrincipalKeyProvider = ipKeyProvider + rpFedClient.path = path + keyProvider = resourcePrincipalKeyProviderV1{ResourcePrincipalClient: rpFedClient} + return +} + +func (p *resourcePrincipalConfigurationProvider) AuthType() (common.AuthConfig, error) { + return common.AuthConfig{common.UnknownAuthenticationType, false, nil}, + fmt.Errorf("unsupported, keep the interface") +} + +func (p resourcePrincipalConfigurationProvider) UserOCID() (string, error) { + return "", nil +} + +func (p resourcePrincipalConfigurationProvider) KeyFingerprint() (string, error) { + return "", nil +} + +func (p resourcePrincipalConfigurationProvider) Region() (string, error) { + if p.region == nil { + region := p.keyProvider.ResourcePrincipalClient.instancePrincipalKeyProvider.RegionForFederationClient() + common.Debugf("Region in resource principal configuration provider is nil. Returning instance principal federation clients region: %s", region) + return string(region), nil + } + return string(*p.region), nil +} + +func (p resourcePrincipalConfigurationProvider) Refreshable() bool { + return true +} + +// resourcePrincipalConfigurationProviderForInstanceWithClients returns a configuration for instance principals +// resourcePrincipalTargetServiceTokenClient and resourcePrincipalSessionTokenClient are clients that at last need to have +// their base path and host properly set for their respective services. Additionally the clients can be further customized +// to provide mocking or any other customization for the requests/responses +func resourcePrincipalConfigurationProviderForInstanceWithClients(instancePrincipalProvider common.ConfigurationProvider, + resourcePrincipalTargetServiceTokenClient, resourcePrincipalSessionTokenClient common.BaseClient, instanceID, path string) (*resourcePrincipalConfigurationProvider, error) { + var ok bool + var ip instancePrincipalConfigurationProvider + if ip, ok = instancePrincipalProvider.(instancePrincipalConfigurationProvider); !ok { + return nil, fmt.Errorf("instancePrincipalConfigurationProvider needs to be of type vald Instance Principal Configuration Provider") + } + + keyProvider, err := newResourcePrincipalKeyProvider(ip.keyProvider, resourcePrincipalTargetServiceTokenClient, resourcePrincipalSessionTokenClient, instanceID, path) + if err != nil { + return nil, err + } + + provider := &resourcePrincipalConfigurationProvider{ + region: nil, + keyProvider: keyProvider, + } + return provider, nil +} + +const identityResourcePrincipalSessionTokenPath = "/v1/resourcePrincipalSessionToken" + +// resourcePrincipalConfigurationProviderForInstanceWithInterceptor creates a resource principal configuration provider with +// a interceptor used to customize the call going to the resource principal token request to the target service +// for a given instance ID +func resourcePrincipalConfigurationProviderForInstanceWithInterceptor(instancePrincipalProvider common.ConfigurationProvider, resourcePrincipalTokenEndpoint, instanceID string, interceptor common.RequestInterceptor) (provider *resourcePrincipalConfigurationProvider, err error) { + + //Build the target service client + rpTargetServiceClient, err := common.NewClientWithConfig(instancePrincipalProvider) + if err != nil { + return + } + + rpTokenURL, err := url.Parse(resourcePrincipalTokenEndpoint) + if err != nil { + return + } + + rpTargetServiceClient.Host = rpTokenURL.Scheme + "://" + rpTokenURL.Host + rpTargetServiceClient.Interceptor = interceptor + + var path string + if rpTokenURL.Path != "" { + path = rpTokenURL.Path + } else { + path = identityResourcePrincipalSessionTokenPath + } + + //Build the identity client for token service + rpTokenSessionClient, err := common.NewClientWithConfig(instancePrincipalProvider) + if err != nil { + return + } + + // Set RPST endpoint if passed in from env var, otherwise create it from region + resourcePrincipalSessionTokenEndpoint := requireEnv(ResourcePrincipalSessionTokenEndpoint) + if resourcePrincipalSessionTokenEndpoint != nil { + rpSessionTokenURL, err := url.Parse(*resourcePrincipalSessionTokenEndpoint) + if err != nil { + return nil, err + } + + rpTokenSessionClient.Host = rpSessionTokenURL.Scheme + "://" + rpSessionTokenURL.Host + } else { + regionStr, err := instancePrincipalProvider.Region() + if err != nil { + return nil, fmt.Errorf("missing RPST env var and cannot determine region: %v", err) + } + region := common.StringToRegion(regionStr) + rpTokenSessionClient.Host = fmt.Sprintf("https://%s", region.Endpoint("auth")) + } + + rpTokenSessionClient.BasePath = identityResourcePrincipalSessionTokenPath + + return resourcePrincipalConfigurationProviderForInstanceWithClients(instancePrincipalProvider, rpTargetServiceClient, rpTokenSessionClient, instanceID, path) +} + +// ResourcePrincipalConfigurationProviderWithInterceptor creates a resource principal configuration provider with endpoints +// a interceptor used to customize the call going to the resource principal token request to the target service +// see https://godoc.org/github.com/oracle/oci-go-sdk/common#RequestInterceptor +func ResourcePrincipalConfigurationProviderWithInterceptor(instancePrincipalProvider common.ConfigurationProvider, + resourcePrincipalTokenEndpoint, resourcePrincipalSessionTokenEndpoint string, + interceptor common.RequestInterceptor) (common.ConfigurationProvider, error) { + + return resourcePrincipalConfigurationProviderForInstanceWithInterceptor(instancePrincipalProvider, resourcePrincipalTokenEndpoint, "", interceptor) +} + +// resourcePrincipalConfigurationProviderV1 creates a resource principal configuration provider with +// endpoints for both resource principal token and resource principal token session +func resourcePrincipalConfigurationProviderV1(resourcePrincipalTokenEndpoint, resourceID string) (*resourcePrincipalConfigurationProvider, error) { + + instancePrincipalProvider, err := InstancePrincipalConfigurationProvider() + if err != nil { + return nil, err + } + return resourcePrincipalConfigurationProviderForInstanceWithInterceptor(instancePrincipalProvider, resourcePrincipalTokenEndpoint, resourceID, nil) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v3.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v3.go new file mode 100644 index 00000000000..4fa6ffab99e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/resource_principals_v3.go @@ -0,0 +1,351 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "context" + "crypto/rsa" + "fmt" + "net/http" + "net/url" + "strings" + "sync" + "time" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +type resourcePrincipalV3Client struct { + securityToken securityToken + mux sync.Mutex + sessionKeySupplier sessionKeySupplier + rptUrl string + rpstUrl string + + leafResourcePrincipalKeyProvider ConfigurationProviderWithClaimAccess + + //ResourcePrincipalTargetServiceClient client that calls the target service to acquire a resource principal token + //ResourcePrincipalTargetServiceClient common.BaseClient + + //ResourcePrincipalSessionTokenClient. The client used to communicate with identity to exchange a resource principal for + // resource principal session token + //ResourcePrincipalSessionTokenClient common.BaseClient +} + +// acquireResourcePrincipalToken acquires the resource principal from the target service +func (c *resourcePrincipalV3Client) acquireResourcePrincipalToken(rptClient common.BaseClient, path string, signer common.HTTPRequestSigner) (tokenResponse resourcePrincipalTokenResponse, parentRptURL string, err error) { + rpServiceClient := rptClient + rpServiceClient.Signer = signer + + //Create a request with the instanceId + request := common.MakeDefaultHTTPRequest(http.MethodGet, path) + + //Call the target service + response, err := rpServiceClient.Call(context.Background(), &request) + if err != nil { + return + } + + defer common.CloseBodyIfValid(response) + + // Extract the opc-parent-rpt-url header value + parentRptURL = response.Header.Get(OpcParentRptUrlHeader) + + tokenResponse = resourcePrincipalTokenResponse{} + err = common.UnmarshalResponse(response, &tokenResponse) + return +} + +// exchangeToken exchanges a resource principal token from the target service with a session token from identity +func (c *resourcePrincipalV3Client) exchangeToken(rpstClient common.BaseClient, signer common.HTTPRequestSigner, publicKeyBase64 string, tokenResponse resourcePrincipalTokenResponse) (sessionToken string, err error) { + rpServiceClient := rpstClient + rpServiceClient.Signer = signer + + // Call identity service to get resource principal session token + sessionTokenReq := resourcePrincipalSessionTokenRequest{ + resourcePrincipalSessionTokenRequestBody{ + ServicePrincipalSessionToken: tokenResponse.Body.ServicePrincipalSessionToken, + ResourcePrincipalToken: tokenResponse.Body.ResourcePrincipalToken, + SessionPublicKey: publicKeyBase64, + }, + } + + sessionTokenHTTPReq, err := common.MakeDefaultHTTPRequestWithTaggedStruct(http.MethodPost, + "", sessionTokenReq) + if err != nil { + return + } + + sessionTokenHTTPRes, err := rpServiceClient.Call(context.Background(), &sessionTokenHTTPReq) + if err != nil { + return + } + defer common.CloseBodyIfValid(sessionTokenHTTPRes) + + sessionTokenRes := x509FederationResponse{} + err = common.UnmarshalResponse(sessionTokenHTTPRes, &sessionTokenRes) + if err != nil { + return + } + + sessionToken = sessionTokenRes.Token.Token + return +} + +// getSecurityToken makes the appropriate calls to acquire a resource principal security token +func (c *resourcePrincipalV3Client) getSecurityToken() (securityToken, error) { + + //c.leafResourcePrincipalKeyProvider.KeyID() + //common.Debugf("Refreshing resource principal token") + + //Read the public key from the session supplier. + pem := c.sessionKeySupplier.PublicKeyPemRaw() + pemSanitized := sanitizeCertificateString(string(pem)) + + return c.getSecurityTokenWithDepth(c.leafResourcePrincipalKeyProvider, 1, c.rptUrl, pemSanitized) + +} + +func (c *resourcePrincipalV3Client) getSecurityTokenWithDepth(keyProvider ConfigurationProviderWithClaimAccess, depth int, rptUrl, publicKey string) (securityToken, error) { + //Build the target service client + rpTargetServiceClient, err := common.NewClientWithConfig(keyProvider) + if err != nil { + return nil, err + } + + rpTokenURL, err := url.Parse(rptUrl) + if err != nil { + return nil, err + } + + common.Debugf("rptURL: %v", rpTokenURL) + + rpTargetServiceClient.Host = rpTokenURL.Scheme + "://" + rpTokenURL.Host + + //Build the identity client for token service + rpTokenSessionClient, err := common.NewClientWithConfig(keyProvider) + if err != nil { + return nil, err + } + + // Set RPST endpoint if passed in from env var, otherwise create it from region + if c.rpstUrl != "" { + rpSessionTokenURL, err := url.Parse(c.rpstUrl) + if err != nil { + return nil, err + } + + rpTokenSessionClient.Host = rpSessionTokenURL.Scheme + "://" + rpSessionTokenURL.Host + } else { + regionStr, err := c.leafResourcePrincipalKeyProvider.Region() + if err != nil { + return nil, fmt.Errorf("missing RPST env var and cannot determine region: %v", err) + } + region := common.StringToRegion(regionStr) + rpTokenSessionClient.Host = fmt.Sprintf("https://%s", region.Endpoint("auth")) + } + + rpTokenSessionClient.BasePath = identityResourcePrincipalSessionTokenPath + + //Acquire resource principal token from target service + common.Debugf("Acquiring resource principal token from target service") + tokenResponse, parentRptURL, err := c.acquireResourcePrincipalToken(rpTargetServiceClient, rpTokenURL.Path, common.DefaultRequestSigner(keyProvider)) + if err != nil { + return nil, err + } + + //Exchange resource principal token for session token from identity + common.Debugf("Exchanging resource principal token for resource principal session token") + sessionToken, err := c.exchangeToken(rpTokenSessionClient, common.DefaultRequestSigner(keyProvider), publicKey, tokenResponse) + if err != nil { + return nil, err + } + + // Base condition for recursion + // return the security token obtained last in the following cases + // 1. if depth is more than 10 + // 2. if opc-parent-rpt-url header is not passed or is empty + // 3. if opc-parent-rpt-url matches the last rpt url + if depth >= 10 || parentRptURL == "" || strings.EqualFold(parentRptURL, rptUrl) { + return newPrincipalToken(sessionToken) + } + + fd, err := newStaticFederationClient(sessionToken, c.sessionKeySupplier) + + if err != nil { + err := fmt.Errorf("can not create resource principal, due to: %s ", err.Error()) + return nil, resourcePrincipalError{err: err} + } + + region, _ := keyProvider.Region() + + configProviderForNextCall := resourcePrincipalKeyProvider{ + fd, common.Region(region), + } + + return c.getSecurityTokenWithDepth(&configProviderForNextCall, depth+1, parentRptURL, publicKey) + +} + +func (c *resourcePrincipalV3Client) renewSecurityToken() (err error) { + if err = c.sessionKeySupplier.Refresh(); err != nil { + return fmt.Errorf("failed to refresh session key: %s", err.Error()) + } + + common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000")) + if c.securityToken, err = c.getSecurityToken(); err != nil { + return fmt.Errorf("failed to get security token: %s", err.Error()) + } + common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000")) + + return nil +} + +func (c *resourcePrincipalV3Client) renewSecurityTokenIfNotValid() (err error) { + if c.securityToken == nil || !c.securityToken.Valid() { + if err = c.renewSecurityToken(); err != nil { + return fmt.Errorf("failed to renew resource principal security token: %s", err.Error()) + } + } + return nil +} + +func (c *resourcePrincipalV3Client) PrivateKey() (*rsa.PrivateKey, error) { + c.mux.Lock() + defer c.mux.Unlock() + if err := c.renewSecurityTokenIfNotValid(); err != nil { + return nil, err + } + return c.sessionKeySupplier.PrivateKey(), nil +} + +func (c *resourcePrincipalV3Client) SecurityToken() (token string, err error) { + c.mux.Lock() + defer c.mux.Unlock() + + if err = c.renewSecurityTokenIfNotValid(); err != nil { + return "", err + } + return c.securityToken.String(), nil +} + +type resourcePrincipalKeyProviderV3 struct { + resourcePrincipalClient resourcePrincipalV3Client +} + +type resourcePrincipalV30ConfigurationProvider struct { + keyProvider resourcePrincipalKeyProviderV3 + region *common.Region +} + +func (r *resourcePrincipalV30ConfigurationProvider) Refreshable() bool { + return true +} + +func (r *resourcePrincipalV30ConfigurationProvider) PrivateRSAKey() (*rsa.PrivateKey, error) { + privateKey, err := r.keyProvider.resourcePrincipalClient.PrivateKey() + if err != nil { + err = fmt.Errorf("failed to get resource principal private key: %s", err.Error()) + return nil, err + } + return privateKey, nil +} + +func (r *resourcePrincipalV30ConfigurationProvider) KeyID() (string, error) { + var securityToken string + var err error + if securityToken, err = r.keyProvider.resourcePrincipalClient.SecurityToken(); err != nil { + return "", fmt.Errorf("failed to get resource principal security token: %s", err.Error()) + } + return fmt.Sprintf("ST$%s", securityToken), nil +} + +func (r *resourcePrincipalV30ConfigurationProvider) TenancyOCID() (string, error) { + return r.keyProvider.resourcePrincipalClient.leafResourcePrincipalKeyProvider.TenancyOCID() +} + +func (r *resourcePrincipalV30ConfigurationProvider) UserOCID() (string, error) { + return "", nil +} + +func (r *resourcePrincipalV30ConfigurationProvider) KeyFingerprint() (string, error) { + return "", nil +} + +func (r *resourcePrincipalV30ConfigurationProvider) Region() (string, error) { + if r.region == nil { + common.Debugf("Region in resource principal configuration provider v30 is nil.") + return "", nil + } + return string(*r.region), nil +} + +func (r *resourcePrincipalV30ConfigurationProvider) AuthType() (common.AuthConfig, error) { + return common.AuthConfig{common.UnknownAuthenticationType, false, nil}, + fmt.Errorf("unsupported, keep the interface") +} + +func (r *resourcePrincipalV30ConfigurationProvider) GetClaim(key string) (interface{}, error) { + //TODO implement me + panic("implement me") +} + +type resourcePrincipalV30ConfiguratorBuilder struct { + leafResourcePrincipalKeyProvider ConfigurationProviderWithClaimAccess + rptUrlForParent, rpstUrlForParent *string +} + +// ResourcePrincipalV3ConfiguratorBuilder creates a new resourcePrincipalV30ConfiguratorBuilder. +func ResourcePrincipalV3ConfiguratorBuilder(leafResourcePrincipalKeyProvider ConfigurationProviderWithClaimAccess) *resourcePrincipalV30ConfiguratorBuilder { + return &resourcePrincipalV30ConfiguratorBuilder{ + leafResourcePrincipalKeyProvider: leafResourcePrincipalKeyProvider, + } +} + +// WithParentRPTURL sets the rptUrlForParent field. +func (b *resourcePrincipalV30ConfiguratorBuilder) WithParentRPTURL(rptUrlForParent string) *resourcePrincipalV30ConfiguratorBuilder { + b.rptUrlForParent = &rptUrlForParent + return b +} + +// WithParentRPSTURL sets the rpstUrlForParent field. +func (b *resourcePrincipalV30ConfiguratorBuilder) WithParentRPSTURL(rpstUrlForParent string) *resourcePrincipalV30ConfiguratorBuilder { + b.rpstUrlForParent = &rpstUrlForParent + return b +} + +// Build creates a ConfigurationProviderWithClaimAccess based on the configured values. +func (b *resourcePrincipalV30ConfiguratorBuilder) Build() (ConfigurationProviderWithClaimAccess, error) { + + if b.rptUrlForParent == nil { + err := fmt.Errorf("can not create resource principal, environment variable: %s, not present", + ResourcePrincipalRptURLForParent) + return nil, resourcePrincipalError{err: err} + } + + if b.rpstUrlForParent == nil { + common.Debugf("Environment variable %s not present, setting to empty string", ResourcePrincipalRpstEndpointForParent) + *b.rpstUrlForParent = "" + } + + rpFedClient := resourcePrincipalV3Client{} + rpFedClient.rptUrl = *b.rptUrlForParent + rpFedClient.rpstUrl = *b.rpstUrlForParent + rpFedClient.sessionKeySupplier = newSessionKeySupplier() + rpFedClient.leafResourcePrincipalKeyProvider = b.leafResourcePrincipalKeyProvider + region, _ := b.leafResourcePrincipalKeyProvider.Region() + + return &resourcePrincipalV30ConfigurationProvider{ + keyProvider: resourcePrincipalKeyProviderV3{rpFedClient}, + region: (*common.Region)(®ion), + }, nil +} + +// ResourcePrincipalConfigurationProviderV3 ResourcePrincipalConfigurationProvider is a function that creates and configures a resource principal. +func ResourcePrincipalConfigurationProviderV3(leafResourcePrincipalKeyProvider ConfigurationProviderWithClaimAccess) (ConfigurationProviderWithClaimAccess, error) { + builder := ResourcePrincipalV3ConfiguratorBuilder(leafResourcePrincipalKeyProvider) + builder.rptUrlForParent = requireEnv(ResourcePrincipalRptURLForParent) + builder.rpstUrlForParent = requireEnv(ResourcePrincipalRpstEndpointForParent) + return builder.Build() +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/utils.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/utils.go new file mode 100644 index 00000000000..051dcfe8234 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/auth/utils.go @@ -0,0 +1,98 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package auth + +import ( + "bytes" + "crypto/sha1" + "crypto/x509" + "fmt" + "net/http" + "net/http/httputil" + "strings" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// httpGet makes a simple HTTP GET request to the given URL, expecting only "200 OK" status code. +// This is basically for the Instance Metadata Service. +func httpGet(dispatcher common.HTTPRequestDispatcher, url string) (body bytes.Buffer, statusCode int, err error) { + var response *http.Response + request, err := http.NewRequest(http.MethodGet, url, nil) + + request.Header.Add("Authorization", "Bearer Oracle") + + if response, err = dispatcher.Do(request); err != nil { + return + } + + statusCode = response.StatusCode + common.IfDebug(func() { + if dump, e := httputil.DumpResponse(response, true); e == nil { + common.Logf("Dump Response %v", string(dump)) + } else { + common.Debugln(e) + } + }) + + defer response.Body.Close() + if _, err = body.ReadFrom(response.Body); err != nil { + return + } + + if statusCode != http.StatusOK { + err = fmt.Errorf("HTTP Get failed: URL: %s, Status: %s, Message: %s", + url, response.Status, body.String()) + return + } + + return +} + +func extractTenancyIDFromCertificate(cert *x509.Certificate) string { + for _, nameAttr := range cert.Subject.Names { + value := nameAttr.Value.(string) + if strings.HasPrefix(value, "opc-tenant:") { + return value[len("opc-tenant:"):] + } + } + return "" +} + +func fingerprint(certificate *x509.Certificate) string { + fingerprint := sha1.Sum(certificate.Raw) + return colonSeparatedString(fingerprint) +} + +func colonSeparatedString(fingerprint [sha1.Size]byte) string { + spaceSeparated := fmt.Sprintf("% x", fingerprint) + return strings.Replace(spaceSeparated, " ", ":", -1) +} + +func sanitizeCertificateString(certString string) string { + certString = strings.Replace(certString, "-----BEGIN CERTIFICATE-----", "", -1) + certString = strings.Replace(certString, "-----END CERTIFICATE-----", "", -1) + certString = strings.Replace(certString, "-----BEGIN PUBLIC KEY-----", "", -1) + certString = strings.Replace(certString, "-----END PUBLIC KEY-----", "", -1) + certString = strings.Replace(certString, "\n", "", -1) + return certString +} + +// GetGenericConfigurationProvider checks auth config paras in config file and return the final configuration provider +func GetGenericConfigurationProvider(configProvider common.ConfigurationProvider) (common.ConfigurationProvider, error) { + if authConfig, err := configProvider.AuthType(); err == nil && authConfig.IsFromConfigFile { + switch authConfig.AuthType { + case common.InstancePrincipalDelegationToken: + if region, err := configProvider.Region(); err == nil { + return InstancePrincipalDelegationTokenConfigurationProviderForRegion(authConfig.OboToken, common.StringToRegion(region)) + } + return InstancePrincipalDelegationTokenConfigurationProvider(authConfig.OboToken) + case common.InstancePrincipal: + return InstancePrincipalConfigurationProvider() + case common.UserPrincipal: + return configProvider, nil + } + } + return configProvider, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/circuit_breaker.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/circuit_breaker.go new file mode 100644 index 00000000000..f4ee25899bf --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/circuit_breaker.go @@ -0,0 +1,410 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "fmt" + "math/rand" + "net/http" + "os" + "strconv" + "sync" + "time" + + "github.com/sony/gobreaker" +) + +const ( + // CircuitBreakerDefaultFailureRateThreshold is the requests failure rate which calculates in at most 120 seconds, once reaches to this rate, the circuit breaker state changes from closed to open + CircuitBreakerDefaultFailureRateThreshold float64 = 0.80 + // CircuitBreakerDefaultClosedWindow is the default value of closeStateWindow, which is the cyclic period of the closed state + CircuitBreakerDefaultClosedWindow time.Duration = 120 * time.Second + // CircuitBreakerDefaultResetTimeout is the default value of openStateWindow, which is the wait time before setting the breaker to halfOpen state from open state + CircuitBreakerDefaultResetTimeout time.Duration = 30 * time.Second + // CircuitBreakerDefaultVolumeThreshold is the default value of minimumRequests in closed status + CircuitBreakerDefaultVolumeThreshold uint32 = 10 + // DefaultCircuitBreakerName is the name of the circuit breaker + DefaultCircuitBreakerName string = "DefaultCircuitBreaker" + // DefaultCircuitBreakerServiceName is the servicename of the circuit breaker + DefaultCircuitBreakerServiceName string = "" + // DefaultCircuitBreakerHistoryCount is the default count of failed response history in circuit breaker + DefaultCircuitBreakerHistoryCount int = 5 + // MinAuthClientCircuitBreakerResetTimeout is the min value of openStateWindow, which is the wait time before setting the breaker to halfOpen state from open state + MinAuthClientCircuitBreakerResetTimeout = 30 + // MaxAuthClientCircuitBreakerResetTimeout is the max value of openStateWindow, which is the wait time before setting the breaker to halfOpen state from open state + MaxAuthClientCircuitBreakerResetTimeout = 49 + // AuthClientCircuitBreakerName is the default circuit breaker name for the DefaultAuthClientCircuitBreakerSetting + AuthClientCircuitBreakerName = "FederationClientCircuitBreaker" + // AuthClientCircuitBreakerDefaultFailureThreshold is the default requests failure rate for the DefaultAuthClientCircuitBreakerSetting + AuthClientCircuitBreakerDefaultFailureThreshold float64 = 0.65 + // AuthClientCircuitBreakerDefaultMinimumRequests is the default value of minimumRequests in closed status + AuthClientCircuitBreakerDefaultMinimumRequests uint32 = 3 +) + +// CircuitBreakerSetting wraps all exposed configurable params of circuit breaker +type CircuitBreakerSetting struct { + // Name is the Circuit Breaker's identifier + name string + // isEnabled is the switch of the circuit breaker, used for disable circuit breaker + isEnabled bool + // closeStateWindow is the cyclic period of the closed state, the default value is 120 seconds + closeStateWindow time.Duration + // openStateWindow is the wait time before setting the breaker to halfOpen state from open state, the default value is 30 seconds + openStateWindow time.Duration + // failureRateThreshold is the failure rate which calculates in at most closeStateWindow seconds, once reaches to this rate, the circuit breaker state changes from closed to open + // the circuit will transition from closed to open, the default value is 80% + failureRateThreshold float64 + // minimumRequests is the minimum number of counted requests in closed state, the default value is 10 requests + minimumRequests uint32 + // successStatCodeMap is the error(s) of StatusCode returned from service, which should be considered as the success or failure accounted by circuit breaker + // successStatCodeMap and successStatErrCodeMap are combined to use, if both StatusCode and ErrorCode are required, no need to add it to successStatCodeMap, + // the default value is [429, 500, 502, 503, 504] + successStatCodeMap map[int]bool + // successStatErrCodeMap is the error(s) of StatusCode and ErrorCode returned from service, which should be considered + // as the success or failure accounted by circuit breaker + // the default value is {409, "IncorrectState"} + successStatErrCodeMap map[StatErrCode]bool + // serviceName is the name of the service which can be set using withServiceName option for NewCircuitBreaker. + // the default value is empty string + serviceName string + // numberOfRecordedHistoryResponse is the number of failure responses stored in Circuit breaker history for debugging purpose + // the default value is 5 + numberOfRecordedHistoryResponse int +} + +// String Converts CircuitBreakerSetting to human-readable string representation +func (cbst CircuitBreakerSetting) String() string { + return fmt.Sprintf("{name=%v, isEnabled=%v, closeStateWindow=%v, openStateWindow=%v, failureRateThreshold=%v, minimumRequests=%v, successStatCodeMap=%v, successStatErrCodeMap=%v, serviceName=%v, historyCount=%v}", + cbst.name, cbst.isEnabled, cbst.closeStateWindow, cbst.openStateWindow, cbst.failureRateThreshold, cbst.minimumRequests, cbst.successStatCodeMap, cbst.successStatErrCodeMap, cbst.serviceName, cbst.numberOfRecordedHistoryResponse) +} + +// ResponseHistory wraps the response params +type ResponseHistory struct { + timestamp time.Time + opcReqID string + errorCode string + errorMessage string + statusCode int +} + +// String Converts ResponseHistory to human-readable string representation +func (rh ResponseHistory) String() string { + return fmt.Sprintf("Opc-Req-id - %v\nErrorCode - %v - %v\nErrorMessage - %v\n\n", rh.opcReqID, rh.statusCode, rh.errorCode, rh.errorMessage) +} + +// AddToHistory processed the response and adds to response history queue +func (ocb *OciCircuitBreaker) AddToHistory(resp *http.Response, err ServiceError) { + respHist := new(ResponseHistory) + respHist.opcReqID = err.GetOpcRequestID() + respHist.errorCode = err.GetCode() + respHist.errorMessage = err.GetMessage() + respHist.statusCode = err.GetHTTPStatusCode() + respHist.timestamp, _ = time.Parse(time.RFC1123, resp.Header.Get("Date")) + ocb.historyQueueMutex.Lock() + defer ocb.historyQueueMutex.Unlock() + ocb.historyQueue = append(ocb.historyQueue, *respHist) + // cleaning up older values + if len(ocb.historyQueue) > ocb.Cbst.numberOfRecordedHistoryResponse { + // We have reached the capacity. Clean up the oldest value + ocb.historyQueue = ocb.historyQueue[1:] + } + for index := len(ocb.historyQueue) - 1; index >= 0; index-- { + if time.Since(ocb.historyQueue[index].timestamp) > ocb.Cbst.closeStateWindow { + // This response is older than the circuit breaker closeStateWindow. + // Remove all the older responses from 0 to index + ocb.historyQueue = ocb.historyQueue[index+1:] + break + } + } + return +} + +// GetHistory processes the rsponse in queue to construct a String +func (ocb *OciCircuitBreaker) GetHistory() string { + getHistoryString := "" + ocb.historyQueueMutex.Lock() + defer ocb.historyQueueMutex.Unlock() + for _, value := range ocb.historyQueue { + getHistoryString += value.String() + } + return getHistoryString +} + +// OciCircuitBreaker wraps all exposed configurable params of circuit breaker and 3P gobreaker CircuirBreaker +type OciCircuitBreaker struct { + Cbst *CircuitBreakerSetting + Cb *gobreaker.CircuitBreaker + historyQueue []ResponseHistory + historyQueueMutex sync.Mutex +} + +// NewOciCircuitBreaker is used for initializing specified oci circuit breaker configuration with circuit breaker settings +func NewOciCircuitBreaker(cbst *CircuitBreakerSetting, gbcb *gobreaker.CircuitBreaker) *OciCircuitBreaker { + ocb := new(OciCircuitBreaker) + ocb.Cbst = cbst + if ocb.Cbst.numberOfRecordedHistoryResponse == 0 { + fmt.Println("num hist empty") + ocb.Cbst.numberOfRecordedHistoryResponse = getDefaultNumHistoryCount() + } + ocb.Cb = gbcb + ocb.historyQueue = make([]ResponseHistory, 0, ocb.Cbst.numberOfRecordedHistoryResponse) + + return ocb +} + +// CircuitBreakerOption is the type of the options for NewCircuitBreakerWithOptions. +type CircuitBreakerOption func(cbst *CircuitBreakerSetting) + +// NewGoCircuitBreaker is a function to initialize a CircuitBreaker object with the specified configuration +// Add the interface, to allow the user directly use the 3P gobreaker.Setting's params. +func NewGoCircuitBreaker(st gobreaker.Settings) *gobreaker.CircuitBreaker { + return gobreaker.NewCircuitBreaker(st) +} + +// DefaultCircuitBreakerSetting is used for set circuit breaker with default config +func DefaultCircuitBreakerSetting() *CircuitBreakerSetting { + successStatErrCodeMap := map[StatErrCode]bool{ + {409, "IncorrectState"}: false, + } + successStatCodeMap := map[int]bool{ + 429: false, + 500: false, + 502: false, + 503: false, + 504: false, + } + return newCircuitBreakerSetting( + WithName(DefaultCircuitBreakerName), + WithIsEnabled(true), + WithCloseStateWindow(CircuitBreakerDefaultClosedWindow), + WithOpenStateWindow(CircuitBreakerDefaultResetTimeout), + WithFailureRateThreshold(CircuitBreakerDefaultFailureRateThreshold), + WithMinimumRequests(CircuitBreakerDefaultVolumeThreshold), + WithSuccessStatErrCodeMap(successStatErrCodeMap), + WithSuccessStatCodeMap(successStatCodeMap), + WithHistoryCount(getDefaultNumHistoryCount())) +} + +// DefaultCircuitBreakerSettingWithServiceName is used for set circuit breaker with default config +func DefaultCircuitBreakerSettingWithServiceName(servicename string) *CircuitBreakerSetting { + successStatErrCodeMap := map[StatErrCode]bool{ + {409, "IncorrectState"}: false, + } + successStatCodeMap := map[int]bool{ + 429: false, + 500: false, + 502: false, + 503: false, + 504: false, + } + return newCircuitBreakerSetting( + WithName(DefaultCircuitBreakerName), + WithIsEnabled(true), + WithCloseStateWindow(CircuitBreakerDefaultClosedWindow), + WithOpenStateWindow(CircuitBreakerDefaultResetTimeout), + WithFailureRateThreshold(CircuitBreakerDefaultFailureRateThreshold), + WithMinimumRequests(CircuitBreakerDefaultVolumeThreshold), + WithSuccessStatErrCodeMap(successStatErrCodeMap), + WithSuccessStatCodeMap(successStatCodeMap), + WithServiceName(servicename), + WithHistoryCount(getDefaultNumHistoryCount())) +} + +// NoCircuitBreakerSetting is used for disable Circuit Breaker +func NoCircuitBreakerSetting() *CircuitBreakerSetting { + return NewCircuitBreakerSettingWithOptions(WithIsEnabled(false)) +} + +// NewCircuitBreakerSettingWithOptions is a helper method to assemble a CircuitBreakerSetting object. +// It starts out with the values returned by defaultCircuitBreakerSetting(). +func NewCircuitBreakerSettingWithOptions(opts ...CircuitBreakerOption) *CircuitBreakerSetting { + cbst := DefaultCircuitBreakerSettingWithServiceName(DefaultCircuitBreakerServiceName) + // allow changing values + for _, opt := range opts { + opt(cbst) + } + if defaultLogger != nil && defaultLogger.LogLevel() == verboseLogging { + Debugf("Circuit Breaker setting: %s\n", cbst.String()) + } + + return cbst +} + +// NewCircuitBreaker is used for initialing specified circuit breaker configuration with base client +func NewCircuitBreaker(cbst *CircuitBreakerSetting) *OciCircuitBreaker { + if !cbst.isEnabled { + return nil + } + + st := gobreaker.Settings{} + customizeGoBreakerSetting(&st, cbst) + gbcb := gobreaker.NewCircuitBreaker(st) + + return NewOciCircuitBreaker(cbst, gbcb) +} + +func newCircuitBreakerSetting(opts ...CircuitBreakerOption) *CircuitBreakerSetting { + cbSetting := CircuitBreakerSetting{} + + // allow changing values + for _, opt := range opts { + opt(&cbSetting) + } + return &cbSetting +} + +// customizeGoBreakerSetting is used for converting CircuitBreakerSetting to 3P gobreaker's setting type +func customizeGoBreakerSetting(st *gobreaker.Settings, cbst *CircuitBreakerSetting) { + st.Name = cbst.name + st.Timeout = cbst.openStateWindow + st.Interval = cbst.closeStateWindow + st.OnStateChange = func(name string, from gobreaker.State, to gobreaker.State) { + if to == gobreaker.StateOpen { + Debugf("Circuit Breaker %s is now in Open State\n", name) + } + } + st.ReadyToTrip = func(counts gobreaker.Counts) bool { + failureRatio := float64(counts.TotalFailures) / float64(counts.Requests) + return counts.Requests >= cbst.minimumRequests && failureRatio >= cbst.failureRateThreshold + } + st.IsSuccessful = func(err error) bool { + if serviceErr, ok := IsServiceError(err); ok { + if isSuccessful, ok := cbst.successStatCodeMap[serviceErr.GetHTTPStatusCode()]; ok { + return isSuccessful + } + if isSuccessful, ok := cbst.successStatErrCodeMap[StatErrCode{serviceErr.GetHTTPStatusCode(), serviceErr.GetCode()}]; ok { + return isSuccessful + } + } + return true + } +} + +// WithName is the option for NewCircuitBreaker that sets the Name. +func WithName(name string) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.name = name + } +} + +// WithIsEnabled is the option for NewCircuitBreaker that sets the isEnabled. +func WithIsEnabled(isEnabled bool) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.isEnabled = isEnabled + } +} + +// WithCloseStateWindow is the option for NewCircuitBreaker that sets the closeStateWindow. +func WithCloseStateWindow(window time.Duration) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.closeStateWindow = window + } +} + +// WithOpenStateWindow is the option for NewCircuitBreaker that sets the openStateWindow. +func WithOpenStateWindow(window time.Duration) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.openStateWindow = window + } +} + +// WithFailureRateThreshold is the option for NewCircuitBreaker that sets the failureRateThreshold. +func WithFailureRateThreshold(threshold float64) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.failureRateThreshold = threshold + } +} + +// WithMinimumRequests is the option for NewCircuitBreaker that sets the minimumRequests. +func WithMinimumRequests(num uint32) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.minimumRequests = num + } +} + +// WithSuccessStatCodeMap is the option for NewCircuitBreaker that sets the successStatCodeMap. +func WithSuccessStatCodeMap(successStatCodeMap map[int]bool) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.successStatCodeMap = successStatCodeMap + } +} + +// WithSuccessStatErrCodeMap is the option for NewCircuitBreaker that sets the successStatErrCodeMap. +func WithSuccessStatErrCodeMap(successStatErrCodeMap map[StatErrCode]bool) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.successStatErrCodeMap = successStatErrCodeMap + } +} + +// WithServiceName is the option for NewCircuitBreaker that sets the ServiceName. +func WithServiceName(serviceName string) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.serviceName = serviceName + } +} + +// WithHistoryCount to set the number of failed responses +func WithHistoryCount(count int) CircuitBreakerOption { + // this is the CircuitBreakerOption function type + return func(cbst *CircuitBreakerSetting) { + cbst.numberOfRecordedHistoryResponse = count + } +} + +// getDefaultNumHistoryCount to set the number of failed responses +func getDefaultNumHistoryCount() int { + if val, isSet := os.LookupEnv(circuitBreakerNumberOfHistoryResponseEnv); isSet { + count, err := strconv.Atoi(val) + if err == nil && count > 0 { + return count + } + Debugf("Invalid history count specified. Resetting to default value") + } + return DefaultCircuitBreakerHistoryCount +} + +// GlobalCircuitBreakerSetting is global level circuit breaker setting, it would impact all services, the precedence is lower +// than client level circuit breaker +var GlobalCircuitBreakerSetting *CircuitBreakerSetting = nil + +// ConfigCircuitBreakerFromEnvVar is used for checking the circuit breaker environment variable setting, default value is nil +func ConfigCircuitBreakerFromEnvVar(baseClient *BaseClient) { + if IsEnvVarTrue(isDefaultCircuitBreakerEnabled) { + baseClient.Configuration.CircuitBreaker = NewCircuitBreaker(DefaultCircuitBreakerSetting()) + return + } + if IsEnvVarFalse(isDefaultCircuitBreakerEnabled) { + baseClient.Configuration.CircuitBreaker = nil + } +} + +// ConfigCircuitBreakerFromGlobalVar is used for checking if global circuitBreakerSetting is configured, the priority is higher than cb env var +func ConfigCircuitBreakerFromGlobalVar(baseClient *BaseClient) { + if GlobalCircuitBreakerSetting != nil { + baseClient.Configuration.CircuitBreaker = NewCircuitBreaker(GlobalCircuitBreakerSetting) + } +} + +// DefaultAuthClientCircuitBreakerSetting returns the default circuit breaker setting for the Auth Client +func DefaultAuthClientCircuitBreakerSetting() *CircuitBreakerSetting { + return NewCircuitBreakerSettingWithOptions( + WithOpenStateWindow(time.Duration(rand.Intn(MaxAuthClientCircuitBreakerResetTimeout+1-MinAuthClientCircuitBreakerResetTimeout)+MinAuthClientCircuitBreakerResetTimeout)*time.Second), + WithName(AuthClientCircuitBreakerName), + WithFailureRateThreshold(AuthClientCircuitBreakerDefaultFailureThreshold), + WithMinimumRequests(AuthClientCircuitBreakerDefaultMinimumRequests), + ) +} + +// GlobalAuthClientCircuitBreakerSetting is global level circuit breaker setting for the Auth Client +// than client level circuit breaker +var GlobalAuthClientCircuitBreakerSetting *CircuitBreakerSetting = nil diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/client.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/client.go new file mode 100644 index 00000000000..6ecab637e18 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/client.go @@ -0,0 +1,748 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +// Package common provides supporting functions and structs used by service packages +package common + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net/http" + "net/http/httputil" + "net/url" + "os" + "os/user" + "path" + "path/filepath" + "reflect" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +const ( + // DefaultHostURLTemplate The default url template for service hosts + DefaultHostURLTemplate = "%s.%s.oraclecloud.com" + + // requestHeaderAccept The key for passing a header to indicate Accept + requestHeaderAccept = "Accept" + + // requestHeaderAuthorization The key for passing a header to indicate Authorization + requestHeaderAuthorization = "Authorization" + + // requestHeaderContentLength The key for passing a header to indicate Content Length + requestHeaderContentLength = "Content-Length" + + // requestHeaderContentType The key for passing a header to indicate Content Type + requestHeaderContentType = "Content-Type" + + // requestHeaderExpect The key for passing a header to indicate Expect/100-Continue + requestHeaderExpect = "Expect" + + // requestHeaderDate The key for passing a header to indicate Date + requestHeaderDate = "Date" + + // requestHeaderIfMatch The key for passing a header to indicate If Match + requestHeaderIfMatch = "if-match" + + // requestHeaderOpcClientInfo The key for passing a header to indicate OPC Client Info + requestHeaderOpcClientInfo = "opc-client-info" + + // requestHeaderOpcRetryToken The key for passing a header to indicate OPC Retry Token + requestHeaderOpcRetryToken = "opc-retry-token" + + // requestHeaderOpcRequestID The key for unique Oracle-assigned identifier for the request. + requestHeaderOpcRequestID = "opc-request-id" + + // requestHeaderOpcClientRequestID The key for unique Oracle-assigned identifier for the request. + requestHeaderOpcClientRequestID = "opc-client-request-id" + + // requestHeaderUserAgent The key for passing a header to indicate User Agent + requestHeaderUserAgent = "User-Agent" + + // requestHeaderXContentSHA256 The key for passing a header to indicate SHA256 hash + requestHeaderXContentSHA256 = "X-Content-SHA256" + + // requestHeaderOpcOboToken The key for passing a header to use obo token + requestHeaderOpcOboToken = "opc-obo-token" + + // private constants + defaultScheme = "https" + defaultSDKMarker = "Oracle-GoSDK" + defaultUserAgentTemplate = "%s/%s (%s/%s; go/%s)" //SDK/SDKVersion (OS/OSVersion; Lang/LangVersion) + // http.Client.Timeout includes Dial, TLSHandshake, Request, Response header and body + defaultTimeout = 60 * time.Second + defaultConfigFileName = "config" + defaultConfigDirName = ".oci" + configFilePathEnvVarName = "OCI_CONFIG_FILE" + + secondaryConfigDirName = ".oraclebmc" + maxBodyLenForDebug = 1024 * 1000 + + // appendUserAgentEnv The key for retrieving append user agent value from env var + appendUserAgentEnv = "OCI_SDK_APPEND_USER_AGENT" + + // requestHeaderOpcClientRetries The key for passing a header to set client retries info + requestHeaderOpcClientRetries = "opc-client-retries" + + // isDefaultRetryEnabled The key for set default retry disabled from env var + isDefaultRetryEnabled = "OCI_SDK_DEFAULT_RETRY_ENABLED" + + // isDefaultCircuitBreakerEnabled is the key for set default circuit breaker disabled from env var + isDefaultCircuitBreakerEnabled = "OCI_SDK_DEFAULT_CIRCUITBREAKER_ENABLED" + + //circuitBreakerNumberOfHistoryResponseEnv is the number of recorded history responses + circuitBreakerNumberOfHistoryResponseEnv = "OCI_SDK_CIRCUITBREAKER_NUM_HISTORY_RESPONSE" + + // ociDefaultRefreshIntervalForCustomCerts is the env var for overriding the defaultRefreshIntervalForCustomCerts. + // The value represents the refresh interval in minutes and has a higher precedence than defaultRefreshIntervalForCustomCerts + // but has a lower precedence then the refresh interval configured via OciGlobalRefreshIntervalForCustomCerts + // If the value is negative, then it is assumed that this property is not configured + // if the value is Zero, then the refresh of custom certs will be disabled + ociDefaultRefreshIntervalForCustomCerts = "OCI_DEFAULT_REFRESH_INTERVAL_FOR_CUSTOM_CERTS" + + // ociDefaultCertsPath is the env var for the path to the SSL cert file + ociDefaultCertsPath = "OCI_DEFAULT_CERTS_PATH" + + // ociDefaultClientCertsPath is the env var for the path to the custom client cert + ociDefaultClientCertsPath = "OCI_DEFAULT_CLIENT_CERTS_PATH" + + // ociDefaultClientCertsPrivateKeyPath is the env var for the path to the custom client cert private key + ociDefaultClientCertsPrivateKeyPath = "OCI_DEFAULT_CLIENT_CERTS_PRIVATE_KEY_PATH" + + //maxAttemptsForRefreshableRetry is the number of retry when 401 happened on a refreshable auth type + maxAttemptsForRefreshableRetry = 3 + + //defaultRefreshIntervalForCustomCerts is the default refresh interval in minutes + defaultRefreshIntervalForCustomCerts = 30 +) + +// OciGlobalRefreshIntervalForCustomCerts is the global policy for overriding the refresh interval in minutes. +// This variable has a higher precedence than the env variable OCI_DEFAULT_REFRESH_INTERVAL_FOR_CUSTOM_CERTS +// and the defaultRefreshIntervalForCustomCerts values. +// If the value is negative, then it is assumed that this property is not configured +// if the value is Zero, then the refresh of custom certs will be disabled +var OciGlobalRefreshIntervalForCustomCerts int = -1 + +// RequestInterceptor function used to customize the request before calling the underlying service +type RequestInterceptor func(*http.Request) error + +// HTTPRequestDispatcher wraps the execution of a http request, it is generally implemented by +// http.Client.Do, but can be customized for testing +type HTTPRequestDispatcher interface { + Do(req *http.Request) (*http.Response, error) +} + +// CustomClientConfiguration contains configurations set at client level, currently it only includes RetryPolicy +type CustomClientConfiguration struct { + RetryPolicy *RetryPolicy + CircuitBreaker *OciCircuitBreaker + RealmSpecificServiceEndpointTemplateEnabled *bool +} + +// BaseClient struct implements all basic operations to call oci web services. +type BaseClient struct { + //HTTPClient performs the http network operations + HTTPClient HTTPRequestDispatcher + + //Signer performs auth operation + Signer HTTPRequestSigner + + //A request interceptor can be used to customize the request before signing and dispatching + Interceptor RequestInterceptor + + //The host of the service + Host string + + //The user agent + UserAgent string + + //Base path for all operations of this client + BasePath string + + Configuration CustomClientConfiguration +} + +// SetCustomClientConfiguration sets client with retry and other custom configurations +func (client *BaseClient) SetCustomClientConfiguration(config CustomClientConfiguration) { + client.Configuration = config +} + +// RetryPolicy returns the retryPolicy configured for client +func (client *BaseClient) RetryPolicy() *RetryPolicy { + return client.Configuration.RetryPolicy +} + +// Endpoint returns the endpoint configured for client +func (client *BaseClient) Endpoint() string { + host := client.Host + if !strings.Contains(host, "http") && + !strings.Contains(host, "https") { + host = fmt.Sprintf("%s://%s", defaultScheme, host) + } + return host +} + +func defaultUserAgent() string { + userAgent := fmt.Sprintf(defaultUserAgentTemplate, defaultSDKMarker, Version(), runtime.GOOS, runtime.GOARCH, runtime.Version()) + appendUA := os.Getenv(appendUserAgentEnv) + if appendUA != "" { + userAgent = fmt.Sprintf("%s %s", userAgent, appendUA) + } + return userAgent +} + +var clientCounter int64 + +func getNextSeed() int64 { + newCounterValue := atomic.AddInt64(&clientCounter, 1) + return newCounterValue + time.Now().UnixNano() +} + +func newBaseClient(signer HTTPRequestSigner, dispatcher HTTPRequestDispatcher) BaseClient { + rand.Seed(getNextSeed()) + + baseClient := BaseClient{ + UserAgent: defaultUserAgent(), + Interceptor: nil, + Signer: signer, + HTTPClient: dispatcher, + } + + // check the default retry environment variable setting + if IsEnvVarTrue(isDefaultRetryEnabled) { + defaultRetry := DefaultRetryPolicy() + baseClient.Configuration.RetryPolicy = &defaultRetry + } else if IsEnvVarFalse(isDefaultRetryEnabled) { + policy := NoRetryPolicy() + baseClient.Configuration.RetryPolicy = &policy + } + // check if user defined global retry is configured + if GlobalRetry != nil { + baseClient.Configuration.RetryPolicy = GlobalRetry + } + + return baseClient +} + +func defaultHTTPDispatcher() http.Client { + var httpClient http.Client + refreshInterval := getCustomCertRefreshInterval() + if refreshInterval <= 0 { + Debug("Custom cert refresh has been disabled") + } + var tp = &OciHTTPTransportWrapper{ + RefreshRate: time.Duration(refreshInterval) * time.Minute, + TLSConfigProvider: GetTLSConfigTemplateForTransport(), + } + httpClient = http.Client{ + Timeout: defaultTimeout, + Transport: tp, + } + return httpClient +} + +func defaultBaseClient(provider KeyProvider) BaseClient { + dispatcher := defaultHTTPDispatcher() + signer := DefaultRequestSigner(provider) + return newBaseClient(signer, &dispatcher) +} + +// DefaultBaseClientWithSigner creates a default base client with a given signer +func DefaultBaseClientWithSigner(signer HTTPRequestSigner) BaseClient { + dispatcher := defaultHTTPDispatcher() + return newBaseClient(signer, &dispatcher) +} + +// NewClientWithConfig Create a new client with a configuration provider, the configuration provider +// will be used for the default signer as well as reading the region +// This function does not check for valid regions to implement forward compatibility +func NewClientWithConfig(configProvider ConfigurationProvider) (client BaseClient, err error) { + var ok bool + if ok, err = IsConfigurationProviderValid(configProvider); !ok { + err = fmt.Errorf("can not create client, bad configuration: %s", err.Error()) + return + } + + client = defaultBaseClient(configProvider) + + if authConfig, e := configProvider.AuthType(); e == nil && authConfig.OboToken != nil { + Debugf("authConfig's authType is %s, and token content is %s", authConfig.AuthType, *authConfig.OboToken) + signOboToken(&client, *authConfig.OboToken, configProvider) + } + + return +} + +// NewClientWithOboToken Create a new client that will use oboToken for auth +func NewClientWithOboToken(configProvider ConfigurationProvider, oboToken string) (client BaseClient, err error) { + client, err = NewClientWithConfig(configProvider) + if err != nil { + return + } + + signOboToken(&client, oboToken, configProvider) + + return +} + +// Add obo token header to Interceptor and sign to client +func signOboToken(client *BaseClient, oboToken string, configProvider ConfigurationProvider) { + // Interceptor to add obo token header + client.Interceptor = func(request *http.Request) error { + request.Header.Add(requestHeaderOpcOboToken, oboToken) + return nil + } + // Obo token will also be signed + defaultHeaders := append(DefaultGenericHeaders(), requestHeaderOpcOboToken) + client.Signer = RequestSigner(configProvider, defaultHeaders, DefaultBodyHeaders()) +} + +func getHomeFolder() string { + current, e := user.Current() + if e != nil { + //Give up and try to return something sensible + home := os.Getenv("HOME") + if home == "" { + home = os.Getenv("USERPROFILE") + } + return home + } + return current.HomeDir +} + +// DefaultConfigProvider returns the default config provider. The default config provider +// will look for configurations in 3 places: file in $HOME/.oci/config, HOME/.obmcs/config and +// variables names starting with the string TF_VAR. If the same configuration is found in multiple +// places the provider will prefer the first one. +// If the config file is not placed in the default location, the environment variable +// OCI_CONFIG_FILE can provide the config file location. +func DefaultConfigProvider() ConfigurationProvider { + defaultConfigFile := getDefaultConfigFilePath() + homeFolder := getHomeFolder() + secondaryConfigFile := filepath.Join(homeFolder, secondaryConfigDirName, defaultConfigFileName) + + defaultFileProvider, _ := ConfigurationProviderFromFile(defaultConfigFile, "") + secondaryFileProvider, _ := ConfigurationProviderFromFile(secondaryConfigFile, "") + environmentProvider := environmentConfigurationProvider{EnvironmentVariablePrefix: "TF_VAR"} + + provider, _ := ComposingConfigurationProvider([]ConfigurationProvider{defaultFileProvider, secondaryFileProvider, environmentProvider}) + Debugf("Configuration provided by: %s", provider) + return provider +} + +// CustomProfileSessionTokenConfigProvider returns the session token config provider of the given profile. +// This will look for the configuration in the given config file path. +func CustomProfileSessionTokenConfigProvider(customConfigPath string, profile string) ConfigurationProvider { + if customConfigPath == "" { + customConfigPath = getDefaultConfigFilePath() + } + + sessionTokenConfigurationProvider, _ := ConfigurationProviderForSessionTokenWithProfile(customConfigPath, profile, "") + Debugf("Configuration provided by: %s", sessionTokenConfigurationProvider) + return sessionTokenConfigurationProvider +} + +func getDefaultConfigFilePath() string { + homeFolder := getHomeFolder() + defaultConfigFile := filepath.Join(homeFolder, defaultConfigDirName, defaultConfigFileName) + if _, err := os.Stat(defaultConfigFile); err == nil { + return defaultConfigFile + } + Debugf("The %s does not exist, will check env var %s for file path.", defaultConfigFile, configFilePathEnvVarName) + // Read configuration file path from OCI_CONFIG_FILE env var + fallbackConfigFile, existed := os.LookupEnv(configFilePathEnvVarName) + if !existed { + Debugf("The env var %s does not exist...", configFilePathEnvVarName) + return defaultConfigFile + } + if _, err := os.Stat(fallbackConfigFile); os.IsNotExist(err) { + Debugf("The specified cfg file path in the env var %s does not exist: %s", configFilePathEnvVarName, fallbackConfigFile) + return defaultConfigFile + } + return fallbackConfigFile +} + +// setRawPath sets the Path and RawPath fields of the URL based on the provided +// escaped path p. It maintains the invariant that RawPath is only specified +// when it differs from the default encoding of the path. +// For example: +// - setPath("/foo/bar") will set Path="/foo/bar" and RawPath="" +// - setPath("/foo%2fbar") will set Path="/foo/bar" and RawPath="/foo%2fbar" +func setRawPath(u *url.URL) error { + oldPath := u.Path + path, err := url.PathUnescape(u.Path) + if err != nil { + return err + } + u.Path = path + if escp := u.EscapedPath(); oldPath == escp { + // Default encoding is fine. + u.RawPath = "" + } else { + u.RawPath = oldPath + } + return nil +} + +// CustomProfileConfigProvider returns the config provider of given profile. The custom profile config provider +// will look for configurations in 2 places: file in $HOME/.oci/config, and variables names starting with the +// string TF_VAR. If the same configuration is found in multiple places the provider will prefer the first one. +func CustomProfileConfigProvider(customConfigPath string, profile string) ConfigurationProvider { + homeFolder := getHomeFolder() + if customConfigPath == "" { + customConfigPath = filepath.Join(homeFolder, defaultConfigDirName, defaultConfigFileName) + } + customFileProvider, _ := ConfigurationProviderFromFileWithProfile(customConfigPath, profile, "") + defaultFileProvider, _ := ConfigurationProviderFromFileWithProfile(customConfigPath, "DEFAULT", "") + environmentProvider := environmentConfigurationProvider{EnvironmentVariablePrefix: "TF_VAR"} + provider, _ := ComposingConfigurationProvider([]ConfigurationProvider{customFileProvider, defaultFileProvider, environmentProvider}) + Debugf("Configuration provided by: %s", provider) + return provider +} + +func (client *BaseClient) prepareRequest(request *http.Request) (err error) { + if client.UserAgent == "" { + return fmt.Errorf("user agent can not be blank") + } + + if request.Header == nil { + request.Header = http.Header{} + } + request.Header.Set(requestHeaderUserAgent, client.UserAgent) + request.Header.Set(requestHeaderDate, time.Now().UTC().Format(http.TimeFormat)) + + if !strings.Contains(client.Host, "http") && + !strings.Contains(client.Host, "https") { + client.Host = fmt.Sprintf("%s://%s", defaultScheme, client.Host) + } + + clientURL, err := url.Parse(client.Host) + if err != nil { + return fmt.Errorf("host is invalid. %s", err.Error()) + } + request.URL.Host = clientURL.Host + request.URL.Scheme = clientURL.Scheme + currentPath := request.URL.Path + if !strings.Contains(currentPath, fmt.Sprintf("/%s", client.BasePath)) { + request.URL.Path = path.Clean(fmt.Sprintf("/%s/%s", client.BasePath, currentPath)) + err := setRawPath(request.URL) + if err != nil { + return err + } + } + return +} + +func (client BaseClient) intercept(request *http.Request) (err error) { + if client.Interceptor != nil { + err = client.Interceptor(request) + } + return +} + +// checkForSuccessfulResponse checks if the response is successful +// If Error Code is 4XX/5XX and debug level is set to info, will log the request and response +func checkForSuccessfulResponse(res *http.Response, requestBody *io.ReadCloser) error { + familyStatusCode := res.StatusCode / 100 + if familyStatusCode == 4 || familyStatusCode == 5 { + IfInfo(func() { + // If debug level is set to verbose, the request and request body will be dumped and logged under debug level, this is to avoid duplicate logging + if defaultLogger.LogLevel() < verboseLogging { + logRequest(res.Request, Logf, noLogging) + if requestBody != nil && *requestBody != http.NoBody { + bodyContent, _ := ioutil.ReadAll(*requestBody) + Logf("Dump Request Body: \n%s", string(bodyContent)) + } + } + logResponse(res, Logf, infoLogging) + }) + return newServiceFailureFromResponse(res) + } + IfDebug(func() { + logResponse(res, Debugf, verboseLogging) + }) + return nil +} + +func logRequest(request *http.Request, fn func(format string, v ...interface{}), bodyLoggingLevel int) { + if request == nil { + return + } + dumpBody := true + if checkBodyLengthExceedLimit(request.ContentLength) { + fn("not dumping body too big\n") + dumpBody = false + } + + dumpBody = dumpBody && defaultLogger.LogLevel() >= bodyLoggingLevel && bodyLoggingLevel != noLogging + if dump, e := httputil.DumpRequestOut(request, dumpBody); e == nil { + fn("Dump Request %s", string(dump)) + } else { + fn("%v\n", e) + } +} + +func logResponse(response *http.Response, fn func(format string, v ...interface{}), bodyLoggingLevel int) { + if response == nil { + return + } + dumpBody := true + if checkBodyLengthExceedLimit(response.ContentLength) { + fn("not dumping body too big\n") + dumpBody = false + } + dumpBody = dumpBody && defaultLogger.LogLevel() >= bodyLoggingLevel && bodyLoggingLevel != noLogging + if dump, e := httputil.DumpResponse(response, dumpBody); e == nil { + fn("Dump Response %s", string(dump)) + } else { + fn("%v\n", e) + } +} + +func checkBodyLengthExceedLimit(contentLength int64) bool { + return contentLength > maxBodyLenForDebug +} + +// OCIRequest is any request made to an OCI service. +type OCIRequest interface { + // HTTPRequest assembles an HTTP request. + HTTPRequest(method, path string, binaryRequestBody *OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) +} + +// RequestMetadata is metadata about an OCIRequest. This structure represents the behavior exhibited by the SDK when +// issuing (or reissuing) a request. +type RequestMetadata struct { + // RetryPolicy is the policy for reissuing the request. If no retry policy is set on the request, + // then the request will be issued exactly once. + RetryPolicy *RetryPolicy +} + +// OCIReadSeekCloser is a thread-safe io.ReadSeekCloser to prevent racing with retrying binary requests +type OCIReadSeekCloser struct { + rc io.ReadCloser + lock sync.Mutex + isClosed bool +} + +// NewOCIReadSeekCloser constructs OCIReadSeekCloser, the only input is binary request body +func NewOCIReadSeekCloser(rc io.ReadCloser) *OCIReadSeekCloser { + rsc := OCIReadSeekCloser{} + rsc.rc = rc + return &rsc +} + +// Seek is a thread-safe operation, it implements io.seek() interface, if the original request body implements io.seek() +// interface, or implements "well-known" data type like os.File, io.SectionReader, or wrapped by ioutil.NopCloser can be supported +func (rsc *OCIReadSeekCloser) Seek(offset int64, whence int) (int64, error) { + rsc.lock.Lock() + defer rsc.lock.Unlock() + + if _, ok := rsc.rc.(io.Seeker); ok { + return rsc.rc.(io.Seeker).Seek(offset, whence) + } + // once the binary request body is wrapped with ioutil.NopCloser: + if isNopCloser(rsc.rc) { + unwrappedInterface := reflect.ValueOf(rsc.rc).Field(0).Interface() + if _, ok := unwrappedInterface.(io.Seeker); ok { + return unwrappedInterface.(io.Seeker).Seek(offset, whence) + } + } + return 0, fmt.Errorf("current binary request body type is not seekable, if want to use retry feature, please make sure the request body implements seek() method") +} + +// Close is a thread-safe operation, it closes the instance of the OCIReadSeekCloser's access to the underlying io.ReadCloser. +func (rsc *OCIReadSeekCloser) Close() error { + rsc.lock.Lock() + defer rsc.lock.Unlock() + rsc.isClosed = true + return nil +} + +// Read is a thread-safe operation, it implements io.Read() interface +func (rsc *OCIReadSeekCloser) Read(p []byte) (n int, err error) { + rsc.lock.Lock() + defer rsc.lock.Unlock() + + if rsc.isClosed { + return 0, io.EOF + } + + return rsc.rc.Read(p) +} + +// Seekable is used for check if the binary request body can be seek or no +func (rsc *OCIReadSeekCloser) Seekable() bool { + if rsc == nil { + return false + } + if _, ok := rsc.rc.(io.Seeker); ok { + return true + } + // once the binary request body is wrapped with ioutil.NopCloser: + if isNopCloser(rsc.rc) { + if _, ok := reflect.ValueOf(rsc.rc).Field(0).Interface().(io.Seeker); ok { + return true + } + } + return false +} + +// OCIResponse is the response from issuing a request to an OCI service. +type OCIResponse interface { + // HTTPResponse returns the raw HTTP response. + HTTPResponse() *http.Response +} + +// OCIOperation is the generalization of a request-response cycle undergone by an OCI service. +type OCIOperation func(context.Context, OCIRequest, *OCIReadSeekCloser, map[string]string) (OCIResponse, error) + +// ClientCallDetails a set of settings used by the a single Call operation of the http Client +type ClientCallDetails struct { + Signer HTTPRequestSigner +} + +// Call executes the http request with the given context +func (client BaseClient) Call(ctx context.Context, request *http.Request) (response *http.Response, err error) { + if client.IsRefreshableAuthType() { + return client.RefreshableTokenWrappedCallWithDetails(ctx, request, ClientCallDetails{Signer: client.Signer}) + } + return client.CallWithDetails(ctx, request, ClientCallDetails{Signer: client.Signer}) +} + +// RefreshableTokenWrappedCallWithDetails wraps the CallWithDetails with retry on 401 for Refreshable Toekn (Instance Principal, Resource Principal etc.) +// This is to intimitate the race condition on refresh +func (client BaseClient) RefreshableTokenWrappedCallWithDetails(ctx context.Context, request *http.Request, details ClientCallDetails) (response *http.Response, err error) { + for i := 0; i < maxAttemptsForRefreshableRetry; i++ { + response, err = client.CallWithDetails(ctx, request, ClientCallDetails{Signer: client.Signer}) + if response != nil && response.StatusCode != 401 { + return response, err + } + time.Sleep(1 * time.Second) + } + return +} + +// CallWithDetails executes the http request, the given context using details specified in the parameters, this function +// provides a way to override some settings present in the client +func (client BaseClient) CallWithDetails(ctx context.Context, request *http.Request, details ClientCallDetails) (response *http.Response, err error) { + Debugln("Attempting to call downstream service") + request = request.WithContext(ctx) + err = client.prepareRequest(request) + if err != nil { + return + } + //Intercept + err = client.intercept(request) + if err != nil { + return + } + //Sign the request + err = details.Signer.Sign(request) + if err != nil { + return + } + + //Execute the http request + if ociGoBreaker := client.Configuration.CircuitBreaker; ociGoBreaker != nil { + resp, cbErr := ociGoBreaker.Cb.Execute(func() (interface{}, error) { + return client.httpDo(request) + }) + if httpResp, ok := resp.(*http.Response); ok { + if httpResp != nil && httpResp.StatusCode != 200 { + if failure, ok := IsServiceError(cbErr); ok { + ociGoBreaker.AddToHistory(resp.(*http.Response), failure) + } + } + } + if cbErr != nil && IsCircuitBreakerError(cbErr) { + cbErr = getCircuitBreakerError(request, cbErr, ociGoBreaker) + } + if _, ok := resp.(*http.Response); !ok { + return nil, cbErr + } + return resp.(*http.Response), cbErr + } + return client.httpDo(request) +} + +// IsRefreshableAuthType validates if a signer is from a refreshable config provider +func (client BaseClient) IsRefreshableAuthType() bool { + if signer, ok := client.Signer.(ociRequestSigner); ok { + if provider, ok := signer.KeyProvider.(RefreshableConfigurationProvider); ok { + return provider.Refreshable() + } + } + return false +} + +func (client BaseClient) httpDo(request *http.Request) (response *http.Response, err error) { + + //Copy request body and save for logging + dumpRequestBody := ioutil.NopCloser(bytes.NewBuffer(nil)) + if request.Body != nil && !checkBodyLengthExceedLimit(request.ContentLength) { + if dumpRequestBody, request.Body, err = drainBody(request.Body); err != nil { + dumpRequestBody = ioutil.NopCloser(bytes.NewBuffer(nil)) + } + } + IfDebug(func() { + logRequest(request, Debugf, verboseLogging) + }) + + //Execute the http request + response, err = client.HTTPClient.Do(request) + + if err != nil { + IfInfo(func() { + Logf("%v\n", err) + }) + return response, err + } + + err = checkForSuccessfulResponse(response, &dumpRequestBody) + return response, err +} + +// CloseBodyIfValid closes the body of an http response if the response and the body are valid +func CloseBodyIfValid(httpResponse *http.Response) { + if httpResponse != nil && httpResponse.Body != nil { + if httpResponse.Header != nil && strings.ToLower(httpResponse.Header.Get("content-type")) == "text/event-stream" { + return + } + httpResponse.Body.Close() + } +} + +// IsOciRealmSpecificServiceEndpointTemplateEnabled returns true if the client is configured to use realm specific service endpoint template +// it will first check the client configuration, if not set, it will check the environment variable +func (client BaseClient) IsOciRealmSpecificServiceEndpointTemplateEnabled() bool { + if client.Configuration.RealmSpecificServiceEndpointTemplateEnabled != nil { + return *client.Configuration.RealmSpecificServiceEndpointTemplateEnabled + } + return IsEnvVarTrue(OciRealmSpecificServiceEndpointTemplateEnabledEnvVar) +} + +func getCustomCertRefreshInterval() int { + if OciGlobalRefreshIntervalForCustomCerts >= 0 { + Debugf("Setting refresh interval as %d for custom certs via OciGlobalRefreshIntervalForCustomCerts", OciGlobalRefreshIntervalForCustomCerts) + return OciGlobalRefreshIntervalForCustomCerts + } + if refreshIntervalValue, ok := os.LookupEnv(ociDefaultRefreshIntervalForCustomCerts); ok { + refreshInterval, err := strconv.Atoi(refreshIntervalValue) + if err != nil || refreshInterval < 0 { + Debugf("The environment variable %s is not a valid int or is a negative value, skipping this configuration", ociDefaultRefreshIntervalForCustomCerts) + } else { + Debugf("Setting refresh interval as %d for custom certs via the env variable %s", refreshInterval, ociDefaultRefreshIntervalForCustomCerts) + return refreshInterval + } + } + Debugf("Setting the default refresh interval %d for custom certs", defaultRefreshIntervalForCustomCerts) + return defaultRefreshIntervalForCustomCerts +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/common.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/common.go new file mode 100644 index 00000000000..62085d670e2 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/common.go @@ -0,0 +1,625 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "regexp" + "strings" + "time" +) + +// Region type for regions +type Region string + +const ( + instanceMetadataRegionInfoURLV2 = "http://169.254.169.254/opc/v2/instance/regionInfo" + + // Region Metadata Configuration File + regionMetadataCfgDirName = ".oci" + regionMetadataCfgFileName = "regions-config.json" + + // Region Metadata Environment Variable + regionMetadataEnvVarName = "OCI_REGION_METADATA" + + // Default Realm Environment Variable + defaultRealmEnvVarName = "OCI_DEFAULT_REALM" + + //EndpointTemplateForRegionWithDot Environment Variable + EndpointTemplateForRegionWithDot = "https://{endpoint_service_name}.{region}" + + // Region Metadata + regionIdentifierPropertyName = "regionIdentifier" // e.g. "ap-sydney-1" + realmKeyPropertyName = "realmKey" // e.g. "oc1" + realmDomainComponentPropertyName = "realmDomainComponent" // e.g. "oraclecloud.com" + regionKeyPropertyName = "regionKey" // e.g. "SYD" + + // OciRealmSpecificServiceEndpointTemplateEnabledEnvVar is the environment variable name to enable the realm specific service endpoint template. + OciRealmSpecificServiceEndpointTemplateEnabledEnvVar = "OCI_REALM_SPECIFIC_SERVICE_ENDPOINT_TEMPLATE_ENABLED" +) + +// External region metadata info flag, used to control adding these metadata region info only once. +var readCfgFile, readEnvVar, visitIMDS bool = true, true, false + +// getRegionInfoFromInstanceMetadataService gets the region information +var getRegionInfoFromInstanceMetadataService = getRegionInfoFromInstanceMetadataServiceProd + +// OciRealmSpecificServiceEndpointTemplateEnabled is the flag to enable the realm specific service endpoint template. This one has higher priority than the environment variable. +var OciRealmSpecificServiceEndpointTemplateEnabled *bool = nil + +// OciSdkEnabledServicesMap is a list of services that are enabled, default is an empty list which means all services are enabled +var OciSdkEnabledServicesMap map[string]bool + +// OciDeveloperToolConfigurationFilePathEnvVar is the environment variable name for the OCI Developer Tool Config File Path +const OciDeveloperToolConfigurationFilePathEnvVar = "OCI_DEVELOPER_TOOL_CONFIGURATION_FILE_PATH" + +// OciAllowOnlyDeveloperToolConfigurationRegionsEnvVar is the environment variable name for the OCI Allow only Dev Tool Config Regions +const OciAllowOnlyDeveloperToolConfigurationRegionsEnvVar = "OCI_ALLOW_ONLY_DEVELOPER_TOOL_CONFIGURATION_REGIONS" + +// defaultRealmForUnknownDeveloperToolConfigurationRegion is the default realm for unknown Developer Tool Configuration Regions +const defaultRealmForUnknownDeveloperToolConfigurationRegion = "oraclecloud.com" + +// OciDeveloperToolConfigurationProvider is the provider name for the OCI Developer Tool Configuration file +var OciDeveloperToolConfigurationProvider string + +// ociAllowOnlyDeveloperToolConfigurationRegions is the flag to enable the OCI Allow Only Developer Tool Configuration Regions. This one has lower priority than the environment variable. +var ociAllowOnlyDeveloperToolConfigurationRegions bool + +var ociDeveloperToolConfigurationRegionSchemaList []map[string]string + +// Endpoint returns a endpoint for a service +func (region Region) Endpoint(service string) string { + // Endpoint for dotted region + if strings.Contains(string(region), ".") { + return fmt.Sprintf("%s.%s", service, region) + } + return fmt.Sprintf("%s.%s.%s", service, region, region.secondLevelDomain()) +} + +// EndpointForTemplate returns a endpoint for a service based on template, only unknown region name can fall back to "oc1", but not short code region name. +func (region Region) EndpointForTemplate(service string, serviceEndpointTemplate string) string { + if strings.Contains(string(region), ".") { + endpoint, error := region.EndpointForTemplateDottedRegion(service, serviceEndpointTemplate, "") + if error != nil { + Debugf("%v", error) + + return "" + } + return endpoint + } + + if serviceEndpointTemplate == "" { + return region.Endpoint(service) + } + + // replace service prefix + endpoint := strings.Replace(serviceEndpointTemplate, "{serviceEndpointPrefix}", service, 1) + + // replace region + endpoint = strings.Replace(endpoint, "{region}", string(region), 1) + + // replace second level domain + endpoint = strings.Replace(endpoint, "{secondLevelDomain}", region.secondLevelDomain(), 1) + + return endpoint +} + +// EndpointForTemplateDottedRegion returns a endpoint for a service based on the service name and EndpointTemplateForRegionWithDot template. If a service name is missing it is obtained from serviceEndpointTemplate and endpoint is constructed usingEndpointTemplateForRegionWithDot template. +func (region Region) EndpointForTemplateDottedRegion(service string, serviceEndpointTemplate string, endpointServiceName string) (string, error) { + if !strings.Contains(string(region), ".") { + var endpoint = "" + if serviceEndpointTemplate != "" { + endpoint = region.EndpointForTemplate(service, serviceEndpointTemplate) + return endpoint, nil + } + endpoint = region.EndpointForTemplate(service, "") + return endpoint, nil + } + + if endpointServiceName != "" { + endpoint := strings.Replace(EndpointTemplateForRegionWithDot, "{endpoint_service_name}", endpointServiceName, 1) + endpoint = strings.Replace(endpoint, "{region}", string(region), 1) + Debugf("Constructing endpoint from service name %s and region %s. Endpoint: %s", endpointServiceName, region, endpoint) + return endpoint, nil + } + if serviceEndpointTemplate != "" { + var endpoint = "" + res := strings.Split(serviceEndpointTemplate, "//") + if len(res) > 1 { + res = strings.Split(res[1], ".") + if len(res) > 1 { + endpoint = strings.Replace(EndpointTemplateForRegionWithDot, "{endpoint_service_name}", res[0], 1) + endpoint = strings.Replace(endpoint, "{region}", string(region), 1) + Debugf("Constructing endpoint from service endpoint template %s and region %s. Endpoint: %s", serviceEndpointTemplate, region, endpoint) + } else { + return endpoint, fmt.Errorf("Endpoint service name not present in endpoint template") + } + } else { + return endpoint, fmt.Errorf("invalid serviceEndpointTemplates. ServiceEndpointTemplate should start with https://") + } + return endpoint, nil + } + return "", fmt.Errorf("EndpointForTemplateDottedRegion function requires endpointServiceName or serviceEndpointTemplate, no endpointServiceName or serviceEndpointTemplate provided") +} + +func (region Region) secondLevelDomain() string { + if realmID, ok := regionRealm[region]; ok { + if secondLevelDomain, ok := realm[realmID]; ok { + return secondLevelDomain + } + } + if value, ok := os.LookupEnv(defaultRealmEnvVarName); ok { + return value + } + Debugf("cannot find realm for region : %s, return default realm value.", region) + if _, ok := realm["oc1"]; !ok { + return defaultRealmForUnknownDeveloperToolConfigurationRegion + } + return realm["oc1"] +} + +// RealmID is used for getting realmID from region, if no region found, directly throw error +func (region Region) RealmID() (string, error) { + if realmID, ok := regionRealm[region]; ok { + return realmID, nil + } + + return "", fmt.Errorf("cannot find realm for region : %s", region) +} + +// StringToRegion convert a string to Region type +func StringToRegion(stringRegion string) (r Region) { + regionStr := strings.ToLower(stringRegion) + // check for PLC related regions + if checkAllowOnlyDeveloperToolConfigurationRegions() && (checkDeveloperToolConfigurationFile() || len(ociDeveloperToolConfigurationRegionSchemaList) != 0) { + Debugf("Developer Tool config detected and OCI_ALLOW_ONLY_DEVELOPER_TOOL_CONFIGURATION_REGIONS is set to True, SDK will only use regions defined for Developer Tool Configuration Regions") + setRegionMetadataFromDeveloperToolConfigurationFile(&stringRegion) + if len(ociDeveloperToolConfigurationRegionSchemaList) != 0 { + resetRegionInfo() + bulkAddRegionSchema(ociDeveloperToolConfigurationRegionSchemaList) + } + r = Region(stringRegion) + if _, ok := regionRealm[r]; !ok { + Logf("You're using the %s Developer Tool configuration file, the region you're targeting is not declared in this config file. Please check if this is the correct region you're targeting or contact the %s cloud provider for help. If you want to target both OCI regions and %s regions, please set the OCI_ALLOW_ONLY_DEVELOPER_TOOL_CONFIGURATION_REGIONS env var to False.", OciDeveloperToolConfigurationProvider, OciDeveloperToolConfigurationProvider, regionStr) + } + return r + } + + // check if short region name provided + if region, ok := shortNameRegion[regionStr]; ok { + r = region + return + } + // check if normal region name provided + potentialRegion := Region(regionStr) + if _, ok := regionRealm[potentialRegion]; ok { + r = potentialRegion + return + } + + Debugf("region named: %s, is not recognized from hard-coded region list, will check Region metadata info", stringRegion) + r = checkAndAddRegionMetadata(stringRegion) + + return +} + +// canStringBeRegion test if the string can be a region, if it can, returns the string as is, otherwise it +// returns an error +var blankRegex = regexp.MustCompile(`\s`) + +func canStringBeRegion(stringRegion string) (region string, err error) { + if blankRegex.MatchString(stringRegion) || stringRegion == "" { + return "", fmt.Errorf("region can not be empty or have spaces") + } + return stringRegion, nil +} + +// check region info from original map +func checkAndAddRegionMetadata(region string) Region { + switch { + case setRegionMetadataFromCfgFile(®ion): + case setRegionMetadataFromEnvVar(®ion): + case setRegionFromInstanceMetadataService(®ion): + default: + //err := fmt.Errorf("failed to get region metadata information.") + return Region(region) + } + return Region(region) +} + +// EnableInstanceMetadataServiceLookup provides the interface to lookup IMDS region info +func EnableInstanceMetadataServiceLookup() { + Debugf("Set visitIMDS 'true' to enable IMDS Lookup.") + visitIMDS = true +} + +// setRegionMetadataFromEnvVar checks if region metadata env variable is provided, once it's there, parse and added it +// to region map, and it can make sure the env var can only be visited once. +// Once successfully find the expected region(region name or short code), return true, region name will be stored in +// the input pointer. +func setRegionMetadataFromEnvVar(region *string) bool { + if !readEnvVar { + Debugf("metadata region env variable had already been checked, no need to check again.") + return false //no need to check it again. + } + // Mark readEnvVar Flag as false since it has already been visited. + readEnvVar = false + // check from env variable + if jsonStr, existed := os.LookupEnv(regionMetadataEnvVarName); existed { + Debugf("Raw content of region metadata env var:", jsonStr) + var regionSchema map[string]string + if err := json.Unmarshal([]byte(jsonStr), ®ionSchema); err != nil { + Debugf("Can't unmarshal env var, the error info is", err) + return false + } + // check if the specified region is in the env var. + if checkSchemaItems(regionSchema) { + // set mapping table + addRegionSchema(regionSchema) + if regionSchema[regionKeyPropertyName] == *region || + regionSchema[regionIdentifierPropertyName] == *region { + *region = regionSchema[regionIdentifierPropertyName] + return true + } + } + return false + } + Debugf("The Region Metadata Schema wasn't set in env variable - OCI_REGION_METADATA.") + return false +} + +func setRegionMetadataFromCfgFile(region *string) bool { + if setRegionMetadataFromDeveloperToolConfigurationFile(region) { + return true + } + if setRegionMetadataFromRegionCfgFile(region) { + return true + } + return false +} + +// setRegionMetadataFromCfgFile checks if region metadata config file is provided, once it's there, parse and add all +// the valid regions to region map, the configuration file can only be visited once. +// Once successfully find the expected region(region name or short code), return true, region name will be stored in +// the input pointer. +func setRegionMetadataFromRegionCfgFile(region *string) bool { + if !readCfgFile { + Debugf("metadata region config file had already been checked, no need to check again.") + return false //no need to check it again. + } + // Mark readCfgFile Flag as false since it has already been visited. + readCfgFile = false + homeFolder := getHomeFolder() + configFile := filepath.Join(homeFolder, regionMetadataCfgDirName, regionMetadataCfgFileName) + if jsonArr, ok := readAndParseConfigFile(&configFile); ok { + added := false + for _, jsonItem := range jsonArr { + if checkSchemaItems(jsonItem) { + addRegionSchema(jsonItem) + if jsonItem[regionKeyPropertyName] == *region || + jsonItem[regionIdentifierPropertyName] == *region { + *region = jsonItem[regionIdentifierPropertyName] + added = true + } + } + } + return added + } + return false +} + +// setRegionMetadataFromDeveloperToolConfigurationFile checks if Developer Tool config file is provided, once it's there, parse and add all +// The default location of the Developer Tool config file is ~/.oci/developer-tool-configuration.json. It will also check the environment variable +// the valid regions to region map, the configuration file can only be visited once. +// Once successfully find the expected region(region name or short code), return true, region name will be stored in +// the input pointer. +func setRegionMetadataFromDeveloperToolConfigurationFile(region *string) bool { + if jsonArr, ok := readAndParseDeveloperToolConfigurationFile(); ok { + added := false + if jsonArr["regions"] == nil { + return false + } + var regionJSON []map[string]string + originalJSONContent, err := json.Marshal(jsonArr["regions"]) + if err != nil { + return false + } + err = json.Unmarshal(originalJSONContent, ®ionJSON) + if err != nil { + return false + } + + if IsEnvVarTrue(OciAllowOnlyDeveloperToolConfigurationRegionsEnvVar) { + resetRegionInfo() + } + for _, jsonItem := range regionJSON { + if checkSchemaItems(jsonItem) { + addRegionSchema(jsonItem) + if jsonItem[regionKeyPropertyName] == *region || + jsonItem[regionIdentifierPropertyName] == *region { + *region = jsonItem[regionIdentifierPropertyName] + added = true + } + } + } + return added + } + return false +} + +func readAndParseConfigFile(configFileName *string) (fileContent []map[string]string, ok bool) { + if content, err := ioutil.ReadFile(*configFileName); err == nil { + Debugf("Raw content of region metadata config file content:", string(content[:])) + if err := json.Unmarshal(content, &fileContent); err != nil { + Debugf("Can't unmarshal config file, the error info is", err) + return + } + ok = true + return + } + Debugf("No Region Metadata Config File provided.") + return +} + +func readAndParseDeveloperToolConfigurationFile() (fileContent map[string]interface{}, ok bool) { + homeFolder := getHomeFolder() + configFileName := filepath.Join(homeFolder, regionMetadataCfgDirName, "developer-tool-configuration.json") + if path := os.Getenv(OciDeveloperToolConfigurationFilePathEnvVar); path != "" { + configFileName = path + } + if content, err := ioutil.ReadFile(configFileName); err == nil { + Debugf("Raw content of Developer Tool config file content:", string(content[:])) + if err := json.Unmarshal(content, &fileContent); err != nil { + Debugf("Can't unmarshal env var, the error info is", err) + return + } + ok = true + return + } + Debugf("No Developer Tool Config File provided.") + return +} + +func checkDeveloperToolConfigurationFile() bool { + homeFolder := getHomeFolder() + configFileName := filepath.Join(homeFolder, regionMetadataCfgDirName, "developer-tool-configuration.json") + if path := os.Getenv(OciDeveloperToolConfigurationFilePathEnvVar); path != "" { + configFileName = path + } + if _, err := os.Stat(configFileName); err == nil { + return true + } + return false +} + +// check map regionRealm's region name, if it's already there, no need to add it. +func addRegionSchema(regionSchema map[string]string) { + r := Region(strings.ToLower(regionSchema[regionIdentifierPropertyName])) + if _, ok := regionRealm[r]; !ok { + // set mapping table + shortNameRegion[regionSchema[regionKeyPropertyName]] = r + realm[regionSchema[realmKeyPropertyName]] = regionSchema[realmDomainComponentPropertyName] + regionRealm[r] = regionSchema[realmKeyPropertyName] + return + } + Debugf("Region {} has already been added, no need to add again.", regionSchema[regionIdentifierPropertyName]) +} + +// AddRegionSchemaForPlc add region schema to region map +func AddRegionSchemaForPlc(regionSchema map[string]string) { + ociDeveloperToolConfigurationRegionSchemaList = append(ociDeveloperToolConfigurationRegionSchemaList, regionSchema) + addRegionSchema(regionSchema) + // if !IsEnvVarTrue(OciPlcRegionExclusiveEnvVar) { + // addRegionSchema(regionSchema) + // return + // } + // Debugf("Plc region coexist is not enabled, remove exisiting OCI region schema and add PLC region schema.") + // resetRegionInfo() + // bulkAddRegionSchema(ociPlcRegionSchemaList) +} + +func resetRegionInfo() { + shortNameRegion = make(map[string]Region) + realm = make(map[string]string) + regionRealm = make(map[Region]string) +} + +func bulkAddRegionSchema(regionSchemaList []map[string]string) { + for _, regionSchema := range regionSchemaList { + if checkSchemaItems(regionSchema) { + addRegionSchema(regionSchema) + } + } +} + +// check region schema content if all the required contents are provided +func checkSchemaItems(regionSchema map[string]string) bool { + if checkSchemaItem(regionSchema, regionIdentifierPropertyName) && + checkSchemaItem(regionSchema, realmKeyPropertyName) && + checkSchemaItem(regionSchema, realmDomainComponentPropertyName) && + checkSchemaItem(regionSchema, regionKeyPropertyName) { + return true + } + return false +} + +// check region schema item is valid, if so, convert it to lower case. +func checkSchemaItem(regionSchema map[string]string, key string) bool { + if val, ok := regionSchema[key]; ok { + if val != "" { + regionSchema[key] = strings.ToLower(val) + return true + } + Debugf("Region metadata schema {} is provided,but content is empty.", key) + return false + } + Debugf("Region metadata schema {} is not provided, please update the content", key) + return false +} + +// setRegionFromInstanceMetadataService checks if region metadata can be provided from InstanceMetadataService. +// Once successfully find the expected region(region name or short code), return true, region name will be stored in +// the input pointer. +// setRegionFromInstanceMetadataService will only be checked on the instance, by default it will not be enabled unless +// user explicitly enable it. +func setRegionFromInstanceMetadataService(region *string) bool { + // example of content: + // { + // "realmKey" : "oc1", + // "realmDomainComponent" : "oraclecloud.com", + // "regionKey" : "YUL", + // "regionIdentifier" : "ca-montreal-1" + // } + // Mark visitIMDS Flag as false since it has already been visited. + if !visitIMDS { + Debugf("check from IMDS is disabled or IMDS had already been successfully visited, no need to check again.") + return false + } + content, err := getRegionInfoFromInstanceMetadataService() + if err != nil { + Debugf("Failed to get instance metadata. Error: %v", err) + return false + } + + // Mark visitIMDS Flag as false since we have already successfully get the region info from IMDS. + visitIMDS = false + + var regionInfo map[string]string + err = json.Unmarshal(content, ®ionInfo) + if err != nil { + Debugf("Failed to unmarshal the response content: %v \nError: %v", string(content), err) + return false + } + + if checkSchemaItems(regionInfo) { + addRegionSchema(regionInfo) + if regionInfo[regionKeyPropertyName] == *region || + regionInfo[regionIdentifierPropertyName] == *region { + *region = regionInfo[regionIdentifierPropertyName] + } + } else { + Debugf("Region information is not valid.") + return false + } + + return true +} + +// getRegionInfoFromInstanceMetadataServiceProd calls instance metadata service and get the region information +func getRegionInfoFromInstanceMetadataServiceProd() ([]byte, error) { + request, _ := http.NewRequest(http.MethodGet, instanceMetadataRegionInfoURLV2, nil) + request.Header.Add("Authorization", "Bearer Oracle") + + client := &http.Client{ + Timeout: time.Second * 10, + } + resp, err := client.Do(request) + if err != nil { + return nil, fmt.Errorf("failed to call instance metadata service. Error: %v", err) + } + + statusCode := resp.StatusCode + + defer resp.Body.Close() + + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to get region information from response body. Error: %v", err) + } + + if statusCode != http.StatusOK { + err = fmt.Errorf("HTTP Get failed: URL: %s, Status: %s, Message: %s", + instanceMetadataRegionInfoURLV2, resp.Status, string(content)) + return nil, err + } + + return content, nil +} + +// TemplateParamForPerRealmEndpoint is a template parameter for per-realm endpoint. +type TemplateParamForPerRealmEndpoint struct { + Template string + EndsWithDot bool +} + +// SetMissingTemplateParams function will parse the {} template in client host and replace with empty string. +func SetMissingTemplateParams(client *BaseClient) { + templateRegex := regexp.MustCompile(`{.*?}`) + templates := templateRegex.FindAllString(client.Host, -1) + for _, template := range templates { + client.Host = strings.Replace(client.Host, template, "", -1) + } +} + +func getOciSdkEnabledServicesMap() map[string]bool { + var enabledMap = make(map[string]bool) + if jsonArr, ok := readAndParseDeveloperToolConfigurationFile(); ok { + if jsonArr["provider"] != nil { + OciDeveloperToolConfigurationProvider = jsonArr["provider"].(string) + } + if jsonArr["allowOnlyDeveloperToolConfigurationRegions"] != nil && jsonArr["allowOnlyDeveloperToolConfigurationRegions"] == false { + ociAllowOnlyDeveloperToolConfigurationRegions = jsonArr["allowOnlyDeveloperToolConfigurationRegions"].(bool) + } + if jsonArr["services"] == nil { + return enabledMap + } + serviesJSON, ok := jsonArr["services"].([]interface{}) + if !ok { + return enabledMap + } + re, _ := regexp.Compile(`[^\w]`) + for _, jsonItem := range serviesJSON { + serviceName := strings.ToLower(fmt.Sprint(jsonItem)) + serviceName = re.ReplaceAllString(serviceName, "") + enabledMap[serviceName] = true + } + } + return enabledMap +} + +// AddServiceToEnabledServicesMap adds the service to the enabledServiceMap +// The service name will auto transit to lower case and remove all the non-word characters. +func AddServiceToEnabledServicesMap(serviceName string) { + if OciSdkEnabledServicesMap == nil { + OciSdkEnabledServicesMap = make(map[string]bool) + } + re, _ := regexp.Compile(`[^\w]`) + serviceName = strings.ToLower(serviceName) + serviceName = re.ReplaceAllString(serviceName, "") + OciSdkEnabledServicesMap[serviceName] = true +} + +// CheckForEnabledServices checks if the service is enabled in the enabledServiceMap. +// It will first check if the map is initialized, if not, it will initialize the map. +// If the map is empty, it means all the services are enabled. +// If the map is not empty, it means only the services in the map and value is true are enabled. +func CheckForEnabledServices(serviceName string) bool { + if OciSdkEnabledServicesMap == nil { + OciSdkEnabledServicesMap = getOciSdkEnabledServicesMap() + } + serviceName = strings.ToLower(serviceName) + if len(OciSdkEnabledServicesMap) == 0 { + return true + } + if _, ok := OciSdkEnabledServicesMap[serviceName]; !ok { + return false + } + return OciSdkEnabledServicesMap[serviceName] +} + +// CheckAllowOnlyDeveloperToolConfigurationRegions checks if only developer tool configuration regions are allowed +// This function will first check if the OCI_ALLOW_ONLY_DEVELOPER_TOOL_CONFIGURATION_REGIONS environment variable is set. +// If it is set, it will return the value. +// If it is not set, it will return the value from the ociAllowOnlyDeveloperToolConfigurationRegions variable. +func checkAllowOnlyDeveloperToolConfigurationRegions() bool { + if val, ok := os.LookupEnv("OCI_ALLOW_ONLY_DEVELOPER_TOOL_CONFIGURATION_REGIONS"); ok { + return val == "true" + } + return ociAllowOnlyDeveloperToolConfigurationRegions +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/configuration.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/configuration.go new file mode 100644 index 00000000000..43174ea9f52 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/configuration.go @@ -0,0 +1,820 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "crypto/rsa" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + "sync" +) + +// AuthenticationType for auth +type AuthenticationType string + +const ( + // UserPrincipal is default auth type + UserPrincipal AuthenticationType = "user_principal" + // InstancePrincipal is used for instance principal auth type + InstancePrincipal AuthenticationType = "instance_principal" + // InstancePrincipalDelegationToken is used for instance principal delegation token auth type + InstancePrincipalDelegationToken AuthenticationType = "instance_principle_delegation_token" + // ResourcePrincipalDelegationToken is used for resource principal delegation token auth type + ResourcePrincipalDelegationToken AuthenticationType = "resource_principle_delegation_token" + // UnknownAuthenticationType is used for none meaningful auth type + UnknownAuthenticationType AuthenticationType = "unknown_auth_type" +) + +// AuthConfig is used for getting auth related paras in config file +type AuthConfig struct { + AuthType AuthenticationType + // IsFromConfigFile is used to point out if the authConfig is from configuration file + IsFromConfigFile bool + OboToken *string +} + +// ConfigurationProvider wraps information about the account owner +type ConfigurationProvider interface { + KeyProvider + TenancyOCID() (string, error) + UserOCID() (string, error) + KeyFingerprint() (string, error) + Region() (string, error) + // AuthType() is used for specify the needed auth type, like UserPrincipal, InstancePrincipal, etc. + AuthType() (AuthConfig, error) +} + +var fileMutex = sync.Mutex{} +var fileCache = make(map[string][]byte) + +// Reads the file contents from cache if present otherwise reads the file. +// If file to be read is frequently updated/refreshed, please use readFile(filename) as readFileFromCache(filename) might return the old contents from the cache. +func readFileFromCache(filename string) ([]byte, error) { + fileMutex.Lock() + defer fileMutex.Unlock() + val, ok := fileCache[filename] + if ok { + return val, nil + } + val, err := ioutil.ReadFile(filename) + if err == nil { + fileCache[filename] = val + } + return val, err +} + +// Reads the file and returns the contents +func readFile(filename string) ([]byte, error) { + fileMutex.Lock() + defer fileMutex.Unlock() + val, err := os.ReadFile(filename) + return val, err +} + +// IsConfigurationProviderValid Tests all parts of the configuration provider do not return an error, this method will +// not check AuthType(), since authType() is not required to be there. +func IsConfigurationProviderValid(conf ConfigurationProvider) (ok bool, err error) { + baseFn := []func() (string, error){conf.TenancyOCID, conf.UserOCID, conf.KeyFingerprint, conf.Region, conf.KeyID} + for _, fn := range baseFn { + _, err = fn() + ok = err == nil + if err != nil { + return + } + } + + _, err = conf.PrivateRSAKey() + ok = err == nil + if err != nil { + return + } + return true, nil +} + +// rawConfigurationProvider allows a user to simply construct a configuration provider from raw values. +type rawConfigurationProvider struct { + tenancy string + user string + region string + fingerprint string + privateKey string + privateKeyPassphrase *string +} + +// NewRawConfigurationProvider will create a ConfigurationProvider with the arguments of the function +func NewRawConfigurationProvider(tenancy, user, region, fingerprint, privateKey string, privateKeyPassphrase *string) ConfigurationProvider { + return rawConfigurationProvider{tenancy, user, region, fingerprint, privateKey, privateKeyPassphrase} +} + +func (p rawConfigurationProvider) PrivateRSAKey() (key *rsa.PrivateKey, err error) { + return PrivateKeyFromBytes([]byte(p.privateKey), p.privateKeyPassphrase) +} + +func (p rawConfigurationProvider) KeyID() (keyID string, err error) { + tenancy, err := p.TenancyOCID() + if err != nil { + return + } + + user, err := p.UserOCID() + if err != nil { + return + } + + fingerprint, err := p.KeyFingerprint() + if err != nil { + return + } + + return fmt.Sprintf("%s/%s/%s", tenancy, user, fingerprint), nil +} + +func (p rawConfigurationProvider) TenancyOCID() (string, error) { + if p.tenancy == "" { + return "", fmt.Errorf("tenancy OCID can not be empty") + } + return p.tenancy, nil +} + +func (p rawConfigurationProvider) UserOCID() (string, error) { + if p.user == "" { + return "", fmt.Errorf("user OCID can not be empty") + } + return p.user, nil +} + +func (p rawConfigurationProvider) KeyFingerprint() (string, error) { + if p.fingerprint == "" { + return "", fmt.Errorf("fingerprint can not be empty") + } + return p.fingerprint, nil +} + +func (p rawConfigurationProvider) Region() (string, error) { + return canStringBeRegion(p.region) +} + +func (p rawConfigurationProvider) AuthType() (AuthConfig, error) { + return AuthConfig{UnknownAuthenticationType, false, nil}, nil +} + +// environmentConfigurationProvider reads configuration from environment variables +type environmentConfigurationProvider struct { + PrivateKeyPassword string + EnvironmentVariablePrefix string +} + +// ConfigurationProviderEnvironmentVariables creates a ConfigurationProvider from a uniform set of environment variables starting with a prefix +// The env variables should look like: [prefix]_private_key_path, [prefix]_tenancy_ocid, [prefix]_user_ocid, [prefix]_fingerprint +// [prefix]_region +func ConfigurationProviderEnvironmentVariables(environmentVariablePrefix, privateKeyPassword string) ConfigurationProvider { + return environmentConfigurationProvider{EnvironmentVariablePrefix: environmentVariablePrefix, + PrivateKeyPassword: privateKeyPassword} +} + +func (p environmentConfigurationProvider) String() string { + return fmt.Sprintf("Configuration provided by environment variables prefixed with: %s", p.EnvironmentVariablePrefix) +} + +func (p environmentConfigurationProvider) PrivateRSAKey() (key *rsa.PrivateKey, err error) { + environmentVariable := fmt.Sprintf("%s_%s", p.EnvironmentVariablePrefix, "private_key_path") + var ok bool + var value string + if value, ok = os.LookupEnv(environmentVariable); !ok { + return nil, fmt.Errorf("can not read PrivateKey from env variable: %s", environmentVariable) + } + + expandedPath := expandPath(value) + pemFileContent, err := readFileFromCache(expandedPath) + if err != nil { + Debugln("Can not read PrivateKey location from environment variable: " + environmentVariable) + return + } + + key, err = PrivateKeyFromBytes(pemFileContent, &p.PrivateKeyPassword) + return +} + +func (p environmentConfigurationProvider) KeyID() (keyID string, err error) { + ocid, err := p.TenancyOCID() + if err != nil { + return + } + + userocid, err := p.UserOCID() + if err != nil { + return + } + + fingerprint, err := p.KeyFingerprint() + if err != nil { + return + } + + return fmt.Sprintf("%s/%s/%s", ocid, userocid, fingerprint), nil +} + +func (p environmentConfigurationProvider) TenancyOCID() (value string, err error) { + environmentVariable := fmt.Sprintf("%s_%s", p.EnvironmentVariablePrefix, "tenancy_ocid") + var ok bool + if value, ok = os.LookupEnv(environmentVariable); !ok { + err = fmt.Errorf("can not read Tenancy from environment variable %s", environmentVariable) + } else if value == "" { + err = fmt.Errorf("tenancy OCID can not be empty when reading from environmental variable") + } + return +} + +func (p environmentConfigurationProvider) UserOCID() (value string, err error) { + environmentVariable := fmt.Sprintf("%s_%s", p.EnvironmentVariablePrefix, "user_ocid") + var ok bool + if value, ok = os.LookupEnv(environmentVariable); !ok { + err = fmt.Errorf("can not read user id from environment variable %s", environmentVariable) + } else if value == "" { + err = fmt.Errorf("user OCID can not be empty when reading from environmental variable") + } + return +} + +func (p environmentConfigurationProvider) KeyFingerprint() (value string, err error) { + environmentVariable := fmt.Sprintf("%s_%s", p.EnvironmentVariablePrefix, "fingerprint") + var ok bool + if value, ok = os.LookupEnv(environmentVariable); !ok { + err = fmt.Errorf("can not read fingerprint from environment variable %s", environmentVariable) + } else if value == "" { + err = fmt.Errorf("fingerprint can not be empty when reading from environmental variable") + } + return +} + +func (p environmentConfigurationProvider) Region() (value string, err error) { + environmentVariable := fmt.Sprintf("%s_%s", p.EnvironmentVariablePrefix, "region") + var ok bool + if value, ok = os.LookupEnv(environmentVariable); !ok { + err = fmt.Errorf("can not read region from environment variable %s", environmentVariable) + return value, err + } + + return canStringBeRegion(value) +} + +func (p environmentConfigurationProvider) AuthType() (AuthConfig, error) { + return AuthConfig{UnknownAuthenticationType, false, nil}, + fmt.Errorf("unsupported, keep the interface") +} + +// fileConfigurationProvider. reads configuration information from a file +type fileConfigurationProvider struct { + //The path to the configuration file + ConfigPath string + + //The password for the private key + PrivateKeyPassword string + + //The profile for the configuration + Profile string + + //ConfigFileInfo + FileInfo *configFileInfo + + //Mutex to protect the config file + configMux sync.Mutex +} + +type fileConfigurationProviderError struct { + err error +} + +func (fpe fileConfigurationProviderError) Error() string { + return fmt.Sprintf("%s\nFor more info about config file and how to get required information, see https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm", fpe.err) +} + +// ConfigurationProviderFromFile creates a configuration provider from a configuration file +// by reading the "DEFAULT" profile +func ConfigurationProviderFromFile(configFilePath, privateKeyPassword string) (ConfigurationProvider, error) { + if configFilePath == "" { + return nil, fmt.Errorf("config file path can not be empty") + } + + return fileConfigurationProvider{ + ConfigPath: configFilePath, + PrivateKeyPassword: privateKeyPassword, + Profile: "DEFAULT", + configMux: sync.Mutex{}}, nil +} + +// ConfigurationProviderFromFileWithProfile creates a configuration provider from a configuration file +// and the given profile +func ConfigurationProviderFromFileWithProfile(configFilePath, profile, privateKeyPassword string) (ConfigurationProvider, error) { + if configFilePath == "" { + return nil, fileConfigurationProviderError{err: fmt.Errorf("config file path can not be empty")} + } + + return fileConfigurationProvider{ + ConfigPath: configFilePath, + PrivateKeyPassword: privateKeyPassword, + Profile: profile, + configMux: sync.Mutex{}}, nil +} + +type configFileInfo struct { + UserOcid, Fingerprint, KeyFilePath, TenancyOcid, Region, Passphrase, SecurityTokenFilePath, DelegationTokenFilePath, + AuthenticationType string + PresentConfiguration rune +} + +const ( + hasTenancy = 1 << iota + hasUser + hasFingerprint + hasRegion + hasKeyFile + hasPassphrase + hasSecurityTokenFile + hasDelegationTokenFile + hasAuthenticationType + none +) + +var profileRegex = regexp.MustCompile(`^\[(.*)\]`) + +func parseConfigFile(data []byte, profile string) (info *configFileInfo, err error) { + + if len(data) == 0 { + return nil, fileConfigurationProviderError{err: fmt.Errorf("configuration file content is empty")} + } + + content := string(data) + splitContent := strings.Split(content, "\n") + + //Look for profile + for i, line := range splitContent { + if match := profileRegex.FindStringSubmatch(line); len(match) > 1 && match[1] == profile { + start := i + 1 + return parseConfigAtLine(start, splitContent) + } + } + + return nil, fileConfigurationProviderError{err: fmt.Errorf("configuration file did not contain profile: %s", profile)} +} + +func parseConfigAtLine(start int, content []string) (info *configFileInfo, err error) { + var configurationPresent rune + info = &configFileInfo{} + for i := start; i < len(content); i++ { + line := content[i] + if profileRegex.MatchString(line) { + break + } + + if !strings.Contains(line, "=") { + continue + } + + splits := strings.Split(line, "=") + switch key, value := strings.TrimSpace(splits[0]), strings.TrimSpace(splits[1]); strings.ToLower(key) { + case "passphrase", "pass_phrase": + configurationPresent = configurationPresent | hasPassphrase + info.Passphrase = value + case "user": + configurationPresent = configurationPresent | hasUser + info.UserOcid = value + case "fingerprint": + configurationPresent = configurationPresent | hasFingerprint + info.Fingerprint = value + case "key_file": + configurationPresent = configurationPresent | hasKeyFile + info.KeyFilePath = value + case "tenancy": + configurationPresent = configurationPresent | hasTenancy + info.TenancyOcid = value + case "region": + configurationPresent = configurationPresent | hasRegion + info.Region = value + case "security_token_file": + configurationPresent = configurationPresent | hasSecurityTokenFile + info.SecurityTokenFilePath = value + case "delegation_token_file": + configurationPresent = configurationPresent | hasDelegationTokenFile + info.DelegationTokenFilePath = value + case "authentication_type": + configurationPresent = configurationPresent | hasAuthenticationType + info.AuthenticationType = value + } + } + info.PresentConfiguration = configurationPresent + return + +} + +// cleans and expands the path if it contains a tilde , returns the expanded path or the input path as is if not expansion +// was performed +func expandPath(filename string) (expandedPath string) { + cleanedPath := filepath.Clean(filename) + expandedPath = cleanedPath + if strings.HasPrefix(cleanedPath, "~") { + rest := cleanedPath[2:] + expandedPath = filepath.Join(getHomeFolder(), rest) + } + return +} + +func openConfigFile(configFilePath string) (data []byte, err error) { + expandedPath := expandPath(configFilePath) + data, err = readFileFromCache(expandedPath) + if err != nil { + err = fmt.Errorf("can not read config file: %s due to: %s", configFilePath, err.Error()) + } + + return +} + +func (p fileConfigurationProvider) String() string { + return fmt.Sprintf("Configuration provided by file: %s", p.ConfigPath) +} + +func (p fileConfigurationProvider) readAndParseConfigFile() (info *configFileInfo, err error) { + p.configMux.Lock() + defer p.configMux.Unlock() + if p.FileInfo != nil { + return p.FileInfo, nil + } + + if p.ConfigPath == "" { + return nil, fileConfigurationProviderError{err: fmt.Errorf("configuration path can not be empty")} + } + + data, err := openConfigFile(p.ConfigPath) + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("error while parsing config file: %s. Due to: %s", p.ConfigPath, err.Error())} + return + } + + p.FileInfo, err = parseConfigFile(data, p.Profile) + return p.FileInfo, err +} + +func presentOrError(value string, expectedConf, presentConf rune, confMissing string) (string, error) { + if presentConf&expectedConf == expectedConf { + return value, nil + } + return "", fileConfigurationProviderError{err: errors.New(confMissing + " configuration is missing from file")} +} + +func (p fileConfigurationProvider) TenancyOCID() (value string, err error) { + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read tenancy configuration due to: %s", err.Error())} + return + } + + value, err = presentOrError(info.TenancyOcid, hasTenancy, info.PresentConfiguration, "tenancy") + if err == nil && value == "" { + err = fileConfigurationProviderError{err: fmt.Errorf("tenancy OCID can not be empty when reading from config file")} + } + return +} + +func (p fileConfigurationProvider) UserOCID() (value string, err error) { + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read tenancy configuration due to: %s", err.Error())} + return + } + + if value, err = presentOrError(info.UserOcid, hasUser, info.PresentConfiguration, "user"); err != nil { + // need to check if securityTokenPath is provided, if security token is provided, userOCID can be "". + if _, stErr := presentOrError(info.SecurityTokenFilePath, hasSecurityTokenFile, info.PresentConfiguration, + "securityTokenPath"); stErr == nil { + err = nil + } + } + return +} + +func (p fileConfigurationProvider) KeyFingerprint() (value string, err error) { + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read tenancy configuration due to: %s", err.Error())} + return + } + value, err = presentOrError(info.Fingerprint, hasFingerprint, info.PresentConfiguration, "fingerprint") + if err == nil && value == "" { + return "", fmt.Errorf("fingerprint can not be empty when reading from config file") + } + return +} + +func (p fileConfigurationProvider) KeyID() (keyID string, err error) { + tenancy, err := p.TenancyOCID() + if err != nil { + return + } + + fingerprint, err := p.KeyFingerprint() + if err != nil { + return + } + + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read tenancy configuration due to: %s", err.Error())} + return + } + if info.PresentConfiguration&hasUser == hasUser { + if info.UserOcid == "" { + err = fileConfigurationProviderError{err: fmt.Errorf("user cannot be empty in the config file")} + return + } + return fmt.Sprintf("%s/%s/%s", tenancy, info.UserOcid, fingerprint), nil + } + filePath, pathErr := presentOrError(info.SecurityTokenFilePath, hasSecurityTokenFile, info.PresentConfiguration, "securityTokenFilePath") + if pathErr == nil { + rawString, err := getTokenContent(filePath) + if err != nil { + return "", fileConfigurationProviderError{err: err} + } + return "ST$" + rawString, nil + } + err = fileConfigurationProviderError{err: fmt.Errorf("can not read SecurityTokenFilePath from configuration file due to: %s", pathErr.Error())} + return +} + +func (p fileConfigurationProvider) PrivateRSAKey() (key *rsa.PrivateKey, err error) { + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read tenancy configuration due to: %s", err.Error())} + return + } + + filePath, err := presentOrError(info.KeyFilePath, hasKeyFile, info.PresentConfiguration, "key file path") + if err != nil { + return + } + + expandedPath := expandPath(filePath) + pemFileContent, err := readFileFromCache(expandedPath) + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read PrivateKey from configuration file due to: %s", err.Error())} + return + } + + password := p.PrivateKeyPassword + + if password == "" && ((info.PresentConfiguration & hasPassphrase) == hasPassphrase) { + password = info.Passphrase + } + + key, err = PrivateKeyFromBytes(pemFileContent, &password) + return +} + +func (p fileConfigurationProvider) Region() (value string, err error) { + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read region configuration due to: %s", err.Error())} + return + } + + value, err = presentOrError(info.Region, hasRegion, info.PresentConfiguration, "region") + if err != nil { + val, error := getRegionFromEnvVar() + if error != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("region configuration is missing from file, nor for OCI_REGION env var")} + return + } + value = val + } + + return canStringBeRegion(value) +} + +func (p fileConfigurationProvider) AuthType() (AuthConfig, error) { + info, err := p.readAndParseConfigFile() + if err != nil { + err = fmt.Errorf("can not read tenancy configuration due to: %s", err.Error()) + return AuthConfig{UnknownAuthenticationType, true, nil}, err + } + val, _ := presentOrError(info.AuthenticationType, hasAuthenticationType, info.PresentConfiguration, "authentication_type") + + if val == "instance_principal" { + if filePath, err := presentOrError(info.DelegationTokenFilePath, hasDelegationTokenFile, info.PresentConfiguration, "delegationTokenFilePath"); err == nil { + if delegationToken, err := getTokenContent(filePath); err == nil && delegationToken != "" { + Debugf("delegation token content is %s, and error is %s ", delegationToken, err) + return AuthConfig{InstancePrincipalDelegationToken, true, &delegationToken}, nil + } + return AuthConfig{UnknownAuthenticationType, true, nil}, err + + } + // normal instance principle + return AuthConfig{InstancePrincipal, true, nil}, nil + } + + // by default, if no "authentication_type" is provided, just treated as user principle type, and will not return error + return AuthConfig{UserPrincipal, true, nil}, nil +} + +func getTokenContent(filePath string) (string, error) { + expandedPath := expandPath(filePath) + tokenFileContent, err := readFile(expandedPath) + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read token content from configuration file due to: %s", err.Error())} + return "", err + } + return string(tokenFileContent), nil +} + +// A configuration provider that look for information in multiple configuration providers +type composingConfigurationProvider struct { + Providers []ConfigurationProvider +} + +// ComposingConfigurationProvider creates a composing configuration provider with the given slice of configuration providers +// A composing provider will return the configuration of the first provider that has the required property +// if no provider has the property it will return an error. +func ComposingConfigurationProvider(providers []ConfigurationProvider) (ConfigurationProvider, error) { + if len(providers) == 0 { + return nil, fmt.Errorf("providers can not be an empty slice") + } + + for i, p := range providers { + if p == nil { + return nil, fmt.Errorf("provider in position: %d is nil. ComposingConfiurationProvider does not support nil values", i) + } + } + return composingConfigurationProvider{Providers: providers}, nil +} + +func (c composingConfigurationProvider) TenancyOCID() (string, error) { + for _, p := range c.Providers { + val, err := p.TenancyOCID() + if err == nil { + return val, nil + } + Debugf("did not find a proper configuration for tenancy, err: %v", err) + } + return "", fmt.Errorf("did not find a proper configuration for tenancy") +} + +func (c composingConfigurationProvider) UserOCID() (string, error) { + for _, p := range c.Providers { + val, err := p.UserOCID() + if err == nil { + return val, nil + } + Debugf("did not find a proper configuration for keyFingerprint, err: %v", err) + } + return "", fmt.Errorf("did not find a proper configuration for user") +} + +func (c composingConfigurationProvider) KeyFingerprint() (string, error) { + for _, p := range c.Providers { + val, err := p.KeyFingerprint() + if err == nil { + return val, nil + } + } + return "", fmt.Errorf("did not find a proper configuration for keyFingerprint") +} +func (c composingConfigurationProvider) Region() (string, error) { + for _, p := range c.Providers { + val, err := p.Region() + if err == nil { + return val, nil + } + } + if val, err := getRegionFromEnvVar(); err == nil { + return val, nil + } + return "", fmt.Errorf("did not find a proper configuration for region, nor for OCI_REGION env var") +} + +func (c composingConfigurationProvider) KeyID() (string, error) { + for _, p := range c.Providers { + val, err := p.KeyID() + if err == nil { + return val, nil + } + } + return "", fmt.Errorf("did not find a proper configuration for key id") +} + +func (c composingConfigurationProvider) PrivateRSAKey() (*rsa.PrivateKey, error) { + for _, p := range c.Providers { + val, err := p.PrivateRSAKey() + if err == nil { + return val, nil + } + } + return nil, fmt.Errorf("did not find a proper configuration for private key") +} + +func (c composingConfigurationProvider) AuthType() (AuthConfig, error) { + // only check the first default fileConfigProvider + authConfig, err := c.Providers[0].AuthType() + if err == nil && authConfig.AuthType != UnknownAuthenticationType { + return authConfig, nil + } + return AuthConfig{UnknownAuthenticationType, false, nil}, fmt.Errorf("did not find a proper configuration for auth type") +} + +func getRegionFromEnvVar() (string, error) { + regionEnvVar := "OCI_REGION" + if region, existed := os.LookupEnv(regionEnvVar); existed { + return region, nil + } + return "", fmt.Errorf("did not find OCI_REGION env var") +} + +type sessionTokenConfigurationProvider struct { + fileConfigurationProvider +} + +func (p sessionTokenConfigurationProvider) UserOCID() (value string, err error) { + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read the configuration due to: %s", err.Error())} + return + } + // In case of session token-based authentication, userOCID will not be present + // need to check if session token path is provided in the configuration + if _, stErr := presentOrError(info.SecurityTokenFilePath, hasSecurityTokenFile, info.PresentConfiguration, + "securityTokenPath"); stErr == nil { + err = nil + } + return +} + +func (p sessionTokenConfigurationProvider) KeyID() (keyID string, err error) { + _, err = p.TenancyOCID() + if err != nil { + return + } + + _, err = p.KeyFingerprint() + if err != nil { + return + } + + info, err := p.readAndParseConfigFile() + if err != nil { + err = fileConfigurationProviderError{err: fmt.Errorf("can not read SessionTokenFilePath configuration due to: %s", err.Error())} + return + } + + filePath, pathErr := presentOrError(info.SecurityTokenFilePath, hasSecurityTokenFile, info.PresentConfiguration, "securityTokenFilePath") + if pathErr == nil { + rawString, err := getTokenContent(filePath) + if err != nil { + return "", fileConfigurationProviderError{err: err} + } + return "ST$" + rawString, nil + } + err = fileConfigurationProviderError{err: fmt.Errorf("can not read SessionTokenFilePath from configuration file due to: %s", pathErr.Error())} + return +} + +// ConfigurationProviderForSessionToken creates a session token configuration provider from a configuration file +// by reading the "DEFAULT" profile +func ConfigurationProviderForSessionToken(configFilePath, privateKeyPassword string) (ConfigurationProvider, error) { + if configFilePath == "" { + return nil, fileConfigurationProviderError{err: fmt.Errorf("config file path can not be empty")} + } + + return sessionTokenConfigurationProvider{ + fileConfigurationProvider{ + ConfigPath: configFilePath, + PrivateKeyPassword: privateKeyPassword, + Profile: "DEFAULT", + configMux: sync.Mutex{}}}, nil +} + +// ConfigurationProviderForSessionTokenWithProfile creates a session token configuration provider from a configuration file +// by reading the given profile +func ConfigurationProviderForSessionTokenWithProfile(configFilePath, profile, privateKeyPassword string) (ConfigurationProvider, error) { + if configFilePath == "" { + return nil, fileConfigurationProviderError{err: fmt.Errorf("config file path can not be empty")} + } + + return sessionTokenConfigurationProvider{ + fileConfigurationProvider{ + ConfigPath: configFilePath, + PrivateKeyPassword: privateKeyPassword, + Profile: profile, + configMux: sync.Mutex{}}}, nil +} + +func (p sessionTokenConfigurationProvider) Refreshable() bool { + return true +} + +// RefreshableConfigurationProvider the interface to identity if the config provider is refreshable +type RefreshableConfigurationProvider interface { + Refreshable() bool +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/errors.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/errors.go new file mode 100644 index 00000000000..4d85ddbd2d0 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/errors.go @@ -0,0 +1,306 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net" + "net/http" + "strings" + "syscall" + + "github.com/sony/gobreaker" +) + +// ServiceError models all potential errors generated the service call +type ServiceError interface { + // The http status code of the error + GetHTTPStatusCode() int + + // The human-readable error string as sent by the service + GetMessage() string + + // A short error code that defines the error, meant for programmatic parsing. + // See https://docs.oracle.com/iaas/Content/API/References/apierrors.htm + GetCode() string + + // Unique Oracle-assigned identifier for the request. + // If you need to contact Oracle about a particular request, please provide the request ID. + GetOpcRequestID() string +} + +// ServiceErrorRichInfo models all potential errors generated the service call and contains rich info for debugging purpose +type ServiceErrorRichInfo interface { + ServiceError + // The service this service call is sending to + GetTargetService() string + + // The API name this service call is sending to + GetOperationName() string + + // The timestamp when this request is made + GetTimestamp() SDKTime + + // The endpoint and the Http method of this service call + GetRequestTarget() string + + // The client version, in this case the oci go sdk version + GetClientVersion() string + + // The API reference doc link for this API, optional and maybe empty + GetOperationReferenceLink() string + + // Troubleshooting doc link + GetErrorTroubleshootingLink() string +} + +// ServiceErrorLocalizationMessage models all potential errors generated the service call and has localized error message info +type ServiceErrorLocalizationMessage interface { + ServiceErrorRichInfo + // The original error message string as sent by the service + GetOriginalMessage() string + + // The values to be substituted into the originalMessageTemplate, expressed as a string-to-string map. + GetMessageArgument() map[string]string + + // Template in ICU MessageFormat for the human-readable error string in English, but without the values replaced + GetOriginalMessageTemplate() string +} + +type servicefailure struct { + StatusCode int + Code string `json:"code,omitempty"` + Message string `json:"message,omitempty"` + OriginalMessage string `json:"originalMessage"` + OriginalMessageTemplate string `json:"originalMessageTemplate"` + MessageArgument map[string]string `json:"messageArguments"` + OpcRequestID string `json:"opc-request-id"` + // debugging information + TargetService string `json:"target-service"` + OperationName string `json:"operation-name"` + Timestamp SDKTime `json:"timestamp"` + RequestTarget string `json:"request-target"` + ClientVersion string `json:"client-version"` + + // troubleshooting guidance + OperationReferenceLink string `json:"operation-reference-link"` + ErrorTroubleshootingLink string `json:"error-troubleshooting-link"` +} + +func newServiceFailureFromResponse(response *http.Response) error { + var err error + var timestamp SDKTime + t, err := tryParsingTimeWithValidFormatsForHeaders([]byte(response.Header.Get("Date")), "Date") + + if err != nil { + timestamp = *now() + } else { + timestamp = sdkTimeFromTime(t) + } + + se := servicefailure{ + StatusCode: response.StatusCode, + Code: "BadErrorResponse", + OpcRequestID: response.Header.Get("opc-request-id"), + Timestamp: timestamp, + ClientVersion: defaultSDKMarker + "/" + Version(), + RequestTarget: fmt.Sprintf("%s %s", response.Request.Method, response.Request.URL), + } + + //If there is an error consume the body, entirely + body, err := ioutil.ReadAll(response.Body) + if err != nil { + se.Message = fmt.Sprintf("The body of the response was not readable, due to :%s", err.Error()) + return se + } + + err = json.Unmarshal(body, &se) + if err != nil { + Debugf("Error response could not be parsed due to: %s", err.Error()) + se.Message = fmt.Sprintf("Failed to parse json from response body due to: %s. With response body %s.", err.Error(), string(body[:])) + return se + } + return se +} + +// PostProcessServiceError process the service error after an error is raised and complete it with extra information +func PostProcessServiceError(err error, service string, method string, apiReferenceLink string) error { + var serviceFailure servicefailure + if _, ok := err.(servicefailure); !ok { + return err + } + serviceFailure = err.(servicefailure) + serviceFailure.OperationName = method + serviceFailure.TargetService = service + serviceFailure.ErrorTroubleshootingLink = fmt.Sprintf("https://docs.oracle.com/iaas/Content/API/References/apierrors.htm#apierrors_%v__%v_%s", serviceFailure.StatusCode, serviceFailure.StatusCode, strings.ToLower(serviceFailure.Code)) + serviceFailure.OperationReferenceLink = apiReferenceLink + return serviceFailure +} + +func (se servicefailure) Error() string { + return fmt.Sprintf(`Error returned by %s Service. Http Status Code: %d. Error Code: %s. Opc request id: %s. Message: %s +Operation Name: %s +Timestamp: %s +Client Version: %s +Request Endpoint: %s +Troubleshooting Tips: See %s for more information about resolving this error.%s +To get more info on the failing request, you can set OCI_GO_SDK_DEBUG env var to info or higher level to log the request/response details. +If you are unable to resolve this %s issue, please contact Oracle support and provide them this full error message.`, + se.TargetService, se.StatusCode, se.Code, se.OpcRequestID, se.Message, se.OperationName, se.Timestamp, se.ClientVersion, se.RequestTarget, se.ErrorTroubleshootingLink, se.getOperationReferenceMessage(), se.TargetService) +} + +func (se servicefailure) getOperationReferenceMessage() string { + if se.OperationReferenceLink == "" { + return "" + } + return fmt.Sprintf("\nAlso see %s for details on this operation's requirements.", se.OperationReferenceLink) +} + +func (se servicefailure) GetHTTPStatusCode() int { + return se.StatusCode + +} + +func (se servicefailure) GetMessage() string { + return se.Message +} + +func (se servicefailure) GetOriginalMessage() string { + return se.OriginalMessage +} + +func (se servicefailure) GetOriginalMessageTemplate() string { + return se.OriginalMessageTemplate +} + +func (se servicefailure) GetMessageArgument() map[string]string { + return se.MessageArgument +} + +func (se servicefailure) GetCode() string { + return se.Code +} + +func (se servicefailure) GetOpcRequestID() string { + return se.OpcRequestID +} + +func (se servicefailure) GetTargetService() string { + return se.TargetService +} + +func (se servicefailure) GetOperationName() string { + return se.OperationName +} + +func (se servicefailure) GetTimestamp() SDKTime { + return se.Timestamp +} + +func (se servicefailure) GetRequestTarget() string { + return se.RequestTarget +} + +func (se servicefailure) GetClientVersion() string { + return se.ClientVersion +} + +func (se servicefailure) GetOperationReferenceLink() string { + return se.OperationReferenceLink +} + +func (se servicefailure) GetErrorTroubleshootingLink() string { + return se.ErrorTroubleshootingLink +} + +// IsServiceError returns false if the error is not service side, otherwise true +// additionally it returns an interface representing the ServiceError +func IsServiceError(err error) (failure ServiceError, ok bool) { + failure, ok = err.(ServiceError) + return +} + +// IsServiceErrorRichInfo returns false if the error is not service side or is not containing rich info, otherwise true +// additionally it returns an interface representing the ServiceErrorRichInfo +func IsServiceErrorRichInfo(err error) (failure ServiceErrorRichInfo, ok bool) { + failure, ok = err.(ServiceErrorRichInfo) + return +} + +// IsServiceErrorLocalizationMessage returns false if the error is not service side, otherwise true +// additionally it returns an interface representing the ServiceErrorOriginalMessage +func IsServiceErrorLocalizationMessage(err error) (failure ServiceErrorLocalizationMessage, ok bool) { + failure, ok = err.(ServiceErrorLocalizationMessage) + return +} + +type deadlineExceededByBackoffError struct{} + +func (deadlineExceededByBackoffError) Error() string { + return "now() + computed backoff duration exceeds request deadline" +} + +// DeadlineExceededByBackoff is the error returned by Call() when GetNextDuration() returns a time.Duration that would +// force the user to wait past the request deadline before re-issuing a request. This enables us to exit early, since +// we cannot succeed based on the configured retry policy. +var DeadlineExceededByBackoff error = deadlineExceededByBackoffError{} + +// NonSeekableRequestRetryFailure is the error returned when the request is with binary request body, and is configured +// retry, but the request body is not retryable +type NonSeekableRequestRetryFailure struct { + err error +} + +func (ne NonSeekableRequestRetryFailure) Error() string { + if ne.err == nil { + return "Unable to perform Retry on this request body type, which did not implement seek() interface" + } + return fmt.Sprintf("%s. Unable to perform Retry on this request body type, which did not implement seek() interface", ne.err.Error()) +} + +// IsNetworkError validates if an error is a net.Error and check if it's temporary or timeout +func IsNetworkError(err error) bool { + if err == nil { + return false + } + + if errors.Is(err, syscall.ECONNRESET) { + return true + } + + if r, ok := err.(net.Error); ok && (r.Timeout() || strings.Contains(err.Error(), "net/http: HTTP/1.x transport connection broken")) { + return true + } + + return false +} + +// IsCircuitBreakerError validates if an error's text is Open state ErrOpenState or HalfOpen state ErrTooManyRequests +func IsCircuitBreakerError(err error) bool { + if err == nil { + return false + } + + if err.Error() == gobreaker.ErrOpenState.Error() || err.Error() == gobreaker.ErrTooManyRequests.Error() { + return true + } + return false +} + +func getCircuitBreakerError(request *http.Request, err error, cbr *OciCircuitBreaker) error { + cbErr := fmt.Errorf("%s, so this request was not sent to the %s service.\n\n The circuit breaker was opened because the %s service failed too many times recently. "+ + "Because the circuit breaker has been opened, requests within a %.2f second window of when the circuit breaker opened will not be sent to the %s service.\n\n"+ + "URL which circuit breaker prevented request to - %s \n Circuit Breaker Info \n Name - %s \n State - %s \n\n Errors from %s service which opened the circuit breaker:\n\n%s", + err, cbr.Cbst.serviceName, cbr.Cbst.serviceName, cbr.Cbst.openStateWindow.Seconds(), cbr.Cbst.serviceName, request.URL.Host+request.URL.Path, cbr.Cbst.name, cbr.Cb.State().String(), cbr.Cbst.serviceName, cbr.GetHistory()) + return cbErr +} + +// StatErrCode is a type which wraps error's statusCode and errorCode from service end +type StatErrCode struct { + statusCode int + errorCode string +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/eventual_consistency.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/eventual_consistency.go new file mode 100644 index 00000000000..505fe68cf6a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/eventual_consistency.go @@ -0,0 +1,467 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "bytes" + "errors" + "fmt" + "os" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/gofrs/flock" +) + +const ( + // OciGoSdkEcConfigEnvVarName contains the name of the environment variable that can be used to configure the eventual consistency (EC) communication mode. + // Allowed values for environment variable: + // 1. OCI_GO_SDK_EC_CONFIG = "file,/path/to/shared/timestamp/file" + // 2. OCI_GO_SDK_EC_CONFIG = "inprocess" + // 3. absent -- same as OCI_GO_SDK_EC_CONFIG = "inprocess" + OciGoSdkEcConfigEnvVarName string = "OCI_GO_SDK_EC_CONFIG" +) + +// +// Eventual consistency communication mode +// + +// EcMode is the eventual consistency (EC) communication mode used. +type EcMode int64 + +const ( + // Uninitialized means the EC communication mode has not been set yet. + Uninitialized EcMode = iota // 0 + + // InProcess is the default EC communication mode which only communicates the end-of-window timestamp inside the same process. + InProcess + + // File is the EC communication mode that uses a file to communicate the end-of-window timestamp using a file visible across processes. + // Locking is performed using a lock file. + File +) + +var ( + affectedByEventualConsistencyRetryStatusCodeMap = map[StatErrCode]bool{ + {400, "RelatedResourceNotAuthorizedOrNotFound"}: true, + {404, "NotAuthorizedOrNotFound"}: true, + {409, "NotAuthorizedOrResourceAlreadyExists"}: true, + {409, "ResourceAlreadyExists"}: true, + {400, "InsufficientServicePermissions"}: true, + {400, "ResourceDisabled"}: true, + } +) + +// IsErrorAffectedByEventualConsistency returns true if the error is affected by eventual consistency. +func IsErrorAffectedByEventualConsistency(Error error) bool { + if err, ok := IsServiceError(Error); ok { + return affectedByEventualConsistencyRetryStatusCodeMap[StatErrCode{err.GetHTTPStatusCode(), err.GetCode()}] + } + return false +} + +func getEcMode(mode string) EcMode { + var lmode = strings.ToLower(mode) + switch lmode { + case "file": + return File + case "inprocess": + return InProcess + } + ecLogf("%s: Unknown ec mode '%s', assuming 'inprocess'", OciGoSdkEcConfigEnvVarName, mode) + return InProcess +} + +// EventuallyConsistentContext contains the information about the end of the eventually consistent window. +type EventuallyConsistentContext struct { + // memory-based + endOfWindow atomic.Value + lock sync.RWMutex + timeNowProvider func() time.Time + + // mode selector + ecMode EcMode + + // file-based + + // timestampFileName and timestampLockFile should be set to files that + // are accessible by all processes that need to share information about + // eventual consistency. + // A sensible choice are files inside the temp directory, as returned by os.TempDir() + timestampFileName *string + timestampFileLock *flock.Flock + + // lock and unlock functions + readLock func(e *EventuallyConsistentContext) error + readUnlock func(e *EventuallyConsistentContext) error + writeLock func(e *EventuallyConsistentContext) error + writeUnlock func(e *EventuallyConsistentContext) error + + // get/set functions + getEndOfWindowUnsynchronized func(e *EventuallyConsistentContext) (*time.Time, error) + setEndOfWindowUnsynchronized func(e *EventuallyConsistentContext, newEndOfWindowTime *time.Time) error +} + +// newEcContext creates a new EC context based on the OCI_GO_SDK_EC_CONFIG environment variable. +func newEcContext() *EventuallyConsistentContext { + ecConfig, ecConfigProvided := os.LookupEnv(OciGoSdkEcConfigEnvVarName) + if !ecConfigProvided { + ecConfig = "" + } + + commaIndex := strings.Index(ecConfig, ",") + var ecConfigMode = ecConfig + var ecConfigRest = "" + if commaIndex >= 0 { + ecConfigMode = ecConfig[:commaIndex] + ecConfigRest = ecConfig[commaIndex+1:] + } + ecMode := getEcMode(ecConfigMode) + + switch ecMode { + case File: + if len(ecConfigRest) < 1 { + ecLogf("%s: Expected file name after comma for 'File' mode ('file,/path/to/file'), was: '%s'", OciGoSdkEcConfigEnvVarName, ecConfig) + return nil + } + return newEcContextFile(ecConfigRest) + } + + return newEcContextInProcess() +} + +// newEcContextInProcess creates a new in-process EC context. +func newEcContextInProcess() *EventuallyConsistentContext { + ecContext := EventuallyConsistentContext{ + ecMode: InProcess, + readLock: ecInProcessReadLock, + readUnlock: ecInProcessReadUnlock, + writeLock: ecInProcessWriteLock, + writeUnlock: ecInProcessWriteUnlock, + getEndOfWindowUnsynchronized: ecInProcessGetEndOfWindowUnsynchronized, + setEndOfWindowUnsynchronized: ecInProcessSetEndOfWindowUnsynchronized, + timeNowProvider: func() time.Time { return time.Now() }, + } + return &ecContext +} + +// newEcContextFile creates a new EC context kept in a file. +// timestampFileName should be set to a file accessible by all processes that +// need to share information about eventual consistency. +// A sensible choice are files inside the temp directory, as returned by os.TempDir() +// The lock file will use the same name, with the suffix ".lock" added. +func newEcContextFile(timestampFileName string) *EventuallyConsistentContext { + timestampLockFileName := timestampFileName + ".lock" + ecContext := EventuallyConsistentContext{ + ecMode: File, + readLock: ecFileReadLock, + readUnlock: ecFileReadUnlock, + writeLock: ecFileWriteLock, + writeUnlock: ecFileWriteUnlock, + getEndOfWindowUnsynchronized: ecFileGetEndOfWindowUnsynchronized, + setEndOfWindowUnsynchronized: ecFileSetEndOfWindowUnsynchronized, + timeNowProvider: func() time.Time { return time.Now() }, + timestampFileName: ×tampFileName, + timestampFileLock: flock.New(timestampLockFileName), + } + ecDebugf("%s: Using file modification time of file '%s' and lock file '%s'", OciGoSdkEcConfigEnvVarName, *ecContext.timestampFileName, timestampLockFileName) + return &ecContext +} + +// InitializeEcContextFromEnvVar initializes the EcContext variable as configured +// in the OCI_GO_SDK_EC_CONFIG environment variable. +func InitializeEcContextFromEnvVar() { + EcContext = newEcContext() +} + +// InitializeEcContextInProcess initializes the EcContext variable to be in-process only. +func InitializeEcContextInProcess() { + EcContext = newEcContextInProcess() +} + +// InitializeEcContextFile initializes the EcContext variable to be kept in a timestamp file, +// protected by a lock file. +// timestampFileName should be set to a file accessible by all processes that +// need to share information about eventual consistency. +// A sensible choice are files inside the temp directory, as returned by os.TempDir() +// The lock file will use the same name, with the suffix ".lock" added. +func InitializeEcContextFile(timestampFileName string) { + EcContext = newEcContextFile(timestampFileName) +} + +// +// InProcess functions +// + +func ecInProcessReadLock(e *EventuallyConsistentContext) error { + e.lock.RLock() + return nil +} + +func ecInProcessReadUnlock(e *EventuallyConsistentContext) error { + e.lock.RUnlock() + return nil +} + +func ecInProcessWriteLock(e *EventuallyConsistentContext) error { + e.lock.Lock() + return nil +} + +func ecInProcessWriteUnlock(e *EventuallyConsistentContext) error { + e.lock.Unlock() + return nil +} + +// ecInProcessGetEndOfWindowUnsynchronized returns the end time of an eventually consistent window, +// or nil if no eventually consistent requests were made. +// There is no mutex synchronization. +func ecInProcessGetEndOfWindowUnsynchronized(e *EventuallyConsistentContext) (*time.Time, error) { + untyped := e.endOfWindow.Load() // returns nil if there has been no call to Store for this Value + if untyped == nil { + return (*time.Time)(nil), nil + } + t := untyped.(*time.Time) + + return t, nil +} + +// ecInProcessSetEndOfWindowUnsynchronized sets the end time of the eventually consistent window. +// There is no mutex synchronization. +func ecInProcessSetEndOfWindowUnsynchronized(e *EventuallyConsistentContext, newEndOfWindowTime *time.Time) error { + e.endOfWindow.Store(newEndOfWindowTime) // atomically replace the current object with the new one + return nil +} + +// +// File functions +// + +func ecFileReadLock(e *EventuallyConsistentContext) error { + return e.timestampFileLock.RLock() +} + +func ecFileReadUnlock(e *EventuallyConsistentContext) error { + return e.timestampFileLock.Unlock() +} + +func ecFileWriteLock(e *EventuallyConsistentContext) error { + return e.timestampFileLock.Lock() +} + +func ecFileWriteUnlock(e *EventuallyConsistentContext) error { + return e.timestampFileLock.Unlock() +} + +// ecFileGetEndOfWindowUnsynchronized returns the end time of an eventually consistent window, +// or nil if no eventually consistent requests were made. +// There is no mutex synchronization. +func ecFileGetEndOfWindowUnsynchronized(e *EventuallyConsistentContext) (*time.Time, error) { + file, err := os.Stat(*e.timestampFileName) + + if errors.Is(err, os.ErrNotExist) { + ecDebugf("%s: File '%s' does not exist, meaning no EC in effect", OciGoSdkEcConfigEnvVarName, *e.timestampFileName) + return (*time.Time)(nil), nil + } + if err != nil { + ecLogf("%s: Error getting modified time from file '%s', assuming no EC in effect: %s", OciGoSdkEcConfigEnvVarName, *e.timestampFileName, err) + return (*time.Time)(nil), err + } + + t := file.ModTime() + ecDebugf("%s: Read modified time of file '%s' as '%s'", OciGoSdkEcConfigEnvVarName, *e.timestampFileName, t) + + return &t, nil +} + +// ecFileSetEndOfWindowUnsynchronized sets the end time of the eventually consistent window. +// There is no mutex synchronization. +func ecFileSetEndOfWindowUnsynchronized(e *EventuallyConsistentContext, newEndOfWindowTime *time.Time) error { + if newEndOfWindowTime != nil { + ecDebugf("%s: Updating modified time of file '%s' to '%s'", OciGoSdkEcConfigEnvVarName, *e.timestampFileName, *newEndOfWindowTime) + } else { + ecDebugf("%s: Updating modified time of file '%s' to ", OciGoSdkEcConfigEnvVarName, *e.timestampFileName) + } + + if newEndOfWindowTime == nil { + err := os.Remove(*e.timestampFileName) + if err != nil && !errors.Is(err, os.ErrNotExist) { + ecLogf("%s: Error removing file '%s', may draw wrong EC conflusions: %s", OciGoSdkEcConfigEnvVarName, *e.timestampFileName, err) + } + return err + } + + atime := time.Now() + var err = os.Chtimes(*e.timestampFileName, atime, *newEndOfWindowTime) + if errors.Is(err, os.ErrNotExist) { + _, createErr := os.Create(*e.timestampFileName) + if createErr != nil { + ecLogf("%s: Error creating file '%s', will have to assume no EC in effect: %s", OciGoSdkEcConfigEnvVarName, *e.timestampFileName, createErr) + return createErr + } + err = os.Chtimes(*e.timestampFileName, atime, *newEndOfWindowTime) + } + if err != nil { + ecLogf("%s: Error changing modified time for file '%s', will have to assume no EC in effect: %s", OciGoSdkEcConfigEnvVarName, *e.timestampFileName, err) + return err + } + return nil +} + +// +// General functions for EC window handling, for all EC communication modes +// + +// GetEndOfWindow returns the end time an eventually consistent window, +// or nil if no eventually consistent requests were made +func (e *EventuallyConsistentContext) GetEndOfWindow() *time.Time { + e.readLock(e) // synchronize with potential writers + defer e.readUnlock(e) + + endOfWindowTime, _ := e.getEndOfWindowUnsynchronized(e) + + // TODO: this is noisy logging, consider removing + if endOfWindowTime != nil { + ecDebugln(fmt.Sprintf("EcContext.GetEndOfWindow returns %s", endOfWindowTime)) + } else { + ecDebugln("EcContext.GetEndOfWindow returns ") + } + + return endOfWindowTime +} + +// UpdateEndOfWindow sets the end time of the eventually consistent window the specified +// duration into the future +func (e *EventuallyConsistentContext) UpdateEndOfWindow(windowSize time.Duration) *time.Time { + e.writeLock(e) // synchronize with other potential writers + defer e.writeUnlock(e) + + currentEndOfWindowTime, _ := e.getEndOfWindowUnsynchronized(e) + var newEndOfWindowTime = e.timeNowProvider().Add(windowSize) + if currentEndOfWindowTime == nil || newEndOfWindowTime.After(*currentEndOfWindowTime) { + e.setEndOfWindowUnsynchronized(e, &newEndOfWindowTime) + + // TODO: this is noisy logging, consider removing + ecDebugln(fmt.Sprintf("EcContext.UpdateEndOfWindow to %s", newEndOfWindowTime)) + + return &newEndOfWindowTime + } + return currentEndOfWindowTime +} + +// setEndTimeOfEventuallyConsistentWindow sets the last time an eventually consistent request was made +// to the specified time +func (e *EventuallyConsistentContext) setEndOfWindow(newTime *time.Time) *time.Time { + e.writeLock(e) // synchronize with other potential writers + defer e.writeUnlock(e) + + e.setEndOfWindowUnsynchronized(e, newTime) + + // TODO: this is noisy logging, consider removing + if newTime != nil { + ecDebugln(fmt.Sprintf("EcContext.setEndOfWindow to %s", *newTime)) + } else { + ecDebugln("EcContext.setEndOfWindow to ") + } + + return newTime +} + +// EcContext contains the information about the end of the eventually consistent window for this process. +var EcContext = newEcContext() + +// +// Logging helpers +// + +// getGID returns the Goroutine id. This is purely for logging and debugging. +// See https://blog.sgmansfield.com/2015/12/goroutine-ids/ +func getGID() uint64 { + b := make([]byte, 64) + b = b[:runtime.Stack(b, false)] + b = bytes.TrimPrefix(b, []byte("goroutine ")) + b = b[:bytes.IndexByte(b, ' ')] + n, _ := strconv.ParseUint(string(b), 10, 64) + return n +} + +// some of these errors happen so early, defaultLogger may not have been +// initialized yet. +func initLogIfNecessary() { + if defaultLogger == nil { + l, _ := NewSDKLogger() + SetSDKLogger(l) + } +} + +// Debugf logs v with the provided format if debug mode is set. +// There is no mutex synchronization. You should have acquired e.lock first. +func ecDebugf(format string, v ...interface{}) { + defer func() { + // recover from panic if one occured. + if recover() != nil { + Debugln("ecDebugf failed") + } + }() + + str := fmt.Sprintf(format, v...) + + initLogIfNecessary() + + // prefix message with "(pid=25140, gid=5)" + Debugf("(pid=%d, gid=%d) %s", os.Getpid(), getGID(), str) +} + +// Debug logs v if debug mode is set. +// There is no mutex synchronization. You should have acquired e.lock first. +func ecDebug(v ...interface{}) { + defer func() { + // recover from panic if one occured. + if recover() != nil { + Debugln("ecDebug failed") + } + }() + + initLogIfNecessary() + + // prefix message with "(pid=25140, gid=5)" + Debug(append([]interface{}{"(pid=", os.Getpid(), ", gid=", getGID(), ") "}, v...)...) +} + +// Debugln logs v appending a new line if debug mode is set +// There is no mutex synchronization. You should have acquired e.lock first. +func ecDebugln(v ...interface{}) { + defer func() { + // recover from panic if one occured. + if recover() != nil { + Debugln("ecDebugln failed") + } + }() + + initLogIfNecessary() + + // prefix message with "(pid=25140, gid=5)" + Debugln(append([]interface{}{"(pid=", os.Getpid(), ", gid=", getGID(), ") "}, v...)...) +} + +// Logf logs v with the provided format if info mode is set. +// There is no mutex synchronization. You should have acquired e.lock first. +func ecLogf(format string, v ...interface{}) { + defer func() { + // recover from panic if one occured. + if recover() != nil { + Debugln("ecLogf failed") + } + }() + + initLogIfNecessary() + + str := fmt.Sprintf(format, v...) + // prefix message with "(pid=25140, gid=5)" + Logf("(pid=%d, gid=%d) %s", os.Getpid(), getGID(), str) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/helpers.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/helpers.go new file mode 100644 index 00000000000..9f783d22bec --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/helpers.go @@ -0,0 +1,308 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +//lint:file-ignore SA1019 older versions of staticcheck (those compatible with Golang 1.17) falsely flag x509.IsEncryptedPEMBlock and x509.DecryptPEMBlock. + +package common + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "net/textproto" + "os" + "reflect" + "strconv" + "strings" + "time" + + "github.com/youmark/pkcs8" +) + +// String returns a pointer to the provided string +func String(value string) *string { + return &value +} + +// Int returns a pointer to the provided int +func Int(value int) *int { + return &value +} + +// Int64 returns a pointer to the provided int64 +func Int64(value int64) *int64 { + return &value +} + +// Uint returns a pointer to the provided uint +func Uint(value uint) *uint { + return &value +} + +// Float32 returns a pointer to the provided float32 +func Float32(value float32) *float32 { + return &value +} + +// Float64 returns a pointer to the provided float64 +func Float64(value float64) *float64 { + return &value +} + +// Bool returns a pointer to the provided bool +func Bool(value bool) *bool { + return &value +} + +// PointerString prints the values of pointers in a struct +// Producing a human friendly string for an struct with pointers. +// useful when debugging the values of a struct +func PointerString(datastruct interface{}) (representation string) { + val := reflect.ValueOf(datastruct) + typ := reflect.TypeOf(datastruct) + all := make([]string, 2) + all = append(all, "{") + for i := 0; i < typ.NumField(); i++ { + sf := typ.Field(i) + + //unexported + if sf.PkgPath != "" && !sf.Anonymous { + continue + } + + sv := val.Field(i) + stringValue := "" + if isNil(sv) { + stringValue = fmt.Sprintf("%s=", sf.Name) + } else { + if sv.Type().Kind() == reflect.Ptr { + sv = sv.Elem() + } + stringValue = fmt.Sprintf("%s=%v", sf.Name, sv) + } + all = append(all, stringValue) + } + all = append(all, "}") + representation = strings.TrimSpace(strings.Join(all, " ")) + return +} + +// SDKTime a struct that parses/renders to/from json using RFC339 date-time information +type SDKTime struct { + time.Time +} + +// SDKDate a struct that parses/renders to/from json using only date information +type SDKDate struct { + //Date date information + Date time.Time +} + +func sdkTimeFromTime(t time.Time) SDKTime { + return SDKTime{t} +} + +func sdkDateFromTime(t time.Time) SDKDate { + return SDKDate{Date: t} +} + +func formatTime(t SDKTime) string { + return t.Format(sdkTimeFormat) +} + +func formatDate(t SDKDate) string { + return t.Date.Format(sdkDateFormat) +} + +func now() *SDKTime { + t := SDKTime{time.Now()} + return &t +} + +var timeType = reflect.TypeOf(SDKTime{}) +var timeTypePtr = reflect.TypeOf(&SDKTime{}) + +var sdkDateType = reflect.TypeOf(SDKDate{}) +var sdkDateTypePtr = reflect.TypeOf(&SDKDate{}) + +// Formats for sdk supported time representations +const sdkTimeFormat = time.RFC3339Nano +const rfc1123OptionalLeadingDigitsInDay = "Mon, _2 Jan 2006 15:04:05 MST" +const sdkDateFormat = "2006-01-02" + +func tryParsingTimeWithValidFormatsForHeaders(data []byte, headerName string) (t time.Time, err error) { + header := strings.ToLower(headerName) + switch header { + case "lastmodified", "date": + t, err = tryParsing(data, time.RFC3339Nano, time.RFC3339, time.RFC1123, rfc1123OptionalLeadingDigitsInDay, time.RFC850, time.ANSIC) + return + default: //By default we parse with RFC3339 + t, err = time.Parse(sdkTimeFormat, string(data)) + return + } +} + +func tryParsing(data []byte, layouts ...string) (tm time.Time, err error) { + datestring := string(data) + for _, l := range layouts { + tm, err = time.Parse(l, datestring) + if err == nil { + return + } + } + err = fmt.Errorf("could not parse time: %s with formats: %s", datestring, layouts[:]) + return +} + +// String returns string representation of SDKDate +func (t *SDKDate) String() string { + return t.Date.Format(sdkDateFormat) +} + +// NewSDKDateFromString parses the dateString into SDKDate +func NewSDKDateFromString(dateString string) (*SDKDate, error) { + parsedTime, err := time.Parse(sdkDateFormat, dateString) + if err != nil { + return nil, err + } + + return &SDKDate{Date: parsedTime}, nil +} + +// UnmarshalJSON unmarshals from json +func (t *SDKTime) UnmarshalJSON(data []byte) (e error) { + s := string(data) + if s == "null" { + t.Time = time.Time{} + } else { + //Try parsing with RFC3339 + t.Time, e = time.Parse(`"`+sdkTimeFormat+`"`, string(data)) + } + return +} + +// MarshalJSON marshals to JSON +func (t *SDKTime) MarshalJSON() (buff []byte, e error) { + s := t.Format(sdkTimeFormat) + buff = []byte(`"` + s + `"`) + return +} + +// UnmarshalJSON unmarshals from json +func (t *SDKDate) UnmarshalJSON(data []byte) (e error) { + if string(data) == `"null"` { + t.Date = time.Time{} + return + } + + t.Date, e = tryParsing(data, + strconv.Quote(sdkDateFormat), + ) + return +} + +// MarshalJSON marshals to JSON +func (t *SDKDate) MarshalJSON() (buff []byte, e error) { + s := t.Date.Format(sdkDateFormat) + buff = []byte(strconv.Quote(s)) + return +} + +// PrivateKeyFromBytes is a helper function that will produce a RSA private +// key from bytes. This function is deprecated in favour of PrivateKeyFromBytesWithPassword +// Deprecated +func PrivateKeyFromBytes(pemData []byte, password *string) (key *rsa.PrivateKey, e error) { + if password == nil { + return PrivateKeyFromBytesWithPassword(pemData, nil) + } + + return PrivateKeyFromBytesWithPassword(pemData, []byte(*password)) +} + +// PrivateKeyFromBytesWithPassword is a helper function that will produce a RSA private +// key from bytes and a password. +func PrivateKeyFromBytesWithPassword(pemData, password []byte) (key *rsa.PrivateKey, e error) { + pemBlock, _ := pem.Decode(pemData) + if pemBlock == nil { + e = fmt.Errorf("PEM data was not found in buffer") + return + } + + decrypted := pemBlock.Bytes + // Support for encrypted PKCS8 format, this format can not be handled by x509.IsEncryptedPEMBlock func + if key, e = pkcs8.ParsePKCS8PrivateKeyRSA(pemBlock.Bytes, password); key != nil { + return + } + // if pemBlock.Type == "ENCRYPTED PRIVATE KEY" { + // return pkcs8.ParsePKCS8PrivateKeyRSA(pemData, password) + // } + if x509.IsEncryptedPEMBlock(pemBlock) { + if password == nil { + return nil, errors.New("private key password is required for encrypted private keys") + } + + if decrypted, e = x509.DecryptPEMBlock(pemBlock, password); e != nil { + return + } + } + key, e = parsePKCSPrivateKey(decrypted) + return +} + +// ParsePrivateKey using PKCS1 or PKCS8 +func parsePKCSPrivateKey(decryptedKey []byte) (*rsa.PrivateKey, error) { + if key, err := x509.ParsePKCS1PrivateKey(decryptedKey); err == nil { + return key, nil + } + if key, err := x509.ParsePKCS8PrivateKey(decryptedKey); err == nil { + switch key := key.(type) { + case *rsa.PrivateKey: + return key, nil + default: + return nil, fmt.Errorf("unsupportesd private key type in PKCS8 wrapping") + } + } + return nil, fmt.Errorf("failed to parse private key") +} + +// parseContentLength trims whitespace from cl and returns -1 if can't purse uint, or the value if it's no less than 0 +func parseContentLength(cl string) int64 { + cl = textproto.TrimString(cl) + n, err := strconv.ParseUint(cl, 10, 63) + if err != nil { + return -1 + } + return int64(n) +} + +func generateRandUUID() (string, error) { + b := make([]byte, 16) + _, err := rand.Read(b) + if err != nil { + return "", err + } + uuid := fmt.Sprintf("%x%x%x%x%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) + + return uuid, nil +} + +func makeACopy(original []string) []string { + tmp := make([]string, len(original)) + copy(tmp, original) + return tmp +} + +// IsEnvVarFalse is used for checking if an environment variable is explicitly set to false, otherwise would set it true by default +func IsEnvVarFalse(envVarKey string) bool { + val, existed := os.LookupEnv(envVarKey) + return existed && strings.ToLower(val) == "false" +} + +// IsEnvVarTrue is used for checking if an environment variable is explicitly set to true, otherwise would set it true by default +func IsEnvVarTrue(envVarKey string) bool { + val, existed := os.LookupEnv(envVarKey) + return existed && strings.ToLower(val) == "true" +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/http.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/http.go new file mode 100644 index 00000000000..2e4fc1cf854 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/http.go @@ -0,0 +1,1144 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "reflect" + "regexp" + "strconv" + "strings" + "time" +) + +const ( + //UsingExpectHeaderEnvVar is the key to determine whether expect 100-continue is enabled or not + UsingExpectHeaderEnvVar = "OCI_GOSDK_USING_EXPECT_HEADER" +) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Request Marshaling +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func isNil(v reflect.Value) bool { + return v.Kind() == reflect.Ptr && v.IsNil() +} + +// Returns the string representation of a reflect.Value +// Only transforms primitive values +func toStringValue(v reflect.Value, field reflect.StructField) (string, error) { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return "", fmt.Errorf("can not marshal a nil pointer") + } + v = v.Elem() + } + + if v.Type() == timeType { + t := v.Interface().(SDKTime) + return formatTime(t), nil + } + + if v.Type() == sdkDateType { + t := v.Interface().(SDKDate) + return formatDate(t), nil + } + + switch v.Kind() { + case reflect.Bool: + return strconv.FormatBool(v.Bool()), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(v.Int(), 10), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return strconv.FormatUint(v.Uint(), 10), nil + case reflect.String: + return v.String(), nil + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil + default: + return "", fmt.Errorf("marshaling structure to a http.Request does not support field named: %s of type: %v", + field.Name, v.Type().String()) + } +} + +func addBinaryBody(request *http.Request, value reflect.Value, field reflect.StructField) (e error) { + readCloser, ok := value.Interface().(io.ReadCloser) + isMandatory, err := strconv.ParseBool(field.Tag.Get("mandatory")) + if err != nil { + return fmt.Errorf("mandatory tag is not valid for field %s", field.Name) + } + + if isMandatory && !ok { + e = fmt.Errorf("body of the request is mandatory and needs to be an io.ReadCloser interface. Can not marshal body of binary request") + return + } + + request.Body = readCloser + + //Set the default content type to application/octet-stream if not set + if request.Header.Get(requestHeaderContentType) == "" { + request.Header.Set(requestHeaderContentType, "application/octet-stream") + } + return nil +} + +// getTaggedNilFieldNameOrError, evaluates if a field with json and non mandatory tags is nil +// returns the json tag name, or an error if the tags are incorrectly present +func getTaggedNilFieldNameOrError(field reflect.StructField, fieldValue reflect.Value) (bool, string, error) { + currentTag := field.Tag + jsonTag := currentTag.Get("json") + + if jsonTag == "" { + return false, "", fmt.Errorf("json tag is not valid for field %s", field.Name) + } + + partsJSONTag := strings.Split(jsonTag, ",") + nameJSONField := partsJSONTag[0] + + if _, ok := currentTag.Lookup("mandatory"); !ok { + //No mandatory field set, no-op + return false, nameJSONField, nil + } + isMandatory, err := strconv.ParseBool(currentTag.Get("mandatory")) + if err != nil { + return false, "", fmt.Errorf("mandatory tag is not valid for field %s", field.Name) + } + + // If the field is marked as mandatory, no-op + if isMandatory { + return false, nameJSONField, nil + } + + Debugf("Adjusting tag: mandatory is false and json tag is valid on field: %s", field.Name) + + // If the field can not be nil, then no-op + if !isNillableType(&fieldValue) { + Debugf("WARNING json field is tagged with mandatory flags, but the type can not be nil, field name: %s", field.Name) + return false, nameJSONField, nil + } + + // If field value is nil, tag it as omitEmpty + return fieldValue.IsNil(), nameJSONField, nil + +} + +// isNillableType returns true if the filed can be nil +func isNillableType(value *reflect.Value) bool { + k := value.Kind() + switch k { + case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice: + return true + } + return false +} + +// omitNilFieldsInJSON, removes json keys whose struct value is nil, and the field is tagged with the json and +// mandatory:false tags +func omitNilFieldsInJSON(data interface{}, value reflect.Value) (interface{}, error) { + switch value.Kind() { + case reflect.Struct: + jsonMap := data.(map[string]interface{}) + fieldType := value.Type() + for i := 0; i < fieldType.NumField(); i++ { + currentField := fieldType.Field(i) + //unexported skip + if currentField.PkgPath != "" { + continue + } + + //Does not have json tag, no-op + if _, ok := currentField.Tag.Lookup("json"); !ok { + continue + } + + currentFieldValue := value.Field(i) + ok, jsonFieldName, err := getTaggedNilFieldNameOrError(currentField, currentFieldValue) + if err != nil { + return nil, fmt.Errorf("can not omit nil fields for field: %s, due to: %s", + currentField.Name, err.Error()) + } + + //Delete the struct field from the json representation + if ok { + delete(jsonMap, jsonFieldName) + continue + } + + // Check to make sure the field is part of the json representation of the value + if _, contains := jsonMap[jsonFieldName]; !contains { + Debugf("Field %s is not present in json, omitting", jsonFieldName) + continue + } + + if currentFieldValue.Type() == timeType || currentFieldValue.Type() == timeTypePtr || + currentField.Type == sdkDateType || currentField.Type == sdkDateTypePtr { + continue + } + // does it need to be adjusted? + var adjustedValue interface{} + adjustedValue, err = omitNilFieldsInJSON(jsonMap[jsonFieldName], currentFieldValue) + if err != nil { + return nil, fmt.Errorf("can not omit nil fields for field: %s, due to: %s", + currentField.Name, err.Error()) + } + jsonMap[jsonFieldName] = adjustedValue + } + return jsonMap, nil + case reflect.Slice, reflect.Array: + // Special case: a []byte may have been marshalled as a string + if data != nil && reflect.TypeOf(data).Kind() == reflect.String && value.Type().Elem().Kind() == reflect.Uint8 { + return data, nil + } + jsonList, ok := data.([]interface{}) + if !ok { + return nil, fmt.Errorf("can not omit nil fields, data was expected to be a not-nil list") + } + newList := make([]interface{}, len(jsonList)) + var err error + for i, val := range jsonList { + newList[i], err = omitNilFieldsInJSON(val, value.Index(i)) + if err != nil { + return nil, err + } + } + return newList, nil + case reflect.Map: + jsonMap, ok := data.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("can not omit nil fields, data was expected to be a not-nil map") + } + newMap := make(map[string]interface{}, len(jsonMap)) + var err error + for key, val := range jsonMap { + newMap[key], err = omitNilFieldsInJSON(val, value.MapIndex(reflect.ValueOf(key))) + if err != nil { + return nil, err + } + } + return newMap, nil + case reflect.Ptr, reflect.Interface: + valPtr := value.Elem() + return omitNilFieldsInJSON(data, valPtr) + default: + //Otherwise no-op + return data, nil + } +} + +// removeNilFieldsInJSONWithTaggedStruct remove struct fields tagged with json and mandatory false +// that are nil +func removeNilFieldsInJSONWithTaggedStruct(rawJSON []byte, value reflect.Value) ([]byte, error) { + var rawInterface interface{} + decoder := json.NewDecoder(bytes.NewBuffer(rawJSON)) + decoder.UseNumber() + var err error + if err = decoder.Decode(&rawInterface); err != nil { + return nil, err + } + + fixedMap, err := omitNilFieldsInJSON(rawInterface, value) + if err != nil { + return nil, err + } + return json.Marshal(fixedMap) +} + +func addToBody(request *http.Request, value reflect.Value, field reflect.StructField, binaryBodySpecified *bool) (e error) { + Debugln("Marshaling to body from field:", field.Name) + if request.Body != nil { + Logf("The body of the request is already set. Structure: %s will overwrite it\n", field.Name) + } + tag := field.Tag + encoding := tag.Get("encoding") + + if encoding == "binary" { + *binaryBodySpecified = true + return addBinaryBody(request, value, field) + } + + rawJSON, e := json.Marshal(value.Interface()) + if e != nil { + return + } + marshaled, e := removeNilFieldsInJSONWithTaggedStruct(rawJSON, value) + if e != nil { + return + } + + if defaultLogger.LogLevel() == verboseLogging { + Debugf("Marshaled body is: %s\n", string(marshaled)) + } + + bodyBytes := bytes.NewReader(marshaled) + request.ContentLength = int64(bodyBytes.Len()) + request.Header.Set(requestHeaderContentLength, strconv.FormatInt(request.ContentLength, 10)) + request.Header.Set(requestHeaderContentType, "application/json") + request.Body = ioutil.NopCloser(bodyBytes) + snapshot := *bodyBytes + request.GetBody = func() (io.ReadCloser, error) { + r := snapshot + return ioutil.NopCloser(&r), nil + } + + return +} + +func checkBinaryBodyLength(request *http.Request) (contentLen int64, err error) { + if isNopCloser(request.Body) { + ioReader := reflect.ValueOf(request.Body).Field(0).Interface().(io.Reader) + switch t := ioReader.(type) { + case *bytes.Reader: + return int64(t.Len()), nil + case *bytes.Buffer: + return int64(t.Len()), nil + case *strings.Reader: + return int64(t.Len()), nil + default: + return getNormalBinaryBodyLength(request) + } + } + if reflect.TypeOf(request.Body) == reflect.TypeOf((*os.File)(nil)) { + fi, err := (request.Body.(*os.File)).Stat() + if err != nil { + return contentLen, err + } + return fi.Size(), nil + } + return getNormalBinaryBodyLength(request) +} + +// Helper function to judge if this struct is a nopCloser or nopCloserWriterTo +func isNopCloser(readCloser io.ReadCloser) bool { + if reflect.TypeOf(readCloser) == reflect.TypeOf(io.NopCloser(nil)) || reflect.TypeOf(readCloser) == reflect.TypeOf(io.NopCloser(struct { + io.Reader + io.WriterTo + }{})) { + return true + } + return false +} + +func getNormalBinaryBodyLength(request *http.Request) (contentLen int64, err error) { + // If binary body is seekable + seeker := getSeeker(request.Body) + if seeker != nil { + // save the current position, calculate the unread body length and seek it back to current position + if curPos, err := seeker.Seek(0, io.SeekCurrent); err == nil { + if endPos, err := seeker.Seek(0, io.SeekEnd); err == nil { + contentLen = endPos - curPos + if _, err = seeker.Seek(curPos, io.SeekStart); err == nil { + return contentLen, nil + } + } + } + } + + var dumpRequestBody io.ReadCloser + if dumpRequestBody, request.Body, err = drainBody(request.Body); err != nil { + return contentLen, err + } + contentBody, err := ioutil.ReadAll(dumpRequestBody) + if err != nil { + return contentLen, err + } + return int64(len(contentBody)), nil +} + +func getSeeker(readCloser io.ReadCloser) (seeker io.Seeker) { + if seeker, ok := readCloser.(io.Seeker); ok { + return seeker + } + // the binary body is wrapped with io.NopCloser + if isNopCloser(readCloser) { + if seeker, ok := reflect.ValueOf(readCloser).Field(0).Interface().(io.Seeker); ok { + return seeker + } + } + return seeker +} + +func addToQuery(request *http.Request, value reflect.Value, field reflect.StructField) (e error) { + Debugln("Marshaling to query from field: ", field.Name) + if request.URL == nil { + request.URL = &url.URL{} + } + query := request.URL.Query() + var queryParameterValue, queryParameterName string + + if queryParameterName = field.Tag.Get("name"); queryParameterName == "" { + return fmt.Errorf("marshaling request to a query requires the 'name' tag for field: %s ", field.Name) + } + + mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory"))) + + //If mandatory and nil. Error out + if mandatory && isNil(value) { + return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name) + } + + //if not mandatory and nil. Omit + if !mandatory && isNil(value) { + Debugf("Query parameter value is not mandatory and is nil pointer in field: %s. Skipping query", field.Name) + return + } + + encoding := strings.ToLower(field.Tag.Get("collectionFormat")) + var collectionFormatStringValues []string + switch encoding { + case "csv", "multi": + if value.Kind() != reflect.Slice && value.Kind() != reflect.Array { + e = fmt.Errorf("query parameter is tagged as csv or multi yet its type is neither an Array nor a Slice: %s", field.Name) + break + } + + numOfElements := value.Len() + collectionFormatStringValues = make([]string, numOfElements) + for i := 0; i < numOfElements; i++ { + collectionFormatStringValues[i], e = toStringValue(value.Index(i), field) + if e != nil { + break + } + } + queryParameterValue = strings.Join(collectionFormatStringValues, ",") + case "": + queryParameterValue, e = toStringValue(value, field) + default: + e = fmt.Errorf("encoding of type %s is not supported for query param: %s", encoding, field.Name) + } + + if e != nil { + return + } + + //check for tag "omitEmpty", this is done to accomodate unset fields that do not + //support an empty string: enums in query params + if omitEmpty, present := field.Tag.Lookup("omitEmpty"); present { + omitEmptyBool, _ := strconv.ParseBool(strings.ToLower(omitEmpty)) + if queryParameterValue != "" || !omitEmptyBool { + addToQueryForEncoding(&query, encoding, queryParameterName, queryParameterValue, collectionFormatStringValues) + } else { + Debugf("Omitting %s, is empty and omitEmpty tag is set", field.Name) + } + } else { + addToQueryForEncoding(&query, encoding, queryParameterName, queryParameterValue, collectionFormatStringValues) + } + + request.URL.RawQuery = query.Encode() + return +} + +func addToQueryForEncoding(query *url.Values, encoding string, queryParameterName string, queryParameterValue string, collectionFormatStringValues []string) { + if encoding == "multi" { + for _, stringValue := range collectionFormatStringValues { + query.Add(queryParameterName, stringValue) + } + } else { + query.Set(queryParameterName, queryParameterValue) + } +} + +// Adds to the path of the url in the order they appear in the structure +func addToPath(request *http.Request, value reflect.Value, field reflect.StructField) (e error) { + var additionalURLPathPart string + if additionalURLPathPart, e = toStringValue(value, field); e != nil { + return fmt.Errorf("can not marshal to path in request for field %s. Due to %s", field.Name, e.Error()) + } + + // path should not be empty for any operations + if len(additionalURLPathPart) == 0 { + return fmt.Errorf("value cannot be empty for field %s in path", field.Name) + } + + if request.URL == nil { + request.URL = &url.URL{} + request.URL.Path = "" + } + var currentURLPath = request.URL.Path + + var templatedPathRegex, _ = regexp.Compile(".*{.+}.*") + if !templatedPathRegex.MatchString(currentURLPath) { + Debugln("Marshaling request to path by appending field:", field.Name) + allPath := []string{currentURLPath, additionalURLPathPart} + request.URL.Path = strings.Join(allPath, "/") + } else { + var fieldName string + if fieldName = field.Tag.Get("name"); fieldName == "" { + e = fmt.Errorf("marshaling request to path name and template requires a 'name' tag for field: %s", field.Name) + return + } + urlTemplate := currentURLPath + Debugln("Marshaling to path from field: ", field.Name, " in template: ", urlTemplate) + request.URL.Path = strings.Replace(urlTemplate, "{"+fieldName+"}", additionalURLPathPart, -1) + } + return +} + +func setWellKnownHeaders(request *http.Request, headerName, headerValue string, contentLenSpecified *bool) (e error) { + switch strings.ToLower(headerName) { + case "content-length": + var len int + len, e = strconv.Atoi(headerValue) + if e != nil { + return + } + request.ContentLength = int64(len) + *contentLenSpecified = true + } + return nil +} + +func addToHeader(request *http.Request, value reflect.Value, field reflect.StructField, contentLenSpecified *bool) (e error) { + Debugln("Marshaling to header from field: ", field.Name) + if request.Header == nil { + request.Header = http.Header{} + } + + var headerName, headerValue string + if headerName = field.Tag.Get("name"); headerName == "" { + return fmt.Errorf("marshaling request to a header requires the 'name' tag for field: %s", field.Name) + } + + mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory"))) + //If mandatory and nil. Error out + if mandatory && isNil(value) { + return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name) + } + + // generate opc-request-id if header value is nil and header name matches + value = generateOpcRequestID(headerName, value) + + //if not mandatory and nil. Omit + if !mandatory && isNil(value) { + Debugf("Header value is not mandatory and is nil pointer in field: %s. Skipping header", field.Name) + return + } + + //Otherwise get value and set header + encoding := strings.ToLower(field.Tag.Get("collectionFormat")) + var collectionFormatStringValues []string + switch encoding { + case "csv", "multi": + if value.Kind() != reflect.Slice && value.Kind() != reflect.Array { + e = fmt.Errorf("header is tagged as csv or multi yet its type is neither an Array nor a Slice: %s", field.Name) + return + } + + numOfElements := value.Len() + collectionFormatStringValues = make([]string, numOfElements) + for i := 0; i < numOfElements; i++ { + collectionFormatStringValues[i], e = toStringValue(value.Index(i), field) + if e != nil { + Debugf("Header element could not be marshalled to a string: %w", e) + return + } + } + headerValue = strings.Join(collectionFormatStringValues, ",") + default: + if headerValue, e = toStringValue(value, field); e != nil { + return + } + } + + if e = setWellKnownHeaders(request, headerName, headerValue, contentLenSpecified); e != nil { + return + } + + if isUniqueHeaderRequired(headerName) { + request.Header.Set(headerName, headerValue) + } else { + request.Header.Add(headerName, headerValue) + } + return +} + +// Check if the header is required to be unique +func isUniqueHeaderRequired(headerName string) bool { + return strings.EqualFold(headerName, requestHeaderContentType) || strings.EqualFold(headerName, requestHeaderContentLength) +} + +// Header collection is a map of string to string that gets rendered as individual headers with a given prefix +func addToHeaderCollection(request *http.Request, value reflect.Value, field reflect.StructField) (e error) { + Debugln("Marshaling to header-collection from field:", field.Name) + if request.Header == nil { + request.Header = http.Header{} + } + + var headerPrefix string + if headerPrefix = field.Tag.Get("prefix"); headerPrefix == "" { + return fmt.Errorf("marshaling request to a header requires the 'prefix' tag for field: %s", field.Name) + } + + mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory"))) + //If mandatory and nil. Error out + if mandatory && isNil(value) { + return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name) + } + + //if not mandatory and nil. Omit + if !mandatory && isNil(value) { + Debugf("Header value is not mandatory and is nil pointer in field: %s. Skipping header", field.Name) + return + } + + //cast to map + headerValues, ok := value.Interface().(map[string]string) + if !ok { + e = fmt.Errorf("header fields need to be of type map[string]string") + return + } + + for k, v := range headerValues { + headerName := fmt.Sprintf("%s%s", headerPrefix, k) + request.Header.Set(headerName, v) + } + return +} + +// Makes sure the incoming structure is able to be marshalled +// to a request +func checkForValidRequestStruct(s interface{}) (*reflect.Value, error) { + val := reflect.ValueOf(s) + for val.Kind() == reflect.Ptr { + if val.IsNil() { + return nil, fmt.Errorf("can not marshal to request a pointer to structure") + } + val = val.Elem() + } + + if s == nil { + return nil, fmt.Errorf("can not marshal to request a nil structure") + } + + if val.Kind() != reflect.Struct { + return nil, fmt.Errorf("can not marshal to request, expects struct input. Got %v", val.Kind()) + } + + return &val, nil +} + +// Populates the parts of a request by reading tags in the passed structure +// nested structs are followed recursively depth-first. +func structToRequestPart(request *http.Request, val reflect.Value) (err error) { + typ := val.Type() + contentLenSpecified := false + binaryBodySpecified := false + for i := 0; i < typ.NumField(); i++ { + if err != nil { + return + } + + sf := typ.Field(i) + //unexported + if sf.PkgPath != "" && !sf.Anonymous { + continue + } + + sv := val.Field(i) + if method := sv.MethodByName("ValidateEnumValue"); reflect.Value.IsValid(method) { + if validateResult := method.Call([]reflect.Value{})[1].Interface(); validateResult != nil { + if err = validateResult.(error); err != nil { + return + } + } + } + + tag := sf.Tag.Get("contributesTo") + switch tag { + case "header": + err = addToHeader(request, sv, sf, &contentLenSpecified) + case "header-collection": + err = addToHeaderCollection(request, sv, sf) + case "path": + err = addToPath(request, sv, sf) + case "query": + err = addToQuery(request, sv, sf) + case "body": + err = addToBody(request, sv, sf, &binaryBodySpecified) + case "": + Debugln(sf.Name, " does not contain contributes tag. Skipping.") + default: + err = fmt.Errorf("can not marshal field: %s. It needs to contain valid contributesTo tag", sf.Name) + } + } + + // if content-length is not specified but with binary body, calculate the content length according to request body + if !contentLenSpecified && binaryBodySpecified && request.Body != nil && request.Body != http.NoBody { + contentLen, err := checkBinaryBodyLength(request) + if err == nil { + request.Header.Set(requestHeaderContentLength, strconv.FormatInt(contentLen, 10)) + request.ContentLength = contentLen + } + } + + //If content length is zero, to avoid sending transfer-coding: chunked header, need to explicitly set the body to nil/Nobody. + if request.Header != nil && request.Body != nil && request.Body != http.NoBody && + parseContentLength(request.Header.Get(requestHeaderContentLength)) == 0 { + request.Body = http.NoBody + } + //If headers are and the content type was not set, we default to application/json + if request.Header != nil && request.Header.Get(requestHeaderContentType) == "" { + request.Header.Set(requestHeaderContentType, "application/json") + } + + return +} + +// HTTPRequestMarshaller marshals a structure to an http request using tag values in the struct +// The marshaller tag should like the following +// +// type A struct { +// ANumber string `contributesTo="query" name="number"` +// TheBody `contributesTo="body"` +// } +// +// where the contributesTo tag can be: header, path, query, body +// and the 'name' tag is the name of the value used in the http request(not applicable for path) +// If path is specified as part of the tag, the values are appened to the url path +// in the order they appear in the structure +// The current implementation only supports primitive types, except for the body tag, which needs a struct type. +// The body of a request will be marshaled using the tags of the structure +func HTTPRequestMarshaller(requestStruct interface{}, httpRequest *http.Request) (err error) { + var val *reflect.Value + if val, err = checkForValidRequestStruct(requestStruct); err != nil { + return + } + + Debugln("Marshaling to Request: ", val.Type().Name()) + err = structToRequestPart(httpRequest, *val) + return +} + +// MakeDefaultHTTPRequest creates the basic http request with the necessary headers set +func MakeDefaultHTTPRequest(method, path string) (httpRequest http.Request) { + httpRequest = http.Request{ + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(http.Header), + URL: &url.URL{}, + } + + httpRequest.Header.Set(requestHeaderContentLength, "0") + httpRequest.Header.Set(requestHeaderDate, time.Now().UTC().Format(http.TimeFormat)) + httpRequest.Header.Set(requestHeaderOpcClientInfo, strings.Join([]string{defaultSDKMarker, Version()}, "/")) + httpRequest.Header.Set(requestHeaderAccept, "*/*") + httpRequest.Method = method + httpRequest.URL.Path = path + return +} + +// MakeDefaultHTTPRequestWithTaggedStruct creates an http request from an struct with tagged fields, see HTTPRequestMarshaller +// for more information +func MakeDefaultHTTPRequestWithTaggedStruct(method, path string, requestStruct interface{}) (httpRequest http.Request, err error) { + httpRequest = MakeDefaultHTTPRequest(method, path) + err = HTTPRequestMarshaller(requestStruct, &httpRequest) + if err != nil { + return + } + + return +} + +// MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders creates an http request from an struct with tagged fields, see HTTPRequestMarshaller +// for more information +func MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path string, requestStruct interface{}, extraHeaders map[string]string) (httpRequest http.Request, err error) { + httpRequest, err = MakeDefaultHTTPRequestWithTaggedStruct(method, path, requestStruct) + for key, val := range extraHeaders { + httpRequest.Header.Set(key, val) + } + return +} + +// UpdateRequestBinaryBody updates the http request's body once it is binary request and the request body is seekable +// if the content length is zero, no need to update request body(since it's already been set to http.Nody) +func UpdateRequestBinaryBody(httpRequest *http.Request, rsc *OCIReadSeekCloser) { + if parseContentLength(httpRequest.Header.Get(requestHeaderContentLength)) == 0 { + return + } + httpRequest.Body = rsc + return +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Request UnMarshaling +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Makes sure the incoming structure is able to be unmarshaled +// to a request +func checkForValidResponseStruct(s interface{}) (*reflect.Value, error) { + val := reflect.ValueOf(s) + for val.Kind() == reflect.Ptr { + if val.IsNil() { + return nil, fmt.Errorf("can not unmarshal to response a pointer to nil structure") + } + val = val.Elem() + } + + if s == nil { + return nil, fmt.Errorf("can not unmarshal to response a nil structure") + } + + if val.Kind() != reflect.Struct { + return nil, fmt.Errorf("can not unmarshal to response, expects struct input. Got %v", val.Kind()) + } + + return &val, nil +} + +func intSizeFromKind(kind reflect.Kind) int { + switch kind { + case reflect.Int8, reflect.Uint8: + return 8 + case reflect.Int16, reflect.Uint16: + return 16 + case reflect.Int32, reflect.Uint32: + return 32 + case reflect.Int64, reflect.Uint64: + return 64 + case reflect.Int, reflect.Uint: + return strconv.IntSize + default: + Debugf("The type is not valid: %v. Returing int size for arch\n", kind.String()) + return strconv.IntSize + } + +} + +func analyzeValue(stringValue string, kind reflect.Kind, field reflect.StructField) (val reflect.Value, valPointer reflect.Value, err error) { + switch kind { + case timeType.Kind(): + var t time.Time + t, err = tryParsingTimeWithValidFormatsForHeaders([]byte(stringValue), field.Name) + if err != nil { + return + } + sdkTime := sdkTimeFromTime(t) + val = reflect.ValueOf(sdkTime) + valPointer = reflect.ValueOf(&sdkTime) + return + case sdkDateType.Kind(): + var t time.Time + t, err = tryParsingTimeWithValidFormatsForHeaders([]byte(stringValue), field.Name) + if err != nil { + return + } + sdkDate := sdkDateFromTime(t) + val = reflect.ValueOf(sdkDate) + valPointer = reflect.ValueOf(&sdkDate) + return + case reflect.Bool: + var bVal bool + if bVal, err = strconv.ParseBool(stringValue); err != nil { + return + } + val = reflect.ValueOf(bVal) + valPointer = reflect.ValueOf(&bVal) + return + case reflect.Int: + size := intSizeFromKind(kind) + var iVal int64 + if iVal, err = strconv.ParseInt(stringValue, 10, size); err != nil { + return + } + var iiVal int + iiVal = int(iVal) + val = reflect.ValueOf(iiVal) + valPointer = reflect.ValueOf(&iiVal) + return + case reflect.Int64: + size := intSizeFromKind(kind) + var iVal int64 + if iVal, err = strconv.ParseInt(stringValue, 10, size); err != nil { + return + } + val = reflect.ValueOf(iVal) + valPointer = reflect.ValueOf(&iVal) + return + case reflect.Uint: + size := intSizeFromKind(kind) + var iVal uint64 + if iVal, err = strconv.ParseUint(stringValue, 10, size); err != nil { + return + } + var uiVal uint + uiVal = uint(iVal) + val = reflect.ValueOf(uiVal) + valPointer = reflect.ValueOf(&uiVal) + return + case reflect.String: + val = reflect.ValueOf(stringValue) + valPointer = reflect.ValueOf(&stringValue) + case reflect.Float32: + var fVal float64 + if fVal, err = strconv.ParseFloat(stringValue, 32); err != nil { + return + } + var ffVal float32 + ffVal = float32(fVal) + val = reflect.ValueOf(ffVal) + valPointer = reflect.ValueOf(&ffVal) + return + case reflect.Float64: + var fVal float64 + if fVal, err = strconv.ParseFloat(stringValue, 64); err != nil { + return + } + val = reflect.ValueOf(fVal) + valPointer = reflect.ValueOf(&fVal) + return + default: + err = fmt.Errorf("value for kind: %s not supported", kind) + } + return +} + +// Sets the field of a struct, with the appropriate value of the string +// Only sets basic types +func fromStringValue(newValue string, val *reflect.Value, field reflect.StructField) (err error) { + + if !val.CanSet() { + err = fmt.Errorf("can not set field name: %s of type: %v", field.Name, val.Type().String()) + return + } + + kind := val.Kind() + isPointer := false + if val.Kind() == reflect.Ptr { + isPointer = true + kind = field.Type.Elem().Kind() + } + + value, valPtr, err := analyzeValue(newValue, kind, field) + valueType := val.Type() + if err != nil { + return + } + if !isPointer { + val.Set(value.Convert(valueType)) + } else { + val.Set(valPtr) + } + return +} + +// PolymorphicJSONUnmarshaler is the interface to unmarshal polymorphic json payloads +type PolymorphicJSONUnmarshaler interface { + UnmarshalPolymorphicJSON(data []byte) (interface{}, error) +} + +func valueFromPolymorphicJSON(content []byte, unmarshaler PolymorphicJSONUnmarshaler) (val interface{}, err error) { + err = json.Unmarshal(content, unmarshaler) + if err != nil { + return + } + val, err = unmarshaler.UnmarshalPolymorphicJSON(content) + return +} + +func valueFromJSONBody(response *http.Response, value *reflect.Value, unmarshaler PolymorphicJSONUnmarshaler) (val interface{}, err error) { + //Consumes the body, consider implementing it + //without body consumption + var content []byte + content, err = ioutil.ReadAll(response.Body) + if err != nil { + return + } + + if unmarshaler != nil { + val, err = valueFromPolymorphicJSON(content, unmarshaler) + return + } + + val = reflect.New(value.Type()).Interface() + err = json.Unmarshal(content, &val) + return +} + +func addFromBody(response *http.Response, value *reflect.Value, field reflect.StructField, unmarshaler PolymorphicJSONUnmarshaler) (err error) { + Debugln("Unmarshalling from body to field: ", field.Name) + if response.Body == nil { + Debugln("Unmarshalling body skipped due to nil body content for field: ", field.Name) + return nil + } + + tag := field.Tag + encoding := tag.Get("encoding") + var iVal interface{} + switch encoding { + case "binary": + value.Set(reflect.ValueOf(response.Body)) + return + case "plain-text": + //Expects UTF-8 + byteArr, e := ioutil.ReadAll(response.Body) + if e != nil { + return e + } + str := string(byteArr) + value.Set(reflect.ValueOf(&str)) + return + default: //If the encoding is not set. we'll decode with json + iVal, err = valueFromJSONBody(response, value, unmarshaler) + if err != nil { + return + } + + newVal := reflect.ValueOf(iVal) + if newVal.Kind() == reflect.Ptr { + newVal = newVal.Elem() + } + value.Set(newVal) + return + } +} + +func addFromHeader(response *http.Response, value *reflect.Value, field reflect.StructField) (err error) { + Debugln("Unmarshaling from header to field: ", field.Name) + var headerName string + if headerName = field.Tag.Get("name"); headerName == "" { + return fmt.Errorf("unmarshaling response to a header requires the 'name' tag for field: %s", field.Name) + } + + headerValue := response.Header.Get(headerName) + if headerValue == "" { + Debugf("Unmarshalling did not find header with name:%s", headerName) + return nil + } + + if err = fromStringValue(headerValue, value, field); err != nil { + return fmt.Errorf("unmarshaling response to a header failed for field %s, due to %s", field.Name, + err.Error()) + } + return +} + +func addFromHeaderCollection(response *http.Response, value *reflect.Value, field reflect.StructField) error { + Debugln("Unmarshaling from header-collection to field:", field.Name) + var headerPrefix string + if headerPrefix = field.Tag.Get("prefix"); headerPrefix == "" { + return fmt.Errorf("unmarshaling response to a header-collection requires the 'prefix' tag for field: %s", field.Name) + } + + mapCollection := make(map[string]string) + for name, value := range response.Header { + nameLowerCase := strings.ToLower(name) + if strings.HasPrefix(nameLowerCase, headerPrefix) { + headerNoPrefix := strings.TrimPrefix(nameLowerCase, headerPrefix) + mapCollection[headerNoPrefix] = value[0] + } + } + + Debugln("Marshalled header collection is:", mapCollection) + value.Set(reflect.ValueOf(mapCollection)) + return nil +} + +// Populates a struct from parts of a request by reading tags of the struct +func responseToStruct(response *http.Response, val *reflect.Value, unmarshaler PolymorphicJSONUnmarshaler) (err error) { + typ := val.Type() + for i := 0; i < typ.NumField(); i++ { + if err != nil { + return + } + + sf := typ.Field(i) + + //unexported + if sf.PkgPath != "" { + continue + } + + sv := val.Field(i) + tag := sf.Tag.Get("presentIn") + switch tag { + case "header": + err = addFromHeader(response, &sv, sf) + case "header-collection": + err = addFromHeaderCollection(response, &sv, sf) + case "body": + err = addFromBody(response, &sv, sf, unmarshaler) + case "": + Debugln(sf.Name, " does not contain presentIn tag. Skipping") + default: + err = fmt.Errorf("can not unmarshal field: %s. It needs to contain valid presentIn tag", sf.Name) + } + } + return +} + +// UnmarshalResponse hydrates the fields of a struct with the values of a http response, guided +// by the field tags. The directive tag is "presentIn" and it can be either +// - "header": Will look for the header tagged as "name" in the headers of the struct and set it value to that +// - "body": It will try to marshal the body from a json string to a struct tagged with 'presentIn: "body"'. +// +// Further this method will consume the body it should be safe to close it after this function +// Notice the current implementation only supports native types:int, strings, floats, bool as the field types +func UnmarshalResponse(httpResponse *http.Response, responseStruct interface{}) (err error) { + + // Check for text/event-stream content type, and return without unmarshalling + if httpResponse != nil && httpResponse.Header != nil && strings.ToLower(httpResponse.Header.Get("content-type")) == "text/event-stream" { + return + } + + var val *reflect.Value + if val, err = checkForValidResponseStruct(responseStruct); err != nil { + return + } + + if err = responseToStruct(httpResponse, val, nil); err != nil { + return + } + + return nil +} + +// UnmarshalResponseWithPolymorphicBody similar to UnmarshalResponse but assumes the body of the response +// contains polymorphic json. This function will use the unmarshaler argument to unmarshal json content +func UnmarshalResponseWithPolymorphicBody(httpResponse *http.Response, responseStruct interface{}, unmarshaler PolymorphicJSONUnmarshaler) (err error) { + + var val *reflect.Value + if val, err = checkForValidResponseStruct(responseStruct); err != nil { + return + } + + if err = responseToStruct(httpResponse, val, unmarshaler); err != nil { + return + } + + return nil +} + +// generate request id if user not provided and for each retry operation re-gen a new request id +func generateOpcRequestID(headerName string, value reflect.Value) (newValue reflect.Value) { + newValue = value + isNilValue := isNil(newValue) + isOpcRequestIDHeader := headerName == requestHeaderOpcRequestID || headerName == requestHeaderOpcClientRequestID + + if isNilValue && isOpcRequestIDHeader { + requestID, err := generateRandUUID() + + if err != nil { + // this will not fail the request, just skip add opc-request-id + Debugf("unable to generate opc-request-id. %s", err.Error()) + } else { + newValue = reflect.ValueOf(String(requestID)) + Debugf("add request id for header: %s, with value: %s", headerName, requestID) + } + } + + return +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/http_signer.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/http_signer.go new file mode 100644 index 00000000000..af6e57e837a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/http_signer.go @@ -0,0 +1,270 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "bytes" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "encoding/base64" + "fmt" + "io" + "io/ioutil" + "net/http" + "strings" +) + +// HTTPRequestSigner the interface to sign a request +type HTTPRequestSigner interface { + Sign(r *http.Request) error +} + +// KeyProvider interface that wraps information about the key's account owner +type KeyProvider interface { + PrivateRSAKey() (*rsa.PrivateKey, error) + KeyID() (string, error) +} + +const signerVersion = "1" + +// SignerBodyHashPredicate a function that allows to disable/enable body hashing +// of requests and headers associated with body content +type SignerBodyHashPredicate func(r *http.Request) bool + +// ociRequestSigner implements the http-signatures-draft spec +// as described in https://tools.ietf.org/html/draft-cavage-http-signatures-08 +type ociRequestSigner struct { + KeyProvider KeyProvider + GenericHeaders []string + BodyHeaders []string + ShouldHashBody SignerBodyHashPredicate +} + +var ( + defaultGenericHeaders = []string{"date", "(request-target)", "host"} + defaultBodyHeaders = []string{"content-length", "content-type", "x-content-sha256"} + defaultBodyHashPredicate = func(r *http.Request) bool { + return r.Method == http.MethodPost || r.Method == http.MethodPut || r.Method == http.MethodPatch + } +) + +// DefaultGenericHeaders list of default generic headers that is used in signing +func DefaultGenericHeaders() []string { + return makeACopy(defaultGenericHeaders) +} + +// DefaultBodyHeaders list of default body headers that is used in signing +func DefaultBodyHeaders() []string { + return makeACopy(defaultBodyHeaders) +} + +// DefaultRequestSigner creates a signer with default parameters. +func DefaultRequestSigner(provider KeyProvider) HTTPRequestSigner { + return RequestSigner(provider, defaultGenericHeaders, defaultBodyHeaders) +} + +// RequestSignerExcludeBody creates a signer without hash the body. +func RequestSignerExcludeBody(provider KeyProvider) HTTPRequestSigner { + bodyHashPredicate := func(r *http.Request) bool { + // week request signer will not hash the body + return false + } + return RequestSignerWithBodyHashingPredicate(provider, defaultGenericHeaders, defaultBodyHeaders, bodyHashPredicate) +} + +// NewSignerFromOCIRequestSigner creates a copy of the request signer and attaches the new SignerBodyHashPredicate +// returns an error if the passed signer is not of type ociRequestSigner +func NewSignerFromOCIRequestSigner(oldSigner HTTPRequestSigner, predicate SignerBodyHashPredicate) (HTTPRequestSigner, error) { + if oldS, ok := oldSigner.(ociRequestSigner); ok { + s := ociRequestSigner{ + KeyProvider: oldS.KeyProvider, + GenericHeaders: oldS.GenericHeaders, + BodyHeaders: oldS.BodyHeaders, + ShouldHashBody: predicate, + } + return s, nil + + } + return nil, fmt.Errorf("can not create a signer, input signer needs to be of type ociRequestSigner") +} + +// RequestSigner creates a signer that utilizes the specified headers for signing +// and the default predicate for using the body of the request as part of the signature +func RequestSigner(provider KeyProvider, genericHeaders, bodyHeaders []string) HTTPRequestSigner { + return ociRequestSigner{ + KeyProvider: provider, + GenericHeaders: genericHeaders, + BodyHeaders: bodyHeaders, + ShouldHashBody: defaultBodyHashPredicate} +} + +// RequestSignerWithBodyHashingPredicate creates a signer that utilizes the specified headers for signing, as well as a predicate for using +// the body of the request and bodyHeaders parameter as part of the signature +func RequestSignerWithBodyHashingPredicate(provider KeyProvider, genericHeaders, bodyHeaders []string, shouldHashBody SignerBodyHashPredicate) HTTPRequestSigner { + return ociRequestSigner{ + KeyProvider: provider, + GenericHeaders: genericHeaders, + BodyHeaders: bodyHeaders, + ShouldHashBody: shouldHashBody} +} + +func (signer ociRequestSigner) getSigningHeaders(r *http.Request) []string { + var result []string + result = append(result, signer.GenericHeaders...) + + if signer.ShouldHashBody(r) { + result = append(result, signer.BodyHeaders...) + } + + return result +} + +func (signer ociRequestSigner) getSigningString(request *http.Request) string { + signingHeaders := signer.getSigningHeaders(request) + signingParts := make([]string, len(signingHeaders)) + for i, part := range signingHeaders { + var value string + part = strings.ToLower(part) + switch part { + case "(request-target)": + value = getRequestTarget(request) + case "host": + value = request.URL.Host + if len(value) == 0 { + value = request.Host + } + default: + value = request.Header.Get(part) + } + signingParts[i] = fmt.Sprintf("%s: %s", part, value) + } + + signingString := strings.Join(signingParts, "\n") + return signingString + +} + +func getRequestTarget(request *http.Request) string { + lowercaseMethod := strings.ToLower(request.Method) + return fmt.Sprintf("%s %s", lowercaseMethod, request.URL.RequestURI()) +} + +func calculateHashOfBody(request *http.Request) (err error) { + var hash string + hash, err = GetBodyHash(request) + if err != nil { + return + } + request.Header.Set(requestHeaderXContentSHA256, hash) + return +} + +// drainBody reads all of b to memory and then returns two equivalent +// ReadClosers yielding the same bytes. +// +// It returns an error if the initial slurp of all bytes fails. It does not attempt +// to make the returned ReadClosers have identical error-matching behavior. +func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) { + if b == http.NoBody { + // No copying needed. Preserve the magic sentinel meaning of NoBody. + return http.NoBody, http.NoBody, nil + } + var buf bytes.Buffer + if _, err = buf.ReadFrom(b); err != nil { + return nil, b, err + } + if err = b.Close(); err != nil { + return nil, b, err + } + return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil +} + +func hashAndEncode(data []byte) string { + hashedContent := sha256.Sum256(data) + hash := base64.StdEncoding.EncodeToString(hashedContent[:]) + return hash +} + +// GetBodyHash creates a base64 string from the hash of body the request +func GetBodyHash(request *http.Request) (hashString string, err error) { + if request.Body == nil { + request.ContentLength = 0 + request.Header.Set(requestHeaderContentLength, fmt.Sprintf("%v", request.ContentLength)) + return hashAndEncode([]byte("")), nil + } + + var data []byte + var bReader io.Reader + bReader, request.Body, err = drainBody(request.Body) + if err != nil { + return "", fmt.Errorf("can not read body of request while calculating body hash: %s", err.Error()) + } + + data, err = ioutil.ReadAll(bReader) + if err != nil { + return "", fmt.Errorf("can not read body of request while calculating body hash: %s", err.Error()) + } + + // Since the request can be coming from a binary body. Make an attempt to set the body length + request.ContentLength = int64(len(data)) + request.Header.Set(requestHeaderContentLength, fmt.Sprintf("%v", request.ContentLength)) + + hashString = hashAndEncode(data) + return +} + +func (signer ociRequestSigner) computeSignature(request *http.Request) (signature string, err error) { + signingString := signer.getSigningString(request) + hasher := sha256.New() + hasher.Write([]byte(signingString)) + hashed := hasher.Sum(nil) + + privateKey, err := signer.KeyProvider.PrivateRSAKey() + if err != nil { + return + } + + var unencodedSig []byte + unencodedSig, e := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed) + if e != nil { + err = fmt.Errorf("can not compute signature while signing the request %s: ", e.Error()) + return + } + + signature = base64.StdEncoding.EncodeToString(unencodedSig) + return +} + +// Sign signs the http request, by inspecting the necessary headers. Once signed +// the request will have the proper 'Authorization' header set, otherwise +// and error is returned +func (signer ociRequestSigner) Sign(request *http.Request) (err error) { + if signer.ShouldHashBody(request) { + err = calculateHashOfBody(request) + if err != nil { + return + } + } + + var signature string + if signature, err = signer.computeSignature(request); err != nil { + return + } + + signingHeaders := strings.Join(signer.getSigningHeaders(request), " ") + + var keyID string + if keyID, err = signer.KeyProvider.KeyID(); err != nil { + return + } + + authValue := fmt.Sprintf("Signature version=\"%s\",headers=\"%s\",keyId=\"%s\",algorithm=\"rsa-sha256\",signature=\"%s\"", + signerVersion, signingHeaders, keyID, signature) + + request.Header.Set(requestHeaderAuthorization, authValue) + + return +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/log.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/log.go new file mode 100644 index 00000000000..c5ea9921c02 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/log.go @@ -0,0 +1,231 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "os" + "strings" + "sync" + "time" +) + +// sdkLogger an interface for logging in the SDK +type sdkLogger interface { + //LogLevel returns the log level of sdkLogger + LogLevel() int + + //Log logs v with the provided format if the current log level is loglevel + Log(logLevel int, format string, v ...interface{}) error +} + +// noLogging no logging messages +const noLogging = 0 + +// infoLogging minimal logging messages +const infoLogging = 1 + +// debugLogging some logging messages +const debugLogging = 2 + +// verboseLogging all logging messages +const verboseLogging = 3 + +// DefaultSDKLogger the default implementation of the sdkLogger +type DefaultSDKLogger struct { + currentLoggingLevel int + verboseLogger *log.Logger + debugLogger *log.Logger + infoLogger *log.Logger + nullLogger *log.Logger +} + +// defaultLogger is the defaultLogger in the SDK +var defaultLogger sdkLogger +var loggerLock sync.Mutex +var file *os.File + +// initializes the SDK defaultLogger as a defaultLogger +func init() { + l, _ := NewSDKLogger() + SetSDKLogger(l) +} + +// SetSDKLogger sets the logger used by the sdk +func SetSDKLogger(logger sdkLogger) { + loggerLock.Lock() + defaultLogger = logger + loggerLock.Unlock() +} + +// NewSDKLogger creates a defaultSDKLogger +// Debug logging is turned on/off by the presence of the environment variable "OCI_GO_SDK_DEBUG" +// The value of the "OCI_GO_SDK_DEBUG" environment variable controls the logging level. +// "null" outputs no log messages +// "i" or "info" outputs minimal log messages +// "d" or "debug" outputs some logs messages +// "v" or "verbose" outputs all logs messages, including body of requests +func NewSDKLogger() (DefaultSDKLogger, error) { + logger := DefaultSDKLogger{} + + logger.currentLoggingLevel = noLogging + logger.verboseLogger = log.New(os.Stderr, "VERBOSE ", log.Ldate|log.Lmicroseconds|log.Lshortfile) + logger.debugLogger = log.New(os.Stderr, "DEBUG ", log.Ldate|log.Lmicroseconds|log.Lshortfile) + logger.infoLogger = log.New(os.Stderr, "INFO ", log.Ldate|log.Lmicroseconds|log.Lshortfile) + logger.nullLogger = log.New(ioutil.Discard, "", log.Ldate|log.Lmicroseconds|log.Lshortfile) + + configured, isLogEnabled := os.LookupEnv("OCI_GO_SDK_DEBUG") + + // If env variable not present turn logging off + if !isLogEnabled { + logger.currentLoggingLevel = noLogging + } else { + logOutputModeConfig(logger) + + switch strings.ToLower(configured) { + case "null": + logger.currentLoggingLevel = noLogging + break + case "i", "info": + logger.currentLoggingLevel = infoLogging + break + case "d", "debug": + logger.currentLoggingLevel = debugLogging + break + //1 here for backwards compatibility + case "v", "verbose", "1": + logger.currentLoggingLevel = verboseLogging + break + default: + logger.currentLoggingLevel = infoLogging + } + logger.infoLogger.Println("logger level set to: ", logger.currentLoggingLevel) + } + + return logger, nil +} + +func (l DefaultSDKLogger) getLoggerForLevel(logLevel int) *log.Logger { + if logLevel > l.currentLoggingLevel { + return l.nullLogger + } + + switch logLevel { + case noLogging: + return l.nullLogger + case infoLogging: + return l.infoLogger + case debugLogging: + return l.debugLogger + case verboseLogging: + return l.verboseLogger + default: + return l.nullLogger + } +} + +// Set SDK Log output mode +// Output mode is switched based on environment variable "OCI_GO_SDK_LOG_OUPUT_MODE" +// "file" outputs log to a specific file +// "combine" outputs log to both stderr and specific file +// other unsupported value outputs log to stderr +// output file can be set via environment variable "OCI_GO_SDK_LOG_FILE" +// if this environment variable is not set, a default log file will be created under project root path +func logOutputModeConfig(logger DefaultSDKLogger) { + logMode, isLogOutputModeEnabled := os.LookupEnv("OCI_GO_SDK_LOG_OUTPUT_MODE") + if !isLogOutputModeEnabled { + return + } + fileName, isLogFileNameProvided := os.LookupEnv("OCI_GO_SDK_LOG_FILE") + if !isLogFileNameProvided { + fileName = fmt.Sprintf("logging_%v%s", time.Now().Unix(), ".log") + } + + switch strings.ToLower(logMode) { + case "file", "f": + file = openLogOutputFile(logger, fileName) + logger.infoLogger.SetOutput(file) + logger.debugLogger.SetOutput(file) + logger.verboseLogger.SetOutput(file) + break + case "combine", "c": + file = openLogOutputFile(logger, fileName) + wrt := io.MultiWriter(os.Stderr, file) + + logger.infoLogger.SetOutput(wrt) + logger.debugLogger.SetOutput(wrt) + logger.verboseLogger.SetOutput(wrt) + break + } +} + +func openLogOutputFile(logger DefaultSDKLogger, fileName string) *os.File { + file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + if err != nil { + logger.verboseLogger.Fatal(err) + } + return file +} + +// CloseLogFile close the logging file and return error +func CloseLogFile() error { + return file.Close() +} + +// LogLevel returns the current debug level +func (l DefaultSDKLogger) LogLevel() int { + return l.currentLoggingLevel +} + +// Log logs v with the provided format if the current log level is loglevel +func (l DefaultSDKLogger) Log(logLevel int, format string, v ...interface{}) error { + logger := l.getLoggerForLevel(logLevel) + logger.Output(4, fmt.Sprintf(format, v...)) + return nil +} + +// Logln logs v appending a new line at the end +// Deprecated +func Logln(v ...interface{}) { + defaultLogger.Log(infoLogging, "%v\n", v...) +} + +// Logf logs v with the provided format +func Logf(format string, v ...interface{}) { + defaultLogger.Log(infoLogging, format, v...) +} + +// Debugf logs v with the provided format if debug mode is set +func Debugf(format string, v ...interface{}) { + defaultLogger.Log(debugLogging, format, v...) +} + +// Debug logs v if debug mode is set +func Debug(v ...interface{}) { + m := fmt.Sprint(v...) + defaultLogger.Log(debugLogging, "%s", m) +} + +// Debugln logs v appending a new line if debug mode is set +func Debugln(v ...interface{}) { + m := fmt.Sprint(v...) + defaultLogger.Log(debugLogging, "%s\n", m) +} + +// IfDebug executes closure if debug is enabled +func IfDebug(fn func()) { + if defaultLogger.LogLevel() >= debugLogging { + fn() + } +} + +// IfInfo executes closure if info is enabled +func IfInfo(fn func()) { + if defaultLogger.LogLevel() >= infoLogging { + fn() + } +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/oci_http_transport_wrapper.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/oci_http_transport_wrapper.go new file mode 100644 index 00000000000..5eed0902ae8 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/oci_http_transport_wrapper.go @@ -0,0 +1,120 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "fmt" + "net/http" + "sync" + "time" +) + +// OciHTTPTransportWrapper is a http.RoundTripper that periodically refreshes +// the underlying http.Transport according to its templates. +// Upon the first use (or once the RefreshRate duration is elapsed), +// a new transport will be created from the TransportTemplate (if set). +type OciHTTPTransportWrapper struct { + // RefreshRate specifies the duration at which http.Transport + // (with its tls.Config) must be refreshed. + // Defaults to 5 minutes. + RefreshRate time.Duration + + // TLSConfigProvider creates a new tls.Config. + // If not set, nil tls.Config is returned. + TLSConfigProvider TLSConfigProvider + + // ClientTemplate is responsible for creating a new http.Client with + // a given tls.Config. + // + // If not set, a new http.Client with a cloned http.DefaultTransport is returned. + TransportTemplate TransportTemplateProvider + + // mutable properties + mux sync.RWMutex + lastRefreshedAt time.Time + delegate http.RoundTripper +} + +// RoundTrip implements http.RoundTripper. +func (t *OciHTTPTransportWrapper) RoundTrip(req *http.Request) (*http.Response, error) { + delegate, err := t.refreshDelegate(false /* force */) + if err != nil { + return nil, err + } + + return delegate.RoundTrip(req) +} + +// Refresh forces refresh of the underlying delegate. +func (t *OciHTTPTransportWrapper) Refresh(force bool) error { + _, err := t.refreshDelegate(force) + return err +} + +// Delegate returns the currently active http.RoundTripper. +// Might be nil. +func (t *OciHTTPTransportWrapper) Delegate() http.RoundTripper { + t.mux.RLock() + defer t.mux.RUnlock() + + return t.delegate +} + +// refreshDelegate refreshes the delegate (and its TLS config) if: +// - force is true +// - it's been more than RefreshRate since the last time the client was refreshed. +func (t *OciHTTPTransportWrapper) refreshDelegate(force bool) (http.RoundTripper, error) { + // read-lock first, since it's cheaper than write lock + t.mux.RLock() + if !t.shouldRefreshLocked(force) { + delegate := t.delegate + t.mux.RUnlock() + + return delegate, nil + } + + // upgrade to write-lock, and we'll need to check again for the same condition as above + // to avoid multiple initializations by multiple "refresher" goroutines + t.mux.RUnlock() + t.mux.Lock() + defer t.mux.Unlock() + if !t.shouldRefreshLocked(force) { + return t.delegate, nil + } + + // For this check we need the delegate to be set once before we check for change in cert files + if t.delegate != nil && !t.TLSConfigProvider.WatchedFilesModified() { + Debug("No modification in custom certs or ca bundle skipping refresh") + // Updating the last refresh time to make sure the next check is only done after the refresh interval has passed + t.lastRefreshedAt = time.Now() + return t.delegate, nil + } + + Logf("Loading tls config from TLSConfigProvider") + tlsConfig, err := t.TLSConfigProvider.NewOrDefault() + if err != nil { + return nil, fmt.Errorf("refreshing tls.Config from template: %w", err) + } + + t.delegate, err = t.TransportTemplate.NewOrDefault(tlsConfig) + if err != nil { + return nil, fmt.Errorf("refreshing http.RoundTripper from template: %w", err) + } + + t.lastRefreshedAt = time.Now() + return t.delegate, nil +} + +// shouldRefreshLocked returns whether the client (and its TLS config) +// needs to be refreshed. +func (t *OciHTTPTransportWrapper) shouldRefreshLocked(force bool) bool { + if force || t.delegate == nil { + return true + } + return t.refreshRate() > 0 && time.Since(t.lastRefreshedAt) > t.refreshRate() +} + +func (t *OciHTTPTransportWrapper) refreshRate() time.Duration { + return t.RefreshRate +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/regions.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/regions.go new file mode 100644 index 00000000000..3c9172a5c65 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/regions.go @@ -0,0 +1,341 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +const ( + //RegionAPChuncheon1 region Chuncheon + RegionAPChuncheon1 Region = "ap-chuncheon-1" + //RegionAPHyderabad1 region Hyderabad + RegionAPHyderabad1 Region = "ap-hyderabad-1" + //RegionAPMelbourne1 region Melbourne + RegionAPMelbourne1 Region = "ap-melbourne-1" + //RegionAPMumbai1 region Mumbai + RegionAPMumbai1 Region = "ap-mumbai-1" + //RegionAPOsaka1 region Osaka + RegionAPOsaka1 Region = "ap-osaka-1" + //RegionAPSeoul1 region Seoul + RegionAPSeoul1 Region = "ap-seoul-1" + //RegionAPSydney1 region Sydney + RegionAPSydney1 Region = "ap-sydney-1" + //RegionAPTokyo1 region Tokyo + RegionAPTokyo1 Region = "ap-tokyo-1" + //RegionCAMontreal1 region Montreal + RegionCAMontreal1 Region = "ca-montreal-1" + //RegionCAToronto1 region Toronto + RegionCAToronto1 Region = "ca-toronto-1" + //RegionEUAmsterdam1 region Amsterdam + RegionEUAmsterdam1 Region = "eu-amsterdam-1" + //RegionFRA region Frankfurt + RegionFRA Region = "eu-frankfurt-1" + //RegionEUZurich1 region Zurich + RegionEUZurich1 Region = "eu-zurich-1" + //RegionMEJeddah1 region Jeddah + RegionMEJeddah1 Region = "me-jeddah-1" + //RegionMEDubai1 region Dubai + RegionMEDubai1 Region = "me-dubai-1" + //RegionSASaopaulo1 region Saopaulo + RegionSASaopaulo1 Region = "sa-saopaulo-1" + //RegionUKCardiff1 region Cardiff + RegionUKCardiff1 Region = "uk-cardiff-1" + //RegionLHR region London + RegionLHR Region = "uk-london-1" + //RegionIAD region Ashburn + RegionIAD Region = "us-ashburn-1" + //RegionPHX region Phoenix + RegionPHX Region = "us-phoenix-1" + //RegionSJC1 region Sanjose + RegionSJC1 Region = "us-sanjose-1" + //RegionSAVinhedo1 region Vinhedo + RegionSAVinhedo1 Region = "sa-vinhedo-1" + //RegionSASantiago1 region Santiago + RegionSASantiago1 Region = "sa-santiago-1" + //RegionILJerusalem1 region Jerusalem + RegionILJerusalem1 Region = "il-jerusalem-1" + //RegionEUMarseille1 region Marseille + RegionEUMarseille1 Region = "eu-marseille-1" + //RegionAPSingapore1 region Singapore + RegionAPSingapore1 Region = "ap-singapore-1" + //RegionMEAbudhabi1 region Abudhabi + RegionMEAbudhabi1 Region = "me-abudhabi-1" + //RegionEUMilan1 region Milan + RegionEUMilan1 Region = "eu-milan-1" + //RegionEUStockholm1 region Stockholm + RegionEUStockholm1 Region = "eu-stockholm-1" + //RegionAFJohannesburg1 region Johannesburg + RegionAFJohannesburg1 Region = "af-johannesburg-1" + //RegionEUParis1 region Paris + RegionEUParis1 Region = "eu-paris-1" + //RegionMXQueretaro1 region Queretaro + RegionMXQueretaro1 Region = "mx-queretaro-1" + //RegionEUMadrid1 region Madrid + RegionEUMadrid1 Region = "eu-madrid-1" + //RegionUSChicago1 region Chicago + RegionUSChicago1 Region = "us-chicago-1" + //RegionMXMonterrey1 region Monterrey + RegionMXMonterrey1 Region = "mx-monterrey-1" + //RegionUSSaltlake2 region Saltlake + RegionUSSaltlake2 Region = "us-saltlake-2" + //RegionSABogota1 region Bogota + RegionSABogota1 Region = "sa-bogota-1" + //RegionSAValparaiso1 region Valparaiso + RegionSAValparaiso1 Region = "sa-valparaiso-1" + //RegionAPSingapore2 region Singapore + RegionAPSingapore2 Region = "ap-singapore-2" + //RegionMERiyadh1 region Riyadh + RegionMERiyadh1 Region = "me-riyadh-1" + //RegionUSLangley1 region Langley + RegionUSLangley1 Region = "us-langley-1" + //RegionUSLuke1 region Luke + RegionUSLuke1 Region = "us-luke-1" + //RegionUSGovAshburn1 gov region Ashburn + RegionUSGovAshburn1 Region = "us-gov-ashburn-1" + //RegionUSGovChicago1 gov region Chicago + RegionUSGovChicago1 Region = "us-gov-chicago-1" + //RegionUSGovPhoenix1 gov region Phoenix + RegionUSGovPhoenix1 Region = "us-gov-phoenix-1" + //RegionUKGovLondon1 gov region London + RegionUKGovLondon1 Region = "uk-gov-london-1" + //RegionUKGovCardiff1 gov region Cardiff + RegionUKGovCardiff1 Region = "uk-gov-cardiff-1" + //RegionAPChiyoda1 region Chiyoda + RegionAPChiyoda1 Region = "ap-chiyoda-1" + //RegionAPIbaraki1 region Ibaraki + RegionAPIbaraki1 Region = "ap-ibaraki-1" + //RegionMEDccMuscat1 region Muscat + RegionMEDccMuscat1 Region = "me-dcc-muscat-1" + //RegionAPDccCanberra1 region Canberra + RegionAPDccCanberra1 Region = "ap-dcc-canberra-1" + //RegionEUDccMilan1 region Milan + RegionEUDccMilan1 Region = "eu-dcc-milan-1" + //RegionEUDccMilan2 region Milan + RegionEUDccMilan2 Region = "eu-dcc-milan-2" + //RegionEUDccDublin2 region Dublin + RegionEUDccDublin2 Region = "eu-dcc-dublin-2" + //RegionEUDccRating2 region Rating + RegionEUDccRating2 Region = "eu-dcc-rating-2" + //RegionEUDccRating1 region Rating + RegionEUDccRating1 Region = "eu-dcc-rating-1" + //RegionEUDccDublin1 region Dublin + RegionEUDccDublin1 Region = "eu-dcc-dublin-1" + //RegionAPDccGazipur1 region Gazipur + RegionAPDccGazipur1 Region = "ap-dcc-gazipur-1" + //RegionEUMadrid2 region Madrid + RegionEUMadrid2 Region = "eu-madrid-2" + //RegionEUFrankfurt2 region Frankfurt + RegionEUFrankfurt2 Region = "eu-frankfurt-2" + //RegionEUJovanovac1 region Jovanovac + RegionEUJovanovac1 Region = "eu-jovanovac-1" + //RegionMEDccDoha1 region Doha + RegionMEDccDoha1 Region = "me-dcc-doha-1" + //RegionUSSomerset1 region Somerset + RegionUSSomerset1 Region = "us-somerset-1" + //RegionUSThames1 region Thames + RegionUSThames1 Region = "us-thames-1" + //RegionEUDccZurich1 region Zurich + RegionEUDccZurich1 Region = "eu-dcc-zurich-1" + //RegionEUCrissier1 region Crissier + RegionEUCrissier1 Region = "eu-crissier-1" + //RegionMEAbudhabi3 region Abudhabi + RegionMEAbudhabi3 Region = "me-abudhabi-3" + //RegionMEAlain1 region Alain + RegionMEAlain1 Region = "me-alain-1" + //RegionMEAbudhabi2 region Abudhabi + RegionMEAbudhabi2 Region = "me-abudhabi-2" + //RegionMEAbudhabi4 region Abudhabi + RegionMEAbudhabi4 Region = "me-abudhabi-4" + //RegionAPSeoul2 region Seoul + RegionAPSeoul2 Region = "ap-seoul-2" + //RegionAPSuwon1 region Suwon + RegionAPSuwon1 Region = "ap-suwon-1" + //RegionAPChuncheon2 region Chuncheon + RegionAPChuncheon2 Region = "ap-chuncheon-2" +) + +var shortNameRegion = map[string]Region{ + "yny": RegionAPChuncheon1, + "hyd": RegionAPHyderabad1, + "mel": RegionAPMelbourne1, + "bom": RegionAPMumbai1, + "kix": RegionAPOsaka1, + "icn": RegionAPSeoul1, + "syd": RegionAPSydney1, + "nrt": RegionAPTokyo1, + "yul": RegionCAMontreal1, + "yyz": RegionCAToronto1, + "ams": RegionEUAmsterdam1, + "fra": RegionFRA, + "zrh": RegionEUZurich1, + "jed": RegionMEJeddah1, + "dxb": RegionMEDubai1, + "gru": RegionSASaopaulo1, + "cwl": RegionUKCardiff1, + "lhr": RegionLHR, + "iad": RegionIAD, + "phx": RegionPHX, + "sjc": RegionSJC1, + "vcp": RegionSAVinhedo1, + "scl": RegionSASantiago1, + "mtz": RegionILJerusalem1, + "mrs": RegionEUMarseille1, + "sin": RegionAPSingapore1, + "auh": RegionMEAbudhabi1, + "lin": RegionEUMilan1, + "arn": RegionEUStockholm1, + "jnb": RegionAFJohannesburg1, + "cdg": RegionEUParis1, + "qro": RegionMXQueretaro1, + "mad": RegionEUMadrid1, + "ord": RegionUSChicago1, + "mty": RegionMXMonterrey1, + "aga": RegionUSSaltlake2, + "bog": RegionSABogota1, + "vap": RegionSAValparaiso1, + "xsp": RegionAPSingapore2, + "ruh": RegionMERiyadh1, + "lfi": RegionUSLangley1, + "luf": RegionUSLuke1, + "ric": RegionUSGovAshburn1, + "pia": RegionUSGovChicago1, + "tus": RegionUSGovPhoenix1, + "ltn": RegionUKGovLondon1, + "brs": RegionUKGovCardiff1, + "nja": RegionAPChiyoda1, + "ukb": RegionAPIbaraki1, + "mct": RegionMEDccMuscat1, + "wga": RegionAPDccCanberra1, + "bgy": RegionEUDccMilan1, + "mxp": RegionEUDccMilan2, + "snn": RegionEUDccDublin2, + "dtm": RegionEUDccRating2, + "dus": RegionEUDccRating1, + "ork": RegionEUDccDublin1, + "dac": RegionAPDccGazipur1, + "vll": RegionEUMadrid2, + "str": RegionEUFrankfurt2, + "beg": RegionEUJovanovac1, + "doh": RegionMEDccDoha1, + "ebb": RegionUSSomerset1, + "ebl": RegionUSThames1, + "avz": RegionEUDccZurich1, + "avf": RegionEUCrissier1, + "ahu": RegionMEAbudhabi3, + "rba": RegionMEAlain1, + "rkt": RegionMEAbudhabi2, + "shj": RegionMEAbudhabi4, + "dtz": RegionAPSeoul2, + "dln": RegionAPSuwon1, + "bno": RegionAPChuncheon2, +} + +var realm = map[string]string{ + "oc1": "oraclecloud.com", + "oc2": "oraclegovcloud.com", + "oc3": "oraclegovcloud.com", + "oc4": "oraclegovcloud.uk", + "oc8": "oraclecloud8.com", + "oc9": "oraclecloud9.com", + "oc10": "oraclecloud10.com", + "oc14": "oraclecloud14.com", + "oc15": "oraclecloud15.com", + "oc19": "oraclecloud.eu", + "oc20": "oraclecloud20.com", + "oc21": "oraclecloud21.com", + "oc23": "oraclecloud23.com", + "oc24": "oraclecloud24.com", + "oc26": "oraclecloud26.com", + "oc29": "oraclecloud29.com", + "oc35": "oraclecloud35.com", +} + +var regionRealm = map[Region]string{ + RegionAPChuncheon1: "oc1", + RegionAPHyderabad1: "oc1", + RegionAPMelbourne1: "oc1", + RegionAPMumbai1: "oc1", + RegionAPOsaka1: "oc1", + RegionAPSeoul1: "oc1", + RegionAPSydney1: "oc1", + RegionAPTokyo1: "oc1", + RegionCAMontreal1: "oc1", + RegionCAToronto1: "oc1", + RegionEUAmsterdam1: "oc1", + RegionFRA: "oc1", + RegionEUZurich1: "oc1", + RegionMEJeddah1: "oc1", + RegionMEDubai1: "oc1", + RegionSASaopaulo1: "oc1", + RegionUKCardiff1: "oc1", + RegionLHR: "oc1", + RegionIAD: "oc1", + RegionPHX: "oc1", + RegionSJC1: "oc1", + RegionSAVinhedo1: "oc1", + RegionSASantiago1: "oc1", + RegionILJerusalem1: "oc1", + RegionEUMarseille1: "oc1", + RegionAPSingapore1: "oc1", + RegionMEAbudhabi1: "oc1", + RegionEUMilan1: "oc1", + RegionEUStockholm1: "oc1", + RegionAFJohannesburg1: "oc1", + RegionEUParis1: "oc1", + RegionMXQueretaro1: "oc1", + RegionEUMadrid1: "oc1", + RegionUSChicago1: "oc1", + RegionMXMonterrey1: "oc1", + RegionUSSaltlake2: "oc1", + RegionSABogota1: "oc1", + RegionSAValparaiso1: "oc1", + RegionAPSingapore2: "oc1", + RegionMERiyadh1: "oc1", + + RegionUSLangley1: "oc2", + RegionUSLuke1: "oc2", + + RegionUSGovAshburn1: "oc3", + RegionUSGovChicago1: "oc3", + RegionUSGovPhoenix1: "oc3", + + RegionUKGovLondon1: "oc4", + RegionUKGovCardiff1: "oc4", + + RegionAPChiyoda1: "oc8", + RegionAPIbaraki1: "oc8", + + RegionMEDccMuscat1: "oc9", + + RegionAPDccCanberra1: "oc10", + + RegionEUDccMilan1: "oc14", + RegionEUDccMilan2: "oc14", + RegionEUDccDublin2: "oc14", + RegionEUDccRating2: "oc14", + RegionEUDccRating1: "oc14", + RegionEUDccDublin1: "oc14", + + RegionAPDccGazipur1: "oc15", + + RegionEUMadrid2: "oc19", + RegionEUFrankfurt2: "oc19", + + RegionEUJovanovac1: "oc20", + + RegionMEDccDoha1: "oc21", + + RegionUSSomerset1: "oc23", + RegionUSThames1: "oc23", + + RegionEUDccZurich1: "oc24", + RegionEUCrissier1: "oc24", + + RegionMEAbudhabi3: "oc26", + RegionMEAlain1: "oc26", + + RegionMEAbudhabi2: "oc29", + RegionMEAbudhabi4: "oc29", + + RegionAPSeoul2: "oc35", + RegionAPSuwon1: "oc35", + RegionAPChuncheon2: "oc35", +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/regions.json b/vendor/github.com/oracle/oci-go-sdk/v65/common/regions.json new file mode 100644 index 00000000000..84ffa621cdf --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/regions.json @@ -0,0 +1,440 @@ +[ + { + "regionKey": "yny", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-chuncheon-1", + "realmKey": "oc1" + }, + { + "regionKey": "hyd", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-hyderabad-1", + "realmKey": "oc1" + }, + { + "regionKey": "mel", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-melbourne-1", + "realmKey": "oc1" + }, + { + "regionKey": "bom", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-mumbai-1", + "realmKey": "oc1" + }, + { + "regionKey": "kix", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-osaka-1", + "realmKey": "oc1" + }, + { + "regionKey": "icn", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-seoul-1", + "realmKey": "oc1" + }, + { + "regionKey": "syd", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-sydney-1", + "realmKey": "oc1" + }, + { + "regionKey": "nrt", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-tokyo-1", + "realmKey": "oc1" + }, + { + "regionKey": "yul", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ca-montreal-1", + "realmKey": "oc1" + }, + { + "regionKey": "yyz", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ca-toronto-1", + "realmKey": "oc1" + }, + { + "regionKey": "ams", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-amsterdam-1", + "realmKey": "oc1" + }, + { + "regionKey": "fra", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-frankfurt-1", + "realmKey": "oc1" + }, + { + "regionKey": "zrh", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-zurich-1", + "realmKey": "oc1" + }, + { + "regionKey": "jed", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "me-jeddah-1", + "realmKey": "oc1" + }, + { + "regionKey": "dxb", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "me-dubai-1", + "realmKey": "oc1" + }, + { + "regionKey": "gru", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "sa-saopaulo-1", + "realmKey": "oc1" + }, + { + "regionKey": "cwl", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "uk-cardiff-1", + "realmKey": "oc1" + }, + { + "regionKey": "lhr", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "uk-london-1", + "realmKey": "oc1" + }, + { + "regionKey": "iad", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "us-ashburn-1", + "realmKey": "oc1" + }, + { + "regionKey": "phx", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "us-phoenix-1", + "realmKey": "oc1" + }, + { + "regionKey": "sjc", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "us-sanjose-1", + "realmKey": "oc1" + }, + { + "regionKey": "vcp", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "sa-vinhedo-1", + "realmKey": "oc1" + }, + { + "regionKey": "scl", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "sa-santiago-1", + "realmKey": "oc1" + }, + { + "regionKey": "lfi", + "realmDomainComponent": "oraclegovcloud.com", + "regionIdentifier": "us-langley-1", + "realmKey": "oc2" + }, + { + "regionKey": "luf", + "realmDomainComponent": "oraclegovcloud.com", + "regionIdentifier": "us-luke-1", + "realmKey": "oc2" + }, + { + "regionKey": "ric", + "realmDomainComponent": "oraclegovcloud.com", + "regionIdentifier": "us-gov-ashburn-1", + "realmKey": "oc3" + }, + { + "regionKey": "pia", + "realmDomainComponent": "oraclegovcloud.com", + "regionIdentifier": "us-gov-chicago-1", + "realmKey": "oc3" + }, + { + "regionKey": "tus", + "realmDomainComponent": "oraclegovcloud.com", + "regionIdentifier": "us-gov-phoenix-1", + "realmKey": "oc3" + }, + { + "regionKey": "ltn", + "realmDomainComponent": "oraclegovcloud.uk", + "regionIdentifier": "uk-gov-london-1", + "realmKey": "oc4" + }, + { + "regionKey": "brs", + "realmDomainComponent": "oraclegovcloud.uk", + "regionIdentifier": "uk-gov-cardiff-1", + "realmKey": "oc4" + }, + { + "regionKey": "nja", + "realmDomainComponent": "oraclecloud8.com", + "regionIdentifier": "ap-chiyoda-1", + "realmKey": "oc8" + }, + { + "regionKey": "ukb", + "realmDomainComponent": "oraclecloud8.com", + "regionIdentifier": "ap-ibaraki-1", + "realmKey": "oc8" + }, + { + "regionKey": "mtz", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "il-jerusalem-1", + "realmKey": "oc1" + }, + { + "regionKey": "mrs", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-marseille-1", + "realmKey": "oc1" + }, + { + "regionKey": "sin", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "ap-singapore-1", + "realmKey": "oc1" + }, + { + "regionKey": "auh", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "me-abudhabi-1", + "realmKey": "oc1" + }, + { + "regionKey": "lin", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-milan-1", + "realmKey": "oc1" + }, + { + "regionKey": "arn", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-stockholm-1", + "realmKey": "oc1" + }, + { + "regionKey": "jnb", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "af-johannesburg-1", + "realmKey": "oc1" + }, + { + "regionKey": "mct", + "realmDomainComponent": "oraclecloud9.com", + "regionIdentifier": "me-dcc-muscat-1", + "realmKey": "oc9" + }, + { + "regionKey": "wga", + "realmDomainComponent": "oraclecloud10.com", + "regionIdentifier": "ap-dcc-canberra-1", + "realmKey": "oc10" + }, + { + "regionKey": "cdg", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-paris-1", + "realmKey": "oc1" + }, + { + "regionKey": "qro", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "mx-queretaro-1", + "realmKey": "oc1" + }, + { + "regionKey": "mad", + "realmDomainComponent": "oraclecloud.com", + "regionIdentifier": "eu-madrid-1", + "realmKey": "oc1" + }, + { + "regionKey": "bgy", + "realmDomainComponent": "oraclecloud14.com", + "regionIdentifier": "eu-dcc-milan-1", + "realmKey": "oc14" + }, + { + "regionKey": "ord", + "realmKey": "oc1", + "regionIdentifier": "us-chicago-1", + "realmDomainComponent": "oraclecloud.com" + }, + { + "regionKey": "mxp", + "realmKey": "oc14", + "regionIdentifier": "eu-dcc-milan-2", + "realmDomainComponent": "oraclecloud14.com" + }, + { + "regionKey": "snn", + "realmKey": "oc14", + "regionIdentifier": "eu-dcc-dublin-2", + "realmDomainComponent": "oraclecloud14.com" + }, + { + "regionKey": "dtm", + "realmKey": "oc14", + "regionIdentifier": "eu-dcc-rating-2", + "realmDomainComponent": "oraclecloud14.com" + }, + { + "regionKey": "dus", + "realmKey": "oc14", + "regionIdentifier": "eu-dcc-rating-1", + "realmDomainComponent": "oraclecloud14.com" + }, + { + "regionKey": "ork", + "realmKey": "oc14", + "regionIdentifier": "eu-dcc-dublin-1", + "realmDomainComponent": "oraclecloud14.com" + }, + { + "regionKey": "beg", + "realmKey": "oc20", + "regionIdentifier": "eu-jovanovac-1", + "realmDomainComponent": "oraclecloud20.com" + }, + { + "regionKey": "vll", + "realmKey": "oc19", + "regionIdentifier": "eu-madrid-2", + "realmDomainComponent": "oraclecloud.eu" + }, + { + "regionKey": "str", + "realmKey": "oc19", + "regionIdentifier": "eu-frankfurt-2", + "realmDomainComponent": "oraclecloud.eu" + }, + { + "regionKey": "mty", + "realmKey": "oc1", + "regionIdentifier": "mx-monterrey-1", + "realmDomainComponent": "oraclecloud.com" + }, + { + "regionKey": "aga", + "realmKey": "oc1", + "regionIdentifier": "us-saltlake-2", + "realmDomainComponent": "oraclecloud.com" + }, + { + "regionKey": "avz", + "realmKey": "oc24", + "regionIdentifier": "eu-dcc-zurich-1", + "realmDomainComponent": "oraclecloud24.com" + }, + { + "regionKey": "bog", + "realmKey": "oc1", + "regionIdentifier": "sa-bogota-1", + "realmDomainComponent": "oraclecloud.com" + }, + { + "regionKey": "vap", + "realmKey": "oc1", + "regionIdentifier": "sa-valparaiso-1", + "realmDomainComponent": "oraclecloud.com" + }, + { + "regionKey": "doh", + "realmKey": "oc21", + "regionIdentifier": "me-dcc-doha-1", + "realmDomainComponent": "oraclecloud21.com" + }, + { + "regionKey": "ahu", + "realmKey": "oc26", + "regionIdentifier": "me-abudhabi-3", + "realmDomainComponent": "oraclecloud26.com" + }, + { + "regionKey": "dac", + "realmKey": "oc15", + "regionIdentifier": "ap-dcc-gazipur-1", + "realmDomainComponent": "oraclecloud15.com" + }, + { + "regionKey": "xsp", + "realmKey": "oc1", + "regionIdentifier": "ap-singapore-2", + "realmDomainComponent": "oraclecloud.com" + }, + { + "regionKey": "rkt", + "realmKey": "oc29", + "regionIdentifier": "me-abudhabi-2", + "realmDomainComponent": "oraclecloud29.com" + }, + { + "regionKey": "ruh", + "realmKey": "oc1", + "regionIdentifier": "me-riyadh-1", + "realmDomainComponent": "oraclecloud.com" + }, + { + "regionKey": "shj", + "realmKey": "oc29", + "regionIdentifier": "me-abudhabi-4", + "realmDomainComponent": "oraclecloud29.com" + }, + { + "regionKey": "avf", + "realmKey": "oc24", + "regionIdentifier": "eu-crissier-1", + "realmDomainComponent": "oraclecloud24.com" + }, + { + "regionKey": "ebb", + "realmKey": "oc23", + "regionIdentifier": "us-somerset-1", + "realmDomainComponent": "oraclecloud23.com" + }, + { + "regionKey": "ebl", + "realmKey": "oc23", + "regionIdentifier": "us-thames-1", + "realmDomainComponent": "oraclecloud23.com" + }, + { + "regionKey": "dtz", + "realmKey": "oc35", + "regionIdentifier": "ap-seoul-2", + "realmDomainComponent": "oraclecloud35.com" + }, + { + "regionKey": "dln", + "realmKey": "oc35", + "regionIdentifier": "ap-suwon-1", + "realmDomainComponent": "oraclecloud35.com" + }, + { + "regionKey": "bno", + "realmKey": "oc35", + "regionIdentifier": "ap-chuncheon-2", + "realmDomainComponent": "oraclecloud35.com" + }, + { + "regionKey": "rba", + "realmKey": "oc26", + "regionIdentifier": "me-alain-1", + "realmDomainComponent": "oraclecloud26.com" + } +] \ No newline at end of file diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/retry.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/retry.go new file mode 100644 index 00000000000..1552fa052ef --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/retry.go @@ -0,0 +1,911 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "context" + "errors" + "fmt" + "io" + "math" + "math/rand" + "runtime" + "strings" + "time" +) + +const ( + // UnlimitedNumAttemptsValue is the value for indicating unlimited attempts for reaching success + UnlimitedNumAttemptsValue = uint(0) + + // number of characters contained in the generated retry token + generatedRetryTokenLength = 32 +) + +// OCIRetryableRequest represents a request that can be reissued according to the specified policy. +type OCIRetryableRequest interface { + // Any retryable request must implement the OCIRequest interface + OCIRequest + + // Each operation should implement this method, if has binary body, return OCIReadSeekCloser and true, otherwise return nil, false + BinaryRequestBody() (*OCIReadSeekCloser, bool) + + // Each operation specifies default retry behavior. By passing no arguments to this method, the default retry + // behavior, as determined on a per-operation-basis, will be honored. Variadic retry policy option arguments + // passed to this method will override the default behavior. + RetryPolicy() *RetryPolicy +} + +// OCIOperationResponse represents the output of an OCIOperation, with additional context of error message +// and operation attempt number. +type OCIOperationResponse struct { + // Response from OCI Operation + Response OCIResponse + + // Error from OCI Operation + Error error + + // Operation Attempt Number (one-based) + AttemptNumber uint + + // End of eventually consistent effects, or nil if no such effects + EndOfWindowTime *time.Time + + // Backoff scaling factor (only used for dealing with eventual consistency) + BackoffScalingFactor float64 + + // Time of the initial attempt + InitialAttemptTime time.Time +} + +const ( + defaultMaximumNumberAttempts = uint(8) + defaultExponentialBackoffBase = 2.0 + defaultMinSleepBetween = 0.0 + defaultMaxSleepBetween = 30.0 + + ecMaximumNumberAttempts = uint(9) + ecExponentialBackoffBase = 3.52 + ecMinSleepBetween = 0.0 + ecMaxSleepBetween = 45.0 +) + +var ( + defaultRetryStatusCodeMap = map[StatErrCode]bool{ + {409, "IncorrectState"}: true, + {429, "TooManyRequests"}: true, + + {501, "MethodNotImplemented"}: false, + } +) + +// IsErrorRetryableByDefault returns true if the error is retryable by OCI default retry policy +func IsErrorRetryableByDefault(err error) bool { + if err == nil { + return false + } + + if IsNetworkError(err) { + return true + } + + if err == io.EOF { + return true + } + + if err, ok := IsServiceError(err); ok { + if shouldRetry, ok := defaultRetryStatusCodeMap[StatErrCode{err.GetHTTPStatusCode(), err.GetCode()}]; ok { + return shouldRetry + } + + return 500 <= err.GetHTTPStatusCode() && err.GetHTTPStatusCode() < 505 + } + + return false +} + +// NewOCIOperationResponse assembles an OCI Operation Response object. +// Note that InitialAttemptTime is not set, nor is EndOfWindowTime, and BackoffScalingFactor is set to 1.0. +// EndOfWindowTime and BackoffScalingFactor are only important for eventual consistency. +// InitialAttemptTime can be useful for time-based (as opposed to count-based) retry policies. +func NewOCIOperationResponse(response OCIResponse, err error, attempt uint) OCIOperationResponse { + return OCIOperationResponse{ + Response: response, + Error: err, + AttemptNumber: attempt, + BackoffScalingFactor: 1.0, + } +} + +// NewOCIOperationResponseExtended assembles an OCI Operation Response object, with the value for the EndOfWindowTime, BackoffScalingFactor, and InitialAttemptTime set. +// EndOfWindowTime and BackoffScalingFactor are only important for eventual consistency. +// InitialAttemptTime can be useful for time-based (as opposed to count-based) retry policies. +func NewOCIOperationResponseExtended(response OCIResponse, err error, attempt uint, endOfWindowTime *time.Time, backoffScalingFactor float64, + initialAttemptTime time.Time) OCIOperationResponse { + return OCIOperationResponse{ + Response: response, + Error: err, + AttemptNumber: attempt, + EndOfWindowTime: endOfWindowTime, + BackoffScalingFactor: backoffScalingFactor, + InitialAttemptTime: initialAttemptTime, + } +} + +// +// RetryPolicy +// + +// RetryPolicy is the class that holds all relevant information for retrying operations. +type RetryPolicy struct { + // MaximumNumberAttempts is the maximum number of times to retry a request. Zero indicates an unlimited + // number of attempts. + MaximumNumberAttempts uint + + // ShouldRetryOperation inspects the http response, error, and operation attempt number, and + // - returns true if we should retry the operation + // - returns false otherwise + ShouldRetryOperation func(OCIOperationResponse) bool + + // GetNextDuration computes the duration to pause between operation retries. + NextDuration func(OCIOperationResponse) time.Duration + + // minimum sleep between attempts in seconds + MinSleepBetween float64 + + // maximum sleep between attempts in seconds + MaxSleepBetween float64 + + // the base for the exponential backoff + ExponentialBackoffBase float64 + + // DeterminePolicyToUse may modify the policy to handle eventual consistency; the return values are + // the retry policy to use, the end of the eventually consistent time window, and the backoff scaling factor + // If eventual consistency is not considered, this function should return the unmodified policy that was + // provided as input, along with (*time.Time)(nil) (no time window), and 1.0 (unscaled backoff). + DeterminePolicyToUse func(policy RetryPolicy) (RetryPolicy, *time.Time, float64) + + // if the retry policy considers eventual consistency, but there is no eventual consistency present + // the retries will fall back to the policy specified here; recommendation is to set this to DefaultRetryPolicyWithoutEventualConsistency() + NonEventuallyConsistentPolicy *RetryPolicy + + // Stores the maximum cumulative backoff in seconds. This can usually be calculated using + // MaximumNumberAttempts, MinSleepBetween, MaxSleepBetween, and ExponentialBackoffBase, + // but if MaximumNumberAttempts is 0 (unlimited attempts), then this needs to be set explicitly + // for Eventual Consistency retries to work. + MaximumCumulativeBackoffWithoutJitter float64 +} + +// GlobalRetry is user defined global level retry policy, it would impact all services, the precedence is lower +// than user defined client/request level retry policy +var GlobalRetry *RetryPolicy = nil + +// RetryPolicyOption is the type of the options for NewRetryPolicy. +type RetryPolicyOption func(rp *RetryPolicy) + +// String Converts retry policy to human-readable string representation +func (rp RetryPolicy) String() string { + return fmt.Sprintf("{MaximumNumberAttempts=%v, MinSleepBetween=%v, MaxSleepBetween=%v, ExponentialBackoffBase=%v, NonEventuallyConsistentPolicy=%v}", + rp.MaximumNumberAttempts, rp.MinSleepBetween, rp.MaxSleepBetween, rp.ExponentialBackoffBase, rp.NonEventuallyConsistentPolicy) +} + +// Validate returns true if the RetryPolicy is valid; if not, it also returns an error. +func (rp *RetryPolicy) validate() (success bool, err error) { + var errorStrings []string + if rp.ShouldRetryOperation == nil { + errorStrings = append(errorStrings, "ShouldRetryOperation may not be nil") + } + if rp.NextDuration == nil { + errorStrings = append(errorStrings, "NextDuration may not be nil") + } + if rp.NonEventuallyConsistentPolicy != nil { + if rp.MaximumNumberAttempts == 0 && rp.MaximumCumulativeBackoffWithoutJitter <= 0 { + errorStrings = append(errorStrings, "If eventual consistency is handled, and the MaximumNumberAttempts of the EC retry policy is 0 (unlimited attempts), then the MaximumCumulativeBackoffWithoutJitter of the EC retry policy must be positive; used WithUnlimitedAttempts instead") + } + nonEcRp := rp.NonEventuallyConsistentPolicy + if nonEcRp.MaximumNumberAttempts == 0 && nonEcRp.MaximumCumulativeBackoffWithoutJitter <= 0 { + errorStrings = append(errorStrings, "If eventual consistency is handled, and the MaximumNumberAttempts of the non-EC retry policy is 0 (unlimited attempts), then the MaximumCumulativeBackoffWithoutJitter of the non-EC retry policy must be positive; used WithUnlimitedAttempts instead") + } + } + if len(errorStrings) > 0 { + return false, errors.New(strings.Join(errorStrings, ", ")) + } + + // some legacy code constructing RetryPolicy instances directly may not have set DeterminePolicyToUse. + // In that case, just assume that it doesn't handle eventual consistency. + if rp.DeterminePolicyToUse == nil { + rp.DeterminePolicyToUse = returnSamePolicy + } + + return true, nil +} + +// GetMaximumCumulativeBackoffWithoutJitter returns the maximum cumulative backoff the retry policy would do, +// taking into account whether eventually consistency is considered or not. +// This function uses either GetMaximumCumulativeBackoffWithoutJitter or GetMaximumCumulativeEventuallyConsistentBackoffWithoutJitter, +// whichever is appropriate +func (rp RetryPolicy) GetMaximumCumulativeBackoffWithoutJitter() time.Duration { + if rp.NonEventuallyConsistentPolicy == nil { + return GetMaximumCumulativeBackoffWithoutJitter(rp) + } + return GetMaximumCumulativeEventuallyConsistentBackoffWithoutJitter(rp) +} + +// +// Functions to calculate backoff and maximum cumulative backoff +// + +// GetBackoffWithoutJitter calculates the backoff without jitter for the attempt, given the retry policy. +func GetBackoffWithoutJitter(policy RetryPolicy, attempt uint) time.Duration { + return time.Duration(getBackoffWithoutJitterHelper(policy.MinSleepBetween, policy.MaxSleepBetween, policy.ExponentialBackoffBase, attempt)) * time.Second +} + +// getBackoffWithoutJitterHelper calculates the backoff without jitter for the attempt, given the loose retry policy values. +func getBackoffWithoutJitterHelper(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, attempt uint) float64 { + sleepTime := math.Pow(exponentialBackoffBase, float64(attempt-1)) + if sleepTime < minSleepBetween { + sleepTime = minSleepBetween + } + if sleepTime > maxSleepBetween { + sleepTime = maxSleepBetween + } + return sleepTime +} + +// GetMaximumCumulativeBackoffWithoutJitter calculates the maximum backoff without jitter, according to the retry +// policy, if every retry attempt is made. +func GetMaximumCumulativeBackoffWithoutJitter(policy RetryPolicy) time.Duration { + return getMaximumCumulativeBackoffWithoutJitterHelper(policy.MinSleepBetween, policy.MaxSleepBetween, policy.ExponentialBackoffBase, policy.MaximumNumberAttempts, policy.MaximumCumulativeBackoffWithoutJitter) +} + +func getMaximumCumulativeBackoffWithoutJitterHelper(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, MaximumNumberAttempts uint, MaximumCumulativeBackoffWithoutJitter float64) time.Duration { + var cumulative time.Duration = 0 + + if MaximumNumberAttempts == 0 { + // unlimited + return time.Duration(MaximumCumulativeBackoffWithoutJitter) * time.Second + } + + // use a one-based counter because it's easier to think about operation retry in terms of attempt numbering + for currentOperationAttempt := uint(1); currentOperationAttempt < MaximumNumberAttempts; currentOperationAttempt++ { + cumulative += time.Duration(getBackoffWithoutJitterHelper(minSleepBetween, maxSleepBetween, exponentialBackoffBase, currentOperationAttempt)) * time.Second + } + return cumulative +} + +// +// Functions to calculate backoff and maximum cumulative backoff for eventual consistency +// + +// GetEventuallyConsistentBackoffWithoutJitter calculates the backoff without jitter for the attempt, given the retry policy +// and dealing with eventually consistent effects. The result is then multiplied by backoffScalingFactor. +func GetEventuallyConsistentBackoffWithoutJitter(policy RetryPolicy, attempt uint, backoffScalingFactor float64) time.Duration { + return time.Duration(getEventuallyConsistentBackoffWithoutJitterHelper(policy.MinSleepBetween, policy.MaxSleepBetween, policy.ExponentialBackoffBase, attempt, backoffScalingFactor, + func(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, attempt uint) float64 { + rp := policy.NonEventuallyConsistentPolicy + return getBackoffWithoutJitterHelper(rp.MinSleepBetween, rp.MaxSleepBetween, rp.ExponentialBackoffBase, attempt) + })*1000) * time.Millisecond +} + +// getEventuallyConsistentBackoffWithoutJitterHelper calculates the backoff without jitter for the attempt, given the loose retry policy values, +// and dealing with eventually consistent effects. The result is then multiplied by backoffScalingFactor. +func getEventuallyConsistentBackoffWithoutJitterHelper(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, attempt uint, backoffScalingFactor float64, + defaultBackoffWithoutJitterHelper func(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, attempt uint) float64) float64 { + var sleepTime = math.Pow(exponentialBackoffBase, float64(attempt-1)) + if sleepTime < minSleepBetween { + sleepTime = minSleepBetween + } + if sleepTime > maxSleepBetween { + sleepTime = maxSleepBetween + } + sleepTime = sleepTime * backoffScalingFactor + defaultSleepTime := defaultBackoffWithoutJitterHelper(minSleepBetween, maxSleepBetween, exponentialBackoffBase, attempt) + if defaultSleepTime > sleepTime { + sleepTime = defaultSleepTime + } + return sleepTime +} + +// GetMaximumCumulativeEventuallyConsistentBackoffWithoutJitter calculates the maximum backoff without jitter, according to the retry +// policy and taking eventually consistent effects into account, if every retry attempt is made. +func GetMaximumCumulativeEventuallyConsistentBackoffWithoutJitter(policy RetryPolicy) time.Duration { + return getMaximumCumulativeEventuallyConsistentBackoffWithoutJitterHelper(policy.MinSleepBetween, policy.MaxSleepBetween, policy.ExponentialBackoffBase, + policy.MaximumNumberAttempts, policy.MaximumCumulativeBackoffWithoutJitter, + func(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, attempt uint) float64 { + rp := policy.NonEventuallyConsistentPolicy + return getBackoffWithoutJitterHelper(rp.MinSleepBetween, rp.MaxSleepBetween, rp.ExponentialBackoffBase, attempt) + }) +} + +func getMaximumCumulativeEventuallyConsistentBackoffWithoutJitterHelper(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, MaximumNumberAttempts uint, + MaximumCumulativeBackoffWithoutJitter float64, + defaultBackoffWithoutJitterHelper func(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, attempt uint) float64) time.Duration { + if MaximumNumberAttempts == 0 { + // unlimited + return time.Duration(MaximumCumulativeBackoffWithoutJitter) * time.Second + } + + var cumulative time.Duration = 0 + // use a one-based counter because it's easier to think about operation retry in terms of attempt numbering + for currentOperationAttempt := uint(1); currentOperationAttempt < MaximumNumberAttempts; currentOperationAttempt++ { + cumulative += time.Duration(getEventuallyConsistentBackoffWithoutJitterHelper(minSleepBetween, maxSleepBetween, exponentialBackoffBase, currentOperationAttempt, 1.0, defaultBackoffWithoutJitterHelper)*1000) * time.Millisecond + } + return cumulative +} + +func returnSamePolicy(policy RetryPolicy) (RetryPolicy, *time.Time, float64) { + // we're returning the end of window time nonetheless, even though the default non-eventual consistency (EC) + // retry policy doesn't use it; this is useful in case developers wants to write an EC-aware retry policy + // on their own + eowt := EcContext.GetEndOfWindow() + return policy, eowt, 1.0 +} + +// NoRetryPolicy is a helper method that assembles and returns a return policy that indicates an operation should +// never be retried (the operation is performed exactly once). +func NoRetryPolicy() RetryPolicy { + dontRetryOperation := func(OCIOperationResponse) bool { return false } + zeroNextDuration := func(OCIOperationResponse) time.Duration { return 0 * time.Second } + return newRetryPolicyWithOptionsNoDefault( + WithMaximumNumberAttempts(1), + WithShouldRetryOperation(dontRetryOperation), + WithNextDuration(zeroNextDuration), + withMinSleepBetween(0.0*time.Second), + withMaxSleepBetween(0.0*time.Second), + withExponentialBackoffBase(0.0), + withDeterminePolicyToUse(returnSamePolicy), + withNonEventuallyConsistentPolicy(nil)) +} + +// DefaultShouldRetryOperation is the function that should be used for RetryPolicy.ShouldRetryOperation when +// not taking eventual consistency into account. +func DefaultShouldRetryOperation(r OCIOperationResponse) bool { + if r.Error == nil && 199 < r.Response.HTTPResponse().StatusCode && r.Response.HTTPResponse().StatusCode < 300 { + // success + return false + } + return IsErrorRetryableByDefault(r.Error) +} + +// DefaultRetryPolicy is a helper method that assembles and returns a return policy that is defined to be a default one +// The default retry policy will retry on (409, IncorrectState), (429, TooManyRequests) and any 5XX errors except (501, MethodNotImplemented) +// The default retry behavior is using exponential backoff with jitter, the maximum wait time is 30s plus 1s jitter +// The maximum cumulative backoff after all 8 attempts have been made is about 1.5 minutes. +// It will also retry on errors affected by eventual consistency. +// The eventual consistency retry behavior is using exponential backoff with jitter, the maximum wait time is 45s plus 1s jitter +// Under eventual consistency, the maximum cumulative backoff after all 9 attempts have been made is about 4 minutes. +func DefaultRetryPolicy() RetryPolicy { + return NewRetryPolicyWithOptions( + ReplaceWithValuesFromRetryPolicy(DefaultRetryPolicyWithoutEventualConsistency()), + WithEventualConsistency()) +} + +// DefaultRetryPolicyWithoutEventualConsistency is a helper method that assembles and returns a return policy that is defined to be a default one +// The default retry policy will retry on (409, IncorrectState), (429, TooManyRequests) and any 5XX errors except (501, MethodNotImplemented) +// It will not retry on errors affected by eventual consistency. +// The default retry behavior is using exponential backoff with jitter, the maximum wait time is 30s plus 1s jitter +func DefaultRetryPolicyWithoutEventualConsistency() RetryPolicy { + exponentialBackoffWithJitter := func(r OCIOperationResponse) time.Duration { + sleepTime := getBackoffWithoutJitterHelper(defaultMinSleepBetween, defaultMaxSleepBetween, defaultExponentialBackoffBase, r.AttemptNumber) + nextDuration := time.Duration(1000.0*(sleepTime+rand.Float64())) * time.Millisecond + return nextDuration + } + return newRetryPolicyWithOptionsNoDefault( + WithMaximumNumberAttempts(defaultMaximumNumberAttempts), + WithShouldRetryOperation(DefaultShouldRetryOperation), + WithNextDuration(exponentialBackoffWithJitter), + withMinSleepBetween(defaultMinSleepBetween*time.Second), + withMaxSleepBetween(defaultMaxSleepBetween*time.Second), + withExponentialBackoffBase(defaultExponentialBackoffBase), + withDeterminePolicyToUse(returnSamePolicy), + withNonEventuallyConsistentPolicy(nil)) +} + +// EventuallyConsistentShouldRetryOperation is the function that should be used for RetryPolicy.ShouldRetryOperation when +// taking eventual consistency into account +func EventuallyConsistentShouldRetryOperation(r OCIOperationResponse) bool { + if r.Error == nil && 199 < r.Response.HTTPResponse().StatusCode && r.Response.HTTPResponse().StatusCode < 300 { + // success + Debugln(fmt.Sprintf("EC.ShouldRetryOperation, status = %v, 2xx, returning false", r.Response.HTTPResponse().StatusCode)) + return false + } + if IsErrorRetryableByDefault(r.Error) { + return true + } + // not retryable by default + if _, ok := IsServiceError(r.Error); ok { + now := EcContext.timeNowProvider() + if r.EndOfWindowTime == nil || r.EndOfWindowTime.Before(now) { + // either no eventually consistent effects, or they have disappeared by now + Debugln(fmt.Sprintf("EC.ShouldRetryOperation, no EC or in the past, returning false: endOfWindowTime = %v, now = %v", r.EndOfWindowTime, now)) + return false + } + // there were eventually consistent effects present at the time of the first request + // and they could still affect the retries + if IsErrorAffectedByEventualConsistency(r.Error) { + // and it's one of the three affected error codes + Debugln(fmt.Sprintf("EC.ShouldRetryOperation, affected by EC, EC is present: endOfWindowTime = %v, now = %v", r.EndOfWindowTime, now)) + return true + } + return false + } + + return false +} + +// EventuallyConsistentRetryPolicy is a helper method that assembles and returns a return policy that is defined to be a default one +// plus dealing with errors affected by eventual consistency. +// The default retry behavior is using exponential backoff with jitter, the maximum wait time is 45s plus 1s jitter +func EventuallyConsistentRetryPolicy(nonEventuallyConsistentPolicy RetryPolicy) RetryPolicy { + if nonEventuallyConsistentPolicy.NonEventuallyConsistentPolicy != nil { + // already deals with eventual consistency + return nonEventuallyConsistentPolicy + } + exponentialBackoffWithJitter := func(r OCIOperationResponse) time.Duration { + sleepTime := getEventuallyConsistentBackoffWithoutJitterHelper(ecMinSleepBetween, ecMaxSleepBetween, ecExponentialBackoffBase, r.AttemptNumber, r.BackoffScalingFactor, + func(minSleepBetween float64, maxSleepBetween float64, exponentialBackoffBase float64, attempt uint) float64 { + rp := nonEventuallyConsistentPolicy + return getBackoffWithoutJitterHelper(rp.MinSleepBetween, rp.MaxSleepBetween, rp.ExponentialBackoffBase, attempt) + }) + nextDuration := time.Duration(1000.0*(sleepTime+rand.Float64())) * time.Millisecond + Debugln(fmt.Sprintf("EventuallyConsistentRetryPolicy.NextDuration for attempt %v: sleepTime = %.1fs, nextDuration = %v", r.AttemptNumber, sleepTime, nextDuration)) + return nextDuration + } + returnModifiedPolicy := func(policy RetryPolicy) (RetryPolicy, *time.Time, float64) { return determinePolicyToUse(policy) } + nonEventuallyConsistentPolicyCopy := newRetryPolicyWithOptionsNoDefault( + ReplaceWithValuesFromRetryPolicy(nonEventuallyConsistentPolicy)) + return newRetryPolicyWithOptionsNoDefault( + WithMaximumNumberAttempts(ecMaximumNumberAttempts), + WithShouldRetryOperation(EventuallyConsistentShouldRetryOperation), + WithNextDuration(exponentialBackoffWithJitter), + withMinSleepBetween(ecMinSleepBetween*time.Second), + withMaxSleepBetween(ecMaxSleepBetween*time.Second), + withExponentialBackoffBase(ecExponentialBackoffBase), + withDeterminePolicyToUse(returnModifiedPolicy), + withNonEventuallyConsistentPolicy(&nonEventuallyConsistentPolicyCopy)) +} + +// NewRetryPolicy is a helper method for assembling a Retry Policy object. It does not handle eventual consistency, so as to not break existing code. +// If you want to handle eventual consistency, the simplest way to do that is to replace the code +// +// NewRetryPolicy(a, r, n) +// +// with the code +// +// NewRetryPolicyWithOptions( +// WithMaximumNumberAttempts(a), +// WithFixedBackoff(fb) // fb is the fixed backoff duration +// WithShouldRetryOperation(r)) +// +// or +// +// NewRetryPolicyWithOptions( +// WithMaximumNumberAttempts(a), +// WithExponentialBackoff(mb, e) // mb is the maximum backoff duration, and e is the base for exponential backoff, e.g. 2.0 +// WithShouldRetryOperation(r)) +// +// or, if a == 0 (the maximum number of attempts is unlimited) +// +// NewRetryPolicyWithEventualConsistencyUnlimitedAttempts(a, r, n, mcb) // mcb is the maximum cumulative backoff duration without jitter +func NewRetryPolicy(attempts uint, retryOperation func(OCIOperationResponse) bool, nextDuration func(OCIOperationResponse) time.Duration) RetryPolicy { + return NewRetryPolicyWithOptions( + ReplaceWithValuesFromRetryPolicy(DefaultRetryPolicyWithoutEventualConsistency()), + WithMaximumNumberAttempts(attempts), + WithShouldRetryOperation(retryOperation), + WithNextDuration(nextDuration), + ) +} + +// NewRetryPolicyWithEventualConsistencyUnlimitedAttempts is a helper method for assembling a Retry Policy object. +// It does handle eventual consistency, but other than that, it is very similar to NewRetryPolicy. +// NewRetryPolicyWithEventualConsistency does not support limited attempts, use NewRetryPolicyWithEventualConsistency instead. +func NewRetryPolicyWithEventualConsistencyUnlimitedAttempts(attempts uint, retryOperation func(OCIOperationResponse) bool, nextDuration func(OCIOperationResponse) time.Duration, + maximumCumulativeBackoffWithoutJitter time.Duration) (*RetryPolicy, error) { + + if attempts != 0 { + return nil, fmt.Errorf("NewRetryPolicyWithEventualConsistencyUnlimitedAttempts cannot be used with attempts != 0 (limited attempts), use NewRetryPolicyWithEventualConsistency instead") + } + + result := NewRetryPolicyWithOptions( + ReplaceWithValuesFromRetryPolicy(DefaultRetryPolicyWithoutEventualConsistency()), + WithUnlimitedAttempts(maximumCumulativeBackoffWithoutJitter), + WithShouldRetryOperation(retryOperation), + WithNextDuration(nextDuration), + ) + return &result, nil +} + +// NewRetryPolicyWithOptions is a helper method for assembling a Retry Policy object. +// It starts out with the values returned by DefaultRetryPolicy() and does handle eventual consistency, +// unless you replace all options set using ReplaceWithValuesFromRetryPolicy(DefaultRetryPolicyWithoutEventualConsistency()). +func NewRetryPolicyWithOptions(opts ...RetryPolicyOption) RetryPolicy { + rp := &RetryPolicy{} + + // start with the default retry policy + ReplaceWithValuesFromRetryPolicy(DefaultRetryPolicyWithoutEventualConsistency())(rp) + WithEventualConsistency()(rp) + + // then allow changing values + for _, opt := range opts { + opt(rp) + } + + if rp.DeterminePolicyToUse == nil { + rp.DeterminePolicyToUse = returnSamePolicy + } + + return *rp +} + +// newRetryPolicyWithOptionsNoDefault is a helper method for assembling a Retry Policy object. +// Contrary to newRetryPolicyWithOptions, it does not start out with the values returned by +// DefaultRetryPolicy(). +func newRetryPolicyWithOptionsNoDefault(opts ...RetryPolicyOption) RetryPolicy { + rp := &RetryPolicy{} + + // then allow changing values + for _, opt := range opts { + opt(rp) + } + + if rp.DeterminePolicyToUse == nil { + rp.DeterminePolicyToUse = returnSamePolicy + } + + return *rp +} + +// WithMaximumNumberAttempts is the option for NewRetryPolicyWithOptions that sets the maximum number of attempts. +func WithMaximumNumberAttempts(attempts uint) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.MaximumNumberAttempts = attempts + } +} + +// WithUnlimitedAttempts is the option for NewRetryPolicyWithOptions that sets unlimited number of attempts, +// but it needs to set a MaximumCumulativeBackoffWithoutJitter duration. +// If you use WithUnlimitedAttempts, you should set your own NextDuration function using WithNextDuration. +func WithUnlimitedAttempts(maximumCumulativeBackoffWithoutJitter time.Duration) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.MaximumNumberAttempts = 0 + rp.MaximumCumulativeBackoffWithoutJitter = float64(maximumCumulativeBackoffWithoutJitter / time.Second) + } +} + +// WithShouldRetryOperation is the option for NewRetryPolicyWithOptions that sets the function that checks +// whether retries should be performed. +func WithShouldRetryOperation(retryOperation func(OCIOperationResponse) bool) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.ShouldRetryOperation = retryOperation + } +} + +// WithNextDuration is the option for NewRetryPolicyWithOptions that sets the function for computing the next +// backoff duration. +// It is preferred to use WithFixedBackoff or WithExponentialBackoff instead. +func WithNextDuration(nextDuration func(OCIOperationResponse) time.Duration) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.NextDuration = nextDuration + } +} + +// withMinSleepBetween is the option for NewRetryPolicyWithOptions that sets the minimum backoff duration. +func withMinSleepBetween(minSleepBetween time.Duration) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.MinSleepBetween = float64(minSleepBetween / time.Second) + } +} + +// withMaxsSleepBetween is the option for NewRetryPolicyWithOptions that sets the maximum backoff duration. +func withMaxSleepBetween(maxSleepBetween time.Duration) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.MaxSleepBetween = float64(maxSleepBetween / time.Second) + } +} + +// withExponentialBackoffBase is the option for NewRetryPolicyWithOptions that sets the base for the +// exponential backoff +func withExponentialBackoffBase(base float64) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.ExponentialBackoffBase = base + } +} + +// withDeterminePolicyToUse is the option for NewRetryPolicyWithOptions that sets the function that +// determines which polich should be used and if eventual consistency should be considered +func withDeterminePolicyToUse(determinePolicyToUse func(policy RetryPolicy) (RetryPolicy, *time.Time, float64)) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.DeterminePolicyToUse = determinePolicyToUse + } +} + +// withNonEventuallyConsistentPolicy is the option for NewRetryPolicyWithOptions that sets the fallback +// strategy if eventual consistency should not be considered +func withNonEventuallyConsistentPolicy(nonEventuallyConsistentPolicy *RetryPolicy) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + // we want a non-EC policy for NonEventuallyConsistentPolicy; make sure that NonEventuallyConsistentPolicy is nil + for nonEventuallyConsistentPolicy != nil && nonEventuallyConsistentPolicy.NonEventuallyConsistentPolicy != nil { + nonEventuallyConsistentPolicy = nonEventuallyConsistentPolicy.NonEventuallyConsistentPolicy + } + rp.NonEventuallyConsistentPolicy = nonEventuallyConsistentPolicy + } +} + +// WithExponentialBackoff is an option for NewRetryPolicyWithOptions that sets the exponential backoff base, +// minimum and maximum sleep between attempts, and next duration function. +// Therefore, WithExponentialBackoff is a combination of WithNextDuration, withMinSleepBetween, withMaxSleepBetween, +// and withExponentialBackoffBase. +func WithExponentialBackoff(newMaxSleepBetween time.Duration, newExponentialBackoffBase float64) RetryPolicyOption { + exponentialBackoffWithJitter := func(r OCIOperationResponse) time.Duration { + sleepTime := getBackoffWithoutJitterHelper(defaultMinSleepBetween, newMaxSleepBetween.Seconds(), newExponentialBackoffBase, r.AttemptNumber) + nextDuration := time.Duration(1000.0*(sleepTime+rand.Float64())) * time.Millisecond + Debugln(fmt.Sprintf("NextDuration for attempt %v: sleepTime = %.1fs, nextDuration = %v", r.AttemptNumber, sleepTime, nextDuration)) + return nextDuration + } + + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + withMinSleepBetween(0)(rp) + withMaxSleepBetween(newMaxSleepBetween)(rp) + withExponentialBackoffBase(newExponentialBackoffBase)(rp) + WithNextDuration(exponentialBackoffWithJitter)(rp) + } +} + +// WithFixedBackoff is an option for NewRetryPolicyWithOptions that sets the backoff to always be exactly the same value. There is no jitter either. +// Therefore, WithFixedBackoff is a combination of WithNextDuration, withMinSleepBetween, withMaxSleepBetween, and withExponentialBackoffBase. +func WithFixedBackoff(newSleepBetween time.Duration) RetryPolicyOption { + fixedBackoffWithoutJitter := func(r OCIOperationResponse) time.Duration { + nextDuration := newSleepBetween + Debugln(fmt.Sprintf("NextDuration for attempt %v: nextDuration = %v", r.AttemptNumber, nextDuration)) + return nextDuration + } + + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + withMinSleepBetween(newSleepBetween)(rp) + withMaxSleepBetween(newSleepBetween)(rp) + withExponentialBackoffBase(1.0)(rp) + WithNextDuration(fixedBackoffWithoutJitter)(rp) + } +} + +// WithEventualConsistency is the option for NewRetryPolicyWithOptions that enables considering eventual backoff for the policy. +func WithEventualConsistency() RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + copy := RetryPolicy{ + MaximumNumberAttempts: rp.MaximumNumberAttempts, + ShouldRetryOperation: rp.ShouldRetryOperation, + NextDuration: rp.NextDuration, + MinSleepBetween: rp.MinSleepBetween, + MaxSleepBetween: rp.MaxSleepBetween, + ExponentialBackoffBase: rp.ExponentialBackoffBase, + DeterminePolicyToUse: rp.DeterminePolicyToUse, + NonEventuallyConsistentPolicy: rp.NonEventuallyConsistentPolicy, + } + ecrp := EventuallyConsistentRetryPolicy(copy) + rp.MaximumNumberAttempts = ecrp.MaximumNumberAttempts + rp.ShouldRetryOperation = ecrp.ShouldRetryOperation + rp.NextDuration = ecrp.NextDuration + rp.MinSleepBetween = ecrp.MinSleepBetween + rp.MaxSleepBetween = ecrp.MaxSleepBetween + rp.ExponentialBackoffBase = ecrp.ExponentialBackoffBase + rp.DeterminePolicyToUse = ecrp.DeterminePolicyToUse + rp.NonEventuallyConsistentPolicy = ecrp.NonEventuallyConsistentPolicy + } +} + +// WithConditionalOption is an option for NewRetryPolicyWithOptions that enables or disables another option. +func WithConditionalOption(enabled bool, otherOption RetryPolicyOption) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + if enabled { + otherOption(rp) + } + } +} + +// ReplaceWithValuesFromRetryPolicy is an option for NewRetryPolicyWithOptions that copies over all settings from another RetryPolicy +func ReplaceWithValuesFromRetryPolicy(other RetryPolicy) RetryPolicyOption { + // this is the RetryPolicyOption function type + return func(rp *RetryPolicy) { + rp.MaximumNumberAttempts = other.MaximumNumberAttempts + rp.ShouldRetryOperation = other.ShouldRetryOperation + rp.NextDuration = other.NextDuration + rp.MinSleepBetween = other.MinSleepBetween + rp.MaxSleepBetween = other.MaxSleepBetween + rp.ExponentialBackoffBase = other.ExponentialBackoffBase + rp.DeterminePolicyToUse = other.DeterminePolicyToUse + rp.NonEventuallyConsistentPolicy = other.NonEventuallyConsistentPolicy + rp.MaximumCumulativeBackoffWithoutJitter = other.MaximumCumulativeBackoffWithoutJitter + } +} + +// shouldContinueIssuingRequests returns true if we should continue retrying a request, based on the current attempt +// number and the maximum number of attempts specified, or false otherwise. +func shouldContinueIssuingRequests(current, maximum uint) bool { + return maximum == UnlimitedNumAttemptsValue || current <= maximum +} + +// RetryToken generates a retry token that must be included on any request passed to the Retry method. +func RetryToken() string { + alphanumericChars := []rune("abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") + retryToken := make([]rune, generatedRetryTokenLength) + for i := range retryToken { + retryToken[i] = alphanumericChars[rand.Intn(len(alphanumericChars))] + } + return string(retryToken) +} + +func determinePolicyToUse(policy RetryPolicy) (RetryPolicy, *time.Time, float64) { + initialAttemptTime := EcContext.timeNowProvider() + var useDefaultTimingInstead = true + var endOfWindowTime = (*time.Time)(nil) + var backoffScalingFactor = 1.0 + var policyToUse = policy + + eowt := EcContext.GetEndOfWindow() + if eowt != nil { + // there was an eventually consistent request + if eowt.After(initialAttemptTime) { + // and the eventually consistent effects may still be present + endOfWindowTime = eowt + // if the time between now and the end of the window is less than the time we normally would retry, use the default timing + durationToEndOfWindow := endOfWindowTime.Sub(initialAttemptTime) + maxCumulativeBackoffWithoutJitter := GetMaximumCumulativeBackoffWithoutJitter(*policy.NonEventuallyConsistentPolicy) + Debugln(fmt.Sprintf("durationToEndOfWindow = %v, maxCumulativeBackoffWithoutJitter = %v", durationToEndOfWindow, maxCumulativeBackoffWithoutJitter)) + if durationToEndOfWindow > maxCumulativeBackoffWithoutJitter { + // the end of the eventually consistent window is later than when default retries would end + // do not use default timing + maximumCumulativeBackoffWithoutJitter := GetMaximumCumulativeEventuallyConsistentBackoffWithoutJitter(policy) + backoffScalingFactor = float64(durationToEndOfWindow) / float64(maximumCumulativeBackoffWithoutJitter) + useDefaultTimingInstead = false + Debugln(fmt.Sprintf("Use eventually consistent timing, durationToEndOfWindow = %v, maximumCumulativeBackoffWithoutJitter = %v, backoffScalingFactor = %.2f", + durationToEndOfWindow, maximumCumulativeBackoffWithoutJitter, backoffScalingFactor)) + } else { + Debugln("Use default timing, end of EC window is sooner than default retries") + } + } else { + useDefaultTimingInstead = false + policyToUse = *policy.NonEventuallyConsistentPolicy + Debugln("Use default timing and strategy, end of EC window is in the past") + } + } else { + useDefaultTimingInstead = false + policyToUse = *policy.NonEventuallyConsistentPolicy + Debugln("Use default timing and strategy, no EC window set") + } + + if useDefaultTimingInstead { + // use timing from defaultRetryPolicy, but whether to retry from the policy that was passed into this request + policyToUse = NewRetryPolicyWithOptions( + ReplaceWithValuesFromRetryPolicy(*policy.NonEventuallyConsistentPolicy), + WithShouldRetryOperation(policy.ShouldRetryOperation)) + } + + return policyToUse, endOfWindowTime, backoffScalingFactor +} + +// Retry is a package-level operation that executes the retryable request using the specified operation and retry policy. +func Retry(ctx context.Context, request OCIRetryableRequest, operation OCIOperation, policy RetryPolicy) (OCIResponse, error) { + type retrierResult struct { + response OCIResponse + err error + } + + var response OCIResponse + var err error + retrierChannel := make(chan retrierResult, 1) + + validated, validateError := policy.validate() + if !validated { + return nil, validateError + } + + initialAttemptTime := time.Now() + + go func() { + // Deal with panics more graciously + defer func() { + if r := recover(); r != nil { + stackBuffer := make([]byte, 1024) + bytesWritten := runtime.Stack(stackBuffer, false) + stack := string(stackBuffer[:bytesWritten]) + error := fmt.Errorf("panicked while retrying operation. Panic was: %s\nStack: %s", r, stack) + Debugln(error) + retrierChannel <- retrierResult{nil, error} + } + }() + // if request body is binary request body and seekable, save the current position + var curPos int64 = 0 + isSeekable := false + rsc, isBinaryRequest := request.BinaryRequestBody() + if rsc != nil && rsc.rc != nil { + defer rsc.rc.Close() + } + if policy.MaximumNumberAttempts != uint(1) { + if rsc.Seekable() { + isSeekable = true + curPos, _ = rsc.Seek(0, io.SeekCurrent) + } + } + + // some legacy code constructing RetryPolicy instances directly may not have set DeterminePolicyToUse. + // In that case, just assume that it doesn't handle eventual consistency. + if policy.DeterminePolicyToUse == nil { + policy.DeterminePolicyToUse = returnSamePolicy + } + + // this determines which policy to use, when the eventual consistency window ends, and what the backoff + // scaling factor should be + policyToUse, endOfWindowTime, backoffScalingFactor := policy.DeterminePolicyToUse(policy) + Debugln(fmt.Sprintf("Retry policy to use: %v", policyToUse)) + retryStartTime := time.Now() + extraHeaders := make(map[string]string) + + if policy.MaximumNumberAttempts == 1 { + extraHeaders[requestHeaderOpcClientRetries] = "false" + } else { + extraHeaders[requestHeaderOpcClientRetries] = "true" + } + + // use a one-based counter because it's easier to think about operation retry in terms of attempt numbering + for currentOperationAttempt := uint(1); shouldContinueIssuingRequests(currentOperationAttempt, policyToUse.MaximumNumberAttempts); currentOperationAttempt++ { + Debugln(fmt.Sprintf("operation attempt #%v", currentOperationAttempt)) + // rewind body once needed + if isSeekable { + rsc = NewOCIReadSeekCloser(rsc.rc) + rsc.Seek(curPos, io.SeekStart) + } + response, err = operation(ctx, request, rsc, extraHeaders) + + operationResponse := NewOCIOperationResponseExtended(response, err, currentOperationAttempt, endOfWindowTime, backoffScalingFactor, initialAttemptTime) + + if !policyToUse.ShouldRetryOperation(operationResponse) { + // we should NOT retry operation based on response and/or error => return + retrierChannel <- retrierResult{response, err} + return + } + + // if the request body type is stream, requested retry but doesn't resettable, throw error and stop retrying + if isBinaryRequest && !isSeekable { + retrierChannel <- retrierResult{response, NonSeekableRequestRetryFailure{err}} + return + } + + duration := policyToUse.NextDuration(operationResponse) + //The following condition is kept for backwards compatibility reasons + if deadline, ok := ctx.Deadline(); ok && EcContext.timeNowProvider().Add(duration).After(deadline) { + // we want to retry the operation, but the policy is telling us to wait for a duration that exceeds + // the specified overall deadline for the operation => instead of waiting for however long that + // time period is and then aborting, abort now and save the cycles + retrierChannel <- retrierResult{response, DeadlineExceededByBackoff} + return + } + Debugln(fmt.Sprintf("waiting %v before retrying operation", duration)) + // sleep before retrying the operation + <-time.After(duration) + } + retryEndTime := time.Now() + Debugln(fmt.Sprintf("Total Latency for this API call is: %v ms", retryEndTime.Sub(retryStartTime).Milliseconds())) + retrierChannel <- retrierResult{response, err} + }() + + select { + case <-ctx.Done(): + return response, ctx.Err() + case result := <-retrierChannel: + return result.response, result.err + } +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/sseReader.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/sseReader.go new file mode 100644 index 00000000000..f8c41c82e56 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/sseReader.go @@ -0,0 +1,92 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "bufio" + "bytes" + "context" + "io" + "net/http" +) + +type SseReader struct { + HttpBody io.ReadCloser + eventScanner bufio.Scanner + OnClose func(r *SseReader) +} + +// InvalidSSEResponseError returned in the case that a nil response body was given +// to NewSSEReader() +type InvalidSSEResponseError struct { +} + +const InvalidResponseErrorMessage = "invalid response struct given to NewSSEReader" + +func (e InvalidSSEResponseError) Error() string { + return InvalidResponseErrorMessage +} + +// NewSSEReader returns an SSE Reader given an sse response +func NewSSEReader(response *http.Response) (*SseReader, error) { + + if response == nil || response.Body == nil { + return nil, InvalidSSEResponseError{} + } + + reader := &SseReader{ + HttpBody: response.Body, + eventScanner: *bufio.NewScanner(response.Body), + OnClose: func(r *SseReader) { r.HttpBody.Close() }, // Default on close function, ensures body is closed after use + } + return reader, nil +} + +// Take the response in bytes and trim it if necessary +func processEvent(e []byte) []byte { + e = bytes.TrimPrefix(e, []byte("data: ")) // Text/event-stream always prefixed with 'data: ' + return e +} + +// ReadNextEvent reads the next event in the stream, return it unmarshalled +func (r *SseReader) ReadNextEvent() (event []byte, err error) { + if r.eventScanner.Scan() { + eventBytes := r.eventScanner.Bytes() + return processEvent(eventBytes), nil + } else { + + // Close out the stream since we are finished reading from it + if r.OnClose != nil { + r.OnClose(r) + } + + err := r.eventScanner.Err() + if err == context.Canceled || err == nil { + err = io.EOF + } + return nil, err + } + +} + +// ReadAllEvents reads all events from the response stream, and processes each with given event handler +func (r *SseReader) ReadAllEvents(eventHandler func(e []byte)) error { + for { + + event, err := r.ReadNextEvent() + + if err != nil { + + if err == io.EOF { + err = nil + } + return err + } + + // Ignore empty events + if len(event) > 0 { + eventHandler(event) + } + } +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/tls_config_provider.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/tls_config_provider.go new file mode 100644 index 00000000000..cdcba139993 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/tls_config_provider.go @@ -0,0 +1,156 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "os" + "sync" +) + +// GetTLSConfigTemplateForTransport returns the TLSConfigTemplate to used depending on whether any additional +// CA Bundle or client side certs have been configured +func GetTLSConfigTemplateForTransport() TLSConfigProvider { + certPath := os.Getenv(ociDefaultClientCertsPath) + keyPath := os.Getenv(ociDefaultClientCertsPrivateKeyPath) + caBundlePath := os.Getenv(ociDefaultCertsPath) + if certPath != "" && keyPath != "" { + return &DefaultMTLSConfigProvider{ + caBundlePath: caBundlePath, + clientCertPath: certPath, + clientKeyPath: keyPath, + watchedFilesStatsMap: make(map[string]os.FileInfo), + } + } + return &DefaultTLSConfigProvider{ + caBundlePath: caBundlePath, + } +} + +// TLSConfigProvider is an interface the defines a function that creates a new *tls.Config. +type TLSConfigProvider interface { + NewOrDefault() (*tls.Config, error) + WatchedFilesModified() bool +} + +// DefaultTLSConfigProvider is a provider that provides a TLS tls.config for the HTTPTransport +type DefaultTLSConfigProvider struct { + caBundlePath string + mux sync.Mutex + currentStat os.FileInfo +} + +// NewOrDefault returns a default tls.Config which +// sets its RootCAs to be a *x509.CertPool from caBundlePath. +func (t *DefaultTLSConfigProvider) NewOrDefault() (*tls.Config, error) { + if t.caBundlePath == "" { + return &tls.Config{}, nil + } + + // Keep the current Stat info from the ca bundle in a map + Debugf("Getting Initial Stats for file: %s", t.caBundlePath) + caBundleStat, err := os.Stat(t.caBundlePath) + if err != nil { + return nil, err + } + t.mux.Lock() + defer t.mux.Unlock() + t.currentStat = caBundleStat + + rootCAs, err := CertPoolFrom(t.caBundlePath) + if err != nil { + return nil, err + } + return &tls.Config{ + RootCAs: rootCAs, + }, nil +} + +// WatchedFilesModified returns true if any files in the watchedFilesStatsMap has been modified else returns false +func (t *DefaultTLSConfigProvider) WatchedFilesModified() bool { + modified := false + if t.caBundlePath != "" { + newStat, err := os.Stat(t.caBundlePath) + if err == nil && (t.currentStat.Size() != newStat.Size() || t.currentStat.ModTime() != newStat.ModTime()) { + Logf("Modification detected in cert/ca-bundle file: %s", t.caBundlePath) + modified = true + t.mux.Lock() + defer t.mux.Unlock() + t.currentStat = newStat + } + } + return modified +} + +// DefaultMTLSConfigProvider is a provider that provides a MTLS tls.config for the HTTPTransport +type DefaultMTLSConfigProvider struct { + caBundlePath string + clientCertPath string + clientKeyPath string + mux sync.Mutex + watchedFilesStatsMap map[string]os.FileInfo +} + +// NewOrDefault returns a default tls.Config which sets its RootCAs +// to be a *x509.CertPool from caBundlePath and calls +// tls.LoadX509KeyPair(clientCertPath, clientKeyPath) to set mtls client certs. +func (t *DefaultMTLSConfigProvider) NewOrDefault() (*tls.Config, error) { + rootCAs, err := CertPoolFrom(t.caBundlePath) + if err != nil { + return nil, err + } + cert, err := tls.LoadX509KeyPair(t.clientCertPath, t.clientKeyPath) + if err != nil { + return nil, err + } + + // Configure the initial certs file stats, error skipped because we error out before this if the files don't exist + t.mux.Lock() + defer t.mux.Unlock() + t.watchedFilesStatsMap[t.caBundlePath], _ = os.Stat(t.caBundlePath) + t.watchedFilesStatsMap[t.clientCertPath], _ = os.Stat(t.clientCertPath) + t.watchedFilesStatsMap[t.clientKeyPath], _ = os.Stat(t.clientKeyPath) + + return &tls.Config{ + RootCAs: rootCAs, + Certificates: []tls.Certificate{cert}, + }, nil +} + +// WatchedFilesModified returns true if any files in the watchedFilesStatsMap has been modified else returns false +func (t *DefaultMTLSConfigProvider) WatchedFilesModified() bool { + modified := false + + t.mux.Lock() + defer t.mux.Unlock() + for k, v := range t.watchedFilesStatsMap { + if k != "" { + currentStat, err := os.Stat(k) + if err == nil && (v.Size() != currentStat.Size() || v.ModTime() != currentStat.ModTime()) { + modified = true + Logf("Modification detected in cert/ca-bundle file: %s", k) + t.watchedFilesStatsMap[k] = currentStat + } + } + } + + return modified +} + +// CertPoolFrom creates a new x509.CertPool from a given file. +func CertPoolFrom(caBundleFile string) (*x509.CertPool, error) { + pemCerts, err := os.ReadFile(caBundleFile) + if err != nil { + return nil, err + } + + trust := x509.NewCertPool() + if !trust.AppendCertsFromPEM(pemCerts) { + return nil, fmt.Errorf("creating a new x509.CertPool from %s: no certs added", caBundleFile) + } + + return trust, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/transport_template_provider.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/transport_template_provider.go new file mode 100644 index 00000000000..639e1104af0 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/transport_template_provider.go @@ -0,0 +1,53 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package common + +import ( + "crypto/tls" + "net" + "net/http" + "time" +) + +// TransportTemplateProvider defines a function that creates a new http transport +// from a given TLS client config. +type TransportTemplateProvider func(tlsClientConfig *tls.Config) (http.RoundTripper, error) + +// NewOrDefault creates a new TransportTemplate +// If t is nil, then DefaultTransport is returned +func (t TransportTemplateProvider) NewOrDefault(tlsClientConfig *tls.Config) (http.RoundTripper, error) { + if t == nil { + return DefaultTransport(tlsClientConfig) + } + return t(tlsClientConfig) +} + +// DefaultTransport creates a clone of http.DefaultTransport +// and applies the tlsClientConfig on top of it. +// The result is never nil, to prevent panics in client code. +// Never returns any errors, but needs to return an error +// to adhere to TransportTemplate interface. +func DefaultTransport(tlsClientConfig *tls.Config) (*http.Transport, error) { + transport := CloneHTTPDefaultTransport() + if isExpectHeaderDisabled := IsEnvVarFalse(UsingExpectHeaderEnvVar); !isExpectHeaderDisabled { + transport.Proxy = http.ProxyFromEnvironment + transport.DialContext = (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext + transport.ForceAttemptHTTP2 = true + transport.MaxIdleConns = 100 + transport.IdleConnTimeout = 90 * time.Second + transport.TLSHandshakeTimeout = 10 * time.Second + transport.ExpectContinueTimeout = 3 * time.Second + } + transport.TLSClientConfig = tlsClientConfig + return transport, nil +} + +// CloneHTTPDefaultTransport returns a clone of http.DefaultTransport. +func CloneHTTPDefaultTransport() *http.Transport { + return http.DefaultTransport.(*http.Transport).Clone() +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/utils/opc_request_id.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/utils/opc_request_id.go new file mode 100644 index 00000000000..d82f0bf5e7c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/utils/opc_request_id.go @@ -0,0 +1,30 @@ +package utils + +import ( + "crypto/rand" + "encoding/hex" + "fmt" +) + +// GenerateOpcRequestID - Reference: https://confluence.oci.oraclecorp.com/display/DEX/Request+IDs +// Maximum segment length: 32 characters +// Allowed segment contents: regular expression pattern /^[a-zA-Z0-9]{0,32}$/ +func GenerateOpcRequestID() string { + clientId := generateUniqueID() + stackId := generateUniqueID() + individualId := generateUniqueID() + + opcRequestId := fmt.Sprintf("%s/%s/%s", clientId, stackId, individualId) + + return opcRequestId +} + +func generateUniqueID() string { + b := make([]byte, 16) + _, err := rand.Read(b) + if err != nil { + return "" + } + + return hex.EncodeToString(b) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/common/version.go b/vendor/github.com/oracle/oci-go-sdk/v65/common/version.go new file mode 100644 index 00000000000..f62cbf44c12 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/common/version.go @@ -0,0 +1,37 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated by go generate; DO NOT EDIT + +package common + +import ( + "bytes" + "fmt" + "sync" +) + +const ( + major = "65" + minor = "93" + patch = "1" + tag = "" +) + +var once sync.Once +var version string + +// Version returns semantic version of the sdk +func Version() string { + once.Do(func() { + ver := fmt.Sprintf("%s.%s.%s", major, minor, patch) + verBuilder := bytes.NewBufferString(ver) + if tag != "" && tag != "-" { + _, err := verBuilder.WriteString(tag) + if err != nil { + verBuilder = bytes.NewBufferString(ver) + } + } + version = verBuilder.String() + }) + return version +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/abort_multipart_upload_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/abort_multipart_upload_request_response.go new file mode 100644 index 00000000000..000fc65ac23 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/abort_multipart_upload_request_response.go @@ -0,0 +1,146 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// AbortMultipartUploadRequest wrapper for the AbortMultipartUpload operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/AbortMultipartUpload.go.html to see an example of how to use AbortMultipartUploadRequest. +type AbortMultipartUploadRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // The upload ID for a multipart upload. + UploadId *string `mandatory:"true" contributesTo:"query" name:"uploadId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request AbortMultipartUploadRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request AbortMultipartUploadRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request AbortMultipartUploadRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request AbortMultipartUploadRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["uploadId"] != nil { + templateParam := mandatoryParamMap["uploadId"] + for _, template := range templateParam { + replacementParam := *request.UploadId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request AbortMultipartUploadRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request AbortMultipartUploadRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// AbortMultipartUploadResponse wrapper for the AbortMultipartUpload operation +type AbortMultipartUploadResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response AbortMultipartUploadResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response AbortMultipartUploadResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/access_target_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/access_target_details.go new file mode 100644 index 00000000000..b738e704507 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/access_target_details.go @@ -0,0 +1,48 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// AccessTargetDetails Details of the targets that can be accessed by the private endpoint. +type AccessTargetDetails struct { + + // The Object Storage namespace which the private endpoint can access. Wildcards ('*') are allowed. If value is '*', it means all namespaces can be accessed. It cannot be a regex. + Namespace *string `mandatory:"true" json:"namespace"` + + // The compartment ID which the private endpoint can access. Wildcards ('*') are allowed. If value is '*', it means all compartments in the specified namespace can be accessed. It cannot be a regex. + CompartmentId *string `mandatory:"true" json:"compartmentId"` + + // The name of the bucket. Avoid entering confidential information. Wildcards ('*') are allowed. If value is '*', it means all buckets in the specified namespace and compartment can be accessed. It cannot be a regex. + // Example: my-new-bucket1 + Bucket *string `mandatory:"true" json:"bucket"` +} + +func (m AccessTargetDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m AccessTargetDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/archival_state.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/archival_state.go new file mode 100644 index 00000000000..8d27e0b4e21 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/archival_state.go @@ -0,0 +1,62 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "strings" +) + +// ArchivalStateEnum Enum with underlying type: string +type ArchivalStateEnum string + +// Set of constants representing the allowable values for ArchivalStateEnum +const ( + ArchivalStateArchived ArchivalStateEnum = "Archived" + ArchivalStateRestoring ArchivalStateEnum = "Restoring" + ArchivalStateRestored ArchivalStateEnum = "Restored" +) + +var mappingArchivalStateEnum = map[string]ArchivalStateEnum{ + "Archived": ArchivalStateArchived, + "Restoring": ArchivalStateRestoring, + "Restored": ArchivalStateRestored, +} + +var mappingArchivalStateEnumLowerCase = map[string]ArchivalStateEnum{ + "archived": ArchivalStateArchived, + "restoring": ArchivalStateRestoring, + "restored": ArchivalStateRestored, +} + +// GetArchivalStateEnumValues Enumerates the set of values for ArchivalStateEnum +func GetArchivalStateEnumValues() []ArchivalStateEnum { + values := make([]ArchivalStateEnum, 0) + for _, v := range mappingArchivalStateEnum { + values = append(values, v) + } + return values +} + +// GetArchivalStateEnumStringValues Enumerates the set of values in String for ArchivalStateEnum +func GetArchivalStateEnumStringValues() []string { + return []string{ + "Archived", + "Restoring", + "Restored", + } +} + +// GetMappingArchivalStateEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingArchivalStateEnum(val string) (ArchivalStateEnum, bool) { + enum, ok := mappingArchivalStateEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket.go new file mode 100644 index 00000000000..40cd0ef594d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket.go @@ -0,0 +1,316 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// Bucket A bucket is a container for storing objects in a compartment within a namespace. A bucket is associated with a single compartment. +// The compartment has policies that indicate what actions a user can perform on a bucket and all the objects in the bucket. For more +// information, see Managing Buckets (https://docs.oracle.com/iaas/Content/Object/Tasks/managingbuckets.htm). +// To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type Bucket struct { + + // The Object Storage namespace in which the bucket resides. + Namespace *string `mandatory:"true" json:"namespace"` + + // The name of the bucket. Avoid entering confidential information. + // Example: my-new-bucket1 + Name *string `mandatory:"true" json:"name"` + + // The compartment ID in which the bucket is authorized. + CompartmentId *string `mandatory:"true" json:"compartmentId"` + + // Arbitrary string keys and values for user-defined metadata. + Metadata map[string]string `mandatory:"true" json:"metadata"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the user who created the bucket. + CreatedBy *string `mandatory:"true" json:"createdBy"` + + // The date and time the bucket was created, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The entity tag (ETag) for the bucket. + Etag *string `mandatory:"true" json:"etag"` + + // The type of public access enabled on this bucket. + // A bucket is set to `NoPublicAccess` by default, which only allows an authenticated caller to access the + // bucket and its contents. When `ObjectRead` is enabled on the bucket, public access is allowed for the + // `GetObject`, `HeadObject`, and `ListObjects` operations. When `ObjectReadWithoutList` is enabled on the + // bucket, public access is allowed for the `GetObject` and `HeadObject` operations. + PublicAccessType BucketPublicAccessTypeEnum `mandatory:"false" json:"publicAccessType,omitempty"` + + // The storage tier type assigned to the bucket. A bucket is set to `Standard` tier by default, which means + // objects uploaded or copied to the bucket will be in the standard storage tier. When the `Archive` tier type + // is set explicitly for a bucket, objects uploaded or copied to the bucket will be stored in archive storage. + // The `storageTier` property is immutable after bucket is created. + StorageTier BucketStorageTierEnum `mandatory:"false" json:"storageTier,omitempty"` + + // Whether or not events are emitted for object state changes in this bucket. By default, `objectEventsEnabled` is + // set to `false`. Set `objectEventsEnabled` to `true` to emit events for object state changes. For more information + // about events, see Overview of Events (https://docs.oracle.com/iaas/Content/Events/Concepts/eventsoverview.htm). + ObjectEventsEnabled *bool `mandatory:"false" json:"objectEventsEnabled"` + + // Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Department": "Finance"}` + FreeformTags map[string]string `mandatory:"false" json:"freeformTags"` + + // Defined tags for this resource. Each key is predefined and scoped to a namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Operations": {"CostCenter": "42"}}` + DefinedTags map[string]map[string]interface{} `mandatory:"false" json:"definedTags"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a master encryption key used to call the Key Management + // service to generate a data encryption key or to encrypt or decrypt a data encryption key. + KmsKeyId *string `mandatory:"false" json:"kmsKeyId"` + + // The entity tag (ETag) for the live object lifecycle policy on the bucket. + ObjectLifecyclePolicyEtag *string `mandatory:"false" json:"objectLifecyclePolicyEtag"` + + // The approximate number of objects in the bucket. Count statistics are reported periodically. You will see a + // lag between what is displayed and the actual object count. + ApproximateCount *int64 `mandatory:"false" json:"approximateCount"` + + // The approximate total size in bytes of all objects in the bucket. Size statistics are reported periodically. You will + // see a lag between what is displayed and the actual size of the bucket. + ApproximateSize *int64 `mandatory:"false" json:"approximateSize"` + + // Whether or not this bucket is a replication source. By default, `replicationEnabled` is set to `false`. This will + // be set to 'true' when you create a replication policy for the bucket. + ReplicationEnabled *bool `mandatory:"false" json:"replicationEnabled"` + + // Whether or not this bucket is read only. By default, `isReadOnly` is set to `false`. This will + // be set to 'true' when this bucket is configured as a destination in a replication policy. + IsReadOnly *bool `mandatory:"false" json:"isReadOnly"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the bucket. + Id *string `mandatory:"false" json:"id"` + + // The versioning status on the bucket. A bucket is created with versioning `Disabled` by default. + // For versioning `Enabled`, objects are protected from overwrites and deletes, by maintaining their version history. When versioning is `Suspended`, the previous versions will still remain but new versions will no longer be created when overwitten or deleted. + Versioning BucketVersioningEnum `mandatory:"false" json:"versioning,omitempty"` + + // The auto tiering status on the bucket. A bucket is created with auto tiering `Disabled` by default. + // For auto tiering `InfrequentAccess`, objects are transitioned automatically between the 'Standard' + // and 'InfrequentAccess' tiers based on the access pattern of the objects. + AutoTiering BucketAutoTieringEnum `mandatory:"false" json:"autoTiering,omitempty"` +} + +func (m Bucket) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m Bucket) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingBucketPublicAccessTypeEnum(string(m.PublicAccessType)); !ok && m.PublicAccessType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for PublicAccessType: %s. Supported values are: %s.", m.PublicAccessType, strings.Join(GetBucketPublicAccessTypeEnumStringValues(), ","))) + } + if _, ok := GetMappingBucketStorageTierEnum(string(m.StorageTier)); !ok && m.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", m.StorageTier, strings.Join(GetBucketStorageTierEnumStringValues(), ","))) + } + if _, ok := GetMappingBucketVersioningEnum(string(m.Versioning)); !ok && m.Versioning != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Versioning: %s. Supported values are: %s.", m.Versioning, strings.Join(GetBucketVersioningEnumStringValues(), ","))) + } + if _, ok := GetMappingBucketAutoTieringEnum(string(m.AutoTiering)); !ok && m.AutoTiering != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for AutoTiering: %s. Supported values are: %s.", m.AutoTiering, strings.Join(GetBucketAutoTieringEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// BucketPublicAccessTypeEnum Enum with underlying type: string +type BucketPublicAccessTypeEnum string + +// Set of constants representing the allowable values for BucketPublicAccessTypeEnum +const ( + BucketPublicAccessTypeNopublicaccess BucketPublicAccessTypeEnum = "NoPublicAccess" + BucketPublicAccessTypeObjectread BucketPublicAccessTypeEnum = "ObjectRead" + BucketPublicAccessTypeObjectreadwithoutlist BucketPublicAccessTypeEnum = "ObjectReadWithoutList" +) + +var mappingBucketPublicAccessTypeEnum = map[string]BucketPublicAccessTypeEnum{ + "NoPublicAccess": BucketPublicAccessTypeNopublicaccess, + "ObjectRead": BucketPublicAccessTypeObjectread, + "ObjectReadWithoutList": BucketPublicAccessTypeObjectreadwithoutlist, +} + +var mappingBucketPublicAccessTypeEnumLowerCase = map[string]BucketPublicAccessTypeEnum{ + "nopublicaccess": BucketPublicAccessTypeNopublicaccess, + "objectread": BucketPublicAccessTypeObjectread, + "objectreadwithoutlist": BucketPublicAccessTypeObjectreadwithoutlist, +} + +// GetBucketPublicAccessTypeEnumValues Enumerates the set of values for BucketPublicAccessTypeEnum +func GetBucketPublicAccessTypeEnumValues() []BucketPublicAccessTypeEnum { + values := make([]BucketPublicAccessTypeEnum, 0) + for _, v := range mappingBucketPublicAccessTypeEnum { + values = append(values, v) + } + return values +} + +// GetBucketPublicAccessTypeEnumStringValues Enumerates the set of values in String for BucketPublicAccessTypeEnum +func GetBucketPublicAccessTypeEnumStringValues() []string { + return []string{ + "NoPublicAccess", + "ObjectRead", + "ObjectReadWithoutList", + } +} + +// GetMappingBucketPublicAccessTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingBucketPublicAccessTypeEnum(val string) (BucketPublicAccessTypeEnum, bool) { + enum, ok := mappingBucketPublicAccessTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// BucketStorageTierEnum Enum with underlying type: string +type BucketStorageTierEnum string + +// Set of constants representing the allowable values for BucketStorageTierEnum +const ( + BucketStorageTierStandard BucketStorageTierEnum = "Standard" + BucketStorageTierArchive BucketStorageTierEnum = "Archive" +) + +var mappingBucketStorageTierEnum = map[string]BucketStorageTierEnum{ + "Standard": BucketStorageTierStandard, + "Archive": BucketStorageTierArchive, +} + +var mappingBucketStorageTierEnumLowerCase = map[string]BucketStorageTierEnum{ + "standard": BucketStorageTierStandard, + "archive": BucketStorageTierArchive, +} + +// GetBucketStorageTierEnumValues Enumerates the set of values for BucketStorageTierEnum +func GetBucketStorageTierEnumValues() []BucketStorageTierEnum { + values := make([]BucketStorageTierEnum, 0) + for _, v := range mappingBucketStorageTierEnum { + values = append(values, v) + } + return values +} + +// GetBucketStorageTierEnumStringValues Enumerates the set of values in String for BucketStorageTierEnum +func GetBucketStorageTierEnumStringValues() []string { + return []string{ + "Standard", + "Archive", + } +} + +// GetMappingBucketStorageTierEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingBucketStorageTierEnum(val string) (BucketStorageTierEnum, bool) { + enum, ok := mappingBucketStorageTierEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// BucketVersioningEnum Enum with underlying type: string +type BucketVersioningEnum string + +// Set of constants representing the allowable values for BucketVersioningEnum +const ( + BucketVersioningEnabled BucketVersioningEnum = "Enabled" + BucketVersioningSuspended BucketVersioningEnum = "Suspended" + BucketVersioningDisabled BucketVersioningEnum = "Disabled" +) + +var mappingBucketVersioningEnum = map[string]BucketVersioningEnum{ + "Enabled": BucketVersioningEnabled, + "Suspended": BucketVersioningSuspended, + "Disabled": BucketVersioningDisabled, +} + +var mappingBucketVersioningEnumLowerCase = map[string]BucketVersioningEnum{ + "enabled": BucketVersioningEnabled, + "suspended": BucketVersioningSuspended, + "disabled": BucketVersioningDisabled, +} + +// GetBucketVersioningEnumValues Enumerates the set of values for BucketVersioningEnum +func GetBucketVersioningEnumValues() []BucketVersioningEnum { + values := make([]BucketVersioningEnum, 0) + for _, v := range mappingBucketVersioningEnum { + values = append(values, v) + } + return values +} + +// GetBucketVersioningEnumStringValues Enumerates the set of values in String for BucketVersioningEnum +func GetBucketVersioningEnumStringValues() []string { + return []string{ + "Enabled", + "Suspended", + "Disabled", + } +} + +// GetMappingBucketVersioningEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingBucketVersioningEnum(val string) (BucketVersioningEnum, bool) { + enum, ok := mappingBucketVersioningEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// BucketAutoTieringEnum Enum with underlying type: string +type BucketAutoTieringEnum string + +// Set of constants representing the allowable values for BucketAutoTieringEnum +const ( + BucketAutoTieringDisabled BucketAutoTieringEnum = "Disabled" + BucketAutoTieringInfrequentaccess BucketAutoTieringEnum = "InfrequentAccess" +) + +var mappingBucketAutoTieringEnum = map[string]BucketAutoTieringEnum{ + "Disabled": BucketAutoTieringDisabled, + "InfrequentAccess": BucketAutoTieringInfrequentaccess, +} + +var mappingBucketAutoTieringEnumLowerCase = map[string]BucketAutoTieringEnum{ + "disabled": BucketAutoTieringDisabled, + "infrequentaccess": BucketAutoTieringInfrequentaccess, +} + +// GetBucketAutoTieringEnumValues Enumerates the set of values for BucketAutoTieringEnum +func GetBucketAutoTieringEnumValues() []BucketAutoTieringEnum { + values := make([]BucketAutoTieringEnum, 0) + for _, v := range mappingBucketAutoTieringEnum { + values = append(values, v) + } + return values +} + +// GetBucketAutoTieringEnumStringValues Enumerates the set of values in String for BucketAutoTieringEnum +func GetBucketAutoTieringEnumStringValues() []string { + return []string{ + "Disabled", + "InfrequentAccess", + } +} + +// GetMappingBucketAutoTieringEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingBucketAutoTieringEnum(val string) (BucketAutoTieringEnum, bool) { + enum, ok := mappingBucketAutoTieringEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket_summary.go new file mode 100644 index 00000000000..edb6aabd59c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/bucket_summary.go @@ -0,0 +1,69 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// BucketSummary To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type BucketSummary struct { + + // The Object Storage namespace in which the bucket lives. + Namespace *string `mandatory:"true" json:"namespace"` + + // The name of the bucket. Avoid entering confidential information. + // Example: my-new-bucket1 + Name *string `mandatory:"true" json:"name"` + + // The compartment ID in which the bucket is authorized. + CompartmentId *string `mandatory:"true" json:"compartmentId"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the user who created the bucket. + CreatedBy *string `mandatory:"true" json:"createdBy"` + + // The date and time the bucket was created, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The entity tag (ETag) for the bucket. + Etag *string `mandatory:"true" json:"etag"` + + // Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Department": "Finance"}` + FreeformTags map[string]string `mandatory:"false" json:"freeformTags"` + + // Defined tags for this resource. Each key is predefined and scoped to a namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Operations": {"CostCenter": "42"}}` + DefinedTags map[string]map[string]interface{} `mandatory:"false" json:"definedTags"` +} + +func (m BucketSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m BucketSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/cancel_work_request_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/cancel_work_request_request_response.go new file mode 100644 index 00000000000..2dfd679eb55 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/cancel_work_request_request_response.go @@ -0,0 +1,105 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CancelWorkRequestRequest wrapper for the CancelWorkRequest operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CancelWorkRequest.go.html to see an example of how to use CancelWorkRequestRequest. +type CancelWorkRequestRequest struct { + + // The ID of the asynchronous request. + WorkRequestId *string `mandatory:"true" contributesTo:"path" name:"workRequestId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CancelWorkRequestRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CancelWorkRequestRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CancelWorkRequestRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CancelWorkRequestRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["workRequestId"] != nil { + templateParam := mandatoryParamMap["workRequestId"] + for _, template := range templateParam { + replacementParam := *request.WorkRequestId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CancelWorkRequestRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CancelWorkRequestRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CancelWorkRequestResponse wrapper for the CancelWorkRequest operation +type CancelWorkRequestResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response CancelWorkRequestResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CancelWorkRequestResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/checksum_algorithm.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/checksum_algorithm.go new file mode 100644 index 00000000000..7fb6b8046b4 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/checksum_algorithm.go @@ -0,0 +1,62 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "strings" +) + +// ChecksumAlgorithmEnum Enum with underlying type: string +type ChecksumAlgorithmEnum string + +// Set of constants representing the allowable values for ChecksumAlgorithmEnum +const ( + ChecksumAlgorithmCrc32C ChecksumAlgorithmEnum = "CRC32C" + ChecksumAlgorithmSha256 ChecksumAlgorithmEnum = "SHA256" + ChecksumAlgorithmSha384 ChecksumAlgorithmEnum = "SHA384" +) + +var mappingChecksumAlgorithmEnum = map[string]ChecksumAlgorithmEnum{ + "CRC32C": ChecksumAlgorithmCrc32C, + "SHA256": ChecksumAlgorithmSha256, + "SHA384": ChecksumAlgorithmSha384, +} + +var mappingChecksumAlgorithmEnumLowerCase = map[string]ChecksumAlgorithmEnum{ + "crc32c": ChecksumAlgorithmCrc32C, + "sha256": ChecksumAlgorithmSha256, + "sha384": ChecksumAlgorithmSha384, +} + +// GetChecksumAlgorithmEnumValues Enumerates the set of values for ChecksumAlgorithmEnum +func GetChecksumAlgorithmEnumValues() []ChecksumAlgorithmEnum { + values := make([]ChecksumAlgorithmEnum, 0) + for _, v := range mappingChecksumAlgorithmEnum { + values = append(values, v) + } + return values +} + +// GetChecksumAlgorithmEnumStringValues Enumerates the set of values in String for ChecksumAlgorithmEnum +func GetChecksumAlgorithmEnumStringValues() []string { + return []string{ + "CRC32C", + "SHA256", + "SHA384", + } +} + +// GetMappingChecksumAlgorithmEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingChecksumAlgorithmEnum(val string) (ChecksumAlgorithmEnum, bool) { + enum, ok := mappingChecksumAlgorithmEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_details.go new file mode 100644 index 00000000000..0ee68410dff --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_details.go @@ -0,0 +1,47 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CommitMultipartUploadDetails To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type CommitMultipartUploadDetails struct { + + // The part numbers and entity tags (ETags) for the parts to be committed. + PartsToCommit []CommitMultipartUploadPartDetails `mandatory:"true" json:"partsToCommit"` + + // The part numbers for the parts to be excluded from the completed object. + // Each part created for this upload must be in either partsToExclude or partsToCommit, but cannot be in both. + PartsToExclude []int `mandatory:"false" json:"partsToExclude"` +} + +func (m CommitMultipartUploadDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CommitMultipartUploadDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_part_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_part_details.go new file mode 100644 index 00000000000..0cc13938416 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_part_details.go @@ -0,0 +1,46 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CommitMultipartUploadPartDetails To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type CommitMultipartUploadPartDetails struct { + + // The part number for this part. + PartNum *int `mandatory:"true" json:"partNum"` + + // The entity tag (ETag) returned when this part was uploaded. + Etag *string `mandatory:"true" json:"etag"` +} + +func (m CommitMultipartUploadPartDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CommitMultipartUploadPartDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_request_response.go new file mode 100644 index 00000000000..1f9f5fb2573 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/commit_multipart_upload_request_response.go @@ -0,0 +1,193 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CommitMultipartUploadRequest wrapper for the CommitMultipartUpload operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CommitMultipartUpload.go.html to see an example of how to use CommitMultipartUploadRequest. +type CommitMultipartUploadRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // The upload ID for a multipart upload. + UploadId *string `mandatory:"true" contributesTo:"query" name:"uploadId"` + + // The part numbers and entity tags (ETags) for the parts you want to commit. + CommitMultipartUploadDetails `contributesTo:"body"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. The only valid value is '*', which indicates that the request should + // fail if the resource already exists. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CommitMultipartUploadRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CommitMultipartUploadRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CommitMultipartUploadRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CommitMultipartUploadRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["uploadId"] != nil { + templateParam := mandatoryParamMap["uploadId"] + for _, template := range templateParam { + replacementParam := *request.UploadId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CommitMultipartUploadRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CommitMultipartUploadRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CommitMultipartUploadResponse wrapper for the CommitMultipartUpload operation +type CommitMultipartUploadResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Base-64 representation of the multipart object MD5 hash. + // The multipart object hash is calculated by taking the MD5 hashes of the parts passed to this call, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the MD5 hash of the concatenated values. The multipart object hash is followed + // by a hyphen and the total number of parts (for example, '-6'). + OpcMultipartMd5 *string `presentIn:"header" name:"opc-multipart-md5"` + + // The base64-encoded, 32-bit CRC32C (Castagnoli) checksum of the object. + // Even for objects uploaded using multipart upload, this header returns the CRC32C (Castagnoli) checksum + // of the complete reconstructed object. + OpcContentCrc32c *string `presentIn:"header" name:"opc-content-crc32c"` + + // Base-64 representation of the multipart object SHA256 hash. + // The multipart object hash is calculated by taking the SHA256 hashes of the parts passed to this call, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the SHA256 hash of the concatenated values. The multipart object hash is followed + // by a hyphen and the total number of parts (for example, '-6'). + OpcMultipartSha256 *string `presentIn:"header" name:"opc-multipart-sha256"` + + // Base-64 representation of the multipart object SHA384 hash. + // The multipart object hash is calculated by taking the SHA384 hashes of the parts passed to this call, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the SHA384 hash of the concatenated values. The multipart object hash is followed + // by a hyphen and the total number of parts (for example, '-6'). + OpcMultipartSha384 *string `presentIn:"header" name:"opc-multipart-sha384"` + + // The entity tag (ETag) for the object. + ETag *string `presentIn:"header" name:"etag"` + + // The time the object was last modified, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + LastModified *common.SDKTime `presentIn:"header" name:"last-modified"` + + // VersionId of the newly created object + VersionId *string `presentIn:"header" name:"version-id"` +} + +func (response CommitMultipartUploadResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CommitMultipartUploadResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_details.go new file mode 100644 index 00000000000..b796fcda18c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_details.go @@ -0,0 +1,85 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CopyObjectDetails The parameters required by Object Storage to process a request to copy an object to another bucket. +// To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type CopyObjectDetails struct { + + // The name of the object to be copied. + SourceObjectName *string `mandatory:"true" json:"sourceObjectName"` + + // The destination region the object will be copied to, for example "us-ashburn-1". + DestinationRegion *string `mandatory:"true" json:"destinationRegion"` + + // The destination Object Storage namespace the object will be copied to. + DestinationNamespace *string `mandatory:"true" json:"destinationNamespace"` + + // The destination bucket the object will be copied to. + DestinationBucket *string `mandatory:"true" json:"destinationBucket"` + + // The name of the destination object resulting from the copy operation. Avoid entering confidential information. + DestinationObjectName *string `mandatory:"true" json:"destinationObjectName"` + + // The entity tag (ETag) to match against that of the source object. Used to confirm that the source object + // with a given name is the version of that object storing a specified ETag. + SourceObjectIfMatchETag *string `mandatory:"false" json:"sourceObjectIfMatchETag"` + + // VersionId of the object to copy. If not provided then current version is copied by default. + SourceVersionId *string `mandatory:"false" json:"sourceVersionId"` + + // The entity tag (ETag) to match against that of the destination object (an object intended to be overwritten). + // Used to confirm that the destination object stored under a given name is the version of that object + // storing a specified entity tag. + DestinationObjectIfMatchETag *string `mandatory:"false" json:"destinationObjectIfMatchETag"` + + // The entity tag (ETag) to avoid matching. The only valid value is '*', which indicates that the request should fail + // if the object already exists in the destination bucket. + DestinationObjectIfNoneMatchETag *string `mandatory:"false" json:"destinationObjectIfNoneMatchETag"` + + // Arbitrary string keys and values for the user-defined metadata for the object. Keys must be in + // "opc-meta-*" format. Avoid entering confidential information. Metadata key-value pairs entered + // in this field are assigned to the destination object. If you enter no metadata values, the destination + // object will inherit any existing metadata values associated with the source object. + DestinationObjectMetadata map[string]string `mandatory:"false" json:"destinationObjectMetadata"` + + // The storage tier that the object should be stored in. If not specified, the object will be stored in + // the same storage tier as the bucket. + DestinationObjectStorageTier StorageTierEnum `mandatory:"false" json:"destinationObjectStorageTier,omitempty"` +} + +func (m CopyObjectDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CopyObjectDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingStorageTierEnum(string(m.DestinationObjectStorageTier)); !ok && m.DestinationObjectStorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for DestinationObjectStorageTier: %s. Supported values are: %s.", m.DestinationObjectStorageTier, strings.Join(GetStorageTierEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_request_response.go new file mode 100644 index 00000000000..71e63bbc760 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/copy_object_request_response.go @@ -0,0 +1,160 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CopyObjectRequest wrapper for the CopyObject operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CopyObject.go.html to see an example of how to use CopyObjectRequest. +type CopyObjectRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The source and destination of the object to be copied. + CopyObjectDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The optional header that specifies "AES256" as the encryption algorithm. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerAlgorithm *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-algorithm"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or + // decrypt the data. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKey *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This + // value is used to check the integrity of the encryption key. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKeySha256 *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key-sha256"` + + // The optional header that specifies "AES256" as the encryption algorithm to use to decrypt the source + // object. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSourceSseCustomerAlgorithm *string `mandatory:"false" contributesTo:"header" name:"opc-source-sse-customer-algorithm"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to decrypt + // the source object. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSourceSseCustomerKey *string `mandatory:"false" contributesTo:"header" name:"opc-source-sse-customer-key"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key used to + // decrypt the source object. This value is used to check the integrity of the encryption key. For + // more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSourceSseCustomerKeySha256 *string `mandatory:"false" contributesTo:"header" name:"opc-source-sse-customer-key-sha256"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a master encryption key used to call the Key + // Management service to generate a data encryption key or to encrypt or decrypt a data encryption key. + OpcSseKmsKeyId *string `mandatory:"false" contributesTo:"header" name:"opc-sse-kms-key-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CopyObjectRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CopyObjectRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CopyObjectRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CopyObjectRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CopyObjectRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CopyObjectRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CopyObjectResponse wrapper for the CopyObject operation +type CopyObjectResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the asynchronous request. If you need to contact Oracle about a + // particular request, provide this request ID. + OpcWorkRequestId *string `presentIn:"header" name:"opc-work-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response CopyObjectResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CopyObjectResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_details.go new file mode 100644 index 00000000000..394c11bbdde --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_details.go @@ -0,0 +1,234 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CreateBucketDetails To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type CreateBucketDetails struct { + + // The name of the bucket. Valid characters are uppercase or lowercase letters, numbers, hyphens, underscores, and periods. + // Bucket names must be unique within an Object Storage namespace. Avoid entering confidential information. + // example: Example: my-new-bucket1 + Name *string `mandatory:"true" json:"name"` + + // The ID of the compartment in which to create the bucket. + CompartmentId *string `mandatory:"true" json:"compartmentId"` + + // Arbitrary string, up to 4KB, of keys and values for user-defined metadata. + Metadata map[string]string `mandatory:"false" json:"metadata"` + + // The type of public access enabled on this bucket. + // A bucket is set to `NoPublicAccess` by default, which only allows an authenticated caller to access the + // bucket and its contents. When `ObjectRead` is enabled on the bucket, public access is allowed for the + // `GetObject`, `HeadObject`, and `ListObjects` operations. When `ObjectReadWithoutList` is enabled on the bucket, + // public access is allowed for the `GetObject` and `HeadObject` operations. + PublicAccessType CreateBucketDetailsPublicAccessTypeEnum `mandatory:"false" json:"publicAccessType,omitempty"` + + // The type of storage tier of this bucket. + // A bucket is set to 'Standard' tier by default, which means the bucket will be put in the standard storage tier. + // When 'Archive' tier type is set explicitly, the bucket is put in the Archive Storage tier. The 'storageTier' + // property is immutable after bucket is created. + StorageTier CreateBucketDetailsStorageTierEnum `mandatory:"false" json:"storageTier,omitempty"` + + // Whether or not events are emitted for object state changes in this bucket. By default, `objectEventsEnabled` is + // set to `false`. Set `objectEventsEnabled` to `true` to emit events for object state changes. For more information + // about events, see Overview of Events (https://docs.oracle.com/iaas/Content/Events/Concepts/eventsoverview.htm). + ObjectEventsEnabled *bool `mandatory:"false" json:"objectEventsEnabled"` + + // Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Department": "Finance"}` + FreeformTags map[string]string `mandatory:"false" json:"freeformTags"` + + // Defined tags for this resource. Each key is predefined and scoped to a namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Operations": {"CostCenter": "42"}}` + DefinedTags map[string]map[string]interface{} `mandatory:"false" json:"definedTags"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a master encryption key used to call the Key + // Management service to generate a data encryption key or to encrypt or decrypt a data encryption key. + KmsKeyId *string `mandatory:"false" json:"kmsKeyId"` + + // Set the versioning status on the bucket. By default, a bucket is created with versioning `Disabled`. Use this option to enable versioning during bucket creation. Objects in a version enabled bucket are protected from overwrites and deletions. Previous versions of the same object will be available in the bucket. + Versioning CreateBucketDetailsVersioningEnum `mandatory:"false" json:"versioning,omitempty"` + + // Set the auto tiering status on the bucket. By default, a bucket is created with auto tiering `Disabled`. + // Use this option to enable auto tiering during bucket creation. Objects in a bucket with auto tiering set to + // `InfrequentAccess` are transitioned automatically between the 'Standard' and 'InfrequentAccess' + // tiers based on the access pattern of the objects. + AutoTiering BucketAutoTieringEnum `mandatory:"false" json:"autoTiering,omitempty"` +} + +func (m CreateBucketDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CreateBucketDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingCreateBucketDetailsPublicAccessTypeEnum(string(m.PublicAccessType)); !ok && m.PublicAccessType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for PublicAccessType: %s. Supported values are: %s.", m.PublicAccessType, strings.Join(GetCreateBucketDetailsPublicAccessTypeEnumStringValues(), ","))) + } + if _, ok := GetMappingCreateBucketDetailsStorageTierEnum(string(m.StorageTier)); !ok && m.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", m.StorageTier, strings.Join(GetCreateBucketDetailsStorageTierEnumStringValues(), ","))) + } + if _, ok := GetMappingCreateBucketDetailsVersioningEnum(string(m.Versioning)); !ok && m.Versioning != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Versioning: %s. Supported values are: %s.", m.Versioning, strings.Join(GetCreateBucketDetailsVersioningEnumStringValues(), ","))) + } + if _, ok := GetMappingBucketAutoTieringEnum(string(m.AutoTiering)); !ok && m.AutoTiering != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for AutoTiering: %s. Supported values are: %s.", m.AutoTiering, strings.Join(GetBucketAutoTieringEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreateBucketDetailsPublicAccessTypeEnum Enum with underlying type: string +type CreateBucketDetailsPublicAccessTypeEnum string + +// Set of constants representing the allowable values for CreateBucketDetailsPublicAccessTypeEnum +const ( + CreateBucketDetailsPublicAccessTypeNopublicaccess CreateBucketDetailsPublicAccessTypeEnum = "NoPublicAccess" + CreateBucketDetailsPublicAccessTypeObjectread CreateBucketDetailsPublicAccessTypeEnum = "ObjectRead" + CreateBucketDetailsPublicAccessTypeObjectreadwithoutlist CreateBucketDetailsPublicAccessTypeEnum = "ObjectReadWithoutList" +) + +var mappingCreateBucketDetailsPublicAccessTypeEnum = map[string]CreateBucketDetailsPublicAccessTypeEnum{ + "NoPublicAccess": CreateBucketDetailsPublicAccessTypeNopublicaccess, + "ObjectRead": CreateBucketDetailsPublicAccessTypeObjectread, + "ObjectReadWithoutList": CreateBucketDetailsPublicAccessTypeObjectreadwithoutlist, +} + +var mappingCreateBucketDetailsPublicAccessTypeEnumLowerCase = map[string]CreateBucketDetailsPublicAccessTypeEnum{ + "nopublicaccess": CreateBucketDetailsPublicAccessTypeNopublicaccess, + "objectread": CreateBucketDetailsPublicAccessTypeObjectread, + "objectreadwithoutlist": CreateBucketDetailsPublicAccessTypeObjectreadwithoutlist, +} + +// GetCreateBucketDetailsPublicAccessTypeEnumValues Enumerates the set of values for CreateBucketDetailsPublicAccessTypeEnum +func GetCreateBucketDetailsPublicAccessTypeEnumValues() []CreateBucketDetailsPublicAccessTypeEnum { + values := make([]CreateBucketDetailsPublicAccessTypeEnum, 0) + for _, v := range mappingCreateBucketDetailsPublicAccessTypeEnum { + values = append(values, v) + } + return values +} + +// GetCreateBucketDetailsPublicAccessTypeEnumStringValues Enumerates the set of values in String for CreateBucketDetailsPublicAccessTypeEnum +func GetCreateBucketDetailsPublicAccessTypeEnumStringValues() []string { + return []string{ + "NoPublicAccess", + "ObjectRead", + "ObjectReadWithoutList", + } +} + +// GetMappingCreateBucketDetailsPublicAccessTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingCreateBucketDetailsPublicAccessTypeEnum(val string) (CreateBucketDetailsPublicAccessTypeEnum, bool) { + enum, ok := mappingCreateBucketDetailsPublicAccessTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// CreateBucketDetailsStorageTierEnum Enum with underlying type: string +type CreateBucketDetailsStorageTierEnum string + +// Set of constants representing the allowable values for CreateBucketDetailsStorageTierEnum +const ( + CreateBucketDetailsStorageTierStandard CreateBucketDetailsStorageTierEnum = "Standard" + CreateBucketDetailsStorageTierArchive CreateBucketDetailsStorageTierEnum = "Archive" +) + +var mappingCreateBucketDetailsStorageTierEnum = map[string]CreateBucketDetailsStorageTierEnum{ + "Standard": CreateBucketDetailsStorageTierStandard, + "Archive": CreateBucketDetailsStorageTierArchive, +} + +var mappingCreateBucketDetailsStorageTierEnumLowerCase = map[string]CreateBucketDetailsStorageTierEnum{ + "standard": CreateBucketDetailsStorageTierStandard, + "archive": CreateBucketDetailsStorageTierArchive, +} + +// GetCreateBucketDetailsStorageTierEnumValues Enumerates the set of values for CreateBucketDetailsStorageTierEnum +func GetCreateBucketDetailsStorageTierEnumValues() []CreateBucketDetailsStorageTierEnum { + values := make([]CreateBucketDetailsStorageTierEnum, 0) + for _, v := range mappingCreateBucketDetailsStorageTierEnum { + values = append(values, v) + } + return values +} + +// GetCreateBucketDetailsStorageTierEnumStringValues Enumerates the set of values in String for CreateBucketDetailsStorageTierEnum +func GetCreateBucketDetailsStorageTierEnumStringValues() []string { + return []string{ + "Standard", + "Archive", + } +} + +// GetMappingCreateBucketDetailsStorageTierEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingCreateBucketDetailsStorageTierEnum(val string) (CreateBucketDetailsStorageTierEnum, bool) { + enum, ok := mappingCreateBucketDetailsStorageTierEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// CreateBucketDetailsVersioningEnum Enum with underlying type: string +type CreateBucketDetailsVersioningEnum string + +// Set of constants representing the allowable values for CreateBucketDetailsVersioningEnum +const ( + CreateBucketDetailsVersioningEnabled CreateBucketDetailsVersioningEnum = "Enabled" + CreateBucketDetailsVersioningDisabled CreateBucketDetailsVersioningEnum = "Disabled" +) + +var mappingCreateBucketDetailsVersioningEnum = map[string]CreateBucketDetailsVersioningEnum{ + "Enabled": CreateBucketDetailsVersioningEnabled, + "Disabled": CreateBucketDetailsVersioningDisabled, +} + +var mappingCreateBucketDetailsVersioningEnumLowerCase = map[string]CreateBucketDetailsVersioningEnum{ + "enabled": CreateBucketDetailsVersioningEnabled, + "disabled": CreateBucketDetailsVersioningDisabled, +} + +// GetCreateBucketDetailsVersioningEnumValues Enumerates the set of values for CreateBucketDetailsVersioningEnum +func GetCreateBucketDetailsVersioningEnumValues() []CreateBucketDetailsVersioningEnum { + values := make([]CreateBucketDetailsVersioningEnum, 0) + for _, v := range mappingCreateBucketDetailsVersioningEnum { + values = append(values, v) + } + return values +} + +// GetCreateBucketDetailsVersioningEnumStringValues Enumerates the set of values in String for CreateBucketDetailsVersioningEnum +func GetCreateBucketDetailsVersioningEnumStringValues() []string { + return []string{ + "Enabled", + "Disabled", + } +} + +// GetMappingCreateBucketDetailsVersioningEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingCreateBucketDetailsVersioningEnum(val string) (CreateBucketDetailsVersioningEnum, bool) { + enum, ok := mappingCreateBucketDetailsVersioningEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_request_response.go new file mode 100644 index 00000000000..7c52535b6ea --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_bucket_request_response.go @@ -0,0 +1,117 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CreateBucketRequest wrapper for the CreateBucket operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateBucket.go.html to see an example of how to use CreateBucketRequest. +type CreateBucketRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // Request object for creating a bucket. + CreateBucketDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CreateBucketRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CreateBucketRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CreateBucketRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CreateBucketRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CreateBucketRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CreateBucketRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreateBucketResponse wrapper for the CreateBucket operation +type CreateBucketResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The Bucket instance + Bucket `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the bucket that was created. + ETag *string `presentIn:"header" name:"etag"` + + // The full path to the bucket that was created. + Location *string `presentIn:"header" name:"location"` +} + +func (response CreateBucketResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CreateBucketResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_details.go new file mode 100644 index 00000000000..f69e35ee600 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_details.go @@ -0,0 +1,86 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CreateMultipartUploadDetails To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type CreateMultipartUploadDetails struct { + + // The name of the object to which this multi-part upload is targeted. Avoid entering confidential information. + // Example: test/object1.log + Object *string `mandatory:"true" json:"object"` + + // The optional Content-Type header that defines the standard MIME type format of the object to upload. + // Specifying values for this header has no effect on Object Storage behavior. Programs that read the object + // determine what to do based on the value provided. For example, you could use this header to identify and + // perform special operations on text only objects. + ContentType *string `mandatory:"false" json:"contentType"` + + // The optional Content-Language header that defines the content language of the object to upload. Specifying + // values for this header has no effect on Object Storage behavior. Programs that read the object determine what + // to do based on the value provided. For example, you could use this header to identify and differentiate objects + // based on a particular language. + ContentLanguage *string `mandatory:"false" json:"contentLanguage"` + + // The optional Content-Encoding header that defines the content encodings that were applied to the object to + // upload. Specifying values for this header has no effect on Object Storage behavior. Programs that read the + // object determine what to do based on the value provided. For example, you could use this header to determine + // what decoding mechanisms need to be applied to obtain the media-type specified by the Content-Type header of + // the object. + ContentEncoding *string `mandatory:"false" json:"contentEncoding"` + + // The optional Content-Disposition header that defines presentational information for the object to be + // returned in GetObject and HeadObject responses. Specifying values for this header has no effect on Object + // Storage behavior. Programs that read the object determine what to do based on the value provided. + // For example, you could use this header to let users download objects with custom filenames in a browser. + ContentDisposition *string `mandatory:"false" json:"contentDisposition"` + + // The optional Cache-Control header that defines the caching behavior value to be returned in GetObject and + // HeadObject responses. Specifying values for this header has no effect on Object Storage behavior. Programs + // that read the object determine what to do based on the value provided. + // For example, you could use this header to identify objects that require caching restrictions. + CacheControl *string `mandatory:"false" json:"cacheControl"` + + // The storage tier that the object should be stored in. If not specified, the object will be stored in + // the same storage tier as the bucket. + StorageTier StorageTierEnum `mandatory:"false" json:"storageTier,omitempty"` + + // Arbitrary string keys and values for the user-defined metadata for the object. + // Keys must be in "opc-meta-*" format. Avoid entering confidential information. + Metadata map[string]string `mandatory:"false" json:"metadata"` +} + +func (m CreateMultipartUploadDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CreateMultipartUploadDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingStorageTierEnum(string(m.StorageTier)); !ok && m.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", m.StorageTier, strings.Join(GetStorageTierEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_request_response.go new file mode 100644 index 00000000000..94570021ded --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_multipart_upload_request_response.go @@ -0,0 +1,208 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CreateMultipartUploadRequest wrapper for the CreateMultipartUpload operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateMultipartUpload.go.html to see an example of how to use CreateMultipartUploadRequest. +type CreateMultipartUploadRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // Request object for creating a multipart upload. + CreateMultipartUploadDetails `contributesTo:"body"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. The only valid value is '*', which indicates that the request should + // fail if the resource already exists. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The optional header that specifies "AES256" as the encryption algorithm. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerAlgorithm *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-algorithm"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or + // decrypt the data. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKey *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This + // value is used to check the integrity of the encryption key. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKeySha256 *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key-sha256"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a master encryption key used to call the Key + // Management service to generate a data encryption key or to encrypt or decrypt a data encryption key. + OpcSseKmsKeyId *string `mandatory:"false" contributesTo:"header" name:"opc-sse-kms-key-id"` + + // The optional checksum algorithm to use to compute and store the checksum of the body of the HTTP request (or the parts in case of multipart uploads), + // in addition to the default MD5 checksum. + OpcChecksumAlgorithm CreateMultipartUploadOpcChecksumAlgorithmEnum `mandatory:"false" contributesTo:"header" name:"opc-checksum-algorithm"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CreateMultipartUploadRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CreateMultipartUploadRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CreateMultipartUploadRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CreateMultipartUploadRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CreateMultipartUploadRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CreateMultipartUploadRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingCreateMultipartUploadOpcChecksumAlgorithmEnum(string(request.OpcChecksumAlgorithm)); !ok && request.OpcChecksumAlgorithm != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for OpcChecksumAlgorithm: %s. Supported values are: %s.", request.OpcChecksumAlgorithm, strings.Join(GetCreateMultipartUploadOpcChecksumAlgorithmEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreateMultipartUploadResponse wrapper for the CreateMultipartUpload operation +type CreateMultipartUploadResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The MultipartUpload instance + MultipartUpload `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The full path to the new upload. + Location *string `presentIn:"header" name:"location"` +} + +func (response CreateMultipartUploadResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CreateMultipartUploadResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// CreateMultipartUploadOpcChecksumAlgorithmEnum Enum with underlying type: string +type CreateMultipartUploadOpcChecksumAlgorithmEnum string + +// Set of constants representing the allowable values for CreateMultipartUploadOpcChecksumAlgorithmEnum +const ( + CreateMultipartUploadOpcChecksumAlgorithmCrc32c CreateMultipartUploadOpcChecksumAlgorithmEnum = "CRC32C" + CreateMultipartUploadOpcChecksumAlgorithmSha256 CreateMultipartUploadOpcChecksumAlgorithmEnum = "SHA256" + CreateMultipartUploadOpcChecksumAlgorithmSha384 CreateMultipartUploadOpcChecksumAlgorithmEnum = "SHA384" +) + +var mappingCreateMultipartUploadOpcChecksumAlgorithmEnum = map[string]CreateMultipartUploadOpcChecksumAlgorithmEnum{ + "CRC32C": CreateMultipartUploadOpcChecksumAlgorithmCrc32c, + "SHA256": CreateMultipartUploadOpcChecksumAlgorithmSha256, + "SHA384": CreateMultipartUploadOpcChecksumAlgorithmSha384, +} + +var mappingCreateMultipartUploadOpcChecksumAlgorithmEnumLowerCase = map[string]CreateMultipartUploadOpcChecksumAlgorithmEnum{ + "crc32c": CreateMultipartUploadOpcChecksumAlgorithmCrc32c, + "sha256": CreateMultipartUploadOpcChecksumAlgorithmSha256, + "sha384": CreateMultipartUploadOpcChecksumAlgorithmSha384, +} + +// GetCreateMultipartUploadOpcChecksumAlgorithmEnumValues Enumerates the set of values for CreateMultipartUploadOpcChecksumAlgorithmEnum +func GetCreateMultipartUploadOpcChecksumAlgorithmEnumValues() []CreateMultipartUploadOpcChecksumAlgorithmEnum { + values := make([]CreateMultipartUploadOpcChecksumAlgorithmEnum, 0) + for _, v := range mappingCreateMultipartUploadOpcChecksumAlgorithmEnum { + values = append(values, v) + } + return values +} + +// GetCreateMultipartUploadOpcChecksumAlgorithmEnumStringValues Enumerates the set of values in String for CreateMultipartUploadOpcChecksumAlgorithmEnum +func GetCreateMultipartUploadOpcChecksumAlgorithmEnumStringValues() []string { + return []string{ + "CRC32C", + "SHA256", + "SHA384", + } +} + +// GetMappingCreateMultipartUploadOpcChecksumAlgorithmEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingCreateMultipartUploadOpcChecksumAlgorithmEnum(val string) (CreateMultipartUploadOpcChecksumAlgorithmEnum, bool) { + enum, ok := mappingCreateMultipartUploadOpcChecksumAlgorithmEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_details.go new file mode 100644 index 00000000000..d037474179a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_details.go @@ -0,0 +1,124 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CreatePreauthenticatedRequestDetails The representation of CreatePreauthenticatedRequestDetails +type CreatePreauthenticatedRequestDetails struct { + + // A user-specified name for the pre-authenticated request. Names can be helpful in managing pre-authenticated requests. + // Avoid entering confidential information. + Name *string `mandatory:"true" json:"name"` + + // The operation that can be performed on this resource. + AccessType CreatePreauthenticatedRequestDetailsAccessTypeEnum `mandatory:"true" json:"accessType"` + + // The expiration date for the pre-authenticated request as per RFC 3339 (https://tools.ietf.org/html/rfc3339). + // After this date the pre-authenticated request will no longer be valid. + TimeExpires *common.SDKTime `mandatory:"true" json:"timeExpires"` + + // Specifies whether a list operation is allowed on a PAR with accessType "AnyObjectRead" or "AnyObjectReadWrite". + // Deny: Prevents the user from performing a list operation. + // ListObjects: Authorizes the user to perform a list operation. + BucketListingAction PreauthenticatedRequestBucketListingActionEnum `mandatory:"false" json:"bucketListingAction,omitempty"` + + // The name of the object that is being granted access to by the pre-authenticated request. Avoid entering confidential + // information. The object name can be null and if so, the pre-authenticated request grants access to the entire bucket + // if the access type allows that. The object name can be a prefix as well, in that case pre-authenticated request + // grants access to all the objects within the bucket starting with that prefix provided that we have the correct access type. + ObjectName *string `mandatory:"false" json:"objectName"` +} + +func (m CreatePreauthenticatedRequestDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CreatePreauthenticatedRequestDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingCreatePreauthenticatedRequestDetailsAccessTypeEnum(string(m.AccessType)); !ok && m.AccessType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for AccessType: %s. Supported values are: %s.", m.AccessType, strings.Join(GetCreatePreauthenticatedRequestDetailsAccessTypeEnumStringValues(), ","))) + } + + if _, ok := GetMappingPreauthenticatedRequestBucketListingActionEnum(string(m.BucketListingAction)); !ok && m.BucketListingAction != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for BucketListingAction: %s. Supported values are: %s.", m.BucketListingAction, strings.Join(GetPreauthenticatedRequestBucketListingActionEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreatePreauthenticatedRequestDetailsAccessTypeEnum Enum with underlying type: string +type CreatePreauthenticatedRequestDetailsAccessTypeEnum string + +// Set of constants representing the allowable values for CreatePreauthenticatedRequestDetailsAccessTypeEnum +const ( + CreatePreauthenticatedRequestDetailsAccessTypeObjectread CreatePreauthenticatedRequestDetailsAccessTypeEnum = "ObjectRead" + CreatePreauthenticatedRequestDetailsAccessTypeObjectwrite CreatePreauthenticatedRequestDetailsAccessTypeEnum = "ObjectWrite" + CreatePreauthenticatedRequestDetailsAccessTypeObjectreadwrite CreatePreauthenticatedRequestDetailsAccessTypeEnum = "ObjectReadWrite" + CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectwrite CreatePreauthenticatedRequestDetailsAccessTypeEnum = "AnyObjectWrite" + CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectread CreatePreauthenticatedRequestDetailsAccessTypeEnum = "AnyObjectRead" + CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectreadwrite CreatePreauthenticatedRequestDetailsAccessTypeEnum = "AnyObjectReadWrite" +) + +var mappingCreatePreauthenticatedRequestDetailsAccessTypeEnum = map[string]CreatePreauthenticatedRequestDetailsAccessTypeEnum{ + "ObjectRead": CreatePreauthenticatedRequestDetailsAccessTypeObjectread, + "ObjectWrite": CreatePreauthenticatedRequestDetailsAccessTypeObjectwrite, + "ObjectReadWrite": CreatePreauthenticatedRequestDetailsAccessTypeObjectreadwrite, + "AnyObjectWrite": CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectwrite, + "AnyObjectRead": CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectread, + "AnyObjectReadWrite": CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectreadwrite, +} + +var mappingCreatePreauthenticatedRequestDetailsAccessTypeEnumLowerCase = map[string]CreatePreauthenticatedRequestDetailsAccessTypeEnum{ + "objectread": CreatePreauthenticatedRequestDetailsAccessTypeObjectread, + "objectwrite": CreatePreauthenticatedRequestDetailsAccessTypeObjectwrite, + "objectreadwrite": CreatePreauthenticatedRequestDetailsAccessTypeObjectreadwrite, + "anyobjectwrite": CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectwrite, + "anyobjectread": CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectread, + "anyobjectreadwrite": CreatePreauthenticatedRequestDetailsAccessTypeAnyobjectreadwrite, +} + +// GetCreatePreauthenticatedRequestDetailsAccessTypeEnumValues Enumerates the set of values for CreatePreauthenticatedRequestDetailsAccessTypeEnum +func GetCreatePreauthenticatedRequestDetailsAccessTypeEnumValues() []CreatePreauthenticatedRequestDetailsAccessTypeEnum { + values := make([]CreatePreauthenticatedRequestDetailsAccessTypeEnum, 0) + for _, v := range mappingCreatePreauthenticatedRequestDetailsAccessTypeEnum { + values = append(values, v) + } + return values +} + +// GetCreatePreauthenticatedRequestDetailsAccessTypeEnumStringValues Enumerates the set of values in String for CreatePreauthenticatedRequestDetailsAccessTypeEnum +func GetCreatePreauthenticatedRequestDetailsAccessTypeEnumStringValues() []string { + return []string{ + "ObjectRead", + "ObjectWrite", + "ObjectReadWrite", + "AnyObjectWrite", + "AnyObjectRead", + "AnyObjectReadWrite", + } +} + +// GetMappingCreatePreauthenticatedRequestDetailsAccessTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingCreatePreauthenticatedRequestDetailsAccessTypeEnum(val string) (CreatePreauthenticatedRequestDetailsAccessTypeEnum, bool) { + enum, ok := mappingCreatePreauthenticatedRequestDetailsAccessTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_request_response.go new file mode 100644 index 00000000000..b76a8bbebcc --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_preauthenticated_request_request_response.go @@ -0,0 +1,125 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CreatePreauthenticatedRequestRequest wrapper for the CreatePreauthenticatedRequest operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreatePreauthenticatedRequest.go.html to see an example of how to use CreatePreauthenticatedRequestRequest. +type CreatePreauthenticatedRequestRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // Information needed to create the pre-authenticated request. + CreatePreauthenticatedRequestDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CreatePreauthenticatedRequestRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CreatePreauthenticatedRequestRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CreatePreauthenticatedRequestRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CreatePreauthenticatedRequestRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CreatePreauthenticatedRequestRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CreatePreauthenticatedRequestRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreatePreauthenticatedRequestResponse wrapper for the CreatePreauthenticatedRequest operation +type CreatePreauthenticatedRequestResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The PreauthenticatedRequest instance + PreauthenticatedRequest `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response CreatePreauthenticatedRequestResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CreatePreauthenticatedRequestResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_details.go new file mode 100644 index 00000000000..e044f620346 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_details.go @@ -0,0 +1,82 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CreatePrivateEndpointDetails Details to create a private endpoint +type CreatePrivateEndpointDetails struct { + + // This name associated with the endpoint. Valid characters are uppercase or lowercase letters, numbers, hyphens, + // underscores, and periods. + // Example: my-new-private-endpoint1 + Name *string `mandatory:"true" json:"name"` + + // The ID of the compartment in which to create the Private Endpoint. + CompartmentId *string `mandatory:"true" json:"compartmentId"` + + // The OCID of the customer's subnet where the private endpoint VNIC will reside. + SubnetId *string `mandatory:"true" json:"subnetId"` + + // A prefix to use for the private endpoint. The customer VCN's DNS records are + // updated with this prefix. The prefix input from the customer will be the first sub-domain in the endpointFqdn. + // Example: If the prefix chosen is "abc", then the endpointFqdn will be 'abc.private.objectstorage..oraclecloud.com' + Prefix *string `mandatory:"true" json:"prefix"` + + // A list of targets that can be accessed by the private endpoint. + AccessTargets []AccessTargetDetails `mandatory:"true" json:"accessTargets"` + + // A list of additional prefix that you can provide along with any other prefix. These resulting endpointFqdn's are added to the + // customer VCN's DNS record. + AdditionalPrefixes []string `mandatory:"false" json:"additionalPrefixes"` + + // The private IP address to assign to this private endpoint. If you provide a value, + // it must be an available IP address in the customer's subnet. If it's not available, an error + // is returned. + // If you do not provide a value, an available IP address in the subnet is automatically chosen. + PrivateEndpointIp *string `mandatory:"false" json:"privateEndpointIp"` + + // A list of the OCIDs of the network security groups (NSGs) to add the private endpoint's VNIC to. + // For more information about NSGs, see + // NetworkSecurityGroup. + NsgIds []string `mandatory:"false" json:"nsgIds"` + + // Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Department": "Finance"}` + FreeformTags map[string]string `mandatory:"false" json:"freeformTags"` + + // Defined tags for this resource. Each key is predefined and scoped to a namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Operations": {"CostCenter": "42"}}` + DefinedTags map[string]map[string]interface{} `mandatory:"false" json:"definedTags"` +} + +func (m CreatePrivateEndpointDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CreatePrivateEndpointDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_request_response.go new file mode 100644 index 00000000000..46d8f159b88 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_private_endpoint_request_response.go @@ -0,0 +1,112 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CreatePrivateEndpointRequest wrapper for the CreatePrivateEndpoint operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreatePrivateEndpoint.go.html to see an example of how to use CreatePrivateEndpointRequest. +type CreatePrivateEndpointRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // Details to create a private endpoint. + CreatePrivateEndpointDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CreatePrivateEndpointRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CreatePrivateEndpointRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CreatePrivateEndpointRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CreatePrivateEndpointRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CreatePrivateEndpointRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CreatePrivateEndpointRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreatePrivateEndpointResponse wrapper for the CreatePrivateEndpoint operation +type CreatePrivateEndpointResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the asynchronous request. If you need to contact Oracle about a + // particular request, provide this request ID. + OpcWorkRequestId *string `presentIn:"header" name:"opc-work-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response CreatePrivateEndpointResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CreatePrivateEndpointResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_details.go new file mode 100644 index 00000000000..65c5cea2f19 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_details.go @@ -0,0 +1,48 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CreateReplicationPolicyDetails The details to create a replication policy. +type CreateReplicationPolicyDetails struct { + + // The name of the policy. Avoid entering confidential information. + Name *string `mandatory:"true" json:"name"` + + // The destination region to replicate to, for example "us-ashburn-1". + DestinationRegionName *string `mandatory:"true" json:"destinationRegionName"` + + // The bucket to replicate to in the destination region. Replication policy creation does not automatically + // create a destination bucket. Create the destination bucket before creating the policy. + DestinationBucketName *string `mandatory:"true" json:"destinationBucketName"` +} + +func (m CreateReplicationPolicyDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CreateReplicationPolicyDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_request_response.go new file mode 100644 index 00000000000..f9cdee10914 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_replication_policy_request_response.go @@ -0,0 +1,125 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CreateReplicationPolicyRequest wrapper for the CreateReplicationPolicy operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateReplicationPolicy.go.html to see an example of how to use CreateReplicationPolicyRequest. +type CreateReplicationPolicyRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The replication policy. + CreateReplicationPolicyDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CreateReplicationPolicyRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CreateReplicationPolicyRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CreateReplicationPolicyRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CreateReplicationPolicyRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CreateReplicationPolicyRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CreateReplicationPolicyRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreateReplicationPolicyResponse wrapper for the CreateReplicationPolicy operation +type CreateReplicationPolicyResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The ReplicationPolicy instance + ReplicationPolicy `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response CreateReplicationPolicyResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CreateReplicationPolicyResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_details.go new file mode 100644 index 00000000000..87b050ab5b7 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_details.go @@ -0,0 +1,50 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CreateRetentionRuleDetails The details to create a retention rule. +type CreateRetentionRuleDetails struct { + + // A user-specified name for the retention rule. Names can be helpful in identifying retention rules. + // Avoid entering confidential information. + DisplayName *string `mandatory:"false" json:"displayName"` + + Duration *Duration `mandatory:"false" json:"duration"` + + // The date and time as per RFC 3339 (https://tools.ietf.org/html/rfc3339) after which this rule is locked + // and can only be deleted by deleting the bucket. Once a rule is locked, only increases in the duration are + // allowed and no other properties can be changed. This property cannot be updated for rules that are in a + // locked state. Specifying it when a duration is not specified is considered an error. + TimeRuleLocked *common.SDKTime `mandatory:"false" json:"timeRuleLocked"` +} + +func (m CreateRetentionRuleDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CreateRetentionRuleDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_request_response.go new file mode 100644 index 00000000000..fcc434f8c25 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/create_retention_rule_request_response.go @@ -0,0 +1,127 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// CreateRetentionRuleRequest wrapper for the CreateRetentionRule operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateRetentionRule.go.html to see an example of how to use CreateRetentionRuleRequest. +type CreateRetentionRuleRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The retention rule to create for the bucket. + CreateRetentionRuleDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request CreateRetentionRuleRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request CreateRetentionRuleRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request CreateRetentionRuleRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request CreateRetentionRuleRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request CreateRetentionRuleRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request CreateRetentionRuleRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CreateRetentionRuleResponse wrapper for the CreateRetentionRule operation +type CreateRetentionRuleResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The RetentionRule instance + RetentionRule `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // The entity tag (ETag) for the retention rule that was created. + Etag *string `presentIn:"header" name:"etag"` +} + +func (response CreateRetentionRuleResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response CreateRetentionRuleResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_bucket_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_bucket_request_response.go new file mode 100644 index 00000000000..e3a80f4379d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_bucket_request_response.go @@ -0,0 +1,124 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// DeleteBucketRequest wrapper for the DeleteBucket operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteBucket.go.html to see an example of how to use DeleteBucketRequest. +type DeleteBucketRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request DeleteBucketRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request DeleteBucketRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request DeleteBucketRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request DeleteBucketRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request DeleteBucketRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request DeleteBucketRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DeleteBucketResponse wrapper for the DeleteBucket operation +type DeleteBucketResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response DeleteBucketResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response DeleteBucketResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_lifecycle_policy_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_lifecycle_policy_request_response.go new file mode 100644 index 00000000000..34f953d2e4e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_lifecycle_policy_request_response.go @@ -0,0 +1,124 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// DeleteObjectLifecyclePolicyRequest wrapper for the DeleteObjectLifecyclePolicy operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteObjectLifecyclePolicy.go.html to see an example of how to use DeleteObjectLifecyclePolicyRequest. +type DeleteObjectLifecyclePolicyRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request DeleteObjectLifecyclePolicyRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request DeleteObjectLifecyclePolicyRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request DeleteObjectLifecyclePolicyRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request DeleteObjectLifecyclePolicyRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request DeleteObjectLifecyclePolicyRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request DeleteObjectLifecyclePolicyRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DeleteObjectLifecyclePolicyResponse wrapper for the DeleteObjectLifecyclePolicy operation +type DeleteObjectLifecyclePolicyResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response DeleteObjectLifecyclePolicyResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response DeleteObjectLifecyclePolicyResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_request_response.go new file mode 100644 index 00000000000..33617fec79e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_object_request_response.go @@ -0,0 +1,151 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// DeleteObjectRequest wrapper for the DeleteObject operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteObject.go.html to see an example of how to use DeleteObjectRequest. +type DeleteObjectRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // VersionId used to identify a particular version of the object + VersionId *string `mandatory:"false" contributesTo:"query" name:"versionId"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request DeleteObjectRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request DeleteObjectRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request DeleteObjectRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request DeleteObjectRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request DeleteObjectRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request DeleteObjectRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DeleteObjectResponse wrapper for the DeleteObject operation +type DeleteObjectResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The time the object was deleted, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + LastModified *common.SDKTime `presentIn:"header" name:"last-modified"` + + // The `versionId` of the delete marker created as a result of the DELETE Object. + // If the request contains a specific `versionId`, then this response header will be the same as the requested `versionId` of the object that was deleted. + VersionId *string `presentIn:"header" name:"version-id"` + + // This is `true` if the deleted object is a delete marker, otherwise `false` + IsDeleteMarker *bool `presentIn:"header" name:"is-delete-marker"` +} + +func (response DeleteObjectResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response DeleteObjectResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_preauthenticated_request_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_preauthenticated_request_request_response.go new file mode 100644 index 00000000000..bdd4bab0bd3 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_preauthenticated_request_request_response.go @@ -0,0 +1,133 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// DeletePreauthenticatedRequestRequest wrapper for the DeletePreauthenticatedRequest operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeletePreauthenticatedRequest.go.html to see an example of how to use DeletePreauthenticatedRequestRequest. +type DeletePreauthenticatedRequestRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The unique identifier for the pre-authenticated request. This can be used to manage operations against + // the pre-authenticated request, such as GET or DELETE. + ParId *string `mandatory:"true" contributesTo:"path" name:"parId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request DeletePreauthenticatedRequestRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request DeletePreauthenticatedRequestRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request DeletePreauthenticatedRequestRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request DeletePreauthenticatedRequestRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["parId"] != nil { + templateParam := mandatoryParamMap["parId"] + for _, template := range templateParam { + replacementParam := *request.ParId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request DeletePreauthenticatedRequestRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request DeletePreauthenticatedRequestRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DeletePreauthenticatedRequestResponse wrapper for the DeletePreauthenticatedRequest operation +type DeletePreauthenticatedRequestResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response DeletePreauthenticatedRequestResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response DeletePreauthenticatedRequestResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_private_endpoint_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_private_endpoint_request_response.go new file mode 100644 index 00000000000..ab2463eb2a6 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_private_endpoint_request_response.go @@ -0,0 +1,128 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// DeletePrivateEndpointRequest wrapper for the DeletePrivateEndpoint operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeletePrivateEndpoint.go.html to see an example of how to use DeletePrivateEndpointRequest. +type DeletePrivateEndpointRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the private endpoint. Avoid entering confidential information. + // Example: `my-new-pe-1` + PeName *string `mandatory:"true" contributesTo:"path" name:"peName"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request DeletePrivateEndpointRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request DeletePrivateEndpointRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request DeletePrivateEndpointRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request DeletePrivateEndpointRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["peName"] != nil { + templateParam := mandatoryParamMap["peName"] + for _, template := range templateParam { + replacementParam := *request.PeName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request DeletePrivateEndpointRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request DeletePrivateEndpointRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DeletePrivateEndpointResponse wrapper for the DeletePrivateEndpoint operation +type DeletePrivateEndpointResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the asynchronous request. If you need to contact Oracle about a + // particular request, provide this request ID. + OpcWorkRequestId *string `presentIn:"header" name:"opc-work-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response DeletePrivateEndpointResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response DeletePrivateEndpointResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_replication_policy_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_replication_policy_request_response.go new file mode 100644 index 00000000000..26e43f2e79d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_replication_policy_request_response.go @@ -0,0 +1,132 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// DeleteReplicationPolicyRequest wrapper for the DeleteReplicationPolicy operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteReplicationPolicy.go.html to see an example of how to use DeleteReplicationPolicyRequest. +type DeleteReplicationPolicyRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The ID of the replication policy. + ReplicationId *string `mandatory:"true" contributesTo:"path" name:"replicationId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request DeleteReplicationPolicyRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request DeleteReplicationPolicyRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request DeleteReplicationPolicyRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request DeleteReplicationPolicyRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["replicationId"] != nil { + templateParam := mandatoryParamMap["replicationId"] + for _, template := range templateParam { + replacementParam := *request.ReplicationId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request DeleteReplicationPolicyRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request DeleteReplicationPolicyRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DeleteReplicationPolicyResponse wrapper for the DeleteReplicationPolicy operation +type DeleteReplicationPolicyResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response DeleteReplicationPolicyResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response DeleteReplicationPolicyResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_retention_rule_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_retention_rule_request_response.go new file mode 100644 index 00000000000..ed0a6ce619c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/delete_retention_rule_request_response.go @@ -0,0 +1,137 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// DeleteRetentionRuleRequest wrapper for the DeleteRetentionRule operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteRetentionRule.go.html to see an example of how to use DeleteRetentionRuleRequest. +type DeleteRetentionRuleRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The ID of the retention rule. + RetentionRuleId *string `mandatory:"true" contributesTo:"path" name:"retentionRuleId"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request DeleteRetentionRuleRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request DeleteRetentionRuleRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request DeleteRetentionRuleRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request DeleteRetentionRuleRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["retentionRuleId"] != nil { + templateParam := mandatoryParamMap["retentionRuleId"] + for _, template := range templateParam { + replacementParam := *request.RetentionRuleId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request DeleteRetentionRuleRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request DeleteRetentionRuleRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DeleteRetentionRuleResponse wrapper for the DeleteRetentionRule operation +type DeleteRetentionRuleResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response DeleteRetentionRuleResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response DeleteRetentionRuleResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/duration.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/duration.go new file mode 100644 index 00000000000..f9fd842cd82 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/duration.go @@ -0,0 +1,92 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// Duration The amount of time that objects in the bucket should be preserved for and which is calculated in relation to +// each object's Last-Modified timestamp. If duration is not present, then there is no time limit and the objects +// in the bucket will be preserved indefinitely. +type Duration struct { + + // The timeAmount is interpreted in units defined by the timeUnit parameter, and is calculated in relation + // to each object's Last-Modified timestamp. + TimeAmount *int64 `mandatory:"true" json:"timeAmount"` + + // The unit that should be used to interpret timeAmount. + TimeUnit DurationTimeUnitEnum `mandatory:"true" json:"timeUnit"` +} + +func (m Duration) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m Duration) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingDurationTimeUnitEnum(string(m.TimeUnit)); !ok && m.TimeUnit != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for TimeUnit: %s. Supported values are: %s.", m.TimeUnit, strings.Join(GetDurationTimeUnitEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// DurationTimeUnitEnum Enum with underlying type: string +type DurationTimeUnitEnum string + +// Set of constants representing the allowable values for DurationTimeUnitEnum +const ( + DurationTimeUnitYears DurationTimeUnitEnum = "YEARS" + DurationTimeUnitDays DurationTimeUnitEnum = "DAYS" +) + +var mappingDurationTimeUnitEnum = map[string]DurationTimeUnitEnum{ + "YEARS": DurationTimeUnitYears, + "DAYS": DurationTimeUnitDays, +} + +var mappingDurationTimeUnitEnumLowerCase = map[string]DurationTimeUnitEnum{ + "years": DurationTimeUnitYears, + "days": DurationTimeUnitDays, +} + +// GetDurationTimeUnitEnumValues Enumerates the set of values for DurationTimeUnitEnum +func GetDurationTimeUnitEnumValues() []DurationTimeUnitEnum { + values := make([]DurationTimeUnitEnum, 0) + for _, v := range mappingDurationTimeUnitEnum { + values = append(values, v) + } + return values +} + +// GetDurationTimeUnitEnumStringValues Enumerates the set of values in String for DurationTimeUnitEnum +func GetDurationTimeUnitEnumStringValues() []string { + return []string{ + "YEARS", + "DAYS", + } +} + +// GetMappingDurationTimeUnitEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingDurationTimeUnitEnum(val string) (DurationTimeUnitEnum, bool) { + enum, ok := mappingDurationTimeUnitEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/fqdns.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/fqdns.go new file mode 100644 index 00000000000..d72e2456f9c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/fqdns.go @@ -0,0 +1,42 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// Fqdns The object representing FQDN details formed using prefix and additionalPrefixes. +type Fqdns struct { + PrefixFqdns *PrefixFqdns `mandatory:"false" json:"prefixFqdns"` + + // An object containing FQDNs formed using additionalPrefixes. + AdditionalPrefixesFqdns map[string]PrefixFqdns `mandatory:"false" json:"additionalPrefixesFqdns"` +} + +func (m Fqdns) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m Fqdns) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_bucket_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_bucket_request_response.go new file mode 100644 index 00000000000..6ebf769a9b4 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_bucket_request_response.go @@ -0,0 +1,199 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetBucketRequest wrapper for the GetBucket operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetBucket.go.html to see an example of how to use GetBucketRequest. +type GetBucketRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. Wildcards ('*') are not allowed. If the specified ETag does not + // match the ETag of the existing resource, the request returns the expected response. If the ETag matches + // the ETag of the existing resource, the request returns an HTTP 304 status without a response body. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Bucket summary includes the 'namespace', 'name', 'compartmentId', 'createdBy', 'timeCreated', + // and 'etag' fields. This parameter can also include 'approximateCount' (approximate number of objects), 'approximateSize' + // (total approximate size in bytes of all objects) and 'autoTiering' (state of auto tiering on the bucket). + // For example 'approximateCount,approximateSize,autoTiering'. + Fields []GetBucketFieldsEnum `contributesTo:"query" name:"fields" omitEmpty:"true" collectionFormat:"csv"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetBucketRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetBucketRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetBucketRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetBucketRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetBucketRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetBucketRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + for _, val := range request.Fields { + if _, ok := GetMappingGetBucketFieldsEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Fields: %s. Supported values are: %s.", val, strings.Join(GetGetBucketFieldsEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetBucketResponse wrapper for the GetBucket operation +type GetBucketResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The Bucket instance + Bucket `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The current entity tag (ETag) for the bucket. + ETag *string `presentIn:"header" name:"etag"` + + // Flag to indicate whether or not the object was modified. If this is true, + // the getter for the object itself will return null. Callers should check this + // if they specified one of the request params that might result in a conditional + // response (like 'if-match'/'if-none-match'). + IsNotModified bool +} + +func (response GetBucketResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetBucketResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// GetBucketFieldsEnum Enum with underlying type: string +type GetBucketFieldsEnum string + +// Set of constants representing the allowable values for GetBucketFieldsEnum +const ( + GetBucketFieldsApproximatecount GetBucketFieldsEnum = "approximateCount" + GetBucketFieldsApproximatesize GetBucketFieldsEnum = "approximateSize" + GetBucketFieldsAutotiering GetBucketFieldsEnum = "autoTiering" +) + +var mappingGetBucketFieldsEnum = map[string]GetBucketFieldsEnum{ + "approximateCount": GetBucketFieldsApproximatecount, + "approximateSize": GetBucketFieldsApproximatesize, + "autoTiering": GetBucketFieldsAutotiering, +} + +var mappingGetBucketFieldsEnumLowerCase = map[string]GetBucketFieldsEnum{ + "approximatecount": GetBucketFieldsApproximatecount, + "approximatesize": GetBucketFieldsApproximatesize, + "autotiering": GetBucketFieldsAutotiering, +} + +// GetGetBucketFieldsEnumValues Enumerates the set of values for GetBucketFieldsEnum +func GetGetBucketFieldsEnumValues() []GetBucketFieldsEnum { + values := make([]GetBucketFieldsEnum, 0) + for _, v := range mappingGetBucketFieldsEnum { + values = append(values, v) + } + return values +} + +// GetGetBucketFieldsEnumStringValues Enumerates the set of values in String for GetBucketFieldsEnum +func GetGetBucketFieldsEnumStringValues() []string { + return []string{ + "approximateCount", + "approximateSize", + "autoTiering", + } +} + +// GetMappingGetBucketFieldsEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingGetBucketFieldsEnum(val string) (GetBucketFieldsEnum, bool) { + enum, ok := mappingGetBucketFieldsEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_metadata_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_metadata_request_response.go new file mode 100644 index 00000000000..71bf2de436d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_metadata_request_response.go @@ -0,0 +1,108 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetNamespaceMetadataRequest wrapper for the GetNamespaceMetadata operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetNamespaceMetadata.go.html to see an example of how to use GetNamespaceMetadataRequest. +type GetNamespaceMetadataRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetNamespaceMetadataRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetNamespaceMetadataRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetNamespaceMetadataRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetNamespaceMetadataRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetNamespaceMetadataRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetNamespaceMetadataRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetNamespaceMetadataResponse wrapper for the GetNamespaceMetadata operation +type GetNamespaceMetadataResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The NamespaceMetadata instance + NamespaceMetadata `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response GetNamespaceMetadataResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetNamespaceMetadataResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_request_response.go new file mode 100644 index 00000000000..c7aedf77e8c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_namespace_request_response.go @@ -0,0 +1,92 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetNamespaceRequest wrapper for the GetNamespace operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetNamespace.go.html to see an example of how to use GetNamespaceRequest. +type GetNamespaceRequest struct { + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // This is an optional field representing either the tenancy OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) or the compartment + // OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) within the tenancy whose Object Storage namespace is to be retrieved. + CompartmentId *string `mandatory:"false" contributesTo:"query" name:"compartmentId"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetNamespaceRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetNamespaceRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetNamespaceRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetNamespaceRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetNamespaceRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetNamespaceRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetNamespaceResponse wrapper for the GetNamespace operation +type GetNamespaceResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The string instance + Value *string `presentIn:"body"` +} + +func (response GetNamespaceResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetNamespaceResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_lifecycle_policy_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_lifecycle_policy_request_response.go new file mode 100644 index 00000000000..0225d0fdd48 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_lifecycle_policy_request_response.go @@ -0,0 +1,125 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetObjectLifecyclePolicyRequest wrapper for the GetObjectLifecyclePolicy operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetObjectLifecyclePolicy.go.html to see an example of how to use GetObjectLifecyclePolicyRequest. +type GetObjectLifecyclePolicyRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetObjectLifecyclePolicyRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetObjectLifecyclePolicyRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetObjectLifecyclePolicyRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetObjectLifecyclePolicyRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetObjectLifecyclePolicyRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetObjectLifecyclePolicyRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetObjectLifecyclePolicyResponse wrapper for the GetObjectLifecyclePolicy operation +type GetObjectLifecyclePolicyResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The ObjectLifecyclePolicy instance + ObjectLifecyclePolicy `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // The entity tag (ETag) for the object lifecycle policy. + ETag *string `presentIn:"header" name:"etag"` +} + +func (response GetObjectLifecyclePolicyResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetObjectLifecyclePolicyResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_request_response.go new file mode 100644 index 00000000000..34e51770182 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_object_request_response.go @@ -0,0 +1,372 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "io" + "net/http" + "strings" +) + +// GetObjectRequest wrapper for the GetObject operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetObject.go.html to see an example of how to use GetObjectRequest. +type GetObjectRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // VersionId used to identify a particular version of the object + VersionId *string `mandatory:"false" contributesTo:"query" name:"versionId"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. Wildcards ('*') are not allowed. If the specified ETag does not + // match the ETag of the existing resource, the request returns the expected response. If the ETag matches + // the ETag of the existing resource, the request returns an HTTP 304 status without a response body. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Optional byte range to fetch, as described in RFC 7233 (https://tools.ietf.org/html/rfc7233#section-2.1). + // Note that only a single range of bytes is supported. + Range *string `mandatory:"false" contributesTo:"header" name:"range"` + + // The optional header that specifies "AES256" as the encryption algorithm. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerAlgorithm *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-algorithm"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or + // decrypt the data. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKey *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This + // value is used to check the integrity of the encryption key. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKeySha256 *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key-sha256"` + + // Specify this query parameter to override the value of the Content-Disposition response header in the GetObject response. + HttpResponseContentDisposition *string `mandatory:"false" contributesTo:"query" name:"httpResponseContentDisposition"` + + // Specify this query parameter to override the Cache-Control response header in the GetObject response. + HttpResponseCacheControl *string `mandatory:"false" contributesTo:"query" name:"httpResponseCacheControl"` + + // Specify this query parameter to override the Content-Type response header in the GetObject response. + HttpResponseContentType *string `mandatory:"false" contributesTo:"query" name:"httpResponseContentType"` + + // Specify this query parameter to override the Content-Language response header in the GetObject response. + HttpResponseContentLanguage *string `mandatory:"false" contributesTo:"query" name:"httpResponseContentLanguage"` + + // Specify this query parameter to override the Content-Encoding response header in the GetObject response. + HttpResponseContentEncoding *string `mandatory:"false" contributesTo:"query" name:"httpResponseContentEncoding"` + + // Specify this query parameter to override the Expires response header in the GetObject response. + HttpResponseExpires *string `mandatory:"false" contributesTo:"query" name:"httpResponseExpires"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetObjectRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetObjectRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetObjectRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetObjectRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetObjectRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetObjectRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetObjectResponse wrapper for the GetObject operation +type GetObjectResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The io.ReadCloser instance + Content io.ReadCloser `presentIn:"body" encoding:"binary"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the object. + ETag *string `presentIn:"header" name:"etag"` + + // The user-defined metadata for the object. + OpcMeta map[string]string `presentIn:"header-collection" prefix:"opc-meta-"` + + // The object size in bytes. + ContentLength *int64 `presentIn:"header" name:"content-length"` + + // Content-Range header for range requests, per RFC 7233 (https://tools.ietf.org/html/rfc7233#section-4.2). + ContentRange *string `presentIn:"header" name:"content-range"` + + // Content-MD5 header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.15). + // Unavailable for objects uploaded using multipart upload. + ContentMd5 *string `presentIn:"header" name:"content-md5"` + + // Only applicable to objects uploaded using multipart upload. + // Base-64 representation of the multipart object hash. + // The multipart object hash is calculated by taking the MD5 hashes of the parts, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the MD5 hash of the concatenated values. + OpcMultipartMd5 *string `presentIn:"header" name:"opc-multipart-md5"` + + // The base64-encoded, 32-bit CRC32C (Castagnoli) checksum of the object. + // Even for objects uploaded using multipart upload, this header returns the CRC32C (Castagnoli) checksum + // of the complete reconstructed object. + OpcContentCrc32c *string `presentIn:"header" name:"opc-content-crc32c"` + + // Applicable only if SHA256 was specified in the opc-checksum-algorithm request header during upload. + // The base64-encoded SHA256 hash of the object as computed during upload. + // Unavailable for objects uploaded using multipart upload. + OpcContentSha256 *string `presentIn:"header" name:"opc-content-sha256"` + + // Only applicable to objects uploaded using multipart upload. + // Applicable only if SHA256 was specified in the opc-checksum-algorithm request header during upload. + // Base-64 representation of the multipart object SHA256 hash. + // The multipart object hash is calculated by taking the SHA256 hashes of the parts, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the SHA256 hash of the concatenated values. + OpcMultipartSha256 *string `presentIn:"header" name:"opc-multipart-sha256"` + + // Applicable only if SHA384 was specified in the opc-checksum-algorithm request header during upload. + // The base64-encoded SHA384 hash of the object as computed during upload. + // Unavailable for objects uploaded using multipart upload. + OpcContentSha384 *string `presentIn:"header" name:"opc-content-sha384"` + + // Only applicable to objects uploaded using multipart upload. + // Applicable only if SHA384 was specified in the opc-checksum-algorithm request header during upload. + // Base-64 representation of the multipart object SHA384 hash. + // The multipart object hash is calculated by taking the SHA384 hashes of the parts, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the SHA384 hash of the concatenated values. + OpcMultipartSha384 *string `presentIn:"header" name:"opc-multipart-sha384"` + + // Content-Type header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.17). + ContentType *string `presentIn:"header" name:"content-type"` + + // Content-Language header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.12). + ContentLanguage *string `presentIn:"header" name:"content-language"` + + // Content-Encoding header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.11). + ContentEncoding *string `presentIn:"header" name:"content-encoding"` + + // Cache-Control header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.9). + CacheControl *string `presentIn:"header" name:"cache-control"` + + // Content-Disposition header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-19.5.1). + ContentDisposition *string `presentIn:"header" name:"content-disposition"` + + // The object modification time, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + LastModified *common.SDKTime `presentIn:"header" name:"last-modified"` + + // The storage tier that the object is stored in. + StorageTier GetObjectStorageTierEnum `presentIn:"header" name:"storage-tier"` + + // Archival state of an object. This field is set only for objects in Archive tier. + ArchivalState GetObjectArchivalStateEnum `presentIn:"header" name:"archival-state"` + + // Time that the object is returned to the archived state. This field is only present for restored objects. + TimeOfArchival *common.SDKTime `presentIn:"header" name:"time-of-archival"` + + // VersionId of the object + VersionId *string `presentIn:"header" name:"version-id"` + + // The date and time after which the object is no longer cached by a browser, proxy, or other caching entity. See + // RFC 2616 (https://tools.ietf.org/rfc/rfc2616#section-14.21). + Expires *common.SDKTime `presentIn:"header" name:"expires"` + + // Flag to indicate whether or not the object was modified. If this is true, + // the getter for the object itself will return null. Callers should check this + // if they specified one of the request params that might result in a conditional + // response (like 'if-match'/'if-none-match'). + IsNotModified bool +} + +func (response GetObjectResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetObjectResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// GetObjectStorageTierEnum Enum with underlying type: string +type GetObjectStorageTierEnum string + +// Set of constants representing the allowable values for GetObjectStorageTierEnum +const ( + GetObjectStorageTierStandard GetObjectStorageTierEnum = "Standard" + GetObjectStorageTierInfrequentaccess GetObjectStorageTierEnum = "InfrequentAccess" + GetObjectStorageTierArchive GetObjectStorageTierEnum = "Archive" +) + +var mappingGetObjectStorageTierEnum = map[string]GetObjectStorageTierEnum{ + "Standard": GetObjectStorageTierStandard, + "InfrequentAccess": GetObjectStorageTierInfrequentaccess, + "Archive": GetObjectStorageTierArchive, +} + +var mappingGetObjectStorageTierEnumLowerCase = map[string]GetObjectStorageTierEnum{ + "standard": GetObjectStorageTierStandard, + "infrequentaccess": GetObjectStorageTierInfrequentaccess, + "archive": GetObjectStorageTierArchive, +} + +// GetGetObjectStorageTierEnumValues Enumerates the set of values for GetObjectStorageTierEnum +func GetGetObjectStorageTierEnumValues() []GetObjectStorageTierEnum { + values := make([]GetObjectStorageTierEnum, 0) + for _, v := range mappingGetObjectStorageTierEnum { + values = append(values, v) + } + return values +} + +// GetGetObjectStorageTierEnumStringValues Enumerates the set of values in String for GetObjectStorageTierEnum +func GetGetObjectStorageTierEnumStringValues() []string { + return []string{ + "Standard", + "InfrequentAccess", + "Archive", + } +} + +// GetMappingGetObjectStorageTierEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingGetObjectStorageTierEnum(val string) (GetObjectStorageTierEnum, bool) { + enum, ok := mappingGetObjectStorageTierEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// GetObjectArchivalStateEnum Enum with underlying type: string +type GetObjectArchivalStateEnum string + +// Set of constants representing the allowable values for GetObjectArchivalStateEnum +const ( + GetObjectArchivalStateArchived GetObjectArchivalStateEnum = "Archived" + GetObjectArchivalStateRestoring GetObjectArchivalStateEnum = "Restoring" + GetObjectArchivalStateRestored GetObjectArchivalStateEnum = "Restored" +) + +var mappingGetObjectArchivalStateEnum = map[string]GetObjectArchivalStateEnum{ + "Archived": GetObjectArchivalStateArchived, + "Restoring": GetObjectArchivalStateRestoring, + "Restored": GetObjectArchivalStateRestored, +} + +var mappingGetObjectArchivalStateEnumLowerCase = map[string]GetObjectArchivalStateEnum{ + "archived": GetObjectArchivalStateArchived, + "restoring": GetObjectArchivalStateRestoring, + "restored": GetObjectArchivalStateRestored, +} + +// GetGetObjectArchivalStateEnumValues Enumerates the set of values for GetObjectArchivalStateEnum +func GetGetObjectArchivalStateEnumValues() []GetObjectArchivalStateEnum { + values := make([]GetObjectArchivalStateEnum, 0) + for _, v := range mappingGetObjectArchivalStateEnum { + values = append(values, v) + } + return values +} + +// GetGetObjectArchivalStateEnumStringValues Enumerates the set of values in String for GetObjectArchivalStateEnum +func GetGetObjectArchivalStateEnumStringValues() []string { + return []string{ + "Archived", + "Restoring", + "Restored", + } +} + +// GetMappingGetObjectArchivalStateEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingGetObjectArchivalStateEnum(val string) (GetObjectArchivalStateEnum, bool) { + enum, ok := mappingGetObjectArchivalStateEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_preauthenticated_request_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_preauthenticated_request_request_response.go new file mode 100644 index 00000000000..1e13227d25c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_preauthenticated_request_request_response.go @@ -0,0 +1,136 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetPreauthenticatedRequestRequest wrapper for the GetPreauthenticatedRequest operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetPreauthenticatedRequest.go.html to see an example of how to use GetPreauthenticatedRequestRequest. +type GetPreauthenticatedRequestRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The unique identifier for the pre-authenticated request. This can be used to manage operations against + // the pre-authenticated request, such as GET or DELETE. + ParId *string `mandatory:"true" contributesTo:"path" name:"parId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetPreauthenticatedRequestRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetPreauthenticatedRequestRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetPreauthenticatedRequestRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetPreauthenticatedRequestRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["parId"] != nil { + templateParam := mandatoryParamMap["parId"] + for _, template := range templateParam { + replacementParam := *request.ParId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetPreauthenticatedRequestRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetPreauthenticatedRequestRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetPreauthenticatedRequestResponse wrapper for the GetPreauthenticatedRequest operation +type GetPreauthenticatedRequestResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The PreauthenticatedRequestSummary instance + PreauthenticatedRequestSummary `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response GetPreauthenticatedRequestResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetPreauthenticatedRequestResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_private_endpoint_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_private_endpoint_request_response.go new file mode 100644 index 00000000000..54d3348b47a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_private_endpoint_request_response.go @@ -0,0 +1,141 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetPrivateEndpointRequest wrapper for the GetPrivateEndpoint operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetPrivateEndpoint.go.html to see an example of how to use GetPrivateEndpointRequest. +type GetPrivateEndpointRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the private endpoint. Avoid entering confidential information. + // Example: `my-new-pe-1` + PeName *string `mandatory:"true" contributesTo:"path" name:"peName"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. Wildcards ('*') are not allowed. If the specified ETag does not + // match the ETag of the existing resource, the request returns the expected response. If the ETag matches + // the ETag of the existing resource, the request returns an HTTP 304 status without a response body. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetPrivateEndpointRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetPrivateEndpointRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetPrivateEndpointRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetPrivateEndpointRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["peName"] != nil { + templateParam := mandatoryParamMap["peName"] + for _, template := range templateParam { + replacementParam := *request.PeName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetPrivateEndpointRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetPrivateEndpointRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetPrivateEndpointResponse wrapper for the GetPrivateEndpoint operation +type GetPrivateEndpointResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The PrivateEndpoint instance + PrivateEndpoint `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the Private Endpoint. + ETag *string `presentIn:"header" name:"etag"` + + // Flag to indicate whether or not the object was modified. If this is true, + // the getter for the object itself will return null. Callers should check this + // if they specified one of the request params that might result in a conditional + // response (like 'if-match'/'if-none-match'). + IsNotModified bool +} + +func (response GetPrivateEndpointResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetPrivateEndpointResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_replication_policy_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_replication_policy_request_response.go new file mode 100644 index 00000000000..698c5ea3b6d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_replication_policy_request_response.go @@ -0,0 +1,135 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetReplicationPolicyRequest wrapper for the GetReplicationPolicy operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetReplicationPolicy.go.html to see an example of how to use GetReplicationPolicyRequest. +type GetReplicationPolicyRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The ID of the replication policy. + ReplicationId *string `mandatory:"true" contributesTo:"path" name:"replicationId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetReplicationPolicyRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetReplicationPolicyRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetReplicationPolicyRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetReplicationPolicyRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["replicationId"] != nil { + templateParam := mandatoryParamMap["replicationId"] + for _, template := range templateParam { + replacementParam := *request.ReplicationId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetReplicationPolicyRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetReplicationPolicyRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetReplicationPolicyResponse wrapper for the GetReplicationPolicy operation +type GetReplicationPolicyResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The ReplicationPolicy instance + ReplicationPolicy `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response GetReplicationPolicyResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetReplicationPolicyResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_retention_rule_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_retention_rule_request_response.go new file mode 100644 index 00000000000..5dd4766fe29 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_retention_rule_request_response.go @@ -0,0 +1,141 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetRetentionRuleRequest wrapper for the GetRetentionRule operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetRetentionRule.go.html to see an example of how to use GetRetentionRuleRequest. +type GetRetentionRuleRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The ID of the retention rule. + RetentionRuleId *string `mandatory:"true" contributesTo:"path" name:"retentionRuleId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetRetentionRuleRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetRetentionRuleRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetRetentionRuleRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetRetentionRuleRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["retentionRuleId"] != nil { + templateParam := mandatoryParamMap["retentionRuleId"] + for _, template := range templateParam { + replacementParam := *request.RetentionRuleId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetRetentionRuleRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetRetentionRuleRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetRetentionRuleResponse wrapper for the GetRetentionRule operation +type GetRetentionRuleResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The RetentionRule instance + RetentionRule `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the retention rule. + Etag *string `presentIn:"header" name:"etag"` + + // The time the retention rule was last modified, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29) + LastModified *common.SDKTime `presentIn:"header" name:"last-modified"` +} + +func (response GetRetentionRuleResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetRetentionRuleResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_work_request_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_work_request_request_response.go new file mode 100644 index 00000000000..6514487edd5 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/get_work_request_request_response.go @@ -0,0 +1,111 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetWorkRequestRequest wrapper for the GetWorkRequest operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetWorkRequest.go.html to see an example of how to use GetWorkRequestRequest. +type GetWorkRequestRequest struct { + + // The ID of the asynchronous request. + WorkRequestId *string `mandatory:"true" contributesTo:"path" name:"workRequestId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetWorkRequestRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetWorkRequestRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetWorkRequestRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request GetWorkRequestRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["workRequestId"] != nil { + templateParam := mandatoryParamMap["workRequestId"] + for _, template := range templateParam { + replacementParam := *request.WorkRequestId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetWorkRequestRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetWorkRequestRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetWorkRequestResponse wrapper for the GetWorkRequest operation +type GetWorkRequestResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The WorkRequest instance + WorkRequest `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // A decimal number representing the number of seconds the client should wait before polling this endpoint again. + RetryAfter *float32 `presentIn:"header" name:"retry-after"` +} + +func (response GetWorkRequestResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetWorkRequestResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_bucket_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_bucket_request_response.go new file mode 100644 index 00000000000..40ceee0a651 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_bucket_request_response.go @@ -0,0 +1,138 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// HeadBucketRequest wrapper for the HeadBucket operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/HeadBucket.go.html to see an example of how to use HeadBucketRequest. +type HeadBucketRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. Wildcards ('*') are not allowed. If the specified ETag does not + // match the ETag of the existing resource, the request returns the expected response. If the ETag matches + // the ETag of the existing resource, the request returns an HTTP 304 status without a response body. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request HeadBucketRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request HeadBucketRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request HeadBucketRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request HeadBucketRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request HeadBucketRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request HeadBucketRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// HeadBucketResponse wrapper for the HeadBucket operation +type HeadBucketResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The current entity tag (ETag) for the bucket. + ETag *string `presentIn:"header" name:"etag"` + + // Flag to indicate whether or not the object was modified. If this is true, + // the getter for the object itself will return null. Callers should check this + // if they specified one of the request params that might result in a conditional + // response (like 'if-match'/'if-none-match'). + IsNotModified bool +} + +func (response HeadBucketResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response HeadBucketResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_object_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_object_request_response.go new file mode 100644 index 00000000000..ae1c555b96b --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/head_object_request_response.go @@ -0,0 +1,339 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// HeadObjectRequest wrapper for the HeadObject operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/HeadObject.go.html to see an example of how to use HeadObjectRequest. +type HeadObjectRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // VersionId used to identify a particular version of the object + VersionId *string `mandatory:"false" contributesTo:"query" name:"versionId"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. Wildcards ('*') are not allowed. If the specified ETag does not + // match the ETag of the existing resource, the request returns the expected response. If the ETag matches + // the ETag of the existing resource, the request returns an HTTP 304 status without a response body. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The optional header that specifies "AES256" as the encryption algorithm. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerAlgorithm *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-algorithm"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or + // decrypt the data. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKey *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This + // value is used to check the integrity of the encryption key. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKeySha256 *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key-sha256"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request HeadObjectRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request HeadObjectRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request HeadObjectRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request HeadObjectRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request HeadObjectRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request HeadObjectRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// HeadObjectResponse wrapper for the HeadObject operation +type HeadObjectResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the object. + ETag *string `presentIn:"header" name:"etag"` + + // The user-defined metadata for the object. + OpcMeta map[string]string `presentIn:"header-collection" prefix:"opc-meta-"` + + // The object size in bytes. + ContentLength *int64 `presentIn:"header" name:"content-length"` + + // Content-MD5 header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.15). + // Unavailable for objects uploaded using multipart upload. + ContentMd5 *string `presentIn:"header" name:"content-md5"` + + // Only applicable to objects uploaded using multipart upload. + // Base-64 representation of the multipart object hash. + // The multipart object hash is calculated by taking the MD5 hashes of the parts, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the MD5 hash of the concatenated values. + OpcMultipartMd5 *string `presentIn:"header" name:"opc-multipart-md5"` + + // The base64-encoded, 32-bit CRC32C (Castagnoli) checksum of the object. + // Even for objects uploaded using multipart upload, this header returns the CRC32C (Castagnoli) checksum + // of the complete reconstructed object. + OpcContentCrc32c *string `presentIn:"header" name:"opc-content-crc32c"` + + // Applicable only if SHA256 was specified in the opc-checksum-algorithm request header during upload. + // The base64-encoded SHA256 hash of the object as computed during upload. + // Unavailable for objects uploaded using multipart upload. + OpcContentSha256 *string `presentIn:"header" name:"opc-content-sha256"` + + // Only applicable to objects uploaded using multipart upload. + // Applicable only if SHA256 was specified in the opc-checksum-algorithm request header during upload. + // Base-64 representation of the multipart object SHA256 hash. + // The multipart object hash is calculated by taking the SHA256 hashes of the parts, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the SHA256 hash of the concatenated values. + OpcMultipartSha256 *string `presentIn:"header" name:"opc-multipart-sha256"` + + // Applicable only if SHA384 was specified in the opc-checksum-algorithm request header during upload. + // The base64-encoded SHA384 hash of the object as computed during upload. + // Unavailable for objects uploaded using multipart upload. + OpcContentSha384 *string `presentIn:"header" name:"opc-content-sha384"` + + // Only applicable to objects uploaded using multipart upload. + // Applicable only if SHA384 was specified in the opc-checksum-algorithm request header during upload. + // Base-64 representation of the multipart object SHA384 hash. + // The multipart object hash is calculated by taking the SHA384 hashes of the parts, + // concatenating the binary representation of those hashes in order of their part numbers, + // and then calculating the SHA384 hash of the concatenated values. + OpcMultipartSha384 *string `presentIn:"header" name:"opc-multipart-sha384"` + + // Content-Type header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.17). + ContentType *string `presentIn:"header" name:"content-type"` + + // Content-Language header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.12). + ContentLanguage *string `presentIn:"header" name:"content-language"` + + // Content-Encoding header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.11). + ContentEncoding *string `presentIn:"header" name:"content-encoding"` + + // Cache-Control header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.9). + CacheControl *string `presentIn:"header" name:"cache-control"` + + // Content-Disposition header, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-19.5.1). + ContentDisposition *string `presentIn:"header" name:"content-disposition"` + + // The object modification time, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + LastModified *common.SDKTime `presentIn:"header" name:"last-modified"` + + // The storage tier that the object is stored in. + StorageTier HeadObjectStorageTierEnum `presentIn:"header" name:"storage-tier"` + + // Archival state of an object. This field is set only for objects in Archive tier. + ArchivalState HeadObjectArchivalStateEnum `presentIn:"header" name:"archival-state"` + + // Time that the object is returned to the archived state. This field is only present for restored objects. + TimeOfArchival *common.SDKTime `presentIn:"header" name:"time-of-archival"` + + // VersionId of the object requested + VersionId *string `presentIn:"header" name:"version-id"` + + // Flag to indicate whether or not the object was modified. If this is true, + // the getter for the object itself will return null. Callers should check this + // if they specified one of the request params that might result in a conditional + // response (like 'if-match'/'if-none-match'). + IsNotModified bool +} + +func (response HeadObjectResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response HeadObjectResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// HeadObjectStorageTierEnum Enum with underlying type: string +type HeadObjectStorageTierEnum string + +// Set of constants representing the allowable values for HeadObjectStorageTierEnum +const ( + HeadObjectStorageTierStandard HeadObjectStorageTierEnum = "Standard" + HeadObjectStorageTierInfrequentaccess HeadObjectStorageTierEnum = "InfrequentAccess" + HeadObjectStorageTierArchive HeadObjectStorageTierEnum = "Archive" +) + +var mappingHeadObjectStorageTierEnum = map[string]HeadObjectStorageTierEnum{ + "Standard": HeadObjectStorageTierStandard, + "InfrequentAccess": HeadObjectStorageTierInfrequentaccess, + "Archive": HeadObjectStorageTierArchive, +} + +var mappingHeadObjectStorageTierEnumLowerCase = map[string]HeadObjectStorageTierEnum{ + "standard": HeadObjectStorageTierStandard, + "infrequentaccess": HeadObjectStorageTierInfrequentaccess, + "archive": HeadObjectStorageTierArchive, +} + +// GetHeadObjectStorageTierEnumValues Enumerates the set of values for HeadObjectStorageTierEnum +func GetHeadObjectStorageTierEnumValues() []HeadObjectStorageTierEnum { + values := make([]HeadObjectStorageTierEnum, 0) + for _, v := range mappingHeadObjectStorageTierEnum { + values = append(values, v) + } + return values +} + +// GetHeadObjectStorageTierEnumStringValues Enumerates the set of values in String for HeadObjectStorageTierEnum +func GetHeadObjectStorageTierEnumStringValues() []string { + return []string{ + "Standard", + "InfrequentAccess", + "Archive", + } +} + +// GetMappingHeadObjectStorageTierEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingHeadObjectStorageTierEnum(val string) (HeadObjectStorageTierEnum, bool) { + enum, ok := mappingHeadObjectStorageTierEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// HeadObjectArchivalStateEnum Enum with underlying type: string +type HeadObjectArchivalStateEnum string + +// Set of constants representing the allowable values for HeadObjectArchivalStateEnum +const ( + HeadObjectArchivalStateArchived HeadObjectArchivalStateEnum = "Archived" + HeadObjectArchivalStateRestoring HeadObjectArchivalStateEnum = "Restoring" + HeadObjectArchivalStateRestored HeadObjectArchivalStateEnum = "Restored" +) + +var mappingHeadObjectArchivalStateEnum = map[string]HeadObjectArchivalStateEnum{ + "Archived": HeadObjectArchivalStateArchived, + "Restoring": HeadObjectArchivalStateRestoring, + "Restored": HeadObjectArchivalStateRestored, +} + +var mappingHeadObjectArchivalStateEnumLowerCase = map[string]HeadObjectArchivalStateEnum{ + "archived": HeadObjectArchivalStateArchived, + "restoring": HeadObjectArchivalStateRestoring, + "restored": HeadObjectArchivalStateRestored, +} + +// GetHeadObjectArchivalStateEnumValues Enumerates the set of values for HeadObjectArchivalStateEnum +func GetHeadObjectArchivalStateEnumValues() []HeadObjectArchivalStateEnum { + values := make([]HeadObjectArchivalStateEnum, 0) + for _, v := range mappingHeadObjectArchivalStateEnum { + values = append(values, v) + } + return values +} + +// GetHeadObjectArchivalStateEnumStringValues Enumerates the set of values in String for HeadObjectArchivalStateEnum +func GetHeadObjectArchivalStateEnumStringValues() []string { + return []string{ + "Archived", + "Restoring", + "Restored", + } +} + +// GetMappingHeadObjectArchivalStateEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingHeadObjectArchivalStateEnum(val string) (HeadObjectArchivalStateEnum, bool) { + enum, ok := mappingHeadObjectArchivalStateEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_buckets_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_buckets_request_response.go new file mode 100644 index 00000000000..12e0179f29e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_buckets_request_response.go @@ -0,0 +1,187 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListBucketsRequest wrapper for the ListBuckets operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListBuckets.go.html to see an example of how to use ListBucketsRequest. +type ListBucketsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The ID of the compartment in which to list buckets. + CompartmentId *string `mandatory:"true" contributesTo:"query" name:"compartmentId"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // Bucket summary in list of buckets includes the 'namespace', 'name', 'compartmentId', 'createdBy', 'timeCreated', + // and 'etag' fields. This parameter can also include 'tags' (freeformTags and definedTags). The only supported value of this parameter is 'tags' for now. Example 'tags'. + Fields []ListBucketsFieldsEnum `contributesTo:"query" name:"fields" omitEmpty:"true" collectionFormat:"csv"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListBucketsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListBucketsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListBucketsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListBucketsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["compartmentId"] != nil { + templateParam := mandatoryParamMap["compartmentId"] + for _, template := range templateParam { + replacementParam := *request.CompartmentId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListBucketsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListBucketsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + for _, val := range request.Fields { + if _, ok := GetMappingListBucketsFieldsEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Fields: %s. Supported values are: %s.", val, strings.Join(GetListBucketsFieldsEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListBucketsResponse wrapper for the ListBuckets operation +type ListBucketsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []BucketSummary instances + Items []BucketSummary `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of buckets. + // In the GET request, set the limit to the number of buckets items that you want returned in the response. + // If the `opc-next-page` header appears in the response, then this is a partial list and there are additional + // buckets to get. Include the header's value as the `page` parameter in the subsequent GET request to get the + // next batch of buckets. Repeat this process to retrieve the entire list of buckets. + // By default, the page limit is set to 25 buckets per page, but you can specify a value from 1 to 1000. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListBucketsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListBucketsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// ListBucketsFieldsEnum Enum with underlying type: string +type ListBucketsFieldsEnum string + +// Set of constants representing the allowable values for ListBucketsFieldsEnum +const ( + ListBucketsFieldsTags ListBucketsFieldsEnum = "tags" +) + +var mappingListBucketsFieldsEnum = map[string]ListBucketsFieldsEnum{ + "tags": ListBucketsFieldsTags, +} + +var mappingListBucketsFieldsEnumLowerCase = map[string]ListBucketsFieldsEnum{ + "tags": ListBucketsFieldsTags, +} + +// GetListBucketsFieldsEnumValues Enumerates the set of values for ListBucketsFieldsEnum +func GetListBucketsFieldsEnumValues() []ListBucketsFieldsEnum { + values := make([]ListBucketsFieldsEnum, 0) + for _, v := range mappingListBucketsFieldsEnum { + values = append(values, v) + } + return values +} + +// GetListBucketsFieldsEnumStringValues Enumerates the set of values in String for ListBucketsFieldsEnum +func GetListBucketsFieldsEnumStringValues() []string { + return []string{ + "tags", + } +} + +// GetMappingListBucketsFieldsEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingListBucketsFieldsEnum(val string) (ListBucketsFieldsEnum, bool) { + enum, ok := mappingListBucketsFieldsEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_upload_parts_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_upload_parts_request_response.go new file mode 100644 index 00000000000..fcb8d9b2a80 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_upload_parts_request_response.go @@ -0,0 +1,167 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListMultipartUploadPartsRequest wrapper for the ListMultipartUploadParts operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListMultipartUploadParts.go.html to see an example of how to use ListMultipartUploadPartsRequest. +type ListMultipartUploadPartsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // The upload ID for a multipart upload. + UploadId *string `mandatory:"true" contributesTo:"query" name:"uploadId"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListMultipartUploadPartsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListMultipartUploadPartsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListMultipartUploadPartsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListMultipartUploadPartsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["uploadId"] != nil { + templateParam := mandatoryParamMap["uploadId"] + for _, template := range templateParam { + replacementParam := *request.UploadId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListMultipartUploadPartsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListMultipartUploadPartsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListMultipartUploadPartsResponse wrapper for the ListMultipartUploadParts operation +type ListMultipartUploadPartsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []MultipartUploadPartSummary instances + Items []MultipartUploadPartSummary `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of multipart upload parts. + // In the GET request, set the limit to the number of multipart upload parts that you want returned in the + // response. If the `opc-next-page` header appears in the response, then this is a partial list and there are + // additional multipart upload parts to get. Include the header's value as the `page` parameter in the subsequent + // GET request to get the next batch of multipart upload parts. Repeat this process to retrieve the entire list + // of multipart upload parts. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListMultipartUploadPartsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListMultipartUploadPartsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_uploads_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_uploads_request_response.go new file mode 100644 index 00000000000..2a2bbce5044 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_multipart_uploads_request_response.go @@ -0,0 +1,140 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListMultipartUploadsRequest wrapper for the ListMultipartUploads operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListMultipartUploads.go.html to see an example of how to use ListMultipartUploadsRequest. +type ListMultipartUploadsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListMultipartUploadsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListMultipartUploadsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListMultipartUploadsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListMultipartUploadsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListMultipartUploadsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListMultipartUploadsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListMultipartUploadsResponse wrapper for the ListMultipartUploads operation +type ListMultipartUploadsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []MultipartUpload instances + Items []MultipartUpload `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of multipart uploads. + // In the GET request, set the limit to the number of multipart uploads that you want returned in the response. + // If the `opc-next-page` header appears in the response, then this is a partial list and there are + // additional multipart uploads to get. Include the header's value as the `page` parameter in the subsequent + // GET request to get the next batch of objects. Repeat this process to retrieve the entire list of + // multipart uploads. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListMultipartUploadsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListMultipartUploadsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_object_versions_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_object_versions_request_response.go new file mode 100644 index 00000000000..40872ba033f --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_object_versions_request_response.go @@ -0,0 +1,235 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListObjectVersionsRequest wrapper for the ListObjectVersions operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListObjectVersions.go.html to see an example of how to use ListObjectVersionsRequest. +type ListObjectVersionsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The string to use for matching against the start of object names in a list query. + Prefix *string `mandatory:"false" contributesTo:"query" name:"prefix"` + + // Returns object names which are lexicographically greater than or equal to this parameter. + Start *string `mandatory:"false" contributesTo:"query" name:"start"` + + // Returns object names which are lexicographically strictly less than this parameter. + End *string `mandatory:"false" contributesTo:"query" name:"end"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // When this parameter is set, only objects whose names do not contain the delimiter character + // (after an optionally specified prefix) are returned in the objects key of the response body. + // Scanned objects whose names contain the delimiter have the part of their name up to the first + // occurrence of the delimiter (including the optional prefix) returned as a set of prefixes. + // Note that only '/' is a supported delimiter character at this time. + Delimiter *string `mandatory:"false" contributesTo:"query" name:"delimiter"` + + // Object summary by default includes only the 'name' field. Use this parameter to also + // include 'size' (object size in bytes), 'etag', 'md5', 'timeCreated' (object creation date and time), + // 'timeModified' (object modification date and time), 'storageTier' and 'archivalState' fields. + // Specify the value of this parameter as a comma-separated, case-insensitive list of those field names. + // For example 'name,etag,timeCreated,md5,timeModified,storageTier,archivalState'. + Fields ListObjectVersionsFieldsEnum `mandatory:"false" contributesTo:"query" name:"fields" omitEmpty:"true"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Returns object names which are lexicographically strictly greater than this parameter. + StartAfter *string `mandatory:"false" contributesTo:"query" name:"startAfter"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListObjectVersionsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListObjectVersionsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListObjectVersionsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListObjectVersionsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListObjectVersionsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListObjectVersionsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingListObjectVersionsFieldsEnum(string(request.Fields)); !ok && request.Fields != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Fields: %s. Supported values are: %s.", request.Fields, strings.Join(GetListObjectVersionsFieldsEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListObjectVersionsResponse wrapper for the ListObjectVersions operation +type ListObjectVersionsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of ObjectVersionCollection instances + ObjectVersionCollection `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of object versions. + // In the GET request, set the limit to the number of object versions that you want returned in the response. + // If the `opc-next-page` header appears in the response, then this is a partial list and there are + // additional object versions to get. Include the header's value as the `page` parameter in the subsequent + // GET request to get the next batch of object versions and prefixes. Repeat this process to retrieve the entire list of + // object versions and prefixes. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListObjectVersionsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListObjectVersionsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// ListObjectVersionsFieldsEnum Enum with underlying type: string +type ListObjectVersionsFieldsEnum string + +// Set of constants representing the allowable values for ListObjectVersionsFieldsEnum +const ( + ListObjectVersionsFieldsName ListObjectVersionsFieldsEnum = "name" + ListObjectVersionsFieldsSize ListObjectVersionsFieldsEnum = "size" + ListObjectVersionsFieldsEtag ListObjectVersionsFieldsEnum = "etag" + ListObjectVersionsFieldsTimecreated ListObjectVersionsFieldsEnum = "timeCreated" + ListObjectVersionsFieldsMd5 ListObjectVersionsFieldsEnum = "md5" + ListObjectVersionsFieldsTimemodified ListObjectVersionsFieldsEnum = "timeModified" + ListObjectVersionsFieldsStoragetier ListObjectVersionsFieldsEnum = "storageTier" + ListObjectVersionsFieldsArchivalstate ListObjectVersionsFieldsEnum = "archivalState" +) + +var mappingListObjectVersionsFieldsEnum = map[string]ListObjectVersionsFieldsEnum{ + "name": ListObjectVersionsFieldsName, + "size": ListObjectVersionsFieldsSize, + "etag": ListObjectVersionsFieldsEtag, + "timeCreated": ListObjectVersionsFieldsTimecreated, + "md5": ListObjectVersionsFieldsMd5, + "timeModified": ListObjectVersionsFieldsTimemodified, + "storageTier": ListObjectVersionsFieldsStoragetier, + "archivalState": ListObjectVersionsFieldsArchivalstate, +} + +var mappingListObjectVersionsFieldsEnumLowerCase = map[string]ListObjectVersionsFieldsEnum{ + "name": ListObjectVersionsFieldsName, + "size": ListObjectVersionsFieldsSize, + "etag": ListObjectVersionsFieldsEtag, + "timecreated": ListObjectVersionsFieldsTimecreated, + "md5": ListObjectVersionsFieldsMd5, + "timemodified": ListObjectVersionsFieldsTimemodified, + "storagetier": ListObjectVersionsFieldsStoragetier, + "archivalstate": ListObjectVersionsFieldsArchivalstate, +} + +// GetListObjectVersionsFieldsEnumValues Enumerates the set of values for ListObjectVersionsFieldsEnum +func GetListObjectVersionsFieldsEnumValues() []ListObjectVersionsFieldsEnum { + values := make([]ListObjectVersionsFieldsEnum, 0) + for _, v := range mappingListObjectVersionsFieldsEnum { + values = append(values, v) + } + return values +} + +// GetListObjectVersionsFieldsEnumStringValues Enumerates the set of values in String for ListObjectVersionsFieldsEnum +func GetListObjectVersionsFieldsEnumStringValues() []string { + return []string{ + "name", + "size", + "etag", + "timeCreated", + "md5", + "timeModified", + "storageTier", + "archivalState", + } +} + +// GetMappingListObjectVersionsFieldsEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingListObjectVersionsFieldsEnum(val string) (ListObjectVersionsFieldsEnum, bool) { + enum, ok := mappingListObjectVersionsFieldsEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects.go new file mode 100644 index 00000000000..c7860cd18eb --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects.go @@ -0,0 +1,51 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ListObjects To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type ListObjects struct { + + // An array of object summaries. + Objects []ObjectSummary `mandatory:"true" json:"objects"` + + // Prefixes that are common to the results returned by the request if the request specified a delimiter. + Prefixes []string `mandatory:"false" json:"prefixes"` + + // The name of the object to use in the `start` parameter to obtain the next page of + // a truncated ListObjects response. Avoid entering confidential information. + // Example: test/object1.log + NextStartWith *string `mandatory:"false" json:"nextStartWith"` +} + +func (m ListObjects) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ListObjects) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects_request_response.go new file mode 100644 index 00000000000..92140dc88ed --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_objects_request_response.go @@ -0,0 +1,153 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListObjectsRequest wrapper for the ListObjects operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListObjects.go.html to see an example of how to use ListObjectsRequest. +type ListObjectsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The string to use for matching against the start of object names in a list query. + Prefix *string `mandatory:"false" contributesTo:"query" name:"prefix"` + + // Returns object names which are lexicographically greater than or equal to this parameter. + Start *string `mandatory:"false" contributesTo:"query" name:"start"` + + // Returns object names which are lexicographically strictly less than this parameter. + End *string `mandatory:"false" contributesTo:"query" name:"end"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // When this parameter is set, only objects whose names do not contain the delimiter character + // (after an optionally specified prefix) are returned in the objects key of the response body. + // Scanned objects whose names contain the delimiter have the part of their name up to the first + // occurrence of the delimiter (including the optional prefix) returned as a set of prefixes. + // Note that only '/' is a supported delimiter character at this time. + Delimiter *string `mandatory:"false" contributesTo:"query" name:"delimiter"` + + // Object summary by default includes only the 'name' field. Use this parameter to also + // include 'size' (object size in bytes), 'etag', 'md5', 'timeCreated' (object creation date and time), + // 'timeModified' (object modification date and time), 'storageTier' and 'archivalState' fields. + // Specify the value of this parameter as a comma-separated, case-insensitive list of those field names. + // For example 'name,etag,timeCreated,md5,timeModified,storageTier,archivalState'. + Fields *string `mandatory:"false" contributesTo:"query" name:"fields" omitEmpty:"true"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Returns object names which are lexicographically strictly greater than this parameter. + StartAfter *string `mandatory:"false" contributesTo:"query" name:"startAfter"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListObjectsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListObjectsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListObjectsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListObjectsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListObjectsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListObjectsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListObjectsResponse wrapper for the ListObjects operation +type ListObjectsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The ListObjects instance + ListObjects `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response ListObjectsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListObjectsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_preauthenticated_requests_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_preauthenticated_requests_request_response.go new file mode 100644 index 00000000000..0ff71394272 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_preauthenticated_requests_request_response.go @@ -0,0 +1,143 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListPreauthenticatedRequestsRequest wrapper for the ListPreauthenticatedRequests operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListPreauthenticatedRequests.go.html to see an example of how to use ListPreauthenticatedRequestsRequest. +type ListPreauthenticatedRequestsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // User-specified object name prefixes can be used to query and return a list of pre-authenticated requests. + ObjectNamePrefix *string `mandatory:"false" contributesTo:"query" name:"objectNamePrefix"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListPreauthenticatedRequestsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListPreauthenticatedRequestsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListPreauthenticatedRequestsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListPreauthenticatedRequestsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListPreauthenticatedRequestsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListPreauthenticatedRequestsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListPreauthenticatedRequestsResponse wrapper for the ListPreauthenticatedRequests operation +type ListPreauthenticatedRequestsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []PreauthenticatedRequestSummary instances + Items []PreauthenticatedRequestSummary `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of pre-authenticated requests. + // In the GET request, set the limit to the number of pre-authenticated requests that you want returned in + // the response. If the `opc-next-page` header appears in the response, then this is a partial list and there + // are additional pre-authenticated requests to get. Include the header's value as the `page` parameter in + // the subsequent GET request to get the next batch of pre-authenticated requests. Repeat this process to + // retrieve the entire list of pre-authenticated requests. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListPreauthenticatedRequestsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListPreauthenticatedRequestsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_private_endpoints_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_private_endpoints_request_response.go new file mode 100644 index 00000000000..2aa4c203b4c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_private_endpoints_request_response.go @@ -0,0 +1,195 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListPrivateEndpointsRequest wrapper for the ListPrivateEndpoints operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListPrivateEndpoints.go.html to see an example of how to use ListPrivateEndpointsRequest. +type ListPrivateEndpointsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The ID of the compartment in which to list buckets. + CompartmentId *string `mandatory:"true" contributesTo:"query" name:"compartmentId"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // PrivateEndpoint summary in list of PrivateEndpoints includes the 'namespace', 'name', 'compartmentId', + // 'createdBy', 'timeCreated', 'timeModified' and 'etag' fields. + // This parameter can also include 'tags' (freeformTags and definedTags). + // The only supported value of this parameter is 'tags' for now. Example 'tags'. + Fields []ListPrivateEndpointsFieldsEnum `contributesTo:"query" name:"fields" omitEmpty:"true" collectionFormat:"csv"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The lifecycle state of the Private Endpoint + LifecycleState PrivateEndpointLifecycleStateEnum `mandatory:"false" contributesTo:"query" name:"lifecycleState" omitEmpty:"true"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListPrivateEndpointsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListPrivateEndpointsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListPrivateEndpointsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListPrivateEndpointsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["compartmentId"] != nil { + templateParam := mandatoryParamMap["compartmentId"] + for _, template := range templateParam { + replacementParam := *request.CompartmentId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListPrivateEndpointsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListPrivateEndpointsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + for _, val := range request.Fields { + if _, ok := GetMappingListPrivateEndpointsFieldsEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Fields: %s. Supported values are: %s.", val, strings.Join(GetListPrivateEndpointsFieldsEnumStringValues(), ","))) + } + } + + if _, ok := GetMappingPrivateEndpointLifecycleStateEnum(string(request.LifecycleState)); !ok && request.LifecycleState != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for LifecycleState: %s. Supported values are: %s.", request.LifecycleState, strings.Join(GetPrivateEndpointLifecycleStateEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListPrivateEndpointsResponse wrapper for the ListPrivateEndpoints operation +type ListPrivateEndpointsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []PrivateEndpointSummary instances + Items []PrivateEndpointSummary `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of PEs. + // In the GET request, set the limit to the number of Private Endpoint items that you want returned in the response. + // If the `opc-next-page` header appears in the response, then this is a partial list and there are additional + // Private Endpoint's to get. Include the header's value as the `page` parameter in the subsequent GET request to get the + // next batch of PEs. Repeat this process to retrieve the entire list of Private Endpoint's. + // By default, the page limit is set to 25 Private Endpoint's per page, but you can specify a value from 1 to 1000. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListPrivateEndpointsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListPrivateEndpointsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// ListPrivateEndpointsFieldsEnum Enum with underlying type: string +type ListPrivateEndpointsFieldsEnum string + +// Set of constants representing the allowable values for ListPrivateEndpointsFieldsEnum +const ( + ListPrivateEndpointsFieldsTags ListPrivateEndpointsFieldsEnum = "tags" +) + +var mappingListPrivateEndpointsFieldsEnum = map[string]ListPrivateEndpointsFieldsEnum{ + "tags": ListPrivateEndpointsFieldsTags, +} + +var mappingListPrivateEndpointsFieldsEnumLowerCase = map[string]ListPrivateEndpointsFieldsEnum{ + "tags": ListPrivateEndpointsFieldsTags, +} + +// GetListPrivateEndpointsFieldsEnumValues Enumerates the set of values for ListPrivateEndpointsFieldsEnum +func GetListPrivateEndpointsFieldsEnumValues() []ListPrivateEndpointsFieldsEnum { + values := make([]ListPrivateEndpointsFieldsEnum, 0) + for _, v := range mappingListPrivateEndpointsFieldsEnum { + values = append(values, v) + } + return values +} + +// GetListPrivateEndpointsFieldsEnumStringValues Enumerates the set of values in String for ListPrivateEndpointsFieldsEnum +func GetListPrivateEndpointsFieldsEnumStringValues() []string { + return []string{ + "tags", + } +} + +// GetMappingListPrivateEndpointsFieldsEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingListPrivateEndpointsFieldsEnum(val string) (ListPrivateEndpointsFieldsEnum, bool) { + enum, ok := mappingListPrivateEndpointsFieldsEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_policies_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_policies_request_response.go new file mode 100644 index 00000000000..5099e708ac6 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_policies_request_response.go @@ -0,0 +1,139 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListReplicationPoliciesRequest wrapper for the ListReplicationPolicies operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListReplicationPolicies.go.html to see an example of how to use ListReplicationPoliciesRequest. +type ListReplicationPoliciesRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListReplicationPoliciesRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListReplicationPoliciesRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListReplicationPoliciesRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListReplicationPoliciesRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListReplicationPoliciesRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListReplicationPoliciesRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListReplicationPoliciesResponse wrapper for the ListReplicationPolicies operation +type ListReplicationPoliciesResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []ReplicationPolicySummary instances + Items []ReplicationPolicySummary `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // For paginating a list of replication policies. + // In the GET request, set the limit to the number of buckets items that you want returned in the response. + // If the `opc-next-page` header appears in the response, then this is a partial list and there are additional + // policies to get. Include the header's value as the `page` parameter in the subsequent GET request to get the + // next batch of policies. Repeat this process to retrieve the entire list of policies. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListReplicationPoliciesResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListReplicationPoliciesResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_sources_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_sources_request_response.go new file mode 100644 index 00000000000..13681fd3ddd --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_replication_sources_request_response.go @@ -0,0 +1,139 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListReplicationSourcesRequest wrapper for the ListReplicationSources operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListReplicationSources.go.html to see an example of how to use ListReplicationSourcesRequest. +type ListReplicationSourcesRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListReplicationSourcesRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListReplicationSourcesRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListReplicationSourcesRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListReplicationSourcesRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListReplicationSourcesRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListReplicationSourcesRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListReplicationSourcesResponse wrapper for the ListReplicationSources operation +type ListReplicationSourcesResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []ReplicationSource instances + Items []ReplicationSource `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // For paginating a list of replication sources. + // In the GET request, set the limit to the number of items that you want returned in the response. + // If the `opc-next-page` header appears in the response, then this is a partial list and there are additional + // policies to get. Include the header's value as the `page` parameter in the subsequent GET request to get the + // next batch of policies. Repeat this process to retrieve the entire list of sources. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListReplicationSourcesResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListReplicationSourcesResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_retention_rules_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_retention_rules_request_response.go new file mode 100644 index 00000000000..ff5bf1d95fe --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_retention_rules_request_response.go @@ -0,0 +1,135 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListRetentionRulesRequest wrapper for the ListRetentionRules operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListRetentionRules.go.html to see an example of how to use ListRetentionRulesRequest. +type ListRetentionRulesRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // Unique Oracle-assigned identifier for the request. + // If you need to contact Oracle about a particular request, please provide the request ID. + OpcRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListRetentionRulesRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListRetentionRulesRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListRetentionRulesRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListRetentionRulesRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListRetentionRulesRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListRetentionRulesRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListRetentionRulesResponse wrapper for the ListRetentionRules operation +type ListRetentionRulesResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of RetentionRuleCollection instances + RetentionRuleCollection `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Paginating a list of retention rules. + // If the `opc-next-page` header appears in the response, it indicates that this is a partial list + // of retention rules and there are additional rules to get. Include the value of this header as + // the `page` parameter in a subsequent GET request to get the next set of retention rules. + // Repeat this process to retrieve the entire list of retention rules. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListRetentionRulesResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListRetentionRulesResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_errors_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_errors_request_response.go new file mode 100644 index 00000000000..ea0dd4aedc7 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_errors_request_response.go @@ -0,0 +1,126 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListWorkRequestErrorsRequest wrapper for the ListWorkRequestErrors operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListWorkRequestErrors.go.html to see an example of how to use ListWorkRequestErrorsRequest. +type ListWorkRequestErrorsRequest struct { + + // The ID of the asynchronous request. + WorkRequestId *string `mandatory:"true" contributesTo:"path" name:"workRequestId"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListWorkRequestErrorsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListWorkRequestErrorsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListWorkRequestErrorsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListWorkRequestErrorsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["workRequestId"] != nil { + templateParam := mandatoryParamMap["workRequestId"] + for _, template := range templateParam { + replacementParam := *request.WorkRequestId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListWorkRequestErrorsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListWorkRequestErrorsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListWorkRequestErrorsResponse wrapper for the ListWorkRequestErrors operation +type ListWorkRequestErrorsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []WorkRequestError instances + Items []WorkRequestError `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of work request errors. + // In the GET request, set the limit to the number of work request errors that you want returned in the + // response. If the `opc-next-page` header appears in the response, then this is a partial list and there are + // additional work request errors to get. Include the header's value as the `page` parameter in the subsequent + // GET request to get the next batch of work request errors. Repeat this process to retrieve the entire list of work + // request errors. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response ListWorkRequestErrorsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListWorkRequestErrorsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_logs_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_logs_request_response.go new file mode 100644 index 00000000000..b2f0ab73e3a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_request_logs_request_response.go @@ -0,0 +1,126 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListWorkRequestLogsRequest wrapper for the ListWorkRequestLogs operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListWorkRequestLogs.go.html to see an example of how to use ListWorkRequestLogsRequest. +type ListWorkRequestLogsRequest struct { + + // The ID of the asynchronous request. + WorkRequestId *string `mandatory:"true" contributesTo:"path" name:"workRequestId"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListWorkRequestLogsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListWorkRequestLogsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListWorkRequestLogsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListWorkRequestLogsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["workRequestId"] != nil { + templateParam := mandatoryParamMap["workRequestId"] + for _, template := range templateParam { + replacementParam := *request.WorkRequestId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListWorkRequestLogsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListWorkRequestLogsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListWorkRequestLogsResponse wrapper for the ListWorkRequestLogs operation +type ListWorkRequestLogsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []WorkRequestLogEntry instances + Items []WorkRequestLogEntry `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // For paginating a list of work request logs. + // In the GET request, set the limit to the number of compartment work requests that you want returned in the + // response. If the `opc-next-page` header appears in the response, then this is a partial list and there are + // additional work requests to get. Include the header's value as the `page` parameter in the subsequent + // GET request to get the next batch of work requests. Repeat this process to retrieve the entire list of work + // requests. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` +} + +func (response ListWorkRequestLogsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListWorkRequestLogsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_requests_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_requests_request_response.go new file mode 100644 index 00000000000..2f638308302 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/list_work_requests_request_response.go @@ -0,0 +1,129 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListWorkRequestsRequest wrapper for the ListWorkRequests operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListWorkRequests.go.html to see an example of how to use ListWorkRequestsRequest. +type ListWorkRequestsRequest struct { + + // The ID of the compartment in which to list buckets. + CompartmentId *string `mandatory:"true" contributesTo:"query" name:"compartmentId"` + + // The name of the privateEndpoint for which to list work requests. + PrivateEndpointName *string `mandatory:"false" contributesTo:"query" name:"privateEndpointName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // For list pagination. The value of the `opc-next-page` response header from the previous "List" call. For important + // details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Page *string `mandatory:"false" contributesTo:"query" name:"page"` + + // For list pagination. The maximum number of results per page, or items to return in a paginated + // "List" call. For important details about how pagination works, see + // List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + Limit *int `mandatory:"false" contributesTo:"query" name:"limit"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListWorkRequestsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListWorkRequestsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListWorkRequestsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ListWorkRequestsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["compartmentId"] != nil { + templateParam := mandatoryParamMap["compartmentId"] + for _, template := range templateParam { + replacementParam := *request.CompartmentId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListWorkRequestsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListWorkRequestsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListWorkRequestsResponse wrapper for the ListWorkRequests operation +type ListWorkRequestsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // A list of []WorkRequestSummary instances + Items []WorkRequestSummary `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // For paginating a list of work requests. + // In the GET request, set the limit to the number of compartment work requests that you want returned in the + // response. If the `opc-next-page` header appears in the response, then this is a partial list and there are + // additional work requests to get. Include the header's value as the `page` parameter in the subsequent + // GET request to get the next batch of work requests. Repeat this process to retrieve the entire list of work + // requests. + // For more details about how pagination works, see List Pagination (https://docs.oracle.com/iaas/Content/API/Concepts/usingapi.htm#nine). + OpcNextPage *string `presentIn:"header" name:"opc-next-page"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` +} + +func (response ListWorkRequestsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListWorkRequestsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/make_bucket_writable_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/make_bucket_writable_request_response.go new file mode 100644 index 00000000000..39cb763f2ab --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/make_bucket_writable_request_response.go @@ -0,0 +1,119 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// MakeBucketWritableRequest wrapper for the MakeBucketWritable operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/MakeBucketWritable.go.html to see an example of how to use MakeBucketWritableRequest. +type MakeBucketWritableRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request MakeBucketWritableRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request MakeBucketWritableRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request MakeBucketWritableRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request MakeBucketWritableRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request MakeBucketWritableRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request MakeBucketWritableRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// MakeBucketWritableResponse wrapper for the MakeBucketWritable operation +type MakeBucketWritableResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response MakeBucketWritableResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response MakeBucketWritableResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload.go new file mode 100644 index 00000000000..4550c375e92 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload.go @@ -0,0 +1,66 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// MultipartUpload Multipart uploads provide efficient and resilient uploads, especially for large objects. Multipart uploads also accommodate +// objects that are too large for a single upload operation. With multipart uploads, individual parts of an object can be +// uploaded in parallel to reduce the amount of time you spend uploading. Multipart uploads can also minimize the impact +// of network failures by letting you retry a failed part upload instead of requiring you to retry an entire object upload. +// See Using Multipart Uploads (https://docs.oracle.com/iaas/Content/Object/Tasks/usingmultipartuploads.htm). +// To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type MultipartUpload struct { + + // The Object Storage namespace in which the in-progress multipart upload is stored. + Namespace *string `mandatory:"true" json:"namespace"` + + // The bucket in which the in-progress multipart upload is stored. + Bucket *string `mandatory:"true" json:"bucket"` + + // The object name of the in-progress multipart upload. + Object *string `mandatory:"true" json:"object"` + + // The unique identifier for the in-progress multipart upload. + UploadId *string `mandatory:"true" json:"uploadId"` + + // The date and time the upload was created, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The storage tier that the object is stored in. + StorageTier StorageTierEnum `mandatory:"false" json:"storageTier,omitempty"` +} + +func (m MultipartUpload) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m MultipartUpload) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingStorageTierEnum(string(m.StorageTier)); !ok && m.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", m.StorageTier, strings.Join(GetStorageTierEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload_part_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload_part_summary.go new file mode 100644 index 00000000000..5f1b043a67b --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/multipart_upload_part_summary.go @@ -0,0 +1,53 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// MultipartUploadPartSummary Gets summary information about multipart uploads. +// To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, +// see Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type MultipartUploadPartSummary struct { + + // The current entity tag (ETag) for the part. + Etag *string `mandatory:"true" json:"etag"` + + // The MD5 hash of the bytes of the part. + Md5 *string `mandatory:"true" json:"md5"` + + // The size of the part in bytes. + Size *int64 `mandatory:"true" json:"size"` + + // The part number for this part. + PartNumber *int `mandatory:"true" json:"partNumber"` +} + +func (m MultipartUploadPartSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m MultipartUploadPartSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/namespace_metadata.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/namespace_metadata.go new file mode 100644 index 00000000000..3af5ef4208f --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/namespace_metadata.go @@ -0,0 +1,47 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// NamespaceMetadata NamespaceMetadata maps a namespace string to defaultS3CompartmentId and defaultSwiftCompartmentId values. +type NamespaceMetadata struct { + + // The Object Storage namespace to which the metadata belongs. + Namespace *string `mandatory:"true" json:"namespace"` + + // If the field is set, specifies the default compartment assignment for the Amazon S3 Compatibility API. + DefaultS3CompartmentId *string `mandatory:"true" json:"defaultS3CompartmentId"` + + // If the field is set, specifies the default compartment assignment for the Swift API. + DefaultSwiftCompartmentId *string `mandatory:"true" json:"defaultSwiftCompartmentId"` +} + +func (m NamespaceMetadata) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m NamespaceMetadata) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_policy.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_policy.go new file mode 100644 index 00000000000..d821c011668 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_policy.go @@ -0,0 +1,47 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ObjectLifecyclePolicy The collection of lifecycle policy rules that together form the object lifecycle policy of a given bucket. +type ObjectLifecyclePolicy struct { + + // The date and time the object lifecycle policy was created, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeCreated *common.SDKTime `mandatory:"false" json:"timeCreated"` + + // The live lifecycle policy on the bucket. + // For an example of this value, see the + // PutObjectLifecyclePolicy API documentation (https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/ObjectLifecyclePolicy/PutObjectLifecyclePolicy). + Items []ObjectLifecycleRule `mandatory:"false" json:"items"` +} + +func (m ObjectLifecyclePolicy) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ObjectLifecyclePolicy) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_rule.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_rule.go new file mode 100644 index 00000000000..a0b6bceba67 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_lifecycle_rule.go @@ -0,0 +1,121 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ObjectLifecycleRule To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type ObjectLifecycleRule struct { + + // The name of the lifecycle rule to be applied. + Name *string `mandatory:"true" json:"name"` + + // The action of the object lifecycle policy rule. + // Rules using the action 'ARCHIVE' move objects from Standard and InfrequentAccess storage tiers + // into the Archive storage tier (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). + // Rules using the action 'INFREQUENT_ACCESS' move objects from Standard storage tier into the + // Infrequent Access Storage tier. Objects that are already in InfrequentAccess tier or in Archive + // tier are left untouched. + // Rules using the action 'DELETE' permanently delete objects from buckets. + // Rules using 'ABORT' abort the uncommitted multipart-uploads and permanently delete their parts from buckets. + Action *string `mandatory:"true" json:"action"` + + // Specifies the age of objects to apply the rule to. The timeAmount is interpreted in units defined by the + // timeUnit parameter, and is calculated in relation to each object's Last-Modified time. + TimeAmount *int64 `mandatory:"true" json:"timeAmount"` + + // The unit that should be used to interpret timeAmount. Days are defined as starting and ending at midnight UTC. + // Years are defined as 365.2425 days long and likewise round up to the next midnight UTC. + TimeUnit ObjectLifecycleRuleTimeUnitEnum `mandatory:"true" json:"timeUnit"` + + // A Boolean that determines whether this rule is currently enabled. + IsEnabled *bool `mandatory:"true" json:"isEnabled"` + + // The target of the object lifecycle policy rule. The values of target can be either "objects", + // "multipart-uploads" or "previous-object-versions". + // This field when declared as "objects" is used to specify ARCHIVE, INFREQUENT_ACCESS + // or DELETE rule for objects. + // This field when declared as "previous-object-versions" is used to specify ARCHIVE, + // INFREQUENT_ACCESS or DELETE rule for previous versions of existing objects. + // This field when declared as "multipart-uploads" is used to specify the ABORT (only) rule for + // uncommitted multipart-uploads. + Target *string `mandatory:"false" json:"target"` + + ObjectNameFilter *ObjectNameFilter `mandatory:"false" json:"objectNameFilter"` +} + +func (m ObjectLifecycleRule) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ObjectLifecycleRule) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingObjectLifecycleRuleTimeUnitEnum(string(m.TimeUnit)); !ok && m.TimeUnit != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for TimeUnit: %s. Supported values are: %s.", m.TimeUnit, strings.Join(GetObjectLifecycleRuleTimeUnitEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ObjectLifecycleRuleTimeUnitEnum Enum with underlying type: string +type ObjectLifecycleRuleTimeUnitEnum string + +// Set of constants representing the allowable values for ObjectLifecycleRuleTimeUnitEnum +const ( + ObjectLifecycleRuleTimeUnitDays ObjectLifecycleRuleTimeUnitEnum = "DAYS" + ObjectLifecycleRuleTimeUnitYears ObjectLifecycleRuleTimeUnitEnum = "YEARS" +) + +var mappingObjectLifecycleRuleTimeUnitEnum = map[string]ObjectLifecycleRuleTimeUnitEnum{ + "DAYS": ObjectLifecycleRuleTimeUnitDays, + "YEARS": ObjectLifecycleRuleTimeUnitYears, +} + +var mappingObjectLifecycleRuleTimeUnitEnumLowerCase = map[string]ObjectLifecycleRuleTimeUnitEnum{ + "days": ObjectLifecycleRuleTimeUnitDays, + "years": ObjectLifecycleRuleTimeUnitYears, +} + +// GetObjectLifecycleRuleTimeUnitEnumValues Enumerates the set of values for ObjectLifecycleRuleTimeUnitEnum +func GetObjectLifecycleRuleTimeUnitEnumValues() []ObjectLifecycleRuleTimeUnitEnum { + values := make([]ObjectLifecycleRuleTimeUnitEnum, 0) + for _, v := range mappingObjectLifecycleRuleTimeUnitEnum { + values = append(values, v) + } + return values +} + +// GetObjectLifecycleRuleTimeUnitEnumStringValues Enumerates the set of values in String for ObjectLifecycleRuleTimeUnitEnum +func GetObjectLifecycleRuleTimeUnitEnumStringValues() []string { + return []string{ + "DAYS", + "YEARS", + } +} + +// GetMappingObjectLifecycleRuleTimeUnitEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingObjectLifecycleRuleTimeUnitEnum(val string) (ObjectLifecycleRuleTimeUnitEnum, bool) { + enum, ok := mappingObjectLifecycleRuleTimeUnitEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_name_filter.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_name_filter.go new file mode 100644 index 00000000000..0ee291a99dd --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_name_filter.go @@ -0,0 +1,84 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ObjectNameFilter A filter that compares object names to a set of prefixes or patterns to determine if a rule applies to a +// given object. The filter can contain include glob patterns, exclude glob patterns and inclusion prefixes. +// The inclusion prefixes property is kept for backward compatibility. It is recommended to use inclusion patterns +// instead of prefixes. Exclusions take precedence over inclusions. +type ObjectNameFilter struct { + + // An array of glob patterns to match the object names to include. An empty array includes all objects in the + // bucket. Exclusion patterns take precedence over inclusion patterns. + // A Glob pattern is a sequence of characters to match text. Any character that appears in the pattern, other + // than the special pattern characters described below, matches itself. + // Glob patterns must be between 1 and 1024 characters. + // The special pattern characters have the following meanings: + // \ Escapes the following character + // * Matches any string of characters. + // ? Matches any single character . + // [...] Matches a group of characters. A group of characters can be: + // A set of characters, for example: [Zafg9@]. This matches any character in the brackets. + // A range of characters, for example: [a-z]. This matches any character in the range. + // [a-f] is equivalent to [abcdef]. + // For character ranges only the CHARACTER-CHARACTER pattern is supported. + // [ab-yz] is not valid + // [a-mn-z] is not valid + // Character ranges can not start with ^ or : + // To include a '-' in the range, make it the first or last character. + InclusionPatterns []string `mandatory:"false" json:"inclusionPatterns"` + + // An array of glob patterns to match the object names to exclude. An empty array is ignored. Exclusion + // patterns take precedence over inclusion patterns. + // A Glob pattern is a sequence of characters to match text. Any character that appears in the pattern, other + // than the special pattern characters described below, matches itself. + // Glob patterns must be between 1 and 1024 characters. + // The special pattern characters have the following meanings: + // \ Escapes the following character + // * Matches any string of characters. + // ? Matches any single character . + // [...] Matches a group of characters. A group of characters can be: + // A set of characters, for example: [Zafg9@]. This matches any character in the brackets. + // A range of characters, for example: [a-z]. This matches any character in the range. + // [a-f] is equivalent to [abcdef]. + // For character ranges only the CHARACTER-CHARACTER pattern is supported. + // [ab-yz] is not valid + // [a-mn-z] is not valid + // Character ranges can not start with ^ or : + // To include a '-' in the range, make it the first or last character. + ExclusionPatterns []string `mandatory:"false" json:"exclusionPatterns"` + + // An array of object name prefixes that the rule will apply to. An empty array means to include all objects. + InclusionPrefixes []string `mandatory:"false" json:"inclusionPrefixes"` +} + +func (m ObjectNameFilter) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ObjectNameFilter) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_summary.go new file mode 100644 index 00000000000..245a00ea883 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_summary.go @@ -0,0 +1,71 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ObjectSummary To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type ObjectSummary struct { + + // The name of the object. Avoid entering confidential information. + // Example: test/object1.log + Name *string `mandatory:"true" json:"name"` + + // Size of the object in bytes. + Size *int64 `mandatory:"false" json:"size"` + + // Base64-encoded MD5 hash of the object data. + Md5 *string `mandatory:"false" json:"md5"` + + // The date and time the object was created, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeCreated *common.SDKTime `mandatory:"false" json:"timeCreated"` + + // The current entity tag (ETag) for the object. + Etag *string `mandatory:"false" json:"etag"` + + // The storage tier that the object is stored in. + StorageTier StorageTierEnum `mandatory:"false" json:"storageTier,omitempty"` + + // Archival state of an object. This field is set only for objects in Archive tier. + ArchivalState ArchivalStateEnum `mandatory:"false" json:"archivalState,omitempty"` + + // The date and time the object was modified, as described in RFC 2616 (https://tools.ietf.org/rfc/rfc2616), section 14.29. + TimeModified *common.SDKTime `mandatory:"false" json:"timeModified"` +} + +func (m ObjectSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ObjectSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingStorageTierEnum(string(m.StorageTier)); !ok && m.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", m.StorageTier, strings.Join(GetStorageTierEnumStringValues(), ","))) + } + if _, ok := GetMappingArchivalStateEnum(string(m.ArchivalState)); !ok && m.ArchivalState != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for ArchivalState: %s. Supported values are: %s.", m.ArchivalState, strings.Join(GetArchivalStateEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_collection.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_collection.go new file mode 100644 index 00000000000..a91b37010c8 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_collection.go @@ -0,0 +1,46 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ObjectVersionCollection To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type ObjectVersionCollection struct { + + // An array of object version summaries. + Items []ObjectVersionSummary `mandatory:"true" json:"items"` + + // Prefixes that are common to the results returned by the request if the request specified a delimiter. + Prefixes []string `mandatory:"false" json:"prefixes"` +} + +func (m ObjectVersionCollection) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ObjectVersionCollection) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_summary.go new file mode 100644 index 00000000000..8d95905094c --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/object_version_summary.go @@ -0,0 +1,77 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ObjectVersionSummary To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type ObjectVersionSummary struct { + + // The name of the object. Avoid entering confidential information. + // Example: test/object1.log + Name *string `mandatory:"true" json:"name"` + + // The date and time the object was modified, as described in RFC 2616 (https://tools.ietf.org/rfc/rfc2616#section-14.29). + TimeModified *common.SDKTime `mandatory:"true" json:"timeModified"` + + // VersionId of the object. + VersionId *string `mandatory:"true" json:"versionId"` + + // This flag will indicate if the version is deleted or not. + IsDeleteMarker *bool `mandatory:"true" json:"isDeleteMarker"` + + // Size of the object in bytes. + Size *int64 `mandatory:"false" json:"size"` + + // Base64-encoded MD5 hash of the object data. + Md5 *string `mandatory:"false" json:"md5"` + + // The date and time the object was created, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeCreated *common.SDKTime `mandatory:"false" json:"timeCreated"` + + // The current entity tag (ETag) for the object. + Etag *string `mandatory:"false" json:"etag"` + + // The storage tier that the object is stored in. + StorageTier StorageTierEnum `mandatory:"false" json:"storageTier,omitempty"` + + // Archival state of an object. This field is set only for objects in Archive tier. + ArchivalState ArchivalStateEnum `mandatory:"false" json:"archivalState,omitempty"` +} + +func (m ObjectVersionSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ObjectVersionSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingStorageTierEnum(string(m.StorageTier)); !ok && m.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", m.StorageTier, strings.Join(GetStorageTierEnumStringValues(), ","))) + } + if _, ok := GetMappingArchivalStateEnum(string(m.ArchivalState)); !ok && m.ArchivalState != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for ArchivalState: %s. Supported values are: %s.", m.ArchivalState, strings.Join(GetArchivalStateEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/objectstorage_client.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/objectstorage_client.go new file mode 100644 index 00000000000..32cc0043373 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/objectstorage_client.go @@ -0,0 +1,3824 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "context" + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/common/auth" + "net/http" + + "regexp" +) + +// ObjectStorageClient a client for ObjectStorage +type ObjectStorageClient struct { + common.BaseClient + config *common.ConfigurationProvider + requiredParamsInEndpoint map[string][]common.TemplateParamForPerRealmEndpoint +} + +// NewObjectStorageClientWithConfigurationProvider Creates a new default ObjectStorage client with the given configuration provider. +// the configuration provider will be used for the default signer as well as reading the region +func NewObjectStorageClientWithConfigurationProvider(configProvider common.ConfigurationProvider) (client ObjectStorageClient, err error) { + if enabled := common.CheckForEnabledServices("objectstorage"); !enabled { + return client, fmt.Errorf("the Developer Tool configuration disabled this service, this behavior is controlled by OciSdkEnabledServicesMap variables. Please check if your local developer-tool-configuration.json file configured the service you're targeting or contact the cloud provider on the availability of this service") + } + provider, err := auth.GetGenericConfigurationProvider(configProvider) + if err != nil { + return client, err + } + baseClient, e := common.NewClientWithConfig(provider) + if e != nil { + return client, e + } + return newObjectStorageClientFromBaseClient(baseClient, provider) +} + +// NewObjectStorageClientWithOboToken Creates a new default ObjectStorage client with the given configuration provider. +// The obotoken will be added to default headers and signed; the configuration provider will be used for the signer +// +// as well as reading the region +func NewObjectStorageClientWithOboToken(configProvider common.ConfigurationProvider, oboToken string) (client ObjectStorageClient, err error) { + baseClient, err := common.NewClientWithOboToken(configProvider, oboToken) + if err != nil { + return client, err + } + + return newObjectStorageClientFromBaseClient(baseClient, configProvider) +} + +func newObjectStorageClientFromBaseClient(baseClient common.BaseClient, configProvider common.ConfigurationProvider) (client ObjectStorageClient, err error) { + // ObjectStorage service default circuit breaker is enabled + baseClient.Configuration.CircuitBreaker = common.NewCircuitBreaker(common.DefaultCircuitBreakerSettingWithServiceName("ObjectStorage")) + common.ConfigCircuitBreakerFromEnvVar(&baseClient) + common.ConfigCircuitBreakerFromGlobalVar(&baseClient) + + client = ObjectStorageClient{BaseClient: baseClient} + err = client.setConfigurationProvider(configProvider) + return +} + +// SetRegion overrides the region of this client. +func (client *ObjectStorageClient) SetRegion(region string) { + client.Host, _ = common.StringToRegion(region).EndpointForTemplateDottedRegion("objectstorage", client.getEndpointTemplatePerRealm(region), "objectstorage") + client.parseEndpointTemplatePerRealm() +} + +// SetConfigurationProvider sets the configuration provider including the region, returns an error if is not valid +func (client *ObjectStorageClient) setConfigurationProvider(configProvider common.ConfigurationProvider) error { + if ok, err := common.IsConfigurationProviderValid(configProvider); !ok { + return err + } + + // Error has been checked already + region, _ := configProvider.Region() + client.SetRegion(region) + if client.Host == "" { + return fmt.Errorf("invalid region or Host. Endpoint cannot be constructed without endpointServiceName or serviceEndpointTemplate for a dotted region") + } + client.config = &configProvider + return nil +} + +// ConfigurationProvider the ConfigurationProvider used in this client, or null if none set +func (client *ObjectStorageClient) ConfigurationProvider() *common.ConfigurationProvider { + return client.config +} + +// getEndpointTemplatePerRealm returns the endpoint template for the given region, if not found, returns the default endpoint template +func (client *ObjectStorageClient) getEndpointTemplatePerRealm(region string) string { + if client.IsOciRealmSpecificServiceEndpointTemplateEnabled() { + realm, _ := common.StringToRegion(region).RealmID() + templatePerRealmDict := map[string]string{ + "oc1": "https://{namespaceName+Dot}objectstorage.{region}.oci.customer-oci.com", + } + if template, ok := templatePerRealmDict[realm]; ok { + return template + } + } + return "https://objectstorage.{region}.{secondLevelDomain}" +} + +// parseEndpointTemplatePerRealm parses the endpoint template per realm from the service endpoint template +// This function will build a map of template params to their values, this map is used when building the API endpoint +func (client *ObjectStorageClient) parseEndpointTemplatePerRealm() { + client.requiredParamsInEndpoint = make(map[string][]common.TemplateParamForPerRealmEndpoint) + templateRegex := regexp.MustCompile(`{.*?}`) + templateSubRegex := regexp.MustCompile(`{(.+)\+Dot}`) + templates := templateRegex.FindAllString(client.Host, -1) + for _, template := range templates { + templateParam := templateSubRegex.FindStringSubmatch(template) + if len(templateParam) > 1 { + client.requiredParamsInEndpoint[templateParam[1]] = append(client.requiredParamsInEndpoint[templateParam[1]], common.TemplateParamForPerRealmEndpoint{ + Template: templateParam[0], + EndsWithDot: true, + }) + } else { + templateParam := template[1 : len(template)-1] + client.requiredParamsInEndpoint[templateParam] = append(client.requiredParamsInEndpoint[templateParam], common.TemplateParamForPerRealmEndpoint{ + Template: template, + EndsWithDot: false, + }) + } + } +} + +// SetCustomClientConfiguration sets client with retry and other custom configurations +func (client *ObjectStorageClient) SetCustomClientConfiguration(config common.CustomClientConfiguration) { + client.Configuration = config + client.refreshRegion() +} + +// refreshRegion will refresh the region of this client, this function will be called after setting the CustomClientConfiguration +func (client *ObjectStorageClient) refreshRegion() { + configProvider := *client.config + region, _ := configProvider.Region() + client.SetRegion(region) +} + +// AbortMultipartUpload Aborts an in-progress multipart upload and deletes all parts that have been uploaded. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/AbortMultipartUpload.go.html to see an example of how to use AbortMultipartUpload API. +// A default retry strategy applies to this operation AbortMultipartUpload() +func (client ObjectStorageClient) AbortMultipartUpload(ctx context.Context, request AbortMultipartUploadRequest) (response AbortMultipartUploadResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.abortMultipartUpload, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = AbortMultipartUploadResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = AbortMultipartUploadResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(AbortMultipartUploadResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into AbortMultipartUploadResponse") + } + return +} + +// abortMultipartUpload implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) abortMultipartUpload(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/b/{bucketName}/u/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(AbortMultipartUploadRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response AbortMultipartUploadResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/MultipartUpload/AbortMultipartUpload" + err = common.PostProcessServiceError(err, "ObjectStorage", "AbortMultipartUpload", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CancelWorkRequest Cancels a work request. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CancelWorkRequest.go.html to see an example of how to use CancelWorkRequest API. +// A default retry strategy applies to this operation CancelWorkRequest() +func (client ObjectStorageClient) CancelWorkRequest(ctx context.Context, request CancelWorkRequestRequest) (response CancelWorkRequestResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.cancelWorkRequest, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CancelWorkRequestResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CancelWorkRequestResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CancelWorkRequestResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CancelWorkRequestResponse") + } + return +} + +// cancelWorkRequest implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) cancelWorkRequest(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/workRequests/{workRequestId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CancelWorkRequestRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CancelWorkRequestResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/WorkRequest/CancelWorkRequest" + err = common.PostProcessServiceError(err, "ObjectStorage", "CancelWorkRequest", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CommitMultipartUpload Commits a multipart upload, which involves checking part numbers and entity tags (ETags) of the parts, to create an aggregate object. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CommitMultipartUpload.go.html to see an example of how to use CommitMultipartUpload API. +// A default retry strategy applies to this operation CommitMultipartUpload() +func (client ObjectStorageClient) CommitMultipartUpload(ctx context.Context, request CommitMultipartUploadRequest) (response CommitMultipartUploadResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.commitMultipartUpload, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CommitMultipartUploadResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CommitMultipartUploadResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CommitMultipartUploadResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CommitMultipartUploadResponse") + } + return +} + +// commitMultipartUpload implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) commitMultipartUpload(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/u/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CommitMultipartUploadRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CommitMultipartUploadResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/MultipartUpload/CommitMultipartUpload" + err = common.PostProcessServiceError(err, "ObjectStorage", "CommitMultipartUpload", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CopyObject Creates a request to copy an object within a region or to another region. +// See Object Names (https://docs.oracle.com/iaas/Content/Object/Tasks/managingobjects.htm#namerequirements) +// for object naming requirements. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CopyObject.go.html to see an example of how to use CopyObject API. +// A default retry strategy applies to this operation CopyObject() +func (client ObjectStorageClient) CopyObject(ctx context.Context, request CopyObjectRequest) (response CopyObjectResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.copyObject, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CopyObjectResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CopyObjectResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CopyObjectResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CopyObjectResponse") + } + return +} + +// copyObject implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) copyObject(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/actions/copyObject", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CopyObjectRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CopyObjectResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/CopyObject" + err = common.PostProcessServiceError(err, "ObjectStorage", "CopyObject", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CreateBucket Creates a bucket in the given namespace with a bucket name and optional user-defined metadata. Avoid entering +// confidential information in bucket names. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateBucket.go.html to see an example of how to use CreateBucket API. +// A default retry strategy applies to this operation CreateBucket() +func (client ObjectStorageClient) CreateBucket(ctx context.Context, request CreateBucketRequest) (response CreateBucketResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.createBucket, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CreateBucketResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CreateBucketResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CreateBucketResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CreateBucketResponse") + } + return +} + +// createBucket implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) createBucket(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CreateBucketRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CreateBucketResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Bucket/CreateBucket" + err = common.PostProcessServiceError(err, "ObjectStorage", "CreateBucket", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CreateMultipartUpload Starts a new multipart upload to a specific object in the given bucket in the given namespace. +// See Object Names (https://docs.oracle.com/iaas/Content/Object/Tasks/managingobjects.htm#namerequirements) +// for object naming requirements. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateMultipartUpload.go.html to see an example of how to use CreateMultipartUpload API. +// A default retry strategy applies to this operation CreateMultipartUpload() +func (client ObjectStorageClient) CreateMultipartUpload(ctx context.Context, request CreateMultipartUploadRequest) (response CreateMultipartUploadResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.createMultipartUpload, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CreateMultipartUploadResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CreateMultipartUploadResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CreateMultipartUploadResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CreateMultipartUploadResponse") + } + return +} + +// createMultipartUpload implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) createMultipartUpload(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/u", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CreateMultipartUploadRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CreateMultipartUploadResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/MultipartUpload/CreateMultipartUpload" + err = common.PostProcessServiceError(err, "ObjectStorage", "CreateMultipartUpload", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CreatePreauthenticatedRequest Creates a pre-authenticated request specific to the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreatePreauthenticatedRequest.go.html to see an example of how to use CreatePreauthenticatedRequest API. +// A default retry strategy applies to this operation CreatePreauthenticatedRequest() +func (client ObjectStorageClient) CreatePreauthenticatedRequest(ctx context.Context, request CreatePreauthenticatedRequestRequest) (response CreatePreauthenticatedRequestResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.createPreauthenticatedRequest, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CreatePreauthenticatedRequestResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CreatePreauthenticatedRequestResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CreatePreauthenticatedRequestResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CreatePreauthenticatedRequestResponse") + } + return +} + +// createPreauthenticatedRequest implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) createPreauthenticatedRequest(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/p", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CreatePreauthenticatedRequestRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CreatePreauthenticatedRequestResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PreauthenticatedRequest/CreatePreauthenticatedRequest" + err = common.PostProcessServiceError(err, "ObjectStorage", "CreatePreauthenticatedRequest", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CreatePrivateEndpoint Create a PrivateEndpoint. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreatePrivateEndpoint.go.html to see an example of how to use CreatePrivateEndpoint API. +// A default retry strategy applies to this operation CreatePrivateEndpoint() +func (client ObjectStorageClient) CreatePrivateEndpoint(ctx context.Context, request CreatePrivateEndpointRequest) (response CreatePrivateEndpointResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.createPrivateEndpoint, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CreatePrivateEndpointResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CreatePrivateEndpointResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CreatePrivateEndpointResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CreatePrivateEndpointResponse") + } + return +} + +// createPrivateEndpoint implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) createPrivateEndpoint(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/pe", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CreatePrivateEndpointRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CreatePrivateEndpointResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PrivateEndpoint/CreatePrivateEndpoint" + err = common.PostProcessServiceError(err, "ObjectStorage", "CreatePrivateEndpoint", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CreateReplicationPolicy Creates a replication policy for the specified bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateReplicationPolicy.go.html to see an example of how to use CreateReplicationPolicy API. +// A default retry strategy applies to this operation CreateReplicationPolicy() +func (client ObjectStorageClient) CreateReplicationPolicy(ctx context.Context, request CreateReplicationPolicyRequest) (response CreateReplicationPolicyResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.createReplicationPolicy, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CreateReplicationPolicyResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CreateReplicationPolicyResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CreateReplicationPolicyResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CreateReplicationPolicyResponse") + } + return +} + +// createReplicationPolicy implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) createReplicationPolicy(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/replicationPolicies", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CreateReplicationPolicyRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CreateReplicationPolicyResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Replication/CreateReplicationPolicy" + err = common.PostProcessServiceError(err, "ObjectStorage", "CreateReplicationPolicy", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// CreateRetentionRule Creates a new retention rule in the specified bucket. The new rule will take effect typically within 30 seconds. +// Note that a maximum of 100 rules are supported on a bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/CreateRetentionRule.go.html to see an example of how to use CreateRetentionRule API. +// A default retry strategy applies to this operation CreateRetentionRule() +func (client ObjectStorageClient) CreateRetentionRule(ctx context.Context, request CreateRetentionRuleRequest) (response CreateRetentionRuleResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.createRetentionRule, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = CreateRetentionRuleResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = CreateRetentionRuleResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(CreateRetentionRuleResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into CreateRetentionRuleResponse") + } + return +} + +// createRetentionRule implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) createRetentionRule(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/retentionRules", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(CreateRetentionRuleRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response CreateRetentionRuleResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/RetentionRule/CreateRetentionRule" + err = common.PostProcessServiceError(err, "ObjectStorage", "CreateRetentionRule", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// DeleteBucket Deletes a bucket if the bucket is already empty. If the bucket is not empty, use +// DeleteObject first. In addition, +// you cannot delete a bucket that has a multipart upload in progress or a pre-authenticated +// request associated with that bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteBucket.go.html to see an example of how to use DeleteBucket API. +// A default retry strategy applies to this operation DeleteBucket() +func (client ObjectStorageClient) DeleteBucket(ctx context.Context, request DeleteBucketRequest) (response DeleteBucketResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.deleteBucket, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = DeleteBucketResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = DeleteBucketResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(DeleteBucketResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into DeleteBucketResponse") + } + return +} + +// deleteBucket implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) deleteBucket(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/b/{bucketName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(DeleteBucketRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response DeleteBucketResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Bucket/DeleteBucket" + err = common.PostProcessServiceError(err, "ObjectStorage", "DeleteBucket", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// DeleteObject Deletes an object. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteObject.go.html to see an example of how to use DeleteObject API. +// A default retry strategy applies to this operation DeleteObject() +func (client ObjectStorageClient) DeleteObject(ctx context.Context, request DeleteObjectRequest) (response DeleteObjectResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.deleteObject, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = DeleteObjectResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = DeleteObjectResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(DeleteObjectResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into DeleteObjectResponse") + } + return +} + +// deleteObject implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) deleteObject(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/b/{bucketName}/o/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(DeleteObjectRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response DeleteObjectResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/DeleteObject" + err = common.PostProcessServiceError(err, "ObjectStorage", "DeleteObject", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// DeleteObjectLifecyclePolicy Deletes the object lifecycle policy for the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteObjectLifecyclePolicy.go.html to see an example of how to use DeleteObjectLifecyclePolicy API. +// A default retry strategy applies to this operation DeleteObjectLifecyclePolicy() +func (client ObjectStorageClient) DeleteObjectLifecyclePolicy(ctx context.Context, request DeleteObjectLifecyclePolicyRequest) (response DeleteObjectLifecyclePolicyResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.deleteObjectLifecyclePolicy, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = DeleteObjectLifecyclePolicyResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = DeleteObjectLifecyclePolicyResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(DeleteObjectLifecyclePolicyResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into DeleteObjectLifecyclePolicyResponse") + } + return +} + +// deleteObjectLifecyclePolicy implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) deleteObjectLifecyclePolicy(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/b/{bucketName}/l", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(DeleteObjectLifecyclePolicyRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response DeleteObjectLifecyclePolicyResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/ObjectLifecyclePolicy/DeleteObjectLifecyclePolicy" + err = common.PostProcessServiceError(err, "ObjectStorage", "DeleteObjectLifecyclePolicy", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// DeletePreauthenticatedRequest Deletes the pre-authenticated request for the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeletePreauthenticatedRequest.go.html to see an example of how to use DeletePreauthenticatedRequest API. +// A default retry strategy applies to this operation DeletePreauthenticatedRequest() +func (client ObjectStorageClient) DeletePreauthenticatedRequest(ctx context.Context, request DeletePreauthenticatedRequestRequest) (response DeletePreauthenticatedRequestResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.deletePreauthenticatedRequest, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = DeletePreauthenticatedRequestResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = DeletePreauthenticatedRequestResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(DeletePreauthenticatedRequestResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into DeletePreauthenticatedRequestResponse") + } + return +} + +// deletePreauthenticatedRequest implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) deletePreauthenticatedRequest(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/b/{bucketName}/p/{parId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(DeletePreauthenticatedRequestRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response DeletePreauthenticatedRequestResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PreauthenticatedRequest/DeletePreauthenticatedRequest" + err = common.PostProcessServiceError(err, "ObjectStorage", "DeletePreauthenticatedRequest", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// DeletePrivateEndpoint Deletes a Private Endpoint if it exists in the given namespace. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeletePrivateEndpoint.go.html to see an example of how to use DeletePrivateEndpoint API. +// A default retry strategy applies to this operation DeletePrivateEndpoint() +func (client ObjectStorageClient) DeletePrivateEndpoint(ctx context.Context, request DeletePrivateEndpointRequest) (response DeletePrivateEndpointResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.deletePrivateEndpoint, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = DeletePrivateEndpointResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = DeletePrivateEndpointResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(DeletePrivateEndpointResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into DeletePrivateEndpointResponse") + } + return +} + +// deletePrivateEndpoint implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) deletePrivateEndpoint(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/pe/{peName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(DeletePrivateEndpointRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response DeletePrivateEndpointResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PrivateEndpoint/DeletePrivateEndpoint" + err = common.PostProcessServiceError(err, "ObjectStorage", "DeletePrivateEndpoint", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// DeleteReplicationPolicy Deletes the replication policy associated with the source bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteReplicationPolicy.go.html to see an example of how to use DeleteReplicationPolicy API. +// A default retry strategy applies to this operation DeleteReplicationPolicy() +func (client ObjectStorageClient) DeleteReplicationPolicy(ctx context.Context, request DeleteReplicationPolicyRequest) (response DeleteReplicationPolicyResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.deleteReplicationPolicy, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = DeleteReplicationPolicyResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = DeleteReplicationPolicyResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(DeleteReplicationPolicyResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into DeleteReplicationPolicyResponse") + } + return +} + +// deleteReplicationPolicy implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) deleteReplicationPolicy(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/b/{bucketName}/replicationPolicies/{replicationId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(DeleteReplicationPolicyRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response DeleteReplicationPolicyResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Replication/DeleteReplicationPolicy" + err = common.PostProcessServiceError(err, "ObjectStorage", "DeleteReplicationPolicy", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// DeleteRetentionRule Deletes the specified rule. The deletion takes effect typically within 30 seconds. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/DeleteRetentionRule.go.html to see an example of how to use DeleteRetentionRule API. +// A default retry strategy applies to this operation DeleteRetentionRule() +func (client ObjectStorageClient) DeleteRetentionRule(ctx context.Context, request DeleteRetentionRuleRequest) (response DeleteRetentionRuleResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.deleteRetentionRule, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = DeleteRetentionRuleResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = DeleteRetentionRuleResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(DeleteRetentionRuleResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into DeleteRetentionRuleResponse") + } + return +} + +// deleteRetentionRule implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) deleteRetentionRule(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodDelete, "/n/{namespaceName}/b/{bucketName}/retentionRules/{retentionRuleId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(DeleteRetentionRuleRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response DeleteRetentionRuleResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/RetentionRule/DeleteRetentionRule" + err = common.PostProcessServiceError(err, "ObjectStorage", "DeleteRetentionRule", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetBucket Gets the current representation of the given bucket in the given Object Storage namespace. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetBucket.go.html to see an example of how to use GetBucket API. +// A default retry strategy applies to this operation GetBucket() +func (client ObjectStorageClient) GetBucket(ctx context.Context, request GetBucketRequest) (response GetBucketResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getBucket, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetBucketResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetBucketResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetBucketResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetBucketResponse") + } + return +} + +// getBucket implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getBucket(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetBucketRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetBucketResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Bucket/GetBucket" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetBucket", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetNamespace Each Oracle Cloud Infrastructure tenant is assigned one unique and uneditable Object Storage namespace. The namespace +// is a system-generated string assigned during account creation. For some older tenancies, the namespace string may be +// the tenancy name in all lower-case letters. You cannot edit a namespace. +// GetNamespace returns the name of the Object Storage namespace for the user making the request. +// If an optional compartmentId query parameter is provided, GetNamespace returns the namespace name of the corresponding +// tenancy, provided the user has access to it. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetNamespace.go.html to see an example of how to use GetNamespace API. +// A default retry strategy applies to this operation GetNamespace() +func (client ObjectStorageClient) GetNamespace(ctx context.Context, request GetNamespaceRequest) (response GetNamespaceResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getNamespace, policy) + if err != nil { + if ociResponse != nil { + response = GetNamespaceResponse{RawResponse: ociResponse.HTTPResponse()} + } + return + } + if convertedResponse, ok := ociResponse.(GetNamespaceResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetNamespaceResponse") + } + return +} + +// getNamespace implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getNamespace(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetNamespaceRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetNamespaceResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Namespace/GetNamespace" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetNamespace", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetNamespaceMetadata Gets the metadata for the Object Storage namespace, which contains defaultS3CompartmentId and +// defaultSwiftCompartmentId. +// Any user with the OBJECTSTORAGE_NAMESPACE_READ permission will be able to see the current metadata. If you are +// not authorized, talk to an administrator. If you are an administrator who needs to write policies +// to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetNamespaceMetadata.go.html to see an example of how to use GetNamespaceMetadata API. +// A default retry strategy applies to this operation GetNamespaceMetadata() +func (client ObjectStorageClient) GetNamespaceMetadata(ctx context.Context, request GetNamespaceMetadataRequest) (response GetNamespaceMetadataResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getNamespaceMetadata, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetNamespaceMetadataResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetNamespaceMetadataResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetNamespaceMetadataResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetNamespaceMetadataResponse") + } + return +} + +// getNamespaceMetadata implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getNamespaceMetadata(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetNamespaceMetadataRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetNamespaceMetadataResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Namespace/GetNamespaceMetadata" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetNamespaceMetadata", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetObject Gets the metadata and body of an object. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetObject.go.html to see an example of how to use GetObject API. +// A default retry strategy applies to this operation GetObject() +func (client ObjectStorageClient) GetObject(ctx context.Context, request GetObjectRequest) (response GetObjectResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getObject, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetObjectResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetObjectResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetObjectResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetObjectResponse") + } + return +} + +// getObject implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getObject(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/o/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetObjectRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetObjectResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/GetObject" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetObject", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetObjectLifecyclePolicy Gets the object lifecycle policy for the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetObjectLifecyclePolicy.go.html to see an example of how to use GetObjectLifecyclePolicy API. +// A default retry strategy applies to this operation GetObjectLifecyclePolicy() +func (client ObjectStorageClient) GetObjectLifecyclePolicy(ctx context.Context, request GetObjectLifecyclePolicyRequest) (response GetObjectLifecyclePolicyResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getObjectLifecyclePolicy, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetObjectLifecyclePolicyResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetObjectLifecyclePolicyResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetObjectLifecyclePolicyResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetObjectLifecyclePolicyResponse") + } + return +} + +// getObjectLifecyclePolicy implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getObjectLifecyclePolicy(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/l", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetObjectLifecyclePolicyRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetObjectLifecyclePolicyResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/ObjectLifecyclePolicy/GetObjectLifecyclePolicy" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetObjectLifecyclePolicy", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetPreauthenticatedRequest Gets the pre-authenticated request for the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetPreauthenticatedRequest.go.html to see an example of how to use GetPreauthenticatedRequest API. +// A default retry strategy applies to this operation GetPreauthenticatedRequest() +func (client ObjectStorageClient) GetPreauthenticatedRequest(ctx context.Context, request GetPreauthenticatedRequestRequest) (response GetPreauthenticatedRequestResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getPreauthenticatedRequest, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetPreauthenticatedRequestResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetPreauthenticatedRequestResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetPreauthenticatedRequestResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetPreauthenticatedRequestResponse") + } + return +} + +// getPreauthenticatedRequest implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getPreauthenticatedRequest(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/p/{parId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetPreauthenticatedRequestRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetPreauthenticatedRequestResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PreauthenticatedRequest/GetPreauthenticatedRequest" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetPreauthenticatedRequest", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetPrivateEndpoint Gets the current representation of the given Private Endpoint in the given Object Storage namespace. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetPrivateEndpoint.go.html to see an example of how to use GetPrivateEndpoint API. +// A default retry strategy applies to this operation GetPrivateEndpoint() +func (client ObjectStorageClient) GetPrivateEndpoint(ctx context.Context, request GetPrivateEndpointRequest) (response GetPrivateEndpointResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getPrivateEndpoint, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetPrivateEndpointResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetPrivateEndpointResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetPrivateEndpointResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetPrivateEndpointResponse") + } + return +} + +// getPrivateEndpoint implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getPrivateEndpoint(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/pe/{peName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetPrivateEndpointRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetPrivateEndpointResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PrivateEndpoint/GetPrivateEndpoint" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetPrivateEndpoint", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetReplicationPolicy Get the replication policy. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetReplicationPolicy.go.html to see an example of how to use GetReplicationPolicy API. +// A default retry strategy applies to this operation GetReplicationPolicy() +func (client ObjectStorageClient) GetReplicationPolicy(ctx context.Context, request GetReplicationPolicyRequest) (response GetReplicationPolicyResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getReplicationPolicy, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetReplicationPolicyResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetReplicationPolicyResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetReplicationPolicyResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetReplicationPolicyResponse") + } + return +} + +// getReplicationPolicy implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getReplicationPolicy(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/replicationPolicies/{replicationId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetReplicationPolicyRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetReplicationPolicyResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Replication/GetReplicationPolicy" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetReplicationPolicy", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetRetentionRule Get the specified retention rule. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetRetentionRule.go.html to see an example of how to use GetRetentionRule API. +// A default retry strategy applies to this operation GetRetentionRule() +func (client ObjectStorageClient) GetRetentionRule(ctx context.Context, request GetRetentionRuleRequest) (response GetRetentionRuleResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getRetentionRule, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetRetentionRuleResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetRetentionRuleResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetRetentionRuleResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetRetentionRuleResponse") + } + return +} + +// getRetentionRule implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getRetentionRule(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/retentionRules/{retentionRuleId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetRetentionRuleRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetRetentionRuleResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/RetentionRule/GetRetentionRule" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetRetentionRule", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetWorkRequest Gets the status of the work request for the given ID. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/GetWorkRequest.go.html to see an example of how to use GetWorkRequest API. +// A default retry strategy applies to this operation GetWorkRequest() +func (client ObjectStorageClient) GetWorkRequest(ctx context.Context, request GetWorkRequestRequest) (response GetWorkRequestResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getWorkRequest, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetWorkRequestResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetWorkRequestResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetWorkRequestResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetWorkRequestResponse") + } + return +} + +// getWorkRequest implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) getWorkRequest(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/workRequests/{workRequestId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(GetWorkRequestRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response GetWorkRequestResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/WorkRequest/GetWorkRequest" + err = common.PostProcessServiceError(err, "ObjectStorage", "GetWorkRequest", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// HeadBucket Efficiently checks to see if a bucket exists and gets the current entity tag (ETag) for the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/HeadBucket.go.html to see an example of how to use HeadBucket API. +// A default retry strategy applies to this operation HeadBucket() +func (client ObjectStorageClient) HeadBucket(ctx context.Context, request HeadBucketRequest) (response HeadBucketResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.headBucket, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = HeadBucketResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = HeadBucketResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(HeadBucketResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into HeadBucketResponse") + } + return +} + +// headBucket implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) headBucket(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodHead, "/n/{namespaceName}/b/{bucketName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(HeadBucketRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response HeadBucketResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Bucket/HeadBucket" + err = common.PostProcessServiceError(err, "ObjectStorage", "HeadBucket", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// HeadObject Gets the user-defined metadata and entity tag (ETag) for an object. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/HeadObject.go.html to see an example of how to use HeadObject API. +// A default retry strategy applies to this operation HeadObject() +func (client ObjectStorageClient) HeadObject(ctx context.Context, request HeadObjectRequest) (response HeadObjectResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.headObject, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = HeadObjectResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = HeadObjectResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(HeadObjectResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into HeadObjectResponse") + } + return +} + +// headObject implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) headObject(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodHead, "/n/{namespaceName}/b/{bucketName}/o/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(HeadObjectRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response HeadObjectResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/HeadObject" + err = common.PostProcessServiceError(err, "ObjectStorage", "HeadObject", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListBuckets Gets a list of all BucketSummary items in a compartment. A BucketSummary contains only summary fields for the bucket +// and does not contain fields like the user-defined metadata. +// ListBuckets returns a BucketSummary containing at most 1000 buckets. To paginate through more buckets, use the returned +// `opc-next-page` value with the `page` request parameter. +// To use this and other API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListBuckets.go.html to see an example of how to use ListBuckets API. +// A default retry strategy applies to this operation ListBuckets() +func (client ObjectStorageClient) ListBuckets(ctx context.Context, request ListBucketsRequest) (response ListBucketsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listBuckets, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListBucketsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListBucketsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListBucketsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListBucketsResponse") + } + return +} + +// listBuckets implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listBuckets(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListBucketsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListBucketsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Bucket/ListBuckets" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListBuckets", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListMultipartUploadParts Lists the parts of an in-progress multipart upload. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListMultipartUploadParts.go.html to see an example of how to use ListMultipartUploadParts API. +// A default retry strategy applies to this operation ListMultipartUploadParts() +func (client ObjectStorageClient) ListMultipartUploadParts(ctx context.Context, request ListMultipartUploadPartsRequest) (response ListMultipartUploadPartsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listMultipartUploadParts, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListMultipartUploadPartsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListMultipartUploadPartsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListMultipartUploadPartsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListMultipartUploadPartsResponse") + } + return +} + +// listMultipartUploadParts implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listMultipartUploadParts(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/u/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListMultipartUploadPartsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListMultipartUploadPartsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/MultipartUpload/ListMultipartUploadParts" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListMultipartUploadParts", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListMultipartUploads Lists all of the in-progress multipart uploads for the given bucket in the given Object Storage namespace. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListMultipartUploads.go.html to see an example of how to use ListMultipartUploads API. +// A default retry strategy applies to this operation ListMultipartUploads() +func (client ObjectStorageClient) ListMultipartUploads(ctx context.Context, request ListMultipartUploadsRequest) (response ListMultipartUploadsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listMultipartUploads, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListMultipartUploadsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListMultipartUploadsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListMultipartUploadsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListMultipartUploadsResponse") + } + return +} + +// listMultipartUploads implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listMultipartUploads(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/u", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListMultipartUploadsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListMultipartUploadsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/MultipartUpload/ListMultipartUploads" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListMultipartUploads", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListObjectVersions Lists the object versions in a bucket. +// ListObjectVersions returns an ObjectVersionCollection containing at most 1000 object versions. To paginate through +// more object versions, use the returned `opc-next-page` value with the `page` request parameter. +// To use this and other API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListObjectVersions.go.html to see an example of how to use ListObjectVersions API. +// A default retry strategy applies to this operation ListObjectVersions() +func (client ObjectStorageClient) ListObjectVersions(ctx context.Context, request ListObjectVersionsRequest) (response ListObjectVersionsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listObjectVersions, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListObjectVersionsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListObjectVersionsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListObjectVersionsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListObjectVersionsResponse") + } + return +} + +// listObjectVersions implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listObjectVersions(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/objectversions", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListObjectVersionsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListObjectVersionsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/ListObjectVersions" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListObjectVersions", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListObjects Lists the objects in a bucket. By default, ListObjects returns object names only. See the `fields` +// parameter for other fields that you can optionally include in ListObjects response. +// ListObjects returns at most 1000 objects. To paginate through more objects, use the returned 'nextStartWith' +// value with the 'start' parameter. To filter which objects ListObjects returns, use the 'start' and 'end' +// parameters. +// To use this and other API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListObjects.go.html to see an example of how to use ListObjects API. +// A default retry strategy applies to this operation ListObjects() +func (client ObjectStorageClient) ListObjects(ctx context.Context, request ListObjectsRequest) (response ListObjectsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listObjects, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListObjectsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListObjectsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListObjectsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListObjectsResponse") + } + return +} + +// listObjects implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listObjects(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/o", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListObjectsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListObjectsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/ListObjects" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListObjects", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListPreauthenticatedRequests Lists pre-authenticated requests for the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListPreauthenticatedRequests.go.html to see an example of how to use ListPreauthenticatedRequests API. +// A default retry strategy applies to this operation ListPreauthenticatedRequests() +func (client ObjectStorageClient) ListPreauthenticatedRequests(ctx context.Context, request ListPreauthenticatedRequestsRequest) (response ListPreauthenticatedRequestsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listPreauthenticatedRequests, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListPreauthenticatedRequestsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListPreauthenticatedRequestsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListPreauthenticatedRequestsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListPreauthenticatedRequestsResponse") + } + return +} + +// listPreauthenticatedRequests implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listPreauthenticatedRequests(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/p", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListPreauthenticatedRequestsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListPreauthenticatedRequestsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PreauthenticatedRequest/ListPreauthenticatedRequests" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListPreauthenticatedRequests", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListPrivateEndpoints Gets a list of all PrivateEndpointSummary in a compartment associated with a namespace. +// To use this and other API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListPrivateEndpoints.go.html to see an example of how to use ListPrivateEndpoints API. +// A default retry strategy applies to this operation ListPrivateEndpoints() +func (client ObjectStorageClient) ListPrivateEndpoints(ctx context.Context, request ListPrivateEndpointsRequest) (response ListPrivateEndpointsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listPrivateEndpoints, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListPrivateEndpointsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListPrivateEndpointsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListPrivateEndpointsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListPrivateEndpointsResponse") + } + return +} + +// listPrivateEndpoints implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listPrivateEndpoints(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/pe", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListPrivateEndpointsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListPrivateEndpointsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PrivateEndpointSummary/ListPrivateEndpoints" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListPrivateEndpoints", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListReplicationPolicies List the replication policies associated with a bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListReplicationPolicies.go.html to see an example of how to use ListReplicationPolicies API. +// A default retry strategy applies to this operation ListReplicationPolicies() +func (client ObjectStorageClient) ListReplicationPolicies(ctx context.Context, request ListReplicationPoliciesRequest) (response ListReplicationPoliciesResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listReplicationPolicies, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListReplicationPoliciesResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListReplicationPoliciesResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListReplicationPoliciesResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListReplicationPoliciesResponse") + } + return +} + +// listReplicationPolicies implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listReplicationPolicies(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/replicationPolicies", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListReplicationPoliciesRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListReplicationPoliciesResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Replication/ListReplicationPolicies" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListReplicationPolicies", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListReplicationSources List the replication sources of a destination bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListReplicationSources.go.html to see an example of how to use ListReplicationSources API. +// A default retry strategy applies to this operation ListReplicationSources() +func (client ObjectStorageClient) ListReplicationSources(ctx context.Context, request ListReplicationSourcesRequest) (response ListReplicationSourcesResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listReplicationSources, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListReplicationSourcesResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListReplicationSourcesResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListReplicationSourcesResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListReplicationSourcesResponse") + } + return +} + +// listReplicationSources implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listReplicationSources(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/replicationSources", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListReplicationSourcesRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListReplicationSourcesResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Replication/ListReplicationSources" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListReplicationSources", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListRetentionRules List the retention rules for a bucket. The retention rules are sorted based on creation time, +// with the most recently created retention rule returned first. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListRetentionRules.go.html to see an example of how to use ListRetentionRules API. +// A default retry strategy applies to this operation ListRetentionRules() +func (client ObjectStorageClient) ListRetentionRules(ctx context.Context, request ListRetentionRulesRequest) (response ListRetentionRulesResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listRetentionRules, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListRetentionRulesResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListRetentionRulesResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListRetentionRulesResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListRetentionRulesResponse") + } + return +} + +// listRetentionRules implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listRetentionRules(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/n/{namespaceName}/b/{bucketName}/retentionRules", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListRetentionRulesRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListRetentionRulesResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/RetentionRule/ListRetentionRules" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListRetentionRules", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListWorkRequestErrors Lists the errors of the work request with the given ID. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListWorkRequestErrors.go.html to see an example of how to use ListWorkRequestErrors API. +// A default retry strategy applies to this operation ListWorkRequestErrors() +func (client ObjectStorageClient) ListWorkRequestErrors(ctx context.Context, request ListWorkRequestErrorsRequest) (response ListWorkRequestErrorsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listWorkRequestErrors, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListWorkRequestErrorsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListWorkRequestErrorsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListWorkRequestErrorsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListWorkRequestErrorsResponse") + } + return +} + +// listWorkRequestErrors implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listWorkRequestErrors(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/workRequests/{workRequestId}/errors", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListWorkRequestErrorsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListWorkRequestErrorsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/WorkRequestError/ListWorkRequestErrors" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListWorkRequestErrors", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListWorkRequestLogs Lists the logs of the work request with the given ID. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListWorkRequestLogs.go.html to see an example of how to use ListWorkRequestLogs API. +// A default retry strategy applies to this operation ListWorkRequestLogs() +func (client ObjectStorageClient) ListWorkRequestLogs(ctx context.Context, request ListWorkRequestLogsRequest) (response ListWorkRequestLogsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listWorkRequestLogs, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListWorkRequestLogsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListWorkRequestLogsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListWorkRequestLogsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListWorkRequestLogsResponse") + } + return +} + +// listWorkRequestLogs implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listWorkRequestLogs(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/workRequests/{workRequestId}/logs", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListWorkRequestLogsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListWorkRequestLogsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/WorkRequestLogEntry/ListWorkRequestLogs" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListWorkRequestLogs", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListWorkRequests Lists the work requests in a compartment. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ListWorkRequests.go.html to see an example of how to use ListWorkRequests API. +// A default retry strategy applies to this operation ListWorkRequests() +func (client ObjectStorageClient) ListWorkRequests(ctx context.Context, request ListWorkRequestsRequest) (response ListWorkRequestsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listWorkRequests, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListWorkRequestsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListWorkRequestsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListWorkRequestsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListWorkRequestsResponse") + } + return +} + +// listWorkRequests implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) listWorkRequests(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/workRequests", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ListWorkRequestsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ListWorkRequestsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/WorkRequest/ListWorkRequests" + err = common.PostProcessServiceError(err, "ObjectStorage", "ListWorkRequests", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// MakeBucketWritable Stops replication to the destination bucket and removes the replication policy. When the replication +// policy was created, this destination bucket became read-only except for new and changed objects replicated +// automatically from the source bucket. MakeBucketWritable removes the replication policy. This bucket is no +// longer the target for replication and is now writable, allowing users to make changes to bucket contents. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/MakeBucketWritable.go.html to see an example of how to use MakeBucketWritable API. +// A default retry strategy applies to this operation MakeBucketWritable() +func (client ObjectStorageClient) MakeBucketWritable(ctx context.Context, request MakeBucketWritableRequest) (response MakeBucketWritableResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.makeBucketWritable, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = MakeBucketWritableResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = MakeBucketWritableResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(MakeBucketWritableResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into MakeBucketWritableResponse") + } + return +} + +// makeBucketWritable implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) makeBucketWritable(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/actions/makeBucketWritable", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(MakeBucketWritableRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response MakeBucketWritableResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Replication/MakeBucketWritable" + err = common.PostProcessServiceError(err, "ObjectStorage", "MakeBucketWritable", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// PutObject Creates a new object or overwrites an existing object with the same name. The maximum object size allowed by +// PutObject is 50 GiB. +// See Object Names (https://docs.oracle.com/iaas/Content/Object/Tasks/managingobjects.htm#namerequirements) +// for object naming requirements. +// See Special Instructions for Object Storage PUT (https://docs.oracle.com/iaas/Content/API/Concepts/signingrequests.htm#ObjectStoragePut) +// for request signature requirements. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/PutObject.go.html to see an example of how to use PutObject API. +// A default retry strategy applies to this operation PutObject() +func (client ObjectStorageClient) PutObject(ctx context.Context, request PutObjectRequest) (response PutObjectResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.putObject, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = PutObjectResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = PutObjectResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(PutObjectResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into PutObjectResponse") + } + return +} + +// putObject implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) putObject(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + if !common.IsEnvVarFalse(common.UsingExpectHeaderEnvVar) { + extraHeaders["Expect"] = "100-continue" + } + httpRequest, err := request.HTTPRequest(http.MethodPut, "/n/{namespaceName}/b/{bucketName}/o/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(PutObjectRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response PutObjectResponse + var httpResponse *http.Response + var customSigner common.HTTPRequestSigner + excludeBodySigningPredicate := func(r *http.Request) bool { return false } + customSigner, err = common.NewSignerFromOCIRequestSigner(client.Signer, excludeBodySigningPredicate) + + //if there was an error overriding the signer, then use the signer from the client itself + if err != nil { + customSigner = client.Signer + } + + //Execute the request with a custom signer + httpResponse, err = client.CallWithDetails(ctx, &httpRequest, common.ClientCallDetails{Signer: customSigner}) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/PutObject" + err = common.PostProcessServiceError(err, "ObjectStorage", "PutObject", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// PutObjectLifecyclePolicy Creates or replaces the object lifecycle policy for the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/PutObjectLifecyclePolicy.go.html to see an example of how to use PutObjectLifecyclePolicy API. +// A default retry strategy applies to this operation PutObjectLifecyclePolicy() +func (client ObjectStorageClient) PutObjectLifecyclePolicy(ctx context.Context, request PutObjectLifecyclePolicyRequest) (response PutObjectLifecyclePolicyResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.putObjectLifecyclePolicy, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = PutObjectLifecyclePolicyResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = PutObjectLifecyclePolicyResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(PutObjectLifecyclePolicyResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into PutObjectLifecyclePolicyResponse") + } + return +} + +// putObjectLifecyclePolicy implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) putObjectLifecyclePolicy(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPut, "/n/{namespaceName}/b/{bucketName}/l", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(PutObjectLifecyclePolicyRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response PutObjectLifecyclePolicyResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/ObjectLifecyclePolicy/PutObjectLifecyclePolicy" + err = common.PostProcessServiceError(err, "ObjectStorage", "PutObjectLifecyclePolicy", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ReencryptBucket Re-encrypts the unique data encryption key that encrypts each object written to the bucket by using the most recent +// version of the master encryption key assigned to the bucket. (All data encryption keys are encrypted by a master +// encryption key. Master encryption keys are assigned to buckets and managed by Oracle by default, but you can assign +// a key that you created and control through the Oracle Cloud Infrastructure Key Management service.) The kmsKeyId property +// of the bucket determines which master encryption key is assigned to the bucket. If you assigned a different Key Management +// master encryption key to the bucket, you can call this API to re-encrypt all data encryption keys with the newly +// assigned key. Similarly, you might want to re-encrypt all data encryption keys if the assigned key has been rotated to +// a new key version since objects were last added to the bucket. If you call this API and there is no kmsKeyId associated +// with the bucket, the call will fail. +// Calling this API starts a work request task to re-encrypt the data encryption key of all objects in the bucket. Only +// objects created before the time of the API call will be re-encrypted. The call can take a long time, depending on how many +// objects are in the bucket and how big they are. This API returns a work request ID that you can use to retrieve the status +// of the work request task. +// All the versions of objects will be re-encrypted whether versioning is enabled or suspended at the bucket. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ReencryptBucket.go.html to see an example of how to use ReencryptBucket API. +// A default retry strategy applies to this operation ReencryptBucket() +func (client ObjectStorageClient) ReencryptBucket(ctx context.Context, request ReencryptBucketRequest) (response ReencryptBucketResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.reencryptBucket, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ReencryptBucketResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ReencryptBucketResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ReencryptBucketResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ReencryptBucketResponse") + } + return +} + +// reencryptBucket implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) reencryptBucket(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/actions/reencrypt", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ReencryptBucketRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ReencryptBucketResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Bucket/ReencryptBucket" + err = common.PostProcessServiceError(err, "ObjectStorage", "ReencryptBucket", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ReencryptObject Re-encrypts the data encryption keys that encrypt the object and its chunks. By default, when you create a bucket, the Object Storage +// service manages the master encryption key used to encrypt each object's data encryption keys. The encryption mechanism that you specify for +// the bucket applies to the objects it contains. +// You can alternatively employ one of these encryption strategies for an object: +// - You can assign a key that you created and control through the Oracle Cloud Infrastructure Vault service. +// - You can encrypt an object using your own encryption key. The key you supply is known as a customer-provided encryption key (SSE-C). +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ReencryptObject.go.html to see an example of how to use ReencryptObject API. +// A default retry strategy applies to this operation ReencryptObject() +func (client ObjectStorageClient) ReencryptObject(ctx context.Context, request ReencryptObjectRequest) (response ReencryptObjectResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.reencryptObject, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ReencryptObjectResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ReencryptObjectResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ReencryptObjectResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ReencryptObjectResponse") + } + return +} + +// reencryptObject implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) reencryptObject(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/actions/reencrypt/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(ReencryptObjectRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response ReencryptObjectResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/ReencryptObject" + err = common.PostProcessServiceError(err, "ObjectStorage", "ReencryptObject", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// RenameObject Rename an object in the given Object Storage namespace. +// See Object Names (https://docs.oracle.com/iaas/Content/Object/Tasks/managingobjects.htm#namerequirements) +// for object naming requirements. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/RenameObject.go.html to see an example of how to use RenameObject API. +// A default retry strategy applies to this operation RenameObject() +func (client ObjectStorageClient) RenameObject(ctx context.Context, request RenameObjectRequest) (response RenameObjectResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.renameObject, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = RenameObjectResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = RenameObjectResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(RenameObjectResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into RenameObjectResponse") + } + return +} + +// renameObject implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) renameObject(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/actions/renameObject", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(RenameObjectRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response RenameObjectResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/RenameObject" + err = common.PostProcessServiceError(err, "ObjectStorage", "RenameObject", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// RestoreObjects Restores the object specified by the objectName parameter. +// By default object will be restored for 24 hours. Duration can be configured using the hours parameter. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/RestoreObjects.go.html to see an example of how to use RestoreObjects API. +// A default retry strategy applies to this operation RestoreObjects() +func (client ObjectStorageClient) RestoreObjects(ctx context.Context, request RestoreObjectsRequest) (response RestoreObjectsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.restoreObjects, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = RestoreObjectsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = RestoreObjectsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(RestoreObjectsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into RestoreObjectsResponse") + } + return +} + +// restoreObjects implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) restoreObjects(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/actions/restoreObjects", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(RestoreObjectsRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response RestoreObjectsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/RestoreObjects" + err = common.PostProcessServiceError(err, "ObjectStorage", "RestoreObjects", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// UpdateBucket Performs a partial or full update of a bucket's user-defined metadata. +// Use UpdateBucket to move a bucket from one compartment to another within the same tenancy. Supply the compartmentID +// of the compartment that you want to move the bucket to. For more information about moving resources between compartments, +// see Moving Resources to a Different Compartment (https://docs.oracle.com/iaas/Content/Identity/Tasks/managingcompartments.htm#moveRes). +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateBucket.go.html to see an example of how to use UpdateBucket API. +// A default retry strategy applies to this operation UpdateBucket() +func (client ObjectStorageClient) UpdateBucket(ctx context.Context, request UpdateBucketRequest) (response UpdateBucketResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.updateBucket, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = UpdateBucketResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = UpdateBucketResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(UpdateBucketResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into UpdateBucketResponse") + } + return +} + +// updateBucket implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) updateBucket(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(UpdateBucketRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response UpdateBucketResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Bucket/UpdateBucket" + err = common.PostProcessServiceError(err, "ObjectStorage", "UpdateBucket", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// UpdateNamespaceMetadata By default, buckets created using the Amazon S3 Compatibility API or the Swift API are created in the root +// compartment of the Oracle Cloud Infrastructure tenancy. +// You can change the default Swift/Amazon S3 compartmentId designation to a different compartmentId. All +// subsequent bucket creations will use the new default compartment, but no previously created +// buckets will be modified. A user must have OBJECTSTORAGE_NAMESPACE_UPDATE permission to make changes to the default +// compartments for Amazon S3 and Swift. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateNamespaceMetadata.go.html to see an example of how to use UpdateNamespaceMetadata API. +// A default retry strategy applies to this operation UpdateNamespaceMetadata() +func (client ObjectStorageClient) UpdateNamespaceMetadata(ctx context.Context, request UpdateNamespaceMetadataRequest) (response UpdateNamespaceMetadataResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.updateNamespaceMetadata, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = UpdateNamespaceMetadataResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = UpdateNamespaceMetadataResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(UpdateNamespaceMetadataResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into UpdateNamespaceMetadataResponse") + } + return +} + +// updateNamespaceMetadata implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) updateNamespaceMetadata(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPut, "/n/{namespaceName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(UpdateNamespaceMetadataRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response UpdateNamespaceMetadataResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Namespace/UpdateNamespaceMetadata" + err = common.PostProcessServiceError(err, "ObjectStorage", "UpdateNamespaceMetadata", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// UpdateObjectStorageTier Changes the storage tier of the object specified by the objectName parameter. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateObjectStorageTier.go.html to see an example of how to use UpdateObjectStorageTier API. +// A default retry strategy applies to this operation UpdateObjectStorageTier() +func (client ObjectStorageClient) UpdateObjectStorageTier(ctx context.Context, request UpdateObjectStorageTierRequest) (response UpdateObjectStorageTierResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.updateObjectStorageTier, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = UpdateObjectStorageTierResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = UpdateObjectStorageTierResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(UpdateObjectStorageTierResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into UpdateObjectStorageTierResponse") + } + return +} + +// updateObjectStorageTier implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) updateObjectStorageTier(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/b/{bucketName}/actions/updateObjectStorageTier", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(UpdateObjectStorageTierRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response UpdateObjectStorageTierResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/UpdateObjectStorageTier" + err = common.PostProcessServiceError(err, "ObjectStorage", "UpdateObjectStorageTier", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// UpdatePrivateEndpoint Performs a partial or full update of a user-defined data associated with the Private Endpoint. +// Use UpdatePrivateEndpoint to move a Private Endpoint from one compartment to another within the same tenancy. Supply the compartmentID +// of the compartment that you want to move the Private Endpoint to. Or use it to update the name, subnetId, endpointFqdn or privateEndpointIp or accessTargets of the Private Endpoint. +// For more information about moving resources between compartments, see Moving Resources to a Different Compartment (https://docs.oracle.com/iaas/Content/Identity/Tasks/managingcompartments.htm#moveRes). +// This API follows replace semantics (rather than merge semantics). That means if the body provides values for +// parameters and the resource has exisiting ones, this operation will replace those existing values. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdatePrivateEndpoint.go.html to see an example of how to use UpdatePrivateEndpoint API. +// A default retry strategy applies to this operation UpdatePrivateEndpoint() +func (client ObjectStorageClient) UpdatePrivateEndpoint(ctx context.Context, request UpdatePrivateEndpointRequest) (response UpdatePrivateEndpointResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.updatePrivateEndpoint, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = UpdatePrivateEndpointResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = UpdatePrivateEndpointResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(UpdatePrivateEndpointResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into UpdatePrivateEndpointResponse") + } + return +} + +// updatePrivateEndpoint implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) updatePrivateEndpoint(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPost, "/n/{namespaceName}/pe/{peName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(UpdatePrivateEndpointRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response UpdatePrivateEndpointResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/PrivateEndpoint/UpdatePrivateEndpoint" + err = common.PostProcessServiceError(err, "ObjectStorage", "UpdatePrivateEndpoint", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// UpdateRetentionRule Updates the specified retention rule. Rule changes take effect typically within 30 seconds. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateRetentionRule.go.html to see an example of how to use UpdateRetentionRule API. +// A default retry strategy applies to this operation UpdateRetentionRule() +func (client ObjectStorageClient) UpdateRetentionRule(ctx context.Context, request UpdateRetentionRuleRequest) (response UpdateRetentionRuleResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.updateRetentionRule, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = UpdateRetentionRuleResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = UpdateRetentionRuleResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(UpdateRetentionRuleResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into UpdateRetentionRuleResponse") + } + return +} + +// updateRetentionRule implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) updateRetentionRule(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodPut, "/n/{namespaceName}/b/{bucketName}/retentionRules/{retentionRuleId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(UpdateRetentionRuleRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response UpdateRetentionRuleResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/RetentionRule/UpdateRetentionRule" + err = common.PostProcessServiceError(err, "ObjectStorage", "UpdateRetentionRule", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// UploadPart Uploads a single part of a multipart upload. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UploadPart.go.html to see an example of how to use UploadPart API. +// A default retry strategy applies to this operation UploadPart() +func (client ObjectStorageClient) UploadPart(ctx context.Context, request UploadPartRequest) (response UploadPartResponse, err error) { + var ociResponse common.OCIResponse + policy := common.DefaultRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.uploadPart, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = UploadPartResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = UploadPartResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(UploadPartResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into UploadPartResponse") + } + return +} + +// uploadPart implements the OCIOperation interface (enables retrying operations) +func (client ObjectStorageClient) uploadPart(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + if !common.IsEnvVarFalse(common.UsingExpectHeaderEnvVar) { + extraHeaders["Expect"] = "100-continue" + } + httpRequest, err := request.HTTPRequest(http.MethodPut, "/n/{namespaceName}/b/{bucketName}/u/{objectName}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + host := client.Host + request.(UploadPartRequest).ReplaceMandatoryParamInPath(&client.BaseClient, client.requiredParamsInEndpoint) + common.SetMissingTemplateParams(&client.BaseClient) + defer func() { + client.Host = host + }() + + var response UploadPartResponse + var httpResponse *http.Response + var customSigner common.HTTPRequestSigner + excludeBodySigningPredicate := func(r *http.Request) bool { return false } + customSigner, err = common.NewSignerFromOCIRequestSigner(client.Signer, excludeBodySigningPredicate) + + //if there was an error overriding the signer, then use the signer from the client itself + if err != nil { + customSigner = client.Signer + } + + //Execute the request with a custom signer + httpResponse, err = client.CallWithDetails(ctx, &httpRequest, common.ClientCallDetails{Signer: customSigner}) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/MultipartUpload/UploadPart" + err = common.PostProcessServiceError(err, "ObjectStorage", "UploadPart", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/pattern_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/pattern_details.go new file mode 100644 index 00000000000..6a3ba12b48e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/pattern_details.go @@ -0,0 +1,78 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// PatternDetails Specifying inclusion and exclusion patterns. +type PatternDetails struct { + + // An array of glob patterns to match the object names to include. An empty array includes all objects in the + // bucket. Exclusion patterns take precedence over inclusion patterns. + // A Glob pattern is a sequence of characters to match text. Any character that appears in the pattern, other + // than the special pattern characters described below, matches itself. + // Glob patterns must be between 1 and 1024 characters. + // The special pattern characters have the following meanings: + // \ Escapes the following character + // * Matches any string of characters. + // ? Matches any single character . + // [...] Matches a group of characters. A group of characters can be: + // A set of characters, for example: [Zafg9@]. This matches any character in the brackets. + // A range of characters, for example: [a-z]. This matches any character in the range. + // [a-f] is equivalent to [abcdef]. + // For character ranges only the CHARACTER-CHARACTER pattern is supported. + // [ab-yz] is not valid + // [a-mn-z] is not valid + // Character ranges can not start with ^ or : + // To include a '-' in the range, make it the first or last character. + InclusionPatterns []string `mandatory:"false" json:"inclusionPatterns"` + + // An array of glob patterns to match the object names to exclude. An empty array is ignored. Exclusion + // patterns take precedence over inclusion patterns. + // A Glob pattern is a sequence of characters to match text. Any character that appears in the pattern, other + // than the special pattern characters described below, matches itself. + // Glob patterns must be between 1 and 1024 characters. + // The special pattern characters have the following meanings: + // \ Escapes the following character + // * Matches any string of characters. + // ? Matches any single character . + // [...] Matches a group of characters. A group of characters can be: + // A set of characters, for example: [Zafg9@]. This matches any character in the brackets. + // A range of characters, for example: [a-z]. This matches any character in the range. + // [a-f] is equivalent to [abcdef]. + // For character ranges only the CHARACTER-CHARACTER pattern is supported. + // [ab-yz] is not valid + // [a-mn-z] is not valid + // Character ranges can not start with ^ or : + // To include a '-' in the range, make it the first or last character. + ExclusionPatterns []string `mandatory:"false" json:"exclusionPatterns"` +} + +func (m PatternDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m PatternDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request.go new file mode 100644 index 00000000000..c391cb0dd57 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request.go @@ -0,0 +1,183 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// PreauthenticatedRequest Pre-authenticated requests provide a way to let users access a bucket or an object without having their own credentials. +// When you create a pre-authenticated request, a unique URL is generated. Users in your organization, partners, or third +// parties can use this URL to access the targets identified in the pre-authenticated request. +// See Using Pre-Authenticated Requests (https://docs.oracle.com/iaas/Content/Object/Tasks/usingpreauthenticatedrequests.htm). +// To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, talk to an +// administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type PreauthenticatedRequest struct { + + // The unique identifier to use when directly addressing the pre-authenticated request. + Id *string `mandatory:"true" json:"id"` + + // The user-provided name of the pre-authenticated request. + Name *string `mandatory:"true" json:"name"` + + // The URI to embed in the URL when using the pre-authenticated request. + AccessUri *string `mandatory:"true" json:"accessUri"` + + // The operation that can be performed on this resource. + AccessType PreauthenticatedRequestAccessTypeEnum `mandatory:"true" json:"accessType"` + + // The expiration date for the pre-authenticated request as per RFC 3339 (https://tools.ietf.org/html/rfc3339). After + // this date the pre-authenticated request will no longer be valid. + TimeExpires *common.SDKTime `mandatory:"true" json:"timeExpires"` + + // The date when the pre-authenticated request was created as per specification + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The name of the object that is being granted access to by the pre-authenticated request. Avoid entering confidential + // information. The object name can be null and if so, the pre-authenticated request grants access to the entire bucket. + // Example: test/object1.log + ObjectName *string `mandatory:"false" json:"objectName"` + + // Specifies whether a list operation is allowed on a PAR with accessType "AnyObjectRead" or "AnyObjectReadWrite". + // Deny: Prevents the user from performing a list operation. + // ListObjects: Authorizes the user to perform a list operation. + BucketListingAction PreauthenticatedRequestBucketListingActionEnum `mandatory:"false" json:"bucketListingAction,omitempty"` + + // The full Path for the object. + FullPath *string `mandatory:"false" json:"fullPath"` +} + +func (m PreauthenticatedRequest) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m PreauthenticatedRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingPreauthenticatedRequestAccessTypeEnum(string(m.AccessType)); !ok && m.AccessType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for AccessType: %s. Supported values are: %s.", m.AccessType, strings.Join(GetPreauthenticatedRequestAccessTypeEnumStringValues(), ","))) + } + + if _, ok := GetMappingPreauthenticatedRequestBucketListingActionEnum(string(m.BucketListingAction)); !ok && m.BucketListingAction != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for BucketListingAction: %s. Supported values are: %s.", m.BucketListingAction, strings.Join(GetPreauthenticatedRequestBucketListingActionEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// PreauthenticatedRequestBucketListingActionEnum Enum with underlying type: string +type PreauthenticatedRequestBucketListingActionEnum string + +// Set of constants representing the allowable values for PreauthenticatedRequestBucketListingActionEnum +const ( + PreauthenticatedRequestBucketListingActionDeny PreauthenticatedRequestBucketListingActionEnum = "Deny" + PreauthenticatedRequestBucketListingActionListobjects PreauthenticatedRequestBucketListingActionEnum = "ListObjects" +) + +var mappingPreauthenticatedRequestBucketListingActionEnum = map[string]PreauthenticatedRequestBucketListingActionEnum{ + "Deny": PreauthenticatedRequestBucketListingActionDeny, + "ListObjects": PreauthenticatedRequestBucketListingActionListobjects, +} + +var mappingPreauthenticatedRequestBucketListingActionEnumLowerCase = map[string]PreauthenticatedRequestBucketListingActionEnum{ + "deny": PreauthenticatedRequestBucketListingActionDeny, + "listobjects": PreauthenticatedRequestBucketListingActionListobjects, +} + +// GetPreauthenticatedRequestBucketListingActionEnumValues Enumerates the set of values for PreauthenticatedRequestBucketListingActionEnum +func GetPreauthenticatedRequestBucketListingActionEnumValues() []PreauthenticatedRequestBucketListingActionEnum { + values := make([]PreauthenticatedRequestBucketListingActionEnum, 0) + for _, v := range mappingPreauthenticatedRequestBucketListingActionEnum { + values = append(values, v) + } + return values +} + +// GetPreauthenticatedRequestBucketListingActionEnumStringValues Enumerates the set of values in String for PreauthenticatedRequestBucketListingActionEnum +func GetPreauthenticatedRequestBucketListingActionEnumStringValues() []string { + return []string{ + "Deny", + "ListObjects", + } +} + +// GetMappingPreauthenticatedRequestBucketListingActionEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingPreauthenticatedRequestBucketListingActionEnum(val string) (PreauthenticatedRequestBucketListingActionEnum, bool) { + enum, ok := mappingPreauthenticatedRequestBucketListingActionEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// PreauthenticatedRequestAccessTypeEnum Enum with underlying type: string +type PreauthenticatedRequestAccessTypeEnum string + +// Set of constants representing the allowable values for PreauthenticatedRequestAccessTypeEnum +const ( + PreauthenticatedRequestAccessTypeObjectread PreauthenticatedRequestAccessTypeEnum = "ObjectRead" + PreauthenticatedRequestAccessTypeObjectwrite PreauthenticatedRequestAccessTypeEnum = "ObjectWrite" + PreauthenticatedRequestAccessTypeObjectreadwrite PreauthenticatedRequestAccessTypeEnum = "ObjectReadWrite" + PreauthenticatedRequestAccessTypeAnyobjectwrite PreauthenticatedRequestAccessTypeEnum = "AnyObjectWrite" + PreauthenticatedRequestAccessTypeAnyobjectread PreauthenticatedRequestAccessTypeEnum = "AnyObjectRead" + PreauthenticatedRequestAccessTypeAnyobjectreadwrite PreauthenticatedRequestAccessTypeEnum = "AnyObjectReadWrite" +) + +var mappingPreauthenticatedRequestAccessTypeEnum = map[string]PreauthenticatedRequestAccessTypeEnum{ + "ObjectRead": PreauthenticatedRequestAccessTypeObjectread, + "ObjectWrite": PreauthenticatedRequestAccessTypeObjectwrite, + "ObjectReadWrite": PreauthenticatedRequestAccessTypeObjectreadwrite, + "AnyObjectWrite": PreauthenticatedRequestAccessTypeAnyobjectwrite, + "AnyObjectRead": PreauthenticatedRequestAccessTypeAnyobjectread, + "AnyObjectReadWrite": PreauthenticatedRequestAccessTypeAnyobjectreadwrite, +} + +var mappingPreauthenticatedRequestAccessTypeEnumLowerCase = map[string]PreauthenticatedRequestAccessTypeEnum{ + "objectread": PreauthenticatedRequestAccessTypeObjectread, + "objectwrite": PreauthenticatedRequestAccessTypeObjectwrite, + "objectreadwrite": PreauthenticatedRequestAccessTypeObjectreadwrite, + "anyobjectwrite": PreauthenticatedRequestAccessTypeAnyobjectwrite, + "anyobjectread": PreauthenticatedRequestAccessTypeAnyobjectread, + "anyobjectreadwrite": PreauthenticatedRequestAccessTypeAnyobjectreadwrite, +} + +// GetPreauthenticatedRequestAccessTypeEnumValues Enumerates the set of values for PreauthenticatedRequestAccessTypeEnum +func GetPreauthenticatedRequestAccessTypeEnumValues() []PreauthenticatedRequestAccessTypeEnum { + values := make([]PreauthenticatedRequestAccessTypeEnum, 0) + for _, v := range mappingPreauthenticatedRequestAccessTypeEnum { + values = append(values, v) + } + return values +} + +// GetPreauthenticatedRequestAccessTypeEnumStringValues Enumerates the set of values in String for PreauthenticatedRequestAccessTypeEnum +func GetPreauthenticatedRequestAccessTypeEnumStringValues() []string { + return []string{ + "ObjectRead", + "ObjectWrite", + "ObjectReadWrite", + "AnyObjectWrite", + "AnyObjectRead", + "AnyObjectReadWrite", + } +} + +// GetMappingPreauthenticatedRequestAccessTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingPreauthenticatedRequestAccessTypeEnum(val string) (PreauthenticatedRequestAccessTypeEnum, bool) { + enum, ok := mappingPreauthenticatedRequestAccessTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request_summary.go new file mode 100644 index 00000000000..1a0d6e712b0 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/preauthenticated_request_summary.go @@ -0,0 +1,126 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// PreauthenticatedRequestSummary Get summary information about pre-authenticated requests. +type PreauthenticatedRequestSummary struct { + + // The unique identifier to use when directly addressing the pre-authenticated request. + Id *string `mandatory:"true" json:"id"` + + // The user-provided name of the pre-authenticated request. + Name *string `mandatory:"true" json:"name"` + + // The operation that can be performed on this resource. + AccessType PreauthenticatedRequestSummaryAccessTypeEnum `mandatory:"true" json:"accessType"` + + // The expiration date for the pre-authenticated request as per RFC 3339 (https://tools.ietf.org/html/rfc3339). After this date the pre-authenticated request will no longer be valid. + TimeExpires *common.SDKTime `mandatory:"true" json:"timeExpires"` + + // The date when the pre-authenticated request was created as per RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The name of object that is being granted access to by the pre-authenticated request. This can be null and if it is, + // the pre-authenticated request grants access to the entire bucket. + ObjectName *string `mandatory:"false" json:"objectName"` + + // Specifies whether a list operation is allowed on a PAR with accessType "AnyObjectRead" or "AnyObjectReadWrite". + // Deny: Prevents the user from performing a list operation. + // ListObjects: Authorizes the user to perform a list operation. + BucketListingAction PreauthenticatedRequestBucketListingActionEnum `mandatory:"false" json:"bucketListingAction,omitempty"` +} + +func (m PreauthenticatedRequestSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m PreauthenticatedRequestSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingPreauthenticatedRequestSummaryAccessTypeEnum(string(m.AccessType)); !ok && m.AccessType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for AccessType: %s. Supported values are: %s.", m.AccessType, strings.Join(GetPreauthenticatedRequestSummaryAccessTypeEnumStringValues(), ","))) + } + + if _, ok := GetMappingPreauthenticatedRequestBucketListingActionEnum(string(m.BucketListingAction)); !ok && m.BucketListingAction != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for BucketListingAction: %s. Supported values are: %s.", m.BucketListingAction, strings.Join(GetPreauthenticatedRequestBucketListingActionEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// PreauthenticatedRequestSummaryAccessTypeEnum Enum with underlying type: string +type PreauthenticatedRequestSummaryAccessTypeEnum string + +// Set of constants representing the allowable values for PreauthenticatedRequestSummaryAccessTypeEnum +const ( + PreauthenticatedRequestSummaryAccessTypeObjectread PreauthenticatedRequestSummaryAccessTypeEnum = "ObjectRead" + PreauthenticatedRequestSummaryAccessTypeObjectwrite PreauthenticatedRequestSummaryAccessTypeEnum = "ObjectWrite" + PreauthenticatedRequestSummaryAccessTypeObjectreadwrite PreauthenticatedRequestSummaryAccessTypeEnum = "ObjectReadWrite" + PreauthenticatedRequestSummaryAccessTypeAnyobjectwrite PreauthenticatedRequestSummaryAccessTypeEnum = "AnyObjectWrite" + PreauthenticatedRequestSummaryAccessTypeAnyobjectread PreauthenticatedRequestSummaryAccessTypeEnum = "AnyObjectRead" + PreauthenticatedRequestSummaryAccessTypeAnyobjectreadwrite PreauthenticatedRequestSummaryAccessTypeEnum = "AnyObjectReadWrite" +) + +var mappingPreauthenticatedRequestSummaryAccessTypeEnum = map[string]PreauthenticatedRequestSummaryAccessTypeEnum{ + "ObjectRead": PreauthenticatedRequestSummaryAccessTypeObjectread, + "ObjectWrite": PreauthenticatedRequestSummaryAccessTypeObjectwrite, + "ObjectReadWrite": PreauthenticatedRequestSummaryAccessTypeObjectreadwrite, + "AnyObjectWrite": PreauthenticatedRequestSummaryAccessTypeAnyobjectwrite, + "AnyObjectRead": PreauthenticatedRequestSummaryAccessTypeAnyobjectread, + "AnyObjectReadWrite": PreauthenticatedRequestSummaryAccessTypeAnyobjectreadwrite, +} + +var mappingPreauthenticatedRequestSummaryAccessTypeEnumLowerCase = map[string]PreauthenticatedRequestSummaryAccessTypeEnum{ + "objectread": PreauthenticatedRequestSummaryAccessTypeObjectread, + "objectwrite": PreauthenticatedRequestSummaryAccessTypeObjectwrite, + "objectreadwrite": PreauthenticatedRequestSummaryAccessTypeObjectreadwrite, + "anyobjectwrite": PreauthenticatedRequestSummaryAccessTypeAnyobjectwrite, + "anyobjectread": PreauthenticatedRequestSummaryAccessTypeAnyobjectread, + "anyobjectreadwrite": PreauthenticatedRequestSummaryAccessTypeAnyobjectreadwrite, +} + +// GetPreauthenticatedRequestSummaryAccessTypeEnumValues Enumerates the set of values for PreauthenticatedRequestSummaryAccessTypeEnum +func GetPreauthenticatedRequestSummaryAccessTypeEnumValues() []PreauthenticatedRequestSummaryAccessTypeEnum { + values := make([]PreauthenticatedRequestSummaryAccessTypeEnum, 0) + for _, v := range mappingPreauthenticatedRequestSummaryAccessTypeEnum { + values = append(values, v) + } + return values +} + +// GetPreauthenticatedRequestSummaryAccessTypeEnumStringValues Enumerates the set of values in String for PreauthenticatedRequestSummaryAccessTypeEnum +func GetPreauthenticatedRequestSummaryAccessTypeEnumStringValues() []string { + return []string{ + "ObjectRead", + "ObjectWrite", + "ObjectReadWrite", + "AnyObjectWrite", + "AnyObjectRead", + "AnyObjectReadWrite", + } +} + +// GetMappingPreauthenticatedRequestSummaryAccessTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingPreauthenticatedRequestSummaryAccessTypeEnum(val string) (PreauthenticatedRequestSummaryAccessTypeEnum, bool) { + enum, ok := mappingPreauthenticatedRequestSummaryAccessTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/prefix_fqdns.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/prefix_fqdns.go new file mode 100644 index 00000000000..010d8761f36 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/prefix_fqdns.go @@ -0,0 +1,47 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// PrefixFqdns An object containing FQDNs +type PrefixFqdns struct { + + // ObjectStorage API FQDN + ObjectStorageApiFqdn *string `mandatory:"false" json:"objectStorageApiFqdn"` + + // S3 Compatibility API FQDN + S3CompatibilityApiFqdn *string `mandatory:"false" json:"s3CompatibilityApiFqdn"` + + // Swift API FQDN + SwiftApiFqdn *string `mandatory:"false" json:"swiftApiFqdn"` +} + +func (m PrefixFqdns) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m PrefixFqdns) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint.go new file mode 100644 index 00000000000..e08048eec29 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint.go @@ -0,0 +1,170 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// PrivateEndpoint A private endpoint makes your service accessible through a private IP in the customer's private network. A private endpoint has a name and is associated with a namespace and a single compartment. +type PrivateEndpoint struct { + + // This name associated with the endpoint. Valid characters are uppercase or lowercase letters, numbers, hyphens, + // underscores, and periods. + // Example: my-new-private-endpoint1 + Name *string `mandatory:"true" json:"name"` + + // The Object Storage namespace associated with the private enpoint. + Namespace *string `mandatory:"true" json:"namespace"` + + // The compartment which is associated with the Private Endpoint. + CompartmentId *string `mandatory:"true" json:"compartmentId"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the user who created the Private Endpoint. + CreatedBy *string `mandatory:"true" json:"createdBy"` + + // The date and time the Private Endpoint was created, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The date and time the Private Endpoint was updated, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeModified *common.SDKTime `mandatory:"true" json:"timeModified"` + + // The OCID of the customer's subnet where the private endpoint VNIC will reside. + SubnetId *string `mandatory:"true" json:"subnetId"` + + // The private IP address to assign to this private endpoint. If you provide a value, + // it must be an available IP address in the customer's subnet. If it's not available, an error + // is returned. + // If you do not provide a value, an available IP address in the subnet is automatically chosen. + PrivateEndpointIp *string `mandatory:"true" json:"privateEndpointIp"` + + // A prefix to use for the private endpoint. The customer VCN's DNS records are + // updated with this prefix. The prefix input from the customer will be the first sub-domain in the endpointFqdn. + // Example: If the prefix chosen is "abc", then the endpointFqdn will be 'abc.private.objectstorage..oraclecloud.com' + Prefix *string `mandatory:"true" json:"prefix"` + + Fqdns *Fqdns `mandatory:"true" json:"fqdns"` + + // The entity tag (ETag) for the Private Endpoint. + Etag *string `mandatory:"true" json:"etag"` + + // A list of targets that can be accessed by the private endpoint. At least one or more access targets is required for a private endpoint. + AccessTargets []AccessTargetDetails `mandatory:"true" json:"accessTargets"` + + // A list of additional prefix that you can provide along with any other prefix. These resulting endpointFqdn's are added to the + // customer VCN's DNS record. + AdditionalPrefixes []string `mandatory:"false" json:"additionalPrefixes"` + + // A list of the OCIDs of the network security groups (NSGs) to add the private endpoint's VNIC to. + // For more information about NSGs, see + // NetworkSecurityGroup. + NsgIds []string `mandatory:"false" json:"nsgIds"` + + // The Private Endpoint's lifecycle state. + LifecycleState PrivateEndpointLifecycleStateEnum `mandatory:"false" json:"lifecycleState,omitempty"` + + // Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Department": "Finance"}` + FreeformTags map[string]string `mandatory:"false" json:"freeformTags"` + + // Defined tags for this resource. Each key is predefined and scoped to a namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Operations": {"CostCenter": "42"}}` + DefinedTags map[string]map[string]interface{} `mandatory:"false" json:"definedTags"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the PrivateEndpoint. + Id *string `mandatory:"false" json:"id"` +} + +func (m PrivateEndpoint) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m PrivateEndpoint) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingPrivateEndpointLifecycleStateEnum(string(m.LifecycleState)); !ok && m.LifecycleState != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for LifecycleState: %s. Supported values are: %s.", m.LifecycleState, strings.Join(GetPrivateEndpointLifecycleStateEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// PrivateEndpointLifecycleStateEnum Enum with underlying type: string +type PrivateEndpointLifecycleStateEnum string + +// Set of constants representing the allowable values for PrivateEndpointLifecycleStateEnum +const ( + PrivateEndpointLifecycleStateCreating PrivateEndpointLifecycleStateEnum = "CREATING" + PrivateEndpointLifecycleStateActive PrivateEndpointLifecycleStateEnum = "ACTIVE" + PrivateEndpointLifecycleStateInactive PrivateEndpointLifecycleStateEnum = "INACTIVE" + PrivateEndpointLifecycleStateUpdating PrivateEndpointLifecycleStateEnum = "UPDATING" + PrivateEndpointLifecycleStateDeleting PrivateEndpointLifecycleStateEnum = "DELETING" + PrivateEndpointLifecycleStateDeleted PrivateEndpointLifecycleStateEnum = "DELETED" + PrivateEndpointLifecycleStateFailed PrivateEndpointLifecycleStateEnum = "FAILED" +) + +var mappingPrivateEndpointLifecycleStateEnum = map[string]PrivateEndpointLifecycleStateEnum{ + "CREATING": PrivateEndpointLifecycleStateCreating, + "ACTIVE": PrivateEndpointLifecycleStateActive, + "INACTIVE": PrivateEndpointLifecycleStateInactive, + "UPDATING": PrivateEndpointLifecycleStateUpdating, + "DELETING": PrivateEndpointLifecycleStateDeleting, + "DELETED": PrivateEndpointLifecycleStateDeleted, + "FAILED": PrivateEndpointLifecycleStateFailed, +} + +var mappingPrivateEndpointLifecycleStateEnumLowerCase = map[string]PrivateEndpointLifecycleStateEnum{ + "creating": PrivateEndpointLifecycleStateCreating, + "active": PrivateEndpointLifecycleStateActive, + "inactive": PrivateEndpointLifecycleStateInactive, + "updating": PrivateEndpointLifecycleStateUpdating, + "deleting": PrivateEndpointLifecycleStateDeleting, + "deleted": PrivateEndpointLifecycleStateDeleted, + "failed": PrivateEndpointLifecycleStateFailed, +} + +// GetPrivateEndpointLifecycleStateEnumValues Enumerates the set of values for PrivateEndpointLifecycleStateEnum +func GetPrivateEndpointLifecycleStateEnumValues() []PrivateEndpointLifecycleStateEnum { + values := make([]PrivateEndpointLifecycleStateEnum, 0) + for _, v := range mappingPrivateEndpointLifecycleStateEnum { + values = append(values, v) + } + return values +} + +// GetPrivateEndpointLifecycleStateEnumStringValues Enumerates the set of values in String for PrivateEndpointLifecycleStateEnum +func GetPrivateEndpointLifecycleStateEnumStringValues() []string { + return []string{ + "CREATING", + "ACTIVE", + "INACTIVE", + "UPDATING", + "DELETING", + "DELETED", + "FAILED", + } +} + +// GetMappingPrivateEndpointLifecycleStateEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingPrivateEndpointLifecycleStateEnum(val string) (PrivateEndpointLifecycleStateEnum, bool) { + enum, ok := mappingPrivateEndpointLifecycleStateEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint_summary.go new file mode 100644 index 00000000000..6585c01b575 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/private_endpoint_summary.go @@ -0,0 +1,75 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// PrivateEndpointSummary To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type PrivateEndpointSummary struct { + + // The name given to the Private Endpoint. Avoid entering confidential information. + // Example: my-new-pe1 + Name *string `mandatory:"true" json:"name"` + + // The Object Storage namespace with which the Private Endpoint is associated. + Namespace *string `mandatory:"true" json:"namespace"` + + // The compartment ID in which the Private Endpoint is authorized. + CompartmentId *string `mandatory:"true" json:"compartmentId"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the user who created the Private Endpoint. + CreatedBy *string `mandatory:"true" json:"createdBy"` + + // The date and time the Private Endpoint was created, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The date and time the Private Endpoint was updated, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + TimeModified *common.SDKTime `mandatory:"true" json:"timeModified"` + + // A prefix to use for the private endpoint. The customer VCN's DNS records are + // updated with this prefix. The prefix input from the customer will be the first sub-domain in the endpointFqdn. + // Example: If the prefix chosen is "abc", then the endpointFqdn will be 'abc.private.objectstorage..oraclecloud.com' + Prefix *string `mandatory:"true" json:"prefix"` + + Fqdns *Fqdns `mandatory:"true" json:"fqdns"` + + // The entity tag for the Private Endpoint. + Etag *string `mandatory:"true" json:"etag"` + + // The summaries of Private Endpoints' lifecycle state. + LifecycleState PrivateEndpointLifecycleStateEnum `mandatory:"true" json:"lifecycleState"` +} + +func (m PrivateEndpointSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m PrivateEndpointSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingPrivateEndpointLifecycleStateEnum(string(m.LifecycleState)); !ok && m.LifecycleState != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for LifecycleState: %s. Supported values are: %s.", m.LifecycleState, strings.Join(GetPrivateEndpointLifecycleStateEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_details.go new file mode 100644 index 00000000000..c2ff03ec50d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_details.go @@ -0,0 +1,41 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// PutObjectLifecyclePolicyDetails Creates a new object lifecycle policy for a bucket. +type PutObjectLifecyclePolicyDetails struct { + + // The bucket's set of lifecycle policy rules. + Items []ObjectLifecycleRule `mandatory:"false" json:"items"` +} + +func (m PutObjectLifecyclePolicyDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m PutObjectLifecyclePolicyDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_request_response.go new file mode 100644 index 00000000000..821fa393a03 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_lifecycle_policy_request_response.go @@ -0,0 +1,137 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// PutObjectLifecyclePolicyRequest wrapper for the PutObjectLifecyclePolicy operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/PutObjectLifecyclePolicy.go.html to see an example of how to use PutObjectLifecyclePolicyRequest. +type PutObjectLifecyclePolicyRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The lifecycle policy to apply to the bucket. + PutObjectLifecyclePolicyDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. The only valid value is '*', which indicates that the request should + // fail if the resource already exists. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request PutObjectLifecyclePolicyRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request PutObjectLifecyclePolicyRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request PutObjectLifecyclePolicyRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request PutObjectLifecyclePolicyRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request PutObjectLifecyclePolicyRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request PutObjectLifecyclePolicyRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// PutObjectLifecyclePolicyResponse wrapper for the PutObjectLifecyclePolicy operation +type PutObjectLifecyclePolicyResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The ObjectLifecyclePolicy instance + ObjectLifecyclePolicy `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // The entity tag (ETag) for the object lifecycle policy. + ETag *string `presentIn:"header" name:"etag"` +} + +func (response PutObjectLifecyclePolicyResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response PutObjectLifecyclePolicyResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_request_response.go new file mode 100644 index 00000000000..88361284961 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/put_object_request_response.go @@ -0,0 +1,366 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "io" + "net/http" + "strings" +) + +// PutObjectRequest wrapper for the PutObject operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/PutObject.go.html to see an example of how to use PutObjectRequest. +type PutObjectRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // The content length of the body. + ContentLength *int64 `mandatory:"false" contributesTo:"header" name:"Content-Length"` + + // The object to upload to the object store. + PutObjectBody io.ReadCloser `mandatory:"true" contributesTo:"body" encoding:"binary"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. The only valid value is '*', which indicates that the request should + // fail if the resource already exists. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // A value of `100-continue` requests preliminary verification of the request method, path, and headers before the request body is sent. + // If no error results from such verification, the server will send a 100 (Continue) interim response to indicate readiness for the request body. + // The only allowed value for this parameter is "100-Continue" (case-insensitive). + Expect *string `mandatory:"false" contributesTo:"header" name:"Expect"` + + // The optional header that defines the base64-encoded MD5 hash of the body. If the optional Content-MD5 header is present, Object + // Storage performs an integrity check on the body of the HTTP request by computing the MD5 hash for the body and comparing it to the + // MD5 hash supplied in the header. If the two hashes do not match, the object is rejected and an HTTP-400 Unmatched Content MD5 error + // is returned with the message: + // "The computed MD5 of the request body (ACTUAL_MD5) does not match the Content-MD5 header (HEADER_MD5)" + ContentMD5 *string `mandatory:"false" contributesTo:"header" name:"Content-MD5"` + + // The optional checksum algorithm to use to compute and store the checksum of the body of the HTTP request (or the parts in case of multipart uploads), + // in addition to the default MD5 checksum. + OpcChecksumAlgorithm PutObjectOpcChecksumAlgorithmEnum `mandatory:"false" contributesTo:"header" name:"opc-checksum-algorithm"` + + // Applicable only if CRC32C is specified in the opc-checksum-algorithm request header. + // The optional header that defines the base64-encoded, 32-bit CRC32C (Castagnoli) checksum of the body. If the optional opc-content-crc32c header + // is present, Object Storage performs an integrity check on the body of the HTTP request by computing the CRC32C checksum for the body and comparing + // it to the CRC32C checksum supplied in the header. If the two checksums do not match, the object is rejected and an HTTP-400 Unmatched Content CRC32C error + // is returned with the message: + // "The computed CRC32C of the request body (ACTUAL_CRC32C) does not match the opc-content-crc32c header (HEADER_CRC32C)" + OpcContentCrc32c *string `mandatory:"false" contributesTo:"header" name:"opc-content-crc32c"` + + // Applicable only if SHA256 is specified in the opc-checksum-algorithm request header. + // The optional header that defines the base64-encoded SHA256 hash of the body. If the optional opc-content-sha256 header is present, Object + // Storage performs an integrity check on the body of the HTTP request by computing the SHA256 hash for the body and comparing it to the + // SHA256 hash supplied in the header. If the two hashes do not match, the object is rejected and an HTTP-400 Unmatched Content SHA256 error + // is returned with the message: + // "The computed SHA256 of the request body (ACTUAL_SHA256) does not match the opc-content-sha256 header (HEADER_SHA256)" + OpcContentSha256 *string `mandatory:"false" contributesTo:"header" name:"opc-content-sha256"` + + // Applicable only if SHA384 is specified in the opc-checksum-algorithm request header. + // The optional header that defines the base64-encoded SHA384 hash of the body. If the optional opc-content-sha384 header is present, Object + // Storage performs an integrity check on the body of the HTTP request by computing the SHA384 hash for the body and comparing it to the + // SHA384 hash supplied in the header. If the two hashes do not match, the object is rejected and an HTTP-400 Unmatched Content SHA384 error + // is returned with the message: + // "The computed SHA384 of the request body (ACTUAL_SHA384) does not match the opc-content-sha384 header (HEADER_SHA384)" + OpcContentSha384 *string `mandatory:"false" contributesTo:"header" name:"opc-content-sha384"` + + // The optional Content-Type header that defines the standard MIME type format of the object. Content type defaults to + // 'application/octet-stream' if not specified in the PutObject call. Specifying values for this header has no effect + // on Object Storage behavior. Programs that read the object determine what to do based on the value provided. For example, + // you could use this header to identify and perform special operations on text only objects. + ContentType *string `mandatory:"false" contributesTo:"header" name:"Content-Type"` + + // The optional Content-Language header that defines the content language of the object to upload. Specifying + // values for this header has no effect on Object Storage behavior. Programs that read the object determine what + // to do based on the value provided. For example, you could use this header to identify and differentiate objects + // based on a particular language. + ContentLanguage *string `mandatory:"false" contributesTo:"header" name:"Content-Language"` + + // The optional Content-Encoding header that defines the content encodings that were applied to the object to + // upload. Specifying values for this header has no effect on Object Storage behavior. Programs that read the + // object determine what to do based on the value provided. For example, you could use this header to determine + // what decoding mechanisms need to be applied to obtain the media-type specified by the Content-Type header of + // the object. + ContentEncoding *string `mandatory:"false" contributesTo:"header" name:"Content-Encoding"` + + // The optional Content-Disposition header that defines presentational information for the object to be + // returned in GetObject and HeadObject responses. Specifying values for this header has no effect on Object + // Storage behavior. Programs that read the object determine what to do based on the value provided. + // For example, you could use this header to let users download objects with custom filenames in a browser. + ContentDisposition *string `mandatory:"false" contributesTo:"header" name:"Content-Disposition"` + + // The optional Cache-Control header that defines the caching behavior value to be returned in GetObject and + // HeadObject responses. Specifying values for this header has no effect on Object Storage behavior. Programs + // that read the object determine what to do based on the value provided. + // For example, you could use this header to identify objects that require caching restrictions. + CacheControl *string `mandatory:"false" contributesTo:"header" name:"Cache-Control"` + + // The optional header that specifies "AES256" as the encryption algorithm. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerAlgorithm *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-algorithm"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or + // decrypt the data. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKey *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This + // value is used to check the integrity of the encryption key. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKeySha256 *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key-sha256"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a master encryption key used to call the Key + // Management service to generate a data encryption key or to encrypt or decrypt a data encryption key. + OpcSseKmsKeyId *string `mandatory:"false" contributesTo:"header" name:"opc-sse-kms-key-id"` + + // The storage tier that the object should be stored in. If not specified, the object will be stored in + // the same storage tier as the bucket. + StorageTier PutObjectStorageTierEnum `mandatory:"false" contributesTo:"header" name:"storage-tier"` + + // Optional user-defined metadata key and value. + OpcMeta map[string]string `mandatory:"false" contributesTo:"header-collection" prefix:"opc-meta-"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request PutObjectRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request PutObjectRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + httpRequest, err := common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) + if err == nil && binaryRequestBody.Seekable() { + common.UpdateRequestBinaryBody(&httpRequest, binaryRequestBody) + } + return httpRequest, err +} + +// BinaryRequestBody implements the OCIRequest interface +func (request PutObjectRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + rsc := common.NewOCIReadSeekCloser(request.PutObjectBody) + if rsc.Seekable() { + return rsc, true + } + return nil, true + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request PutObjectRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request PutObjectRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request PutObjectRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingPutObjectOpcChecksumAlgorithmEnum(string(request.OpcChecksumAlgorithm)); !ok && request.OpcChecksumAlgorithm != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for OpcChecksumAlgorithm: %s. Supported values are: %s.", request.OpcChecksumAlgorithm, strings.Join(GetPutObjectOpcChecksumAlgorithmEnumStringValues(), ","))) + } + if _, ok := GetMappingPutObjectStorageTierEnum(string(request.StorageTier)); !ok && request.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", request.StorageTier, strings.Join(GetPutObjectStorageTierEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// PutObjectResponse wrapper for the PutObject operation +type PutObjectResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The base64-encoded MD5 hash of the request body as computed by the server. + OpcContentMd5 *string `presentIn:"header" name:"opc-content-md5"` + + // The base64-encoded, 32-bit CRC32C (Castagnoli) checksum of the request body as computed by the server. Applicable only if CRC32C was specified in opc-checksum-algorithm request header during upload. + OpcContentCrc32c *string `presentIn:"header" name:"opc-content-crc32c"` + + // The base64-encoded SHA256 hash of the request body as computed by the server. Applicable only if SHA256 was specified in opc-checksum-algorithm request header during upload. + OpcContentSha256 *string `presentIn:"header" name:"opc-content-sha256"` + + // The base64-encoded SHA384 hash of the request body as computed by the server. Applicable only if SHA384 was specified in opc-checksum-algorithm request header during upload. + OpcContentSha384 *string `presentIn:"header" name:"opc-content-sha384"` + + // The entity tag (ETag) for the object. + ETag *string `presentIn:"header" name:"etag"` + + // The time the object was modified, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + LastModified *common.SDKTime `presentIn:"header" name:"last-modified"` + + // VersionId of the newly created object + VersionId *string `presentIn:"header" name:"version-id"` +} + +func (response PutObjectResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response PutObjectResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// PutObjectOpcChecksumAlgorithmEnum Enum with underlying type: string +type PutObjectOpcChecksumAlgorithmEnum string + +// Set of constants representing the allowable values for PutObjectOpcChecksumAlgorithmEnum +const ( + PutObjectOpcChecksumAlgorithmCrc32c PutObjectOpcChecksumAlgorithmEnum = "CRC32C" + PutObjectOpcChecksumAlgorithmSha256 PutObjectOpcChecksumAlgorithmEnum = "SHA256" + PutObjectOpcChecksumAlgorithmSha384 PutObjectOpcChecksumAlgorithmEnum = "SHA384" +) + +var mappingPutObjectOpcChecksumAlgorithmEnum = map[string]PutObjectOpcChecksumAlgorithmEnum{ + "CRC32C": PutObjectOpcChecksumAlgorithmCrc32c, + "SHA256": PutObjectOpcChecksumAlgorithmSha256, + "SHA384": PutObjectOpcChecksumAlgorithmSha384, +} + +var mappingPutObjectOpcChecksumAlgorithmEnumLowerCase = map[string]PutObjectOpcChecksumAlgorithmEnum{ + "crc32c": PutObjectOpcChecksumAlgorithmCrc32c, + "sha256": PutObjectOpcChecksumAlgorithmSha256, + "sha384": PutObjectOpcChecksumAlgorithmSha384, +} + +// GetPutObjectOpcChecksumAlgorithmEnumValues Enumerates the set of values for PutObjectOpcChecksumAlgorithmEnum +func GetPutObjectOpcChecksumAlgorithmEnumValues() []PutObjectOpcChecksumAlgorithmEnum { + values := make([]PutObjectOpcChecksumAlgorithmEnum, 0) + for _, v := range mappingPutObjectOpcChecksumAlgorithmEnum { + values = append(values, v) + } + return values +} + +// GetPutObjectOpcChecksumAlgorithmEnumStringValues Enumerates the set of values in String for PutObjectOpcChecksumAlgorithmEnum +func GetPutObjectOpcChecksumAlgorithmEnumStringValues() []string { + return []string{ + "CRC32C", + "SHA256", + "SHA384", + } +} + +// GetMappingPutObjectOpcChecksumAlgorithmEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingPutObjectOpcChecksumAlgorithmEnum(val string) (PutObjectOpcChecksumAlgorithmEnum, bool) { + enum, ok := mappingPutObjectOpcChecksumAlgorithmEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// PutObjectStorageTierEnum Enum with underlying type: string +type PutObjectStorageTierEnum string + +// Set of constants representing the allowable values for PutObjectStorageTierEnum +const ( + PutObjectStorageTierStandard PutObjectStorageTierEnum = "Standard" + PutObjectStorageTierInfrequentaccess PutObjectStorageTierEnum = "InfrequentAccess" + PutObjectStorageTierArchive PutObjectStorageTierEnum = "Archive" +) + +var mappingPutObjectStorageTierEnum = map[string]PutObjectStorageTierEnum{ + "Standard": PutObjectStorageTierStandard, + "InfrequentAccess": PutObjectStorageTierInfrequentaccess, + "Archive": PutObjectStorageTierArchive, +} + +var mappingPutObjectStorageTierEnumLowerCase = map[string]PutObjectStorageTierEnum{ + "standard": PutObjectStorageTierStandard, + "infrequentaccess": PutObjectStorageTierInfrequentaccess, + "archive": PutObjectStorageTierArchive, +} + +// GetPutObjectStorageTierEnumValues Enumerates the set of values for PutObjectStorageTierEnum +func GetPutObjectStorageTierEnumValues() []PutObjectStorageTierEnum { + values := make([]PutObjectStorageTierEnum, 0) + for _, v := range mappingPutObjectStorageTierEnum { + values = append(values, v) + } + return values +} + +// GetPutObjectStorageTierEnumStringValues Enumerates the set of values in String for PutObjectStorageTierEnum +func GetPutObjectStorageTierEnumStringValues() []string { + return []string{ + "Standard", + "InfrequentAccess", + "Archive", + } +} + +// GetMappingPutObjectStorageTierEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingPutObjectStorageTierEnum(val string) (PutObjectStorageTierEnum, bool) { + enum, ok := mappingPutObjectStorageTierEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_bucket_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_bucket_request_response.go new file mode 100644 index 00000000000..18c6a690b5e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_bucket_request_response.go @@ -0,0 +1,123 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ReencryptBucketRequest wrapper for the ReencryptBucket operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ReencryptBucket.go.html to see an example of how to use ReencryptBucketRequest. +type ReencryptBucketRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ReencryptBucketRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ReencryptBucketRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ReencryptBucketRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ReencryptBucketRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ReencryptBucketRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ReencryptBucketRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ReencryptBucketResponse wrapper for the ReencryptBucket operation +type ReencryptBucketResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the asynchronous request. If you need to contact Oracle about a + // particular request, provide this request ID. + OpcWorkRequestId *string `presentIn:"header" name:"opc-work-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response ReencryptBucketResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ReencryptBucketResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_details.go new file mode 100644 index 00000000000..39dc87f1b4d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_details.go @@ -0,0 +1,56 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ReencryptObjectDetails The details used to re-encrypt the data encryption keys associated with an object. +// You can only specify either a kmsKeyId or an sseCustomerKey in the request payload, not both. +// If the request payload is empty, the object is encrypted using the encryption key assigned to the +// bucket. The bucket encryption mechanism can either be a master encryption key managed by Oracle or the Vault service. +// - The sseCustomerKey field specifies the customer-provided encryption key (SSE-C) that will be used to re-encrypt the data encryption keys of the +// object and its chunks. +// - The sourceSSECustomerKey field specifies information about the customer-provided encryption key that is currently +// associated with the object source. Specify a value for the sourceSSECustomerKey only if the object +// is encrypted with a customer-provided encryption key. +type ReencryptObjectDetails struct { + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the master encryption key used to call the Vault + // service to re-encrypt the data encryption keys associated with the object and its chunks. If the kmsKeyId value is + // empty, whether null or an empty string, the API will perform re-encryption by using the kmsKeyId associated with the + // bucket or the master encryption key managed by Oracle, depending on the bucket encryption mechanism. + KmsKeyId *string `mandatory:"false" json:"kmsKeyId"` + + SseCustomerKey *SseCustomerKeyDetails `mandatory:"false" json:"sseCustomerKey"` + + SourceSseCustomerKey *SseCustomerKeyDetails `mandatory:"false" json:"sourceSseCustomerKey"` +} + +func (m ReencryptObjectDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ReencryptObjectDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_request_response.go new file mode 100644 index 00000000000..6b027317ad0 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/reencrypt_object_request_response.go @@ -0,0 +1,139 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ReencryptObjectRequest wrapper for the ReencryptObject operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/ReencryptObject.go.html to see an example of how to use ReencryptObjectRequest. +type ReencryptObjectRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // Request object for re-encrypting the data encryption key associated with an object. + ReencryptObjectDetails `contributesTo:"body"` + + // VersionId used to identify a particular version of the object + VersionId *string `mandatory:"false" contributesTo:"query" name:"versionId"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ReencryptObjectRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ReencryptObjectRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ReencryptObjectRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request ReencryptObjectRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ReencryptObjectRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ReencryptObjectRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ReencryptObjectResponse wrapper for the ReencryptObject operation +type ReencryptObjectResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response ReencryptObjectResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ReencryptObjectResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_details.go new file mode 100644 index 00000000000..d2027205325 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_details.go @@ -0,0 +1,56 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// RenameObjectDetails To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type RenameObjectDetails struct { + + // The name of the source object to be renamed. + SourceName *string `mandatory:"true" json:"sourceName"` + + // The new name of the source object. Avoid entering confidential information. + NewName *string `mandatory:"true" json:"newName"` + + // The if-match entity tag (ETag) of the source object. + SrcObjIfMatchETag *string `mandatory:"false" json:"srcObjIfMatchETag"` + + // The if-match entity tag (ETag) of the new object. + NewObjIfMatchETag *string `mandatory:"false" json:"newObjIfMatchETag"` + + // The if-none-match entity tag (ETag) of the new object. The only valid value is '*', which indicates + // request should fail if the new object already exists. + NewObjIfNoneMatchETag *string `mandatory:"false" json:"newObjIfNoneMatchETag"` +} + +func (m RenameObjectDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m RenameObjectDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_request_response.go new file mode 100644 index 00000000000..79ab1457775 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/rename_object_request_response.go @@ -0,0 +1,131 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// RenameObjectRequest wrapper for the RenameObject operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/RenameObject.go.html to see an example of how to use RenameObjectRequest. +type RenameObjectRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The sourceName and newName of rename operation. Avoid entering confidential information. + RenameObjectDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request RenameObjectRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request RenameObjectRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request RenameObjectRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request RenameObjectRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request RenameObjectRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request RenameObjectRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// RenameObjectResponse wrapper for the RenameObject operation +type RenameObjectResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the object. + ETag *string `presentIn:"header" name:"etag"` + + // The time the object was modified, as described in RFC 2616 (https://tools.ietf.org/html/rfc2616#section-14.29). + LastModified *common.SDKTime `presentIn:"header" name:"last-modified"` + + // VersionId of the renamed object + VersionId *string `presentIn:"header" name:"version-id"` +} + +func (response RenameObjectResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response RenameObjectResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy.go new file mode 100644 index 00000000000..1e01103d6fe --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy.go @@ -0,0 +1,109 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ReplicationPolicy The details of a replication policy. +type ReplicationPolicy struct { + + // The id of the replication policy. + Id *string `mandatory:"true" json:"id"` + + // The name of the policy. + Name *string `mandatory:"true" json:"name"` + + // The destination region to replicate to, for example "us-ashburn-1". + DestinationRegionName *string `mandatory:"true" json:"destinationRegionName"` + + // The bucket to replicate to in the destination region. Replication policy creation does not automatically + // create a destination bucket. Create the destination bucket before creating the policy. + DestinationBucketName *string `mandatory:"true" json:"destinationBucketName"` + + // The date when the replication policy was created as per RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // Changes made to the source bucket before this time has been replicated. + TimeLastSync *common.SDKTime `mandatory:"true" json:"timeLastSync"` + + // The replication status of the policy. If the status is CLIENT_ERROR, once the user fixes the issue + // described in the status message, the status will become ACTIVE. + Status ReplicationPolicyStatusEnum `mandatory:"true" json:"status"` + + // A human-readable description of the status. + StatusMessage *string `mandatory:"true" json:"statusMessage"` +} + +func (m ReplicationPolicy) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ReplicationPolicy) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingReplicationPolicyStatusEnum(string(m.Status)); !ok && m.Status != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Status: %s. Supported values are: %s.", m.Status, strings.Join(GetReplicationPolicyStatusEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ReplicationPolicyStatusEnum Enum with underlying type: string +type ReplicationPolicyStatusEnum string + +// Set of constants representing the allowable values for ReplicationPolicyStatusEnum +const ( + ReplicationPolicyStatusActive ReplicationPolicyStatusEnum = "ACTIVE" + ReplicationPolicyStatusClientError ReplicationPolicyStatusEnum = "CLIENT_ERROR" +) + +var mappingReplicationPolicyStatusEnum = map[string]ReplicationPolicyStatusEnum{ + "ACTIVE": ReplicationPolicyStatusActive, + "CLIENT_ERROR": ReplicationPolicyStatusClientError, +} + +var mappingReplicationPolicyStatusEnumLowerCase = map[string]ReplicationPolicyStatusEnum{ + "active": ReplicationPolicyStatusActive, + "client_error": ReplicationPolicyStatusClientError, +} + +// GetReplicationPolicyStatusEnumValues Enumerates the set of values for ReplicationPolicyStatusEnum +func GetReplicationPolicyStatusEnumValues() []ReplicationPolicyStatusEnum { + values := make([]ReplicationPolicyStatusEnum, 0) + for _, v := range mappingReplicationPolicyStatusEnum { + values = append(values, v) + } + return values +} + +// GetReplicationPolicyStatusEnumStringValues Enumerates the set of values in String for ReplicationPolicyStatusEnum +func GetReplicationPolicyStatusEnumStringValues() []string { + return []string{ + "ACTIVE", + "CLIENT_ERROR", + } +} + +// GetMappingReplicationPolicyStatusEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingReplicationPolicyStatusEnum(val string) (ReplicationPolicyStatusEnum, bool) { + enum, ok := mappingReplicationPolicyStatusEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy_summary.go new file mode 100644 index 00000000000..9504cae6e03 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_policy_summary.go @@ -0,0 +1,109 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ReplicationPolicySummary The summary of a replication policy. +type ReplicationPolicySummary struct { + + // The id of the replication policy. + Id *string `mandatory:"true" json:"id"` + + // The name of the policy. + Name *string `mandatory:"true" json:"name"` + + // The destination region to replicate to, for example "us-ashburn-1". + DestinationRegionName *string `mandatory:"true" json:"destinationRegionName"` + + // The bucket to replicate to in the destination region. Replication policy creation does not automatically + // create a destination bucket. Create the destination bucket before creating the policy. + DestinationBucketName *string `mandatory:"true" json:"destinationBucketName"` + + // The date when the replication policy was created as per RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // Changes made to the source bucket before this time has been replicated. + TimeLastSync *common.SDKTime `mandatory:"true" json:"timeLastSync"` + + // The replication status of the policy. If the status is CLIENT_ERROR, once the user fixes the issue + // described in the status message, the status will become ACTIVE. + Status ReplicationPolicySummaryStatusEnum `mandatory:"true" json:"status"` + + // A human-readable description of the status. + StatusMessage *string `mandatory:"true" json:"statusMessage"` +} + +func (m ReplicationPolicySummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ReplicationPolicySummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingReplicationPolicySummaryStatusEnum(string(m.Status)); !ok && m.Status != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Status: %s. Supported values are: %s.", m.Status, strings.Join(GetReplicationPolicySummaryStatusEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ReplicationPolicySummaryStatusEnum Enum with underlying type: string +type ReplicationPolicySummaryStatusEnum string + +// Set of constants representing the allowable values for ReplicationPolicySummaryStatusEnum +const ( + ReplicationPolicySummaryStatusActive ReplicationPolicySummaryStatusEnum = "ACTIVE" + ReplicationPolicySummaryStatusClientError ReplicationPolicySummaryStatusEnum = "CLIENT_ERROR" +) + +var mappingReplicationPolicySummaryStatusEnum = map[string]ReplicationPolicySummaryStatusEnum{ + "ACTIVE": ReplicationPolicySummaryStatusActive, + "CLIENT_ERROR": ReplicationPolicySummaryStatusClientError, +} + +var mappingReplicationPolicySummaryStatusEnumLowerCase = map[string]ReplicationPolicySummaryStatusEnum{ + "active": ReplicationPolicySummaryStatusActive, + "client_error": ReplicationPolicySummaryStatusClientError, +} + +// GetReplicationPolicySummaryStatusEnumValues Enumerates the set of values for ReplicationPolicySummaryStatusEnum +func GetReplicationPolicySummaryStatusEnumValues() []ReplicationPolicySummaryStatusEnum { + values := make([]ReplicationPolicySummaryStatusEnum, 0) + for _, v := range mappingReplicationPolicySummaryStatusEnum { + values = append(values, v) + } + return values +} + +// GetReplicationPolicySummaryStatusEnumStringValues Enumerates the set of values in String for ReplicationPolicySummaryStatusEnum +func GetReplicationPolicySummaryStatusEnumStringValues() []string { + return []string{ + "ACTIVE", + "CLIENT_ERROR", + } +} + +// GetMappingReplicationPolicySummaryStatusEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingReplicationPolicySummaryStatusEnum(val string) (ReplicationPolicySummaryStatusEnum, bool) { + enum, ok := mappingReplicationPolicySummaryStatusEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_source.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_source.go new file mode 100644 index 00000000000..b6b61f6492f --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/replication_source.go @@ -0,0 +1,47 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// ReplicationSource The details of a replication source bucket that replicates to a target destination bucket. +type ReplicationSource struct { + + // The name of the policy. + PolicyName *string `mandatory:"true" json:"policyName"` + + // The source region replicating data from, for example "us-ashburn-1". + SourceRegionName *string `mandatory:"true" json:"sourceRegionName"` + + // The source bucket replicating data from. + SourceBucketName *string `mandatory:"true" json:"sourceBucketName"` +} + +func (m ReplicationSource) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m ReplicationSource) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_details.go new file mode 100644 index 00000000000..b4cfa80355b --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_details.go @@ -0,0 +1,48 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// RestoreObjectsDetails The representation of RestoreObjectsDetails +type RestoreObjectsDetails struct { + + // An object that is in an archive storage tier and needs to be restored. + ObjectName *string `mandatory:"true" json:"objectName"` + + // The number of hours for which this object will be restored. + // By default objects will be restored for 24 hours. You can instead configure the duration using the hours parameter. + Hours *int `mandatory:"false" json:"hours"` + + // The versionId of the object to restore. Current object version is used by default. + VersionId *string `mandatory:"false" json:"versionId"` +} + +func (m RestoreObjectsDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m RestoreObjectsDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_request_response.go new file mode 100644 index 00000000000..680596986d7 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/restore_objects_request_response.go @@ -0,0 +1,122 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// RestoreObjectsRequest wrapper for the RestoreObjects operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/RestoreObjects.go.html to see an example of how to use RestoreObjectsRequest. +type RestoreObjectsRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // Request to restore object. + RestoreObjectsDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request RestoreObjectsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request RestoreObjectsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request RestoreObjectsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request RestoreObjectsRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request RestoreObjectsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request RestoreObjectsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// RestoreObjectsResponse wrapper for the RestoreObjects operation +type RestoreObjectsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response RestoreObjectsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response RestoreObjectsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule.go new file mode 100644 index 00000000000..203a8e408f7 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule.go @@ -0,0 +1,59 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// RetentionRule The details of a retention rule. +type RetentionRule struct { + + // Unique identifier for the retention rule. + Id *string `mandatory:"true" json:"id"` + + // User specified name for the retention rule. + DisplayName *string `mandatory:"true" json:"displayName"` + + // The entity tag (ETag) for the retention rule. + Etag *string `mandatory:"true" json:"etag"` + + // The date and time that the retention rule was created as per RFC3339 (https://tools.ietf.org/html/rfc3339). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The date and time that the retention rule was modified as per RFC3339 (https://tools.ietf.org/html/rfc3339). + TimeModified *common.SDKTime `mandatory:"true" json:"timeModified"` + + Duration *Duration `mandatory:"false" json:"duration"` + + // The date and time as per RFC 3339 (https://tools.ietf.org/html/rfc3339) after which this rule becomes locked. + // and can only be deleted by deleting the bucket. + TimeRuleLocked *common.SDKTime `mandatory:"false" json:"timeRuleLocked"` +} + +func (m RetentionRule) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m RetentionRule) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_collection.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_collection.go new file mode 100644 index 00000000000..5b92c565a77 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_collection.go @@ -0,0 +1,41 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// RetentionRuleCollection Retention rule collection. +type RetentionRuleCollection struct { + + // An array of retention rule summaries. + Items []RetentionRuleSummary `mandatory:"true" json:"items"` +} + +func (m RetentionRuleCollection) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m RetentionRuleCollection) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_details.go new file mode 100644 index 00000000000..88ec635a880 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_details.go @@ -0,0 +1,50 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// RetentionRuleDetails The details to create or update a retention rule. +type RetentionRuleDetails struct { + + // A user-specified name for the retention rule. Names can be helpful in identifying retention rules. + // Avoid entering confidential information. + DisplayName *string `mandatory:"false" json:"displayName"` + + Duration *Duration `mandatory:"false" json:"duration"` + + // The date and time as per RFC 3339 (https://tools.ietf.org/html/rfc3339) after which this rule is locked + // and can only be deleted by deleting the bucket. Once a rule is locked, only increases in the duration are + // allowed and no other properties can be changed. This property cannot be updated for rules that are in a + // locked state. Specifying it when a duration is not specified is considered an error. + TimeRuleLocked *common.SDKTime `mandatory:"false" json:"timeRuleLocked"` +} + +func (m RetentionRuleDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m RetentionRuleDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_summary.go new file mode 100644 index 00000000000..58cba48a500 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/retention_rule_summary.go @@ -0,0 +1,59 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// RetentionRuleSummary The summary of a retention rule. +type RetentionRuleSummary struct { + + // Unique identifier for the retention rule. + Id *string `mandatory:"true" json:"id"` + + // User specified name for the retention rule. + DisplayName *string `mandatory:"true" json:"displayName"` + + // The entity tag (ETag) for the retention rule. + Etag *string `mandatory:"true" json:"etag"` + + // The date and time that the retention rule was created as per RFC3339 (https://tools.ietf.org/html/rfc3339). + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The date and time that the retention rule was modified as per RFC3339 (https://tools.ietf.org/html/rfc3339). + TimeModified *common.SDKTime `mandatory:"true" json:"timeModified"` + + Duration *Duration `mandatory:"false" json:"duration"` + + // The date and time as per RFC 3339 (https://tools.ietf.org/html/rfc3339) after which this rule becomes locked. + // and can only be deleted by deleting the bucket. + TimeRuleLocked *common.SDKTime `mandatory:"false" json:"timeRuleLocked"` +} + +func (m RetentionRuleSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m RetentionRuleSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/sse_customer_key_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/sse_customer_key_details.go new file mode 100644 index 00000000000..8fbdf5bc071 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/sse_customer_key_details.go @@ -0,0 +1,89 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// SseCustomerKeyDetails Specifies the details of the customer-provided encryption key (SSE-C) associated with an object. +type SseCustomerKeyDetails struct { + + // Specifies the encryption algorithm. The only supported value is "AES256". + Algorithm SseCustomerKeyDetailsAlgorithmEnum `mandatory:"true" json:"algorithm"` + + // Specifies the base64-encoded 256-bit encryption key to use to encrypt or decrypt the object data. + Key *string `mandatory:"true" json:"key"` + + // Specifies the base64-encoded SHA256 hash of the encryption key. This value is used to check the integrity + // of the encryption key. + KeySha256 *string `mandatory:"true" json:"keySha256"` +} + +func (m SseCustomerKeyDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m SseCustomerKeyDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingSseCustomerKeyDetailsAlgorithmEnum(string(m.Algorithm)); !ok && m.Algorithm != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Algorithm: %s. Supported values are: %s.", m.Algorithm, strings.Join(GetSseCustomerKeyDetailsAlgorithmEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// SseCustomerKeyDetailsAlgorithmEnum Enum with underlying type: string +type SseCustomerKeyDetailsAlgorithmEnum string + +// Set of constants representing the allowable values for SseCustomerKeyDetailsAlgorithmEnum +const ( + SseCustomerKeyDetailsAlgorithmAes256 SseCustomerKeyDetailsAlgorithmEnum = "AES256" +) + +var mappingSseCustomerKeyDetailsAlgorithmEnum = map[string]SseCustomerKeyDetailsAlgorithmEnum{ + "AES256": SseCustomerKeyDetailsAlgorithmAes256, +} + +var mappingSseCustomerKeyDetailsAlgorithmEnumLowerCase = map[string]SseCustomerKeyDetailsAlgorithmEnum{ + "aes256": SseCustomerKeyDetailsAlgorithmAes256, +} + +// GetSseCustomerKeyDetailsAlgorithmEnumValues Enumerates the set of values for SseCustomerKeyDetailsAlgorithmEnum +func GetSseCustomerKeyDetailsAlgorithmEnumValues() []SseCustomerKeyDetailsAlgorithmEnum { + values := make([]SseCustomerKeyDetailsAlgorithmEnum, 0) + for _, v := range mappingSseCustomerKeyDetailsAlgorithmEnum { + values = append(values, v) + } + return values +} + +// GetSseCustomerKeyDetailsAlgorithmEnumStringValues Enumerates the set of values in String for SseCustomerKeyDetailsAlgorithmEnum +func GetSseCustomerKeyDetailsAlgorithmEnumStringValues() []string { + return []string{ + "AES256", + } +} + +// GetMappingSseCustomerKeyDetailsAlgorithmEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingSseCustomerKeyDetailsAlgorithmEnum(val string) (SseCustomerKeyDetailsAlgorithmEnum, bool) { + enum, ok := mappingSseCustomerKeyDetailsAlgorithmEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/storage_tier.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/storage_tier.go new file mode 100644 index 00000000000..7e7718aa556 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/storage_tier.go @@ -0,0 +1,62 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "strings" +) + +// StorageTierEnum Enum with underlying type: string +type StorageTierEnum string + +// Set of constants representing the allowable values for StorageTierEnum +const ( + StorageTierStandard StorageTierEnum = "Standard" + StorageTierInfrequentAccess StorageTierEnum = "InfrequentAccess" + StorageTierArchive StorageTierEnum = "Archive" +) + +var mappingStorageTierEnum = map[string]StorageTierEnum{ + "Standard": StorageTierStandard, + "InfrequentAccess": StorageTierInfrequentAccess, + "Archive": StorageTierArchive, +} + +var mappingStorageTierEnumLowerCase = map[string]StorageTierEnum{ + "standard": StorageTierStandard, + "infrequentaccess": StorageTierInfrequentAccess, + "archive": StorageTierArchive, +} + +// GetStorageTierEnumValues Enumerates the set of values for StorageTierEnum +func GetStorageTierEnumValues() []StorageTierEnum { + values := make([]StorageTierEnum, 0) + for _, v := range mappingStorageTierEnum { + values = append(values, v) + } + return values +} + +// GetStorageTierEnumStringValues Enumerates the set of values in String for StorageTierEnum +func GetStorageTierEnumStringValues() []string { + return []string{ + "Standard", + "InfrequentAccess", + "Archive", + } +} + +// GetMappingStorageTierEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingStorageTierEnum(val string) (StorageTierEnum, bool) { + enum, ok := mappingStorageTierEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader.go new file mode 100644 index 00000000000..04fcb6d5566 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader.go @@ -0,0 +1,220 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package transfer + +import ( + "context" + "errors" + "fmt" + "os" + "strings" + "sync" + + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/objectstorage" +) + +// FileUploader is an interface to upload a file +type FileUploader interface { + // split file into multiple parts and uploads them to blob storage, then merge + UploadFileMultiparts(ctx context.Context, request UploadFileRequest) (response UploadResponse, err error) + + // uploads a file to blob storage via PutObject API + UploadFilePutObject(ctx context.Context, request UploadFileRequest) (response UploadResponse, err error) + + // resume a file upload, use it when UploadFile failed + ResumeUploadFile(ctx context.Context, uploadID string) (response UploadResponse, err error) +} + +type fileUpload struct { + uploadID string + manifest *multipartManifest + multipartUploader multipartUploader + fileUploadReqs map[string]UploadFileRequest // save user input to resume +} + +func (fileUpload *fileUpload) UploadFileMultiparts(ctx context.Context, request UploadFileRequest) (response UploadResponse, err error) { + file, err := os.Open(request.FilePath) + + if err != nil { + file.Close() + return + } + + defer file.Close() + + fi, err := file.Stat() + if err != nil { + return + } + + fileSize := fi.Size() + + uploadID, err := fileUpload.multipartUploader.createMultipartUpload(ctx, request.UploadRequest) + + if err != nil { + return + } + fileUpload.uploadID = uploadID + + if fileUpload.fileUploadReqs == nil { + fileUpload.fileUploadReqs = make(map[string]UploadFileRequest) + } + + if fileUpload.manifest == nil { + fileUpload.manifest = &multipartManifest{parts: make(map[string]map[int]uploadPart)} + } + + // save the request for later resume if needed + fileUpload.fileUploadReqs[uploadID] = request + + // UploadFileMultiparts closes the done channel when it returns + done := make(chan struct{}) + defer close(done) + parts := fileUpload.manifest.splitFileToParts(done, *request.PartSize, request.EnableMultipartChecksumVerification, file, fileSize) + response, err = fileUpload.startConcurrentUpload(ctx, done, parts, request) + return +} + +func (fileUpload *fileUpload) UploadFilePutObject(ctx context.Context, request UploadFileRequest) (UploadResponse, error) { + response := UploadResponse{Type: SinglepartUpload} + file, err := os.Open(request.FilePath) + + if err != nil { + file.Close() + return response, err + } + + defer file.Close() + + fi, err := file.Stat() + if err != nil { + return response, err + } + + fileSize := int64(fi.Size()) + + req := objectstorage.PutObjectRequest{ + NamespaceName: request.NamespaceName, + BucketName: request.BucketName, + ObjectName: request.ObjectName, + ContentLength: common.Int64(fileSize), + PutObjectBody: file, + OpcMeta: request.Metadata, + IfMatch: request.IfMatch, + IfNoneMatch: request.IfNoneMatch, + ContentType: request.ContentType, + ContentLanguage: request.ContentLanguage, + ContentEncoding: request.ContentEncoding, + ContentMD5: request.ContentMD5, + OpcClientRequestId: request.OpcClientRequestID, + RequestMetadata: request.RequestMetadata, + StorageTier: request.StorageTier, + OpcSseCustomerAlgorithm: request.OpcSseCustomerAlgorithm, + OpcSseCustomerKey: request.OpcSseCustomerKey, + OpcSseCustomerKeySha256: request.OpcSseCustomerKeySha256, + OpcSseKmsKeyId: request.OpcSseKmsKeyId, + } + + resp, err := request.ObjectStorageClient.PutObject(ctx, req) + + if err != nil { + return response, err + } + + // set the response + response.SinglepartUploadResponse = &SinglepartUploadResponse{PutObjectResponse: resp} + return response, nil +} + +func (fileUpload *fileUpload) ResumeUploadFile(ctx context.Context, uploadID string) (UploadResponse, error) { + response := UploadResponse{Type: MultipartUpload} + if fileUpload.manifest == nil || fileUpload.manifest.parts == nil { + err := errors.New("cannot resume upload file, please call UploadFileMultiparts first") + return response, err + } + + parts := fileUpload.manifest.parts[uploadID] + + failedParts := []uploadPart{} + for _, failedPart := range parts { + if failedPart.err != nil || failedPart.etag == nil { + failedPart.err = nil // reset the previouse error to nil for resume + failedParts = append(failedParts, failedPart) + } + } + + if len(failedParts) == 0 { + err := errors.New("previous upload succeed, cannot resume") + return response, err + } + + failedPartsChannel := make(chan uploadPart, len(failedParts)) + go func() { + // close the channel after splitFile returns + defer func() { + common.Debugln("closing parts channel from failedPartsChannel") + close(failedPartsChannel) + }() + + for _, failedPart := range failedParts { + failedPartsChannel <- failedPart + } + }() + + // ResumeUploadFile closes the done channel when it returns + done := make(chan struct{}) + defer close(done) + + response, err := fileUpload.startConcurrentUpload(ctx, done, failedPartsChannel, fileUpload.fileUploadReqs[uploadID]) + return response, err +} + +func (fileUpload *fileUpload) startConcurrentUpload(ctx context.Context, done <-chan struct{}, parts <-chan uploadPart, request UploadFileRequest) (response UploadResponse, err error) { + result := make(chan uploadPart) + numUploads := *request.NumberOfGoroutines + var wg sync.WaitGroup + wg.Add(numUploads) + + // start fixed number of goroutines to upload parts + for i := 0; i < numUploads; i++ { + go func() { + fileUpload.multipartUploader.uploadParts(ctx, done, parts, result, request.UploadRequest, fileUpload.uploadID) + wg.Done() + }() + } + + go func() { + wg.Wait() + close(result) + }() + + fileUpload.manifest.updateManifest(result, fileUpload.uploadID) + // Calculate multipartMD5 once enabled multipart MD5 verification. + multipartMD5 := fileUpload.manifest.getMultipartMD5Checksum(request.EnableMultipartChecksumVerification, fileUpload.uploadID) + + resp, err := fileUpload.multipartUploader.commit(ctx, request.UploadRequest, fileUpload.manifest.parts[fileUpload.uploadID], fileUpload.uploadID) + + if err != nil { + common.Debugf("failed to commit with error: %v\n", err) + return UploadResponse{ + Type: MultipartUpload, + MultipartUploadResponse: &MultipartUploadResponse{ + isResumable: common.Bool(true), UploadID: common.String(fileUpload.uploadID)}}, + err + } + + if multipartMD5 != nil && *request.EnableMultipartChecksumVerification && strings.Compare(*resp.OpcMultipartMd5, *multipartMD5) != 0 { + err = fmt.Errorf("multipart base64 MD5 checksum verification failure, the sending opcMD5 is %s, the reveived is %s", *resp.OpcMultipartMd5, *multipartMD5) + err = uploadManagerError{err: err} + common.Debugf("MD5 checksum error: %v\n", err) + } + + response = UploadResponse{ + Type: MultipartUpload, + MultipartUploadResponse: &MultipartUploadResponse{ + CommitMultipartUploadResponse: resp, UploadID: common.String(fileUpload.uploadID)}, + } + return +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader_req_resp.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader_req_resp.go new file mode 100644 index 00000000000..380edbb3cef --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/file_uploader_req_resp.go @@ -0,0 +1,44 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package transfer + +import ( + "errors" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// UploadFileRequest defines the input parameters for UploadFile method +type UploadFileRequest struct { + UploadRequest + + // The path of the file to be uploaded (includs file name) + FilePath string +} + +var errorInvalidFilePath = errors.New("filePath is required") + +const defaultFilePartSize = 128 * 1024 * 1024 // 128MB + +func (request UploadFileRequest) validate() error { + err := request.UploadRequest.validate() + + if err != nil { + return err + } + + if len(request.FilePath) == 0 { + return errorInvalidFilePath + } + + return nil +} + +func (request *UploadFileRequest) initDefaultValues() error { + if request.PartSize == nil { + request.PartSize = common.Int64(defaultFilePartSize) + } + + return request.UploadRequest.initDefaultValues() +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/multipart_manifest.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/multipart_manifest.go new file mode 100644 index 00000000000..b3ee07423b3 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/multipart_manifest.go @@ -0,0 +1,211 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package transfer + +import ( + "bytes" + "crypto/md5" + "encoding/base64" + "io" + "os" + "strconv" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// multipartManifest provides thread-safe access to an ongoing manifest upload. +type multipartManifest struct { + // key is UploadID, define it as map since user can upload multiple times + // second key is part number + parts map[string]map[int]uploadPart +} + +type uploadPart struct { + size int64 + offset int64 + partBody []byte + partNum int + hash *string + opcMD5 *string + etag *string + err error + totalParts int +} + +// splitFileToParts starts a goroutine to read a file and break down to parts and send the parts to +// uploadPart channel. It sends the error to error chanel. If done is closed, splitFileToParts +// abandones its works. +func (manifest *multipartManifest) splitFileToParts(done <-chan struct{}, partSize int64, isChecksumEnabled *bool, file *os.File, fileSize int64) <-chan uploadPart { + + parts := make(chan uploadPart) + + // Number of parts of the file + numberOfParts := int(fileSize / partSize) + + // check for any left over bytes + remainder := fileSize % partSize + + totalParts := numberOfParts + if remainder != 0 { + totalParts = numberOfParts + 1 + } + go func() { + // close the channel after splitFile returns + defer func() { + common.Debugln("closing parts channel from splitFileParts") + close(parts) + }() + + // All buffer sizes are the same in the normal case. Offsets depend on the index. + // Second go routine should start at 100, for example, given our + // buffer size of 100. + for i := 0; i < numberOfParts; i++ { + offset := partSize * int64(i) // offset of the file, start with 0 + + buffer := make([]byte, partSize) + _, err := file.ReadAt(buffer, offset) + + part := uploadPart{ + partNum: i + 1, + size: partSize, + offset: offset, + err: err, + partBody: buffer, + totalParts: totalParts, + } + // Once enabled multipartMD5 verification, add opcMD5 for part + part.opcMD5 = getPartMD5Checksum(isChecksumEnabled, part) + + select { + case parts <- part: + case <-done: + return + } + } + + // check for any left over bytes. Add the residual number of bytes as the + // the last chunk size. + if remainder != 0 { + part := uploadPart{ + offset: int64(numberOfParts) * partSize, + partNum: numberOfParts + 1, + totalParts: totalParts, + } + + part.partBody = make([]byte, remainder) + _, err := file.ReadAt(part.partBody, part.offset) + + part.size = remainder + part.err = err + // Once enabled multipartMD5 verification, add opcMD5 for part + part.opcMD5 = getPartMD5Checksum(isChecksumEnabled, part) + + select { + case parts <- part: + case <-done: + return + } + } + }() + + return parts +} + +func (manifest multipartManifest) getMultipartMD5Checksum(isChecksumEnabled *bool, uploadID string) *string { + if isChecksumEnabled == nil || !*isChecksumEnabled { + return nil + } + + parts := manifest.parts[uploadID] + totalParts := len(parts) + var bytesBuf bytes.Buffer + for i := 1; i <= totalParts; i++ { + part := parts[i] + cipherStr, _ := base64.StdEncoding.DecodeString(*part.opcMD5) + bytesBuf.Write(cipherStr) + } + multipartMD5 := base64.StdEncoding.EncodeToString(md5Encode(bytesBuf.Bytes())) + "-" + strconv.Itoa(totalParts) + return &multipartMD5 +} + +func getPartMD5Checksum(isChecksumEnabled *bool, part uploadPart) *string { + if isChecksumEnabled == nil || !*isChecksumEnabled { + return nil + } + + var buffer bytes.Buffer + cipherStr := md5Encode(part.partBody) + opcMD5 := base64.StdEncoding.EncodeToString(cipherStr) + buffer.Write(cipherStr) + return &opcMD5 +} + +func md5Encode(data []byte) []byte { + // Each time handle 1 MiB bytes data + chunkSize := 1024 * 1024 + dataLength := len(data) + chunkNum := dataLength / chunkSize + md5Ctx := md5.New() + for i := 0; i < chunkNum; i++ { + md5Ctx.Write(data[chunkSize*i : chunkSize*(i+1)]) + } + if chunkSize*chunkNum < dataLength { + md5Ctx.Write(data[chunkSize*chunkNum : dataLength]) + } + return md5Ctx.Sum(nil) +} + +// splitStreamToParts starts a goroutine to read a stream and break down to parts and send the parts to +// uploadPart channel. It sends the error to error channel. If done is closed, splitStreamToParts +// abandons its works. +func (manifest *multipartManifest) splitStreamToParts(done <-chan struct{}, partSize int64, isChecksumEnabled *bool, reader io.Reader) <-chan uploadPart { + parts := make(chan uploadPart) + + go func() { + defer close(parts) + partNum := 1 + for { + buffer := make([]byte, partSize) + numberOfBytesRead, err := io.ReadFull(reader, buffer) + + // ignore io.ErrUnexpectedEOF here + if err == io.EOF { + break + } + + // If the number of bytes read is less than the initial buffer size, reduce the buffer size to match the actual content size. + // it's actually the handling of io.ErrUnexpectedEOF + if int64(numberOfBytesRead) < partSize { + buffer = buffer[:numberOfBytesRead] + } + + part := uploadPart{ + partNum: partNum, + size: int64(numberOfBytesRead), + err: nil, + partBody: buffer, + } + // Once enabled multipartMD5 verification, add opcMD5 for part + part.opcMD5 = getPartMD5Checksum(isChecksumEnabled, part) + partNum++ + select { + case parts <- part: + case <-done: + return + } + } + }() + + return parts +} + +// update the result in manifest +func (manifest *multipartManifest) updateManifest(result <-chan uploadPart, uploadID string) { + if manifest.parts[uploadID] == nil { + manifest.parts[uploadID] = make(map[int]uploadPart) + } + for r := range result { + manifest.parts[uploadID][r.partNum] = r + } +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/mutipart_uploader.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/mutipart_uploader.go new file mode 100644 index 00000000000..af9b7aa3fbb --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/mutipart_uploader.go @@ -0,0 +1,161 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package transfer + +import ( + "bytes" + "context" + "io/ioutil" + + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/objectstorage" +) + +// multipartUploader is an interface wrap the methods talk to object storage service +type multipartUploader interface { + createMultipartUpload(ctx context.Context, request UploadRequest) (string, error) + uploadParts(ctx context.Context, done <-chan struct{}, parts <-chan uploadPart, result chan<- uploadPart, request UploadRequest, uploadID string) + uploadPart(ctx context.Context, request UploadRequest, part uploadPart, uploadID string) (objectstorage.UploadPartResponse, error) + commit(ctx context.Context, request UploadRequest, parts map[int]uploadPart, uploadID string) (resp objectstorage.CommitMultipartUploadResponse, err error) +} + +// multipartUpload implements multipartUploader interface +type multipartUpload struct{} + +// createMultipartUpload creates a new multipart upload in Object Storage and return the uploadId +func (uploader *multipartUpload) createMultipartUpload(ctx context.Context, request UploadRequest) (string, error) { + multipartUploadRequest := objectstorage.CreateMultipartUploadRequest{ + NamespaceName: request.NamespaceName, + BucketName: request.BucketName, + IfMatch: request.IfMatch, + IfNoneMatch: request.IfNoneMatch, + OpcClientRequestId: request.OpcClientRequestID, + } + + multipartUploadRequest.Object = request.ObjectName + multipartUploadRequest.ContentType = request.ContentType + multipartUploadRequest.ContentEncoding = request.ContentEncoding + multipartUploadRequest.ContentLanguage = request.ContentLanguage + multipartUploadRequest.Metadata = request.Metadata + multipartUploadRequest.OpcSseCustomerAlgorithm = request.OpcSseCustomerAlgorithm + multipartUploadRequest.OpcSseCustomerKey = request.OpcSseCustomerKey + multipartUploadRequest.OpcSseCustomerKeySha256 = request.OpcSseCustomerKeySha256 + multipartUploadRequest.OpcSseKmsKeyId = request.OpcSseKmsKeyId + switch request.StorageTier { + case objectstorage.PutObjectStorageTierStandard: + multipartUploadRequest.StorageTier = objectstorage.StorageTierStandard + case objectstorage.PutObjectStorageTierArchive: + multipartUploadRequest.StorageTier = objectstorage.StorageTierArchive + case objectstorage.PutObjectStorageTierInfrequentaccess: + multipartUploadRequest.StorageTier = objectstorage.StorageTierInfrequentAccess + } + + resp, err := request.ObjectStorageClient.CreateMultipartUpload(ctx, multipartUploadRequest) + if err == nil { + return *resp.UploadId, nil + } + return "", err +} + +func (uploader *multipartUpload) uploadParts(ctx context.Context, done <-chan struct{}, parts <-chan uploadPart, result chan<- uploadPart, request UploadRequest, uploadID string) { + // loop through the part from parts channel created by splitFileParts method + for part := range parts { + if part.err != nil { + // ignore this part which contains error from split function + result <- part + return + } + + resp, err := uploader.uploadPart(ctx, request, part, uploadID) + if err != nil { + common.Debugf("upload error %v\n", err) + part.err = err + } else { + part.partBody = nil + } + part.etag = resp.ETag + select { + case result <- part: + // Invoke the callBack after upload of each Part + if nil != request.CallBack { + uploadedPart := MultiPartUploadPart{ + PartNum: part.partNum, + TotalParts: part.totalParts, + Offset: part.offset, + Hash: part.hash, + Err: part.err, + OpcMD5: part.opcMD5} + + request.CallBack(uploadedPart) + } + common.Debugf("uploadParts resp %v, %v\n", part.partNum, resp.ETag) + case <-done: + common.Debugln("uploadParts received Done") + return + } + } +} + +// send request to upload part to object storage +func (uploader *multipartUpload) uploadPart(ctx context.Context, request UploadRequest, part uploadPart, uploadID string) (objectstorage.UploadPartResponse, error) { + req := objectstorage.UploadPartRequest{ + NamespaceName: request.NamespaceName, + BucketName: request.BucketName, + ObjectName: request.ObjectName, + UploadId: common.String(uploadID), + UploadPartNum: common.Int(part.partNum), + UploadPartBody: ioutil.NopCloser(bytes.NewReader(part.partBody)), + ContentLength: common.Int64(part.size), + IfMatch: request.IfMatch, + IfNoneMatch: request.IfNoneMatch, + OpcClientRequestId: request.OpcClientRequestID, + RequestMetadata: request.RequestMetadata, + ContentMD5: part.opcMD5, + OpcSseCustomerAlgorithm: request.OpcSseCustomerAlgorithm, + OpcSseCustomerKey: request.OpcSseCustomerKey, + OpcSseCustomerKeySha256: request.OpcSseCustomerKeySha256, + OpcSseKmsKeyId: request.OpcSseKmsKeyId, + } + + resp, err := request.ObjectStorageClient.UploadPart(ctx, req) + + return resp, err +} + +// commits the multipart upload +func (uploader *multipartUpload) commit(ctx context.Context, request UploadRequest, parts map[int]uploadPart, uploadID string) (resp objectstorage.CommitMultipartUploadResponse, err error) { + req := objectstorage.CommitMultipartUploadRequest{ + NamespaceName: request.NamespaceName, + BucketName: request.BucketName, + ObjectName: request.ObjectName, + UploadId: common.String(uploadID), + IfMatch: request.IfMatch, + IfNoneMatch: request.IfNoneMatch, + OpcClientRequestId: request.OpcClientRequestID, + RequestMetadata: request.RequestMetadata, + } + + partsToCommit := []objectstorage.CommitMultipartUploadPartDetails{} + + for _, part := range parts { + if part.etag != nil { + detail := objectstorage.CommitMultipartUploadPartDetails{ + Etag: part.etag, + PartNum: common.Int(part.partNum), + } + + // update the parts to commit + partsToCommit = append(partsToCommit, detail) + } else { + // some parts failed, return error for resume + common.Debugf("uploadPart has error: %v\n", part.err) + err = part.err + return + } + } + + req.PartsToCommit = partsToCommit + resp, err = request.ObjectStorageClient.CommitMultipartUpload(ctx, req) + return +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader.go new file mode 100644 index 00000000000..fe6d227ad0a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader.go @@ -0,0 +1,92 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package transfer + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// StreamUploader is an interface for upload a stream +type StreamUploader interface { + // uploads a stream to blob storage + UploadStream(ctx context.Context, request UploadStreamRequest) (response UploadResponse, err error) +} + +type streamUpload struct { + uploadID string + manifest *multipartManifest + multipartUploader multipartUploader + request UploadStreamRequest +} + +func (streamUpload *streamUpload) UploadStream(ctx context.Context, request UploadStreamRequest) (response UploadResponse, err error) { + + uploadID, err := streamUpload.multipartUploader.createMultipartUpload(ctx, request.UploadRequest) + + if err != nil { + return UploadResponse{}, err + } + streamUpload.uploadID = uploadID + + if streamUpload.manifest == nil { + streamUpload.manifest = &multipartManifest{parts: make(map[string]map[int]uploadPart)} + } + + // UploadFileMultipart closes the done channel when it returns + done := make(chan struct{}) + defer close(done) + parts := streamUpload.manifest.splitStreamToParts(done, *request.PartSize, request.EnableMultipartChecksumVerification, request.StreamReader) + + return streamUpload.startConcurrentUpload(ctx, done, parts, request) +} + +func (streamUpload *streamUpload) startConcurrentUpload(ctx context.Context, done <-chan struct{}, parts <-chan uploadPart, request UploadStreamRequest) (response UploadResponse, err error) { + result := make(chan uploadPart) + numUploads := *request.NumberOfGoroutines + var wg sync.WaitGroup + wg.Add(numUploads) + + // start fixed number of goroutines to upload parts + for i := 0; i < numUploads; i++ { + go func() { + streamUpload.multipartUploader.uploadParts(ctx, done, parts, result, request.UploadRequest, streamUpload.uploadID) + wg.Done() + }() + } + + go func() { + wg.Wait() + close(result) + }() + + streamUpload.manifest.updateManifest(result, streamUpload.uploadID) + // Calculate multipartMD5 once enabled multipart MD5 verification. + multipartMD5 := streamUpload.manifest.getMultipartMD5Checksum(request.EnableMultipartChecksumVerification, streamUpload.uploadID) + + resp, err := streamUpload.multipartUploader.commit(ctx, request.UploadRequest, streamUpload.manifest.parts[streamUpload.uploadID], streamUpload.uploadID) + + if err != nil { + common.Debugf("failed to commit with error: %v\n", err) + return UploadResponse{ + Type: MultipartUpload, + MultipartUploadResponse: &MultipartUploadResponse{UploadID: common.String(streamUpload.uploadID)}}, + err + } + if multipartMD5 != nil && *request.EnableMultipartChecksumVerification && strings.Compare(*resp.OpcMultipartMd5, *multipartMD5) != 0 { + err = fmt.Errorf("multipart base64 MD5 checksum verification failure, the sending opcMD5 is %s, the reveived is %s", *resp.OpcMultipartMd5, *multipartMD5) + err = uploadManagerError{err: err} + common.Debugf("MD5 checksum error: %v\n", err) + } + + response = UploadResponse{ + Type: MultipartUpload, + MultipartUploadResponse: &MultipartUploadResponse{CommitMultipartUploadResponse: resp}, + } + return +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader_req_resp.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader_req_resp.go new file mode 100644 index 00000000000..535b154e342 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/stream_uploader_req_resp.go @@ -0,0 +1,58 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package transfer + +import ( + "errors" + "io" + "reflect" + + "github.com/oracle/oci-go-sdk/v65/common" +) + +// UploadStreamRequest defines the input parameters for UploadFile method +type UploadStreamRequest struct { + UploadRequest + + // The reader of input stream + StreamReader io.Reader +} + +var errorInvalidStream = errors.New("uploadStream is required") + +const defaultStreamPartSize = 10 * 1024 * 1024 // 10MB + +func (request UploadStreamRequest) validate() error { + err := request.UploadRequest.validate() + + if err != nil { + return err + } + + if isNil(request.StreamReader) { + return errorInvalidStream + } + + return nil +} + +func isNil(i interface{}) bool { + if i == nil { + return true + } + kind := reflect.TypeOf(i).Kind() + switch kind { + case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice: + return reflect.ValueOf(i).IsNil() + } + return false +} + +func (request *UploadStreamRequest) initDefaultValues() error { + if request.PartSize == nil { + request.PartSize = common.Int64(defaultStreamPartSize) + } + + return request.UploadRequest.initDefaultValues() +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager.go new file mode 100644 index 00000000000..400a9729f7b --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager.go @@ -0,0 +1,192 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +// Package transfer simplifies interaction with the Object Storage service by abstracting away the method used +// to upload objects. Depending on the configuration parameters, UploadManager may choose to do a single +// put_object request, or break up the upload into multiple parts and utilize multi-part uploads. +// +// An advantage of using multi-part uploads is the ability to retry individual failed parts, as well as being +// able to upload parts in parallel to reduce upload time. +// +// To use this package, you must be authorized in an IAM policy. If you're not authorized, talk to an administrator. +package transfer + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "net/http" + "os" + "runtime" + "strings" + + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/objectstorage" +) + +// UploadManager is the interface that groups the upload methods +type UploadManager struct { + FileUploader FileUploader + StreamUploader StreamUploader +} + +var ( + errorInvalidStreamUploader = uploadManagerError{err: errors.New("streamUploader is required, use NewUploadManager for default implementation")} + errorInvalidFileUploader = uploadManagerError{err: errors.New("fileUploader is required, use NewUploadManager for default implementation")} +) + +// NewUploadManager return a pointer to UploadManager +func NewUploadManager() *UploadManager { + return &UploadManager{ + FileUploader: &fileUpload{multipartUploader: &multipartUpload{}}, + StreamUploader: &streamUpload{multipartUploader: &multipartUpload{}}, + } +} + +// UploadFile uploads an object to Object Storage. Depending on the options provided and the +// size of the object, the object may be uploaded in multiple parts or just an signle object. +func (uploadManager *UploadManager) UploadFile(ctx context.Context, request UploadFileRequest) (response UploadResponse, err error) { + if err = request.validate(); err != nil { + return + } + + if err = request.initDefaultValues(); err != nil { + return + } + + if uploadManager.FileUploader == nil { + err = errorInvalidFileUploader + return + } + + file, err := os.Open(request.FilePath) + + if err != nil { + file.Close() + return + } + + defer file.Close() + + fi, err := file.Stat() + if err != nil { + return + } + + fileSize := fi.Size() + + // parallel upload disabled by user or the file size smaller than or equal to partSize + // use UploadFilePutObject + if !*request.AllowMultipartUploads || + fileSize <= *request.PartSize { + response, err = uploadManager.FileUploader.UploadFilePutObject(ctx, request) + return + } + + response, err = uploadManager.FileUploader.UploadFileMultiparts(ctx, request) + return +} + +// ResumeUploadFile resumes a multipart file upload. +func (uploadManager *UploadManager) ResumeUploadFile(ctx context.Context, uploadID string) (response UploadResponse, err error) { + if len(strings.TrimSpace(uploadID)) == 0 { + err = errors.New("uploadID is required to resume a multipart file upload") + err = uploadManagerError{err: err} + return + } + response, err = uploadManager.FileUploader.ResumeUploadFile(ctx, uploadID) + return +} + +// UploadStream uploads streaming data to Object Storage. If the stream is non-empty, this will always perform a +// multipart upload, splitting parts based on the part size (10 MiB if none specified). If the stream is empty, +// this will upload a single empty object to Object Storage. +// Stream uploads are not currently resumable. +func (uploadManager *UploadManager) UploadStream(ctx context.Context, request UploadStreamRequest) (response UploadResponse, err error) { + if err = request.validate(); err != nil { + return + } + + if err = request.initDefaultValues(); err != nil { + return + } + + if uploadManager.StreamUploader == nil { + err = errorInvalidStreamUploader + return + } + //check if the stream is empty + if isZeroLength(request.StreamReader) { + return uploadEmptyStream(ctx, request) + } + + response, err = uploadManager.StreamUploader.UploadStream(ctx, request) + return +} + +func isZeroLength(streamReader io.Reader) bool { + switch v := streamReader.(type) { + case *bytes.Buffer: + return v.Len() == 0 + case *bytes.Reader: + return v.Len() == 0 + case *strings.Reader: + return v.Len() == 0 + case *os.File: + fi, err := v.Stat() + if err != nil { + return false + } + return fi.Size() == 0 + default: + return false + } +} + +func uploadEmptyStream(ctx context.Context, request UploadStreamRequest) (response UploadResponse, err error) { + putObjReq := objectstorage.PutObjectRequest{ + NamespaceName: request.UploadRequest.NamespaceName, + BucketName: request.UploadRequest.BucketName, + ObjectName: request.UploadRequest.ObjectName, + ContentLength: new(int64), + PutObjectBody: http.NoBody, + OpcMeta: request.UploadRequest.Metadata, + IfMatch: request.UploadRequest.IfMatch, + IfNoneMatch: request.UploadRequest.IfNoneMatch, + ContentType: request.UploadRequest.ContentType, + ContentLanguage: request.UploadRequest.ContentLanguage, + ContentEncoding: request.UploadRequest.ContentEncoding, + ContentMD5: request.UploadRequest.ContentMD5, + OpcClientRequestId: request.UploadRequest.OpcClientRequestID, + RequestMetadata: request.UploadRequest.RequestMetadata, + } + putObjResp, err := request.UploadRequest.ObjectStorageClient.PutObject(ctx, putObjReq) + spUploadResp := SinglepartUploadResponse{putObjResp} + return UploadResponse{SinglepartUpload, &spUploadResp, nil}, err +} + +func getUploadManagerRetryPolicy() *common.RetryPolicy { + attempts := uint(3) + retryOnAllNon200ResponseCodes := func(r common.OCIOperationResponse) bool { + return !(r.Error == nil && 199 < r.Response.HTTPResponse().StatusCode && r.Response.HTTPResponse().StatusCode < 300) + } + + policy := common.NewRetryPolicyWithOptions( + // since this retries on ANY non-2xx response, we don't need special handling for eventual consistency + common.ReplaceWithValuesFromRetryPolicy(common.DefaultRetryPolicyWithoutEventualConsistency()), + common.WithMaximumNumberAttempts(attempts), + common.WithShouldRetryOperation(retryOnAllNon200ResponseCodes), + ) + + return &policy +} + +type uploadManagerError struct { + err error +} + +func (ume uploadManagerError) Error() string { + return fmt.Sprintf("%s\nClient Version: %s, OS Version: %s/%s\nSee https://docs.oracle.com/iaas/Content/API/Concepts/sdk_troubleshooting.htm for common issues and steps to resolve them. If you need to contact support, or file a GitHub issue, please include this full error message.", ume.err, common.Version(), runtime.GOOS, runtime.Version()) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager_req_resp.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager_req_resp.go new file mode 100644 index 00000000000..36fb03c25f4 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/transfer/upload_manager_req_resp.go @@ -0,0 +1,257 @@ +// Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. + +package transfer + +import ( + "errors" + "net/http" + + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/objectstorage" +) + +// requestValidator validate user's input and assign default values if not defined +type requestValidator interface { + // validate inputs, return error if request is not valid + validate() error + + // assign default values + assignDefaultValues() error +} + +// UploadRequest defines the input parameters for UploadFile method +type UploadRequest struct { + // The top-level namespace used for the request. + NamespaceName *string `mandatory:"true"` + + // The name of the bucket. Avoid entering confidential information. Example: my-new-bucket1 + BucketName *string `mandatory:"true"` + + // The name of the object. Avoid entering confidential information. Example: test/object1.log + ObjectName *string `mandatory:"true"` + + // [Optional] Override the default part size of 128 MiB, value is in bytes. + // The max part size is 50GiB + PartSize *int64 `mandatory:"false"` + + // [Optional] Whether or not this UploadManager supports performing mulitpart uploads. Defaults to True. + AllowMultipartUploads *bool `mandatory:"false"` + + // [Optional] Whether or not this UploadManager supports uploading individual parts of a multipart upload in parallel. + // This setting has no effect on uploads that are performed using a single put_object call. Defaults to True. + AllowParrallelUploads *bool `mandatory:"false"` + + // The number of go routines for uploading individual parts of a multipart upload. + // This setting is only used if allow_parallel_uploads is set to True. Defaults to 5. + // The upper bounds of the number is 10,000. + NumberOfGoroutines *int `mandatory:"false"` + + // A configured object storage client to use for interacting with the Object Storage service. + // Default timeout is 60s which includes the time for reading the body. + // Default timeout doesn't work for big file size and big part size(once upload each part longer than 60s), need to manually update timeout to support big file upload. + ObjectStorageClient *objectstorage.ObjectStorageClient `mandatory:"false"` + + // [Optional] The entity tag of the object to match. + IfMatch *string `mandatory:"false"` + + // [Optional] The entity tag of the object to avoid matching. The only valid value is ‘*’, + // which indicates that the request should fail if the object already exists. + IfNoneMatch *string `mandatory:"false"` + + // [Optional] The base-64 encoded MD5 hash of the body. This parameter is only used if the object is uploaded in a single part. + ContentMD5 *string `mandatory:"false"` + + // [Optional] The content type of the object to upload. + ContentType *string `mandatory:"false"` + + // [Optional] The content language of the object to upload. + ContentLanguage *string `mandatory:"false"` + + // [Optional] The content encoding of the object to upload. + ContentEncoding *string `mandatory:"false"` + + // [Optional] Arbitrary string keys and values for the user-defined metadata for the object. + // Keys must be in "opc-meta-*" format. + Metadata map[string]string `mandatory:"false"` + + // [Optional] The client request ID for tracing. + OpcClientRequestID *string `mandatory:"false"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata + + // [Optional] The storage tier of the object to upload. If not specified, the storage tier is + // defaulted to 'Standard' + StorageTier objectstorage.PutObjectStorageTierEnum `mandatory:"false"` + + // [Optional] Callback API that can be invoked during multiPartUploads + CallBack UploadCallBack `mandatory:"false"` + + // [Optional] Whether or not this UploadManager supports performing multipart uploads md5 checksum verification. Defaults to False. + EnableMultipartChecksumVerification *bool `mandatory:"false"` + + // The optional header that specifies "AES256" as the encryption algorithm. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerAlgorithm *string `mandatory:"false"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or + // decrypt the data. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKey *string `mandatory:"false"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This + // value is used to check the integrity of the encryption key. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKeySha256 *string `mandatory:"false"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a master encryption key used to call the Key + // Management service to generate a data encryption key or to encrypt or decrypt a data encryption key. + OpcSseKmsKeyId *string `mandatory:"false"` +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request UploadRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +var ( + errorInvalidNamespace = errors.New("namespaceName is required") + errorInvalidBucketName = errors.New("bucketName is required") + errorInvalidObjectName = errors.New("objectName is required") +) + +const defaultNumberOfGoroutines = 5 // increase the value might cause 409 error form service and client timeout + +func (request UploadRequest) validate() error { + if request.NamespaceName == nil { + return errorInvalidNamespace + } + + if request.BucketName == nil { + return errorInvalidBucketName + } + + if request.ObjectName == nil { + return errorInvalidObjectName + } + + return nil +} + +func (request *UploadRequest) initDefaultValues() error { + if request.ObjectStorageClient == nil { + client, err := objectstorage.NewObjectStorageClientWithConfigurationProvider(common.DefaultConfigProvider()) + + // default timeout is 60s which includes the time for reading the body + // default timeout doesn't work for big file, here will use the default + // 0s which means no timeout + client.HTTPClient = &http.Client{} + + if err != nil { + return err + } + + request.ObjectStorageClient = &client + } + + if request.NumberOfGoroutines == nil || + *request.NumberOfGoroutines <= 0 { + request.NumberOfGoroutines = common.Int(defaultNumberOfGoroutines) + } + + if request.AllowMultipartUploads == nil { + request.AllowMultipartUploads = common.Bool(true) + } + + if request.AllowParrallelUploads == nil { + request.AllowParrallelUploads = common.Bool(true) + } + + if !*request.AllowParrallelUploads { + request.NumberOfGoroutines = common.Int(1) // one go routine for upload + } + + if request.RetryPolicy() == nil { + // default retry policy + request.RequestMetadata = common.RequestMetadata{RetryPolicy: getUploadManagerDefaultRetryPolicy()} + } + + return nil +} + +// UploadResponseType with underlying type: string +type UploadResponseType string + +// Set of constants representing the allowable values for VolumeAttachmentLifecycleState +const ( + MultipartUpload UploadResponseType = "MULTIPARTUPLOAD" + SinglepartUpload UploadResponseType = "SINGLEPARTUPLOAD" +) + +// UploadResponse is the response from commitMultipart or the putObject API operation. +type UploadResponse struct { + + // Polymorphic response type indicates the response type + Type UploadResponseType + + // response for putObject API response (single part upload), will be nil if the operation is multiPart upload + *SinglepartUploadResponse + + // response for commitMultipart API response (multipart upload), will be nil if the operation is singlePart upload + *MultipartUploadResponse +} + +// IsResumable is a function to check is previous failed upload resumable or not +func (resp UploadResponse) IsResumable() bool { + if resp.Type == SinglepartUpload { + return false + } + + return *resp.MultipartUploadResponse.isResumable +} + +// SinglepartUploadResponse is the response from putObject API operation. +type SinglepartUploadResponse struct { + objectstorage.PutObjectResponse +} + +// MultipartUploadResponse is the response from commitMultipart API operation. +type MultipartUploadResponse struct { + objectstorage.CommitMultipartUploadResponse + + // The upload ID for a multipart upload. + UploadID *string + + // The value indicates is the operation IsResumable or not, call the resume function if is true + isResumable *bool +} + +func getUploadManagerDefaultRetryPolicy() *common.RetryPolicy { + attempts := uint(3) + retryOnAllNon200ResponseCodes := func(r common.OCIOperationResponse) bool { + return !(r.Error == nil && 199 < r.Response.HTTPResponse().StatusCode && r.Response.HTTPResponse().StatusCode < 300) + } + + policy := common.NewRetryPolicyWithOptions( + common.WithMaximumNumberAttempts(attempts), + common.WithShouldRetryOperation(retryOnAllNon200ResponseCodes)) + + return &policy +} + +// MultiPartUploadPart holds the details of Part that is uploaded +type MultiPartUploadPart struct { + PartNum int + TotalParts int + Size int64 + Offset int64 + Hash *string + OpcMD5 *string + Etag *string + Err error +} + +// UploadCallBack API that gets invoked after a Part is successuly uploaded +type UploadCallBack func(multiPartUploadPart MultiPartUploadPart) diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_details.go new file mode 100644 index 00000000000..bbe91593fd8 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_details.go @@ -0,0 +1,188 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// UpdateBucketDetails To use any of the API operations, you must be authorized in an IAM policy. If you are not authorized, +// talk to an administrator. If you are an administrator who needs to write policies to give users access, see +// Getting Started with Policies (https://docs.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm). +type UpdateBucketDetails struct { + + // The Object Storage namespace in which the bucket lives. + Namespace *string `mandatory:"false" json:"namespace"` + + // The compartmentId for the compartment to move the bucket to. + CompartmentId *string `mandatory:"false" json:"compartmentId"` + + // The name of the bucket. Valid characters are uppercase or lowercase letters, numbers, hyphens, underscores, and periods. + // Bucket names must be unique within an Object Storage namespace. Avoid entering confidential information. + // Example: my-new-bucket1 + Name *string `mandatory:"false" json:"name"` + + // Arbitrary string, up to 4KB, of keys and values for user-defined metadata. + Metadata map[string]string `mandatory:"false" json:"metadata"` + + // The type of public access enabled on this bucket. A bucket is set to `NoPublicAccess` by default, which only allows an + // authenticated caller to access the bucket and its contents. When `ObjectRead` is enabled on the bucket, public access + // is allowed for the `GetObject`, `HeadObject`, and `ListObjects` operations. When `ObjectReadWithoutList` is enabled + // on the bucket, public access is allowed for the `GetObject` and `HeadObject` operations. + PublicAccessType UpdateBucketDetailsPublicAccessTypeEnum `mandatory:"false" json:"publicAccessType,omitempty"` + + // Whether or not events are emitted for object state changes in this bucket. By default, `objectEventsEnabled` is + // set to `false`. Set `objectEventsEnabled` to `true` to emit events for object state changes. For more information + // about events, see Overview of Events (https://docs.oracle.com/iaas/Content/Events/Concepts/eventsoverview.htm). + ObjectEventsEnabled *bool `mandatory:"false" json:"objectEventsEnabled"` + + // Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Department": "Finance"}` + FreeformTags map[string]string `mandatory:"false" json:"freeformTags"` + + // Defined tags for this resource. Each key is predefined and scoped to a namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Operations": {"CostCenter": "42"}} + DefinedTags map[string]map[string]interface{} `mandatory:"false" json:"definedTags"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the Key Management master encryption key to associate + // with the specified bucket. If this value is empty, the Update operation will remove the associated key, if + // there is one, from the bucket. (The bucket will continue to be encrypted, but with an encryption key managed + // by Oracle.) + KmsKeyId *string `mandatory:"false" json:"kmsKeyId"` + + // The versioning status on the bucket. If in state `Enabled`, multiple versions of the same object can be kept in the bucket. + // When the object is overwritten or deleted, previous versions will still be available. When versioning is `Suspended`, the previous versions will still remain but new versions will no longer be created when overwitten or deleted. + // Versioning cannot be disabled on a bucket once enabled. + Versioning UpdateBucketDetailsVersioningEnum `mandatory:"false" json:"versioning,omitempty"` + + // The auto tiering status on the bucket. If in state `InfrequentAccess`, objects are transitioned + // automatically between the 'Standard' and 'InfrequentAccess' tiers based on the access pattern of the objects. + // When auto tiering is `Disabled`, there will be no automatic transitions between storage tiers. + AutoTiering BucketAutoTieringEnum `mandatory:"false" json:"autoTiering,omitempty"` +} + +func (m UpdateBucketDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m UpdateBucketDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingUpdateBucketDetailsPublicAccessTypeEnum(string(m.PublicAccessType)); !ok && m.PublicAccessType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for PublicAccessType: %s. Supported values are: %s.", m.PublicAccessType, strings.Join(GetUpdateBucketDetailsPublicAccessTypeEnumStringValues(), ","))) + } + if _, ok := GetMappingUpdateBucketDetailsVersioningEnum(string(m.Versioning)); !ok && m.Versioning != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Versioning: %s. Supported values are: %s.", m.Versioning, strings.Join(GetUpdateBucketDetailsVersioningEnumStringValues(), ","))) + } + if _, ok := GetMappingBucketAutoTieringEnum(string(m.AutoTiering)); !ok && m.AutoTiering != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for AutoTiering: %s. Supported values are: %s.", m.AutoTiering, strings.Join(GetBucketAutoTieringEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// UpdateBucketDetailsPublicAccessTypeEnum Enum with underlying type: string +type UpdateBucketDetailsPublicAccessTypeEnum string + +// Set of constants representing the allowable values for UpdateBucketDetailsPublicAccessTypeEnum +const ( + UpdateBucketDetailsPublicAccessTypeNopublicaccess UpdateBucketDetailsPublicAccessTypeEnum = "NoPublicAccess" + UpdateBucketDetailsPublicAccessTypeObjectread UpdateBucketDetailsPublicAccessTypeEnum = "ObjectRead" + UpdateBucketDetailsPublicAccessTypeObjectreadwithoutlist UpdateBucketDetailsPublicAccessTypeEnum = "ObjectReadWithoutList" +) + +var mappingUpdateBucketDetailsPublicAccessTypeEnum = map[string]UpdateBucketDetailsPublicAccessTypeEnum{ + "NoPublicAccess": UpdateBucketDetailsPublicAccessTypeNopublicaccess, + "ObjectRead": UpdateBucketDetailsPublicAccessTypeObjectread, + "ObjectReadWithoutList": UpdateBucketDetailsPublicAccessTypeObjectreadwithoutlist, +} + +var mappingUpdateBucketDetailsPublicAccessTypeEnumLowerCase = map[string]UpdateBucketDetailsPublicAccessTypeEnum{ + "nopublicaccess": UpdateBucketDetailsPublicAccessTypeNopublicaccess, + "objectread": UpdateBucketDetailsPublicAccessTypeObjectread, + "objectreadwithoutlist": UpdateBucketDetailsPublicAccessTypeObjectreadwithoutlist, +} + +// GetUpdateBucketDetailsPublicAccessTypeEnumValues Enumerates the set of values for UpdateBucketDetailsPublicAccessTypeEnum +func GetUpdateBucketDetailsPublicAccessTypeEnumValues() []UpdateBucketDetailsPublicAccessTypeEnum { + values := make([]UpdateBucketDetailsPublicAccessTypeEnum, 0) + for _, v := range mappingUpdateBucketDetailsPublicAccessTypeEnum { + values = append(values, v) + } + return values +} + +// GetUpdateBucketDetailsPublicAccessTypeEnumStringValues Enumerates the set of values in String for UpdateBucketDetailsPublicAccessTypeEnum +func GetUpdateBucketDetailsPublicAccessTypeEnumStringValues() []string { + return []string{ + "NoPublicAccess", + "ObjectRead", + "ObjectReadWithoutList", + } +} + +// GetMappingUpdateBucketDetailsPublicAccessTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingUpdateBucketDetailsPublicAccessTypeEnum(val string) (UpdateBucketDetailsPublicAccessTypeEnum, bool) { + enum, ok := mappingUpdateBucketDetailsPublicAccessTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// UpdateBucketDetailsVersioningEnum Enum with underlying type: string +type UpdateBucketDetailsVersioningEnum string + +// Set of constants representing the allowable values for UpdateBucketDetailsVersioningEnum +const ( + UpdateBucketDetailsVersioningEnabled UpdateBucketDetailsVersioningEnum = "Enabled" + UpdateBucketDetailsVersioningSuspended UpdateBucketDetailsVersioningEnum = "Suspended" +) + +var mappingUpdateBucketDetailsVersioningEnum = map[string]UpdateBucketDetailsVersioningEnum{ + "Enabled": UpdateBucketDetailsVersioningEnabled, + "Suspended": UpdateBucketDetailsVersioningSuspended, +} + +var mappingUpdateBucketDetailsVersioningEnumLowerCase = map[string]UpdateBucketDetailsVersioningEnum{ + "enabled": UpdateBucketDetailsVersioningEnabled, + "suspended": UpdateBucketDetailsVersioningSuspended, +} + +// GetUpdateBucketDetailsVersioningEnumValues Enumerates the set of values for UpdateBucketDetailsVersioningEnum +func GetUpdateBucketDetailsVersioningEnumValues() []UpdateBucketDetailsVersioningEnum { + values := make([]UpdateBucketDetailsVersioningEnum, 0) + for _, v := range mappingUpdateBucketDetailsVersioningEnum { + values = append(values, v) + } + return values +} + +// GetUpdateBucketDetailsVersioningEnumStringValues Enumerates the set of values in String for UpdateBucketDetailsVersioningEnum +func GetUpdateBucketDetailsVersioningEnumStringValues() []string { + return []string{ + "Enabled", + "Suspended", + } +} + +// GetMappingUpdateBucketDetailsVersioningEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingUpdateBucketDetailsVersioningEnum(val string) (UpdateBucketDetailsVersioningEnum, bool) { + enum, ok := mappingUpdateBucketDetailsVersioningEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_request_response.go new file mode 100644 index 00000000000..5bbc1d9a57d --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_bucket_request_response.go @@ -0,0 +1,133 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// UpdateBucketRequest wrapper for the UpdateBucket operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateBucket.go.html to see an example of how to use UpdateBucketRequest. +type UpdateBucketRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // Request object for updating a bucket. + UpdateBucketDetails `contributesTo:"body"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request UpdateBucketRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request UpdateBucketRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request UpdateBucketRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request UpdateBucketRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request UpdateBucketRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request UpdateBucketRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// UpdateBucketResponse wrapper for the UpdateBucket operation +type UpdateBucketResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The Bucket instance + Bucket `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the updated bucket. + ETag *string `presentIn:"header" name:"etag"` +} + +func (response UpdateBucketResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response UpdateBucketResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_details.go new file mode 100644 index 00000000000..dded808607a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_details.go @@ -0,0 +1,45 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// UpdateNamespaceMetadataDetails UpdateNamespaceMetadataDetails is used to update the NamespaceMetadata. To update NamespaceMetadata, a user +// must have OBJECTSTORAGE_NAMESPACE_UPDATE permission. +type UpdateNamespaceMetadataDetails struct { + + // The updated compartment id for use by an S3 client, if this field is set. + DefaultS3CompartmentId *string `mandatory:"false" json:"defaultS3CompartmentId"` + + // The updated compartment id for use by a Swift client, if this field is set. + DefaultSwiftCompartmentId *string `mandatory:"false" json:"defaultSwiftCompartmentId"` +} + +func (m UpdateNamespaceMetadataDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m UpdateNamespaceMetadataDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_request_response.go new file mode 100644 index 00000000000..ec551fb4650 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_namespace_metadata_request_response.go @@ -0,0 +1,111 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// UpdateNamespaceMetadataRequest wrapper for the UpdateNamespaceMetadata operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateNamespaceMetadata.go.html to see an example of how to use UpdateNamespaceMetadataRequest. +type UpdateNamespaceMetadataRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // Request object for update NamespaceMetadata. + UpdateNamespaceMetadataDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request UpdateNamespaceMetadataRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request UpdateNamespaceMetadataRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request UpdateNamespaceMetadataRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request UpdateNamespaceMetadataRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request UpdateNamespaceMetadataRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request UpdateNamespaceMetadataRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// UpdateNamespaceMetadataResponse wrapper for the UpdateNamespaceMetadata operation +type UpdateNamespaceMetadataResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The NamespaceMetadata instance + NamespaceMetadata `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response UpdateNamespaceMetadataResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response UpdateNamespaceMetadataResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_details.go new file mode 100644 index 00000000000..b245db27646 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_details.go @@ -0,0 +1,54 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// UpdateObjectStorageTierDetails To change the storage tier of an object, we specify the object name and the desired +// storage tier in the body. Objects can be moved between Standard and InfrequentAccess +// tiers and from Standard or InfrequentAccess tier to Archive tier. If a version id is +// specified, only the specified version of the object is moved to a different storage +// tier, else the current version is used. +type UpdateObjectStorageTierDetails struct { + + // An object for which the storage tier needs to be changed. + ObjectName *string `mandatory:"true" json:"objectName"` + + // The storage tier that the object should be moved to. + StorageTier StorageTierEnum `mandatory:"true" json:"storageTier"` + + // The versionId of the object. Current object version is used by default. + VersionId *string `mandatory:"false" json:"versionId"` +} + +func (m UpdateObjectStorageTierDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m UpdateObjectStorageTierDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingStorageTierEnum(string(m.StorageTier)); !ok && m.StorageTier != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for StorageTier: %s. Supported values are: %s.", m.StorageTier, strings.Join(GetStorageTierEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_request_response.go new file mode 100644 index 00000000000..ffce81cef72 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_object_storage_tier_request_response.go @@ -0,0 +1,122 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// UpdateObjectStorageTierRequest wrapper for the UpdateObjectStorageTier operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateObjectStorageTier.go.html to see an example of how to use UpdateObjectStorageTierRequest. +type UpdateObjectStorageTierRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The object name and the desired storage tier. + UpdateObjectStorageTierDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request UpdateObjectStorageTierRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request UpdateObjectStorageTierRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request UpdateObjectStorageTierRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request UpdateObjectStorageTierRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request UpdateObjectStorageTierRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request UpdateObjectStorageTierRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// UpdateObjectStorageTierResponse wrapper for the UpdateObjectStorageTier operation +type UpdateObjectStorageTierResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response UpdateObjectStorageTierResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response UpdateObjectStorageTierResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_details.go new file mode 100644 index 00000000000..4f66b594129 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_details.go @@ -0,0 +1,59 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// UpdatePrivateEndpointDetails Information that can be updated for a private endpoint. +type UpdatePrivateEndpointDetails struct { + + // This name associated with the endpoint. Valid characters are uppercase or lowercase letters, numbers, hyphens, + // underscores, and periods. + // Example: my-new-private-endpoint1 + Name *string `mandatory:"false" json:"name"` + + // The Object Storage namespace which will associated with the private endpoint. + Namespace *string `mandatory:"false" json:"namespace"` + + // A list of targets that can be accessed by the private endpoint. + AccessTargets []AccessTargetDetails `mandatory:"false" json:"accessTargets"` + + // Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Department": "Finance"}` + FreeformTags map[string]string `mandatory:"false" json:"freeformTags"` + + // Defined tags for this resource. Each key is predefined and scoped to a namespace. + // For more information, see Resource Tags (https://docs.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). + // Example: `{"Operations": {"CostCenter": "42"}}` + DefinedTags map[string]map[string]interface{} `mandatory:"false" json:"definedTags"` +} + +func (m UpdatePrivateEndpointDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m UpdatePrivateEndpointDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_request_response.go new file mode 100644 index 00000000000..c8c542c11de --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_private_endpoint_request_response.go @@ -0,0 +1,131 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// UpdatePrivateEndpointRequest wrapper for the UpdatePrivateEndpoint operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdatePrivateEndpoint.go.html to see an example of how to use UpdatePrivateEndpointRequest. +type UpdatePrivateEndpointRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the private endpoint. Avoid entering confidential information. + // Example: `my-new-pe-1` + PeName *string `mandatory:"true" contributesTo:"path" name:"peName"` + + // Request object for updating the Private Endpoint. + UpdatePrivateEndpointDetails `contributesTo:"body"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request UpdatePrivateEndpointRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request UpdatePrivateEndpointRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request UpdatePrivateEndpointRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request UpdatePrivateEndpointRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["peName"] != nil { + templateParam := mandatoryParamMap["peName"] + for _, template := range templateParam { + replacementParam := *request.PeName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request UpdatePrivateEndpointRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request UpdatePrivateEndpointRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// UpdatePrivateEndpointResponse wrapper for the UpdatePrivateEndpoint operation +type UpdatePrivateEndpointResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Unique Oracle-assigned identifier for the asynchronous request. If you need to contact Oracle about a + // particular request, provide this request ID. + OpcWorkRequestId *string `presentIn:"header" name:"opc-work-request-id"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response UpdatePrivateEndpointResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response UpdatePrivateEndpointResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_details.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_details.go new file mode 100644 index 00000000000..0bf711009f4 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_details.go @@ -0,0 +1,50 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// UpdateRetentionRuleDetails The details to update a retention rule. +type UpdateRetentionRuleDetails struct { + + // A user-specified name for the retention rule. Names can be helpful in identifying retention rules. + // Avoid entering confidential information. + DisplayName *string `mandatory:"false" json:"displayName"` + + Duration *Duration `mandatory:"false" json:"duration"` + + // The date and time as per RFC 3339 (https://tools.ietf.org/html/rfc3339) after which this rule is locked + // and can only be deleted by deleting the bucket. Once a rule is locked, only increases in the duration are + // allowed and no other properties can be changed. This property cannot be updated for rules that are in a + // locked state. Specifying it when a duration is not specified is considered an error. + TimeRuleLocked *common.SDKTime `mandatory:"false" json:"timeRuleLocked"` +} + +func (m UpdateRetentionRuleDetails) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m UpdateRetentionRuleDetails) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_request_response.go new file mode 100644 index 00000000000..ccec61e7b27 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/update_retention_rule_request_response.go @@ -0,0 +1,146 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// UpdateRetentionRuleRequest wrapper for the UpdateRetentionRule operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UpdateRetentionRule.go.html to see an example of how to use UpdateRetentionRuleRequest. +type UpdateRetentionRuleRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The ID of the retention rule. + RetentionRuleId *string `mandatory:"true" contributesTo:"path" name:"retentionRuleId"` + + // Request object for updating the retention rule. + UpdateRetentionRuleDetails `contributesTo:"body"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request UpdateRetentionRuleRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request UpdateRetentionRuleRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request UpdateRetentionRuleRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request UpdateRetentionRuleRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["retentionRuleId"] != nil { + templateParam := mandatoryParamMap["retentionRuleId"] + for _, template := range templateParam { + replacementParam := *request.RetentionRuleId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request UpdateRetentionRuleRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request UpdateRetentionRuleRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// UpdateRetentionRuleResponse wrapper for the UpdateRetentionRule operation +type UpdateRetentionRuleResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The RetentionRule instance + RetentionRule `presentIn:"body"` + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The entity tag (ETag) for the retention rule that was updated. + Etag *string `presentIn:"header" name:"etag"` +} + +func (response UpdateRetentionRuleResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response UpdateRetentionRuleResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/upload_part_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/upload_part_request_response.go new file mode 100644 index 00000000000..653a7e4561e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/upload_part_request_response.go @@ -0,0 +1,289 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "io" + "net/http" + "strings" +) + +// UploadPartRequest wrapper for the UploadPart operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/objectstorage/UploadPart.go.html to see an example of how to use UploadPartRequest. +type UploadPartRequest struct { + + // The Object Storage namespace used for the request. + NamespaceName *string `mandatory:"true" contributesTo:"path" name:"namespaceName"` + + // The name of the bucket. Avoid entering confidential information. + // Example: `my-new-bucket1` + BucketName *string `mandatory:"true" contributesTo:"path" name:"bucketName"` + + // The name of the object. Avoid entering confidential information. + // Example: `test/object1.log` + ObjectName *string `mandatory:"true" contributesTo:"path" name:"objectName"` + + // The upload ID for a multipart upload. + UploadId *string `mandatory:"true" contributesTo:"query" name:"uploadId"` + + // The part number that identifies the object part currently being uploaded. + UploadPartNum *int `mandatory:"true" contributesTo:"query" name:"uploadPartNum"` + + // The content length of the body. + ContentLength *int64 `mandatory:"false" contributesTo:"header" name:"Content-Length"` + + // The part being uploaded to the Object Storage service. + UploadPartBody io.ReadCloser `mandatory:"true" contributesTo:"body" encoding:"binary"` + + // The client request ID for tracing. + OpcClientRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-client-request-id"` + + // The entity tag (ETag) to match with the ETag of an existing resource. If the specified ETag matches the ETag of + // the existing resource, GET and HEAD requests will return the resource and PUT and POST requests will upload + // the resource. + IfMatch *string `mandatory:"false" contributesTo:"header" name:"if-match"` + + // The entity tag (ETag) to avoid matching. The only valid value is '*', which indicates that the request should + // fail if the resource already exists. + IfNoneMatch *string `mandatory:"false" contributesTo:"header" name:"if-none-match"` + + // A value of `100-continue` requests preliminary verification of the request method, path, and headers before the request body is sent. + // If no error results from such verification, the server will send a 100 (Continue) interim response to indicate readiness for the request body. + // The only allowed value for this parameter is "100-Continue" (case-insensitive). + Expect *string `mandatory:"false" contributesTo:"header" name:"Expect"` + + // The optional header that defines the base64-encoded MD5 hash of the body. If the optional Content-MD5 header is present, Object + // Storage performs an integrity check on the body of the HTTP request by computing the MD5 hash for the body and comparing it to the + // MD5 hash supplied in the header. If the two hashes do not match, the object is rejected and an HTTP-400 Unmatched Content MD5 error + // is returned with the message: + // "The computed MD5 of the request body (ACTUAL_MD5) does not match the Content-MD5 header (HEADER_MD5)" + ContentMD5 *string `mandatory:"false" contributesTo:"header" name:"Content-MD5"` + + // The optional checksum algorithm to use to compute and store the checksum of the body of the HTTP request (or the parts in case of multipart uploads), + // in addition to the default MD5 checksum. + OpcChecksumAlgorithm UploadPartOpcChecksumAlgorithmEnum `mandatory:"false" contributesTo:"header" name:"opc-checksum-algorithm"` + + // Applicable only if CRC32C is specified in the opc-checksum-algorithm request header. + // The optional header that defines the base64-encoded, 32-bit CRC32C (Castagnoli) checksum of the body. If the optional opc-content-crc32c header + // is present, Object Storage performs an integrity check on the body of the HTTP request by computing the CRC32C checksum for the body and comparing + // it to the CRC32C checksum supplied in the header. If the two checksums do not match, the object is rejected and an HTTP-400 Unmatched Content CRC32C error + // is returned with the message: + // "The computed CRC32C of the request body (ACTUAL_CRC32C) does not match the opc-content-crc32c header (HEADER_CRC32C)" + OpcContentCrc32c *string `mandatory:"false" contributesTo:"header" name:"opc-content-crc32c"` + + // Applicable only if SHA256 is specified in the opc-checksum-algorithm request header. + // The optional header that defines the base64-encoded SHA256 hash of the body. If the optional opc-content-sha256 header is present, Object + // Storage performs an integrity check on the body of the HTTP request by computing the SHA256 hash for the body and comparing it to the + // SHA256 hash supplied in the header. If the two hashes do not match, the object is rejected and an HTTP-400 Unmatched Content SHA256 error + // is returned with the message: + // "The computed SHA256 of the request body (ACTUAL_SHA256) does not match the opc-content-sha256 header (HEADER_SHA256)" + OpcContentSha256 *string `mandatory:"false" contributesTo:"header" name:"opc-content-sha256"` + + // Applicable only if SHA384 is specified in the opc-checksum-algorithm request header. + // The optional header that defines the base64-encoded SHA384 hash of the body. If the optional opc-content-sha384 header is present, Object + // Storage performs an integrity check on the body of the HTTP request by computing the SHA384 hash for the body and comparing it to the + // SHA384 hash supplied in the header. If the two hashes do not match, the object is rejected and an HTTP-400 Unmatched Content SHA384 error + // is returned with the message: + // "The computed SHA384 of the request body (ACTUAL_SHA384) does not match the opc-content-sha384 header (HEADER_SHA384)" + OpcContentSha384 *string `mandatory:"false" contributesTo:"header" name:"opc-content-sha384"` + + // The optional header that specifies "AES256" as the encryption algorithm. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerAlgorithm *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-algorithm"` + + // The optional header that specifies the base64-encoded 256-bit encryption key to use to encrypt or + // decrypt the data. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKey *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key"` + + // The optional header that specifies the base64-encoded SHA256 hash of the encryption key. This + // value is used to check the integrity of the encryption key. For more information, see + // Using Your Own Keys for Server-Side Encryption (https://docs.oracle.com/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm). + OpcSseCustomerKeySha256 *string `mandatory:"false" contributesTo:"header" name:"opc-sse-customer-key-sha256"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a master encryption key used to call the Key + // Management service to generate a data encryption key or to encrypt or decrypt a data encryption key. + OpcSseKmsKeyId *string `mandatory:"false" contributesTo:"header" name:"opc-sse-kms-key-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request UploadPartRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request UploadPartRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + httpRequest, err := common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) + if err == nil && binaryRequestBody.Seekable() { + common.UpdateRequestBinaryBody(&httpRequest, binaryRequestBody) + } + return httpRequest, err +} + +// BinaryRequestBody implements the OCIRequest interface +func (request UploadPartRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + rsc := common.NewOCIReadSeekCloser(request.UploadPartBody) + if rsc.Seekable() { + return rsc, true + } + return nil, true + +} + +// ReplaceMandatoryParamInPath replaces the mandatory parameter in the path with the value provided. +// Not all services are supporting this feature and this method will be a no-op for those services. +func (request UploadPartRequest) ReplaceMandatoryParamInPath(client *common.BaseClient, mandatoryParamMap map[string][]common.TemplateParamForPerRealmEndpoint) { + if mandatoryParamMap["namespaceName"] != nil { + templateParam := mandatoryParamMap["namespaceName"] + for _, template := range templateParam { + replacementParam := *request.NamespaceName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["bucketName"] != nil { + templateParam := mandatoryParamMap["bucketName"] + for _, template := range templateParam { + replacementParam := *request.BucketName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["objectName"] != nil { + templateParam := mandatoryParamMap["objectName"] + for _, template := range templateParam { + replacementParam := *request.ObjectName + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } + if mandatoryParamMap["uploadId"] != nil { + templateParam := mandatoryParamMap["uploadId"] + for _, template := range templateParam { + replacementParam := *request.UploadId + if template.EndsWithDot { + replacementParam = replacementParam + "." + } + client.Host = strings.Replace(client.Host, template.Template, replacementParam, -1) + } + } +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request UploadPartRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request UploadPartRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingUploadPartOpcChecksumAlgorithmEnum(string(request.OpcChecksumAlgorithm)); !ok && request.OpcChecksumAlgorithm != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for OpcChecksumAlgorithm: %s. Supported values are: %s.", request.OpcChecksumAlgorithm, strings.Join(GetUploadPartOpcChecksumAlgorithmEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// UploadPartResponse wrapper for the UploadPart operation +type UploadPartResponse struct { + + // The underlying http response + RawResponse *http.Response + + // Echoes back the value passed in the opc-client-request-id header, for use by clients when debugging. + OpcClientRequestId *string `presentIn:"header" name:"opc-client-request-id"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular + // request, provide this request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` + + // The base64-encoded MD5 hash of the request body, as computed by the server. + OpcContentMd5 *string `presentIn:"header" name:"opc-content-md5"` + + // The base64-encoded, 32-bit CRC32C (Castagnoli) checksum of the request body as computed by the server. Applicable only if CRC32C was specified in opc-checksum-algorithm request header during upload. + OpcContentCrc32c *string `presentIn:"header" name:"opc-content-crc32c"` + + // The base64-encoded SHA256 hash of the request body as computed by the server. Applicable only if SHA256 was specified in opc-checksum-algorithm request header during upload. + OpcContentSha256 *string `presentIn:"header" name:"opc-content-sha256"` + + // The base64-encoded SHA384 hash of the request body as computed by the server. Applicable only if SHA384 was specified in opc-checksum-algorithm request header during upload. + OpcContentSha384 *string `presentIn:"header" name:"opc-content-sha384"` + + // The entity tag (ETag) for the object. + ETag *string `presentIn:"header" name:"etag"` +} + +func (response UploadPartResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response UploadPartResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// UploadPartOpcChecksumAlgorithmEnum Enum with underlying type: string +type UploadPartOpcChecksumAlgorithmEnum string + +// Set of constants representing the allowable values for UploadPartOpcChecksumAlgorithmEnum +const ( + UploadPartOpcChecksumAlgorithmCrc32c UploadPartOpcChecksumAlgorithmEnum = "CRC32C" + UploadPartOpcChecksumAlgorithmSha256 UploadPartOpcChecksumAlgorithmEnum = "SHA256" + UploadPartOpcChecksumAlgorithmSha384 UploadPartOpcChecksumAlgorithmEnum = "SHA384" +) + +var mappingUploadPartOpcChecksumAlgorithmEnum = map[string]UploadPartOpcChecksumAlgorithmEnum{ + "CRC32C": UploadPartOpcChecksumAlgorithmCrc32c, + "SHA256": UploadPartOpcChecksumAlgorithmSha256, + "SHA384": UploadPartOpcChecksumAlgorithmSha384, +} + +var mappingUploadPartOpcChecksumAlgorithmEnumLowerCase = map[string]UploadPartOpcChecksumAlgorithmEnum{ + "crc32c": UploadPartOpcChecksumAlgorithmCrc32c, + "sha256": UploadPartOpcChecksumAlgorithmSha256, + "sha384": UploadPartOpcChecksumAlgorithmSha384, +} + +// GetUploadPartOpcChecksumAlgorithmEnumValues Enumerates the set of values for UploadPartOpcChecksumAlgorithmEnum +func GetUploadPartOpcChecksumAlgorithmEnumValues() []UploadPartOpcChecksumAlgorithmEnum { + values := make([]UploadPartOpcChecksumAlgorithmEnum, 0) + for _, v := range mappingUploadPartOpcChecksumAlgorithmEnum { + values = append(values, v) + } + return values +} + +// GetUploadPartOpcChecksumAlgorithmEnumStringValues Enumerates the set of values in String for UploadPartOpcChecksumAlgorithmEnum +func GetUploadPartOpcChecksumAlgorithmEnumStringValues() []string { + return []string{ + "CRC32C", + "SHA256", + "SHA384", + } +} + +// GetMappingUploadPartOpcChecksumAlgorithmEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingUploadPartOpcChecksumAlgorithmEnum(val string) (UploadPartOpcChecksumAlgorithmEnum, bool) { + enum, ok := mappingUploadPartOpcChecksumAlgorithmEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request.go new file mode 100644 index 00000000000..ed7626517b7 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request.go @@ -0,0 +1,189 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// WorkRequest A description of workRequest status. +type WorkRequest struct { + + // The type of work request. + OperationType WorkRequestOperationTypeEnum `mandatory:"false" json:"operationType,omitempty"` + + // The status of the specified work request. + Status WorkRequestStatusEnum `mandatory:"false" json:"status,omitempty"` + + // The id of the work request. + Id *string `mandatory:"false" json:"id"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the compartment that contains the work request. Work + // requests are scoped to the same compartment as the resource the work request affects. + // If the work request affects multiple resources and those resources are not in the same compartment, the OCID of + // the primary resource is used. For example, you can copy an object in a bucket in one compartment to a bucket in + // another compartment. In this case, the OCID of the source compartment is used. + CompartmentId *string `mandatory:"false" json:"compartmentId"` + + Resources []WorkRequestResource `mandatory:"false" json:"resources"` + + // Percentage of the work request completed. + PercentComplete *float32 `mandatory:"false" json:"percentComplete"` + + // The date and time the work request was created, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeAccepted *common.SDKTime `mandatory:"false" json:"timeAccepted"` + + // The date and time the work request was started, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeStarted *common.SDKTime `mandatory:"false" json:"timeStarted"` + + // The date and time the work request was finished, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeFinished *common.SDKTime `mandatory:"false" json:"timeFinished"` +} + +func (m WorkRequest) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m WorkRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingWorkRequestOperationTypeEnum(string(m.OperationType)); !ok && m.OperationType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for OperationType: %s. Supported values are: %s.", m.OperationType, strings.Join(GetWorkRequestOperationTypeEnumStringValues(), ","))) + } + if _, ok := GetMappingWorkRequestStatusEnum(string(m.Status)); !ok && m.Status != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Status: %s. Supported values are: %s.", m.Status, strings.Join(GetWorkRequestStatusEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// WorkRequestOperationTypeEnum Enum with underlying type: string +type WorkRequestOperationTypeEnum string + +// Set of constants representing the allowable values for WorkRequestOperationTypeEnum +const ( + WorkRequestOperationTypeCopyObject WorkRequestOperationTypeEnum = "COPY_OBJECT" + WorkRequestOperationTypeReencrypt WorkRequestOperationTypeEnum = "REENCRYPT" + WorkRequestOperationTypePrivateEndpointCreate WorkRequestOperationTypeEnum = "PRIVATE_ENDPOINT_CREATE" + WorkRequestOperationTypePrivateEndpointUpdate WorkRequestOperationTypeEnum = "PRIVATE_ENDPOINT_UPDATE" + WorkRequestOperationTypePrivateEndpointDelete WorkRequestOperationTypeEnum = "PRIVATE_ENDPOINT_DELETE" +) + +var mappingWorkRequestOperationTypeEnum = map[string]WorkRequestOperationTypeEnum{ + "COPY_OBJECT": WorkRequestOperationTypeCopyObject, + "REENCRYPT": WorkRequestOperationTypeReencrypt, + "PRIVATE_ENDPOINT_CREATE": WorkRequestOperationTypePrivateEndpointCreate, + "PRIVATE_ENDPOINT_UPDATE": WorkRequestOperationTypePrivateEndpointUpdate, + "PRIVATE_ENDPOINT_DELETE": WorkRequestOperationTypePrivateEndpointDelete, +} + +var mappingWorkRequestOperationTypeEnumLowerCase = map[string]WorkRequestOperationTypeEnum{ + "copy_object": WorkRequestOperationTypeCopyObject, + "reencrypt": WorkRequestOperationTypeReencrypt, + "private_endpoint_create": WorkRequestOperationTypePrivateEndpointCreate, + "private_endpoint_update": WorkRequestOperationTypePrivateEndpointUpdate, + "private_endpoint_delete": WorkRequestOperationTypePrivateEndpointDelete, +} + +// GetWorkRequestOperationTypeEnumValues Enumerates the set of values for WorkRequestOperationTypeEnum +func GetWorkRequestOperationTypeEnumValues() []WorkRequestOperationTypeEnum { + values := make([]WorkRequestOperationTypeEnum, 0) + for _, v := range mappingWorkRequestOperationTypeEnum { + values = append(values, v) + } + return values +} + +// GetWorkRequestOperationTypeEnumStringValues Enumerates the set of values in String for WorkRequestOperationTypeEnum +func GetWorkRequestOperationTypeEnumStringValues() []string { + return []string{ + "COPY_OBJECT", + "REENCRYPT", + "PRIVATE_ENDPOINT_CREATE", + "PRIVATE_ENDPOINT_UPDATE", + "PRIVATE_ENDPOINT_DELETE", + } +} + +// GetMappingWorkRequestOperationTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingWorkRequestOperationTypeEnum(val string) (WorkRequestOperationTypeEnum, bool) { + enum, ok := mappingWorkRequestOperationTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// WorkRequestStatusEnum Enum with underlying type: string +type WorkRequestStatusEnum string + +// Set of constants representing the allowable values for WorkRequestStatusEnum +const ( + WorkRequestStatusAccepted WorkRequestStatusEnum = "ACCEPTED" + WorkRequestStatusInProgress WorkRequestStatusEnum = "IN_PROGRESS" + WorkRequestStatusFailed WorkRequestStatusEnum = "FAILED" + WorkRequestStatusCompleted WorkRequestStatusEnum = "COMPLETED" + WorkRequestStatusCanceling WorkRequestStatusEnum = "CANCELING" + WorkRequestStatusCanceled WorkRequestStatusEnum = "CANCELED" +) + +var mappingWorkRequestStatusEnum = map[string]WorkRequestStatusEnum{ + "ACCEPTED": WorkRequestStatusAccepted, + "IN_PROGRESS": WorkRequestStatusInProgress, + "FAILED": WorkRequestStatusFailed, + "COMPLETED": WorkRequestStatusCompleted, + "CANCELING": WorkRequestStatusCanceling, + "CANCELED": WorkRequestStatusCanceled, +} + +var mappingWorkRequestStatusEnumLowerCase = map[string]WorkRequestStatusEnum{ + "accepted": WorkRequestStatusAccepted, + "in_progress": WorkRequestStatusInProgress, + "failed": WorkRequestStatusFailed, + "completed": WorkRequestStatusCompleted, + "canceling": WorkRequestStatusCanceling, + "canceled": WorkRequestStatusCanceled, +} + +// GetWorkRequestStatusEnumValues Enumerates the set of values for WorkRequestStatusEnum +func GetWorkRequestStatusEnumValues() []WorkRequestStatusEnum { + values := make([]WorkRequestStatusEnum, 0) + for _, v := range mappingWorkRequestStatusEnum { + values = append(values, v) + } + return values +} + +// GetWorkRequestStatusEnumStringValues Enumerates the set of values in String for WorkRequestStatusEnum +func GetWorkRequestStatusEnumStringValues() []string { + return []string{ + "ACCEPTED", + "IN_PROGRESS", + "FAILED", + "COMPLETED", + "CANCELING", + "CANCELED", + } +} + +// GetMappingWorkRequestStatusEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingWorkRequestStatusEnum(val string) (WorkRequestStatusEnum, bool) { + enum, ok := mappingWorkRequestStatusEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_error.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_error.go new file mode 100644 index 00000000000..970cb6976d0 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_error.go @@ -0,0 +1,48 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// WorkRequestError The representation of WorkRequestError +type WorkRequestError struct { + + // A machine-usable code for the error that occurred. For the list of error codes, + // see API Errors (https://docs.oracle.com/iaas/Content/API/References/apierrors.htm). + Code *string `mandatory:"false" json:"code"` + + // A human-readable description of the issue that produced the error. + Message *string `mandatory:"false" json:"message"` + + // The time the error occurred. + Timestamp *common.SDKTime `mandatory:"false" json:"timestamp"` +} + +func (m WorkRequestError) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m WorkRequestError) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_log_entry.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_log_entry.go new file mode 100644 index 00000000000..b71817946f5 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_log_entry.go @@ -0,0 +1,45 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// WorkRequestLogEntry The representation of WorkRequestLogEntry +type WorkRequestLogEntry struct { + + // Human-readable log message. + Message *string `mandatory:"false" json:"message"` + + // The date and time the log message was written, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + Timestamp *common.SDKTime `mandatory:"false" json:"timestamp"` +} + +func (m WorkRequestLogEntry) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m WorkRequestLogEntry) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource.go new file mode 100644 index 00000000000..f031ef223a9 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource.go @@ -0,0 +1,118 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// WorkRequestResource The representation of WorkRequestResource +type WorkRequestResource struct { + + // The status of the work request. + ActionType WorkRequestResourceActionTypeEnum `mandatory:"false" json:"actionType,omitempty"` + + // The resource type the work request affects. + EntityType *string `mandatory:"false" json:"entityType"` + + // The resource type identifier. + Identifier *string `mandatory:"false" json:"identifier"` + + // The URI path that you can use for a GET request to access the resource metadata. + EntityUri *string `mandatory:"false" json:"entityUri"` + + // The metadata of the resource. + Metadata map[string]string `mandatory:"false" json:"metadata"` +} + +func (m WorkRequestResource) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m WorkRequestResource) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingWorkRequestResourceActionTypeEnum(string(m.ActionType)); !ok && m.ActionType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for ActionType: %s. Supported values are: %s.", m.ActionType, strings.Join(GetWorkRequestResourceActionTypeEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// WorkRequestResourceActionTypeEnum Enum with underlying type: string +type WorkRequestResourceActionTypeEnum string + +// Set of constants representing the allowable values for WorkRequestResourceActionTypeEnum +const ( + WorkRequestResourceActionTypeCreated WorkRequestResourceActionTypeEnum = "CREATED" + WorkRequestResourceActionTypeUpdated WorkRequestResourceActionTypeEnum = "UPDATED" + WorkRequestResourceActionTypeDeleted WorkRequestResourceActionTypeEnum = "DELETED" + WorkRequestResourceActionTypeRelated WorkRequestResourceActionTypeEnum = "RELATED" + WorkRequestResourceActionTypeInProgress WorkRequestResourceActionTypeEnum = "IN_PROGRESS" + WorkRequestResourceActionTypeRead WorkRequestResourceActionTypeEnum = "READ" + WorkRequestResourceActionTypeWritten WorkRequestResourceActionTypeEnum = "WRITTEN" +) + +var mappingWorkRequestResourceActionTypeEnum = map[string]WorkRequestResourceActionTypeEnum{ + "CREATED": WorkRequestResourceActionTypeCreated, + "UPDATED": WorkRequestResourceActionTypeUpdated, + "DELETED": WorkRequestResourceActionTypeDeleted, + "RELATED": WorkRequestResourceActionTypeRelated, + "IN_PROGRESS": WorkRequestResourceActionTypeInProgress, + "READ": WorkRequestResourceActionTypeRead, + "WRITTEN": WorkRequestResourceActionTypeWritten, +} + +var mappingWorkRequestResourceActionTypeEnumLowerCase = map[string]WorkRequestResourceActionTypeEnum{ + "created": WorkRequestResourceActionTypeCreated, + "updated": WorkRequestResourceActionTypeUpdated, + "deleted": WorkRequestResourceActionTypeDeleted, + "related": WorkRequestResourceActionTypeRelated, + "in_progress": WorkRequestResourceActionTypeInProgress, + "read": WorkRequestResourceActionTypeRead, + "written": WorkRequestResourceActionTypeWritten, +} + +// GetWorkRequestResourceActionTypeEnumValues Enumerates the set of values for WorkRequestResourceActionTypeEnum +func GetWorkRequestResourceActionTypeEnumValues() []WorkRequestResourceActionTypeEnum { + values := make([]WorkRequestResourceActionTypeEnum, 0) + for _, v := range mappingWorkRequestResourceActionTypeEnum { + values = append(values, v) + } + return values +} + +// GetWorkRequestResourceActionTypeEnumStringValues Enumerates the set of values in String for WorkRequestResourceActionTypeEnum +func GetWorkRequestResourceActionTypeEnumStringValues() []string { + return []string{ + "CREATED", + "UPDATED", + "DELETED", + "RELATED", + "IN_PROGRESS", + "READ", + "WRITTEN", + } +} + +// GetMappingWorkRequestResourceActionTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingWorkRequestResourceActionTypeEnum(val string) (WorkRequestResourceActionTypeEnum, bool) { + enum, ok := mappingWorkRequestResourceActionTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource_metadata_key.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource_metadata_key.go new file mode 100644 index 00000000000..7fa82b7479a --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_resource_metadata_key.go @@ -0,0 +1,70 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "strings" +) + +// WorkRequestResourceMetadataKeyEnum Enum with underlying type: string +type WorkRequestResourceMetadataKeyEnum string + +// Set of constants representing the allowable values for WorkRequestResourceMetadataKeyEnum +const ( + WorkRequestResourceMetadataKeyRegion WorkRequestResourceMetadataKeyEnum = "REGION" + WorkRequestResourceMetadataKeyNamespace WorkRequestResourceMetadataKeyEnum = "NAMESPACE" + WorkRequestResourceMetadataKeyBucket WorkRequestResourceMetadataKeyEnum = "BUCKET" + WorkRequestResourceMetadataKeyObject WorkRequestResourceMetadataKeyEnum = "OBJECT" + WorkRequestResourceMetadataKeyPrivateEndpointName WorkRequestResourceMetadataKeyEnum = "PRIVATE_ENDPOINT_NAME" +) + +var mappingWorkRequestResourceMetadataKeyEnum = map[string]WorkRequestResourceMetadataKeyEnum{ + "REGION": WorkRequestResourceMetadataKeyRegion, + "NAMESPACE": WorkRequestResourceMetadataKeyNamespace, + "BUCKET": WorkRequestResourceMetadataKeyBucket, + "OBJECT": WorkRequestResourceMetadataKeyObject, + "PRIVATE_ENDPOINT_NAME": WorkRequestResourceMetadataKeyPrivateEndpointName, +} + +var mappingWorkRequestResourceMetadataKeyEnumLowerCase = map[string]WorkRequestResourceMetadataKeyEnum{ + "region": WorkRequestResourceMetadataKeyRegion, + "namespace": WorkRequestResourceMetadataKeyNamespace, + "bucket": WorkRequestResourceMetadataKeyBucket, + "object": WorkRequestResourceMetadataKeyObject, + "private_endpoint_name": WorkRequestResourceMetadataKeyPrivateEndpointName, +} + +// GetWorkRequestResourceMetadataKeyEnumValues Enumerates the set of values for WorkRequestResourceMetadataKeyEnum +func GetWorkRequestResourceMetadataKeyEnumValues() []WorkRequestResourceMetadataKeyEnum { + values := make([]WorkRequestResourceMetadataKeyEnum, 0) + for _, v := range mappingWorkRequestResourceMetadataKeyEnum { + values = append(values, v) + } + return values +} + +// GetWorkRequestResourceMetadataKeyEnumStringValues Enumerates the set of values in String for WorkRequestResourceMetadataKeyEnum +func GetWorkRequestResourceMetadataKeyEnumStringValues() []string { + return []string{ + "REGION", + "NAMESPACE", + "BUCKET", + "OBJECT", + "PRIVATE_ENDPOINT_NAME", + } +} + +// GetMappingWorkRequestResourceMetadataKeyEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingWorkRequestResourceMetadataKeyEnum(val string) (WorkRequestResourceMetadataKeyEnum, bool) { + enum, ok := mappingWorkRequestResourceMetadataKeyEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_summary.go new file mode 100644 index 00000000000..f0c92944255 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/objectstorage/work_request_summary.go @@ -0,0 +1,189 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Object Storage Service API +// +// Use Object Storage and Archive Storage APIs to manage buckets, objects, and related resources. +// For more information, see Overview of Object Storage (https://docs.oracle.com/iaas/Content/Object/Concepts/objectstorageoverview.htm) and +// Overview of Archive Storage (https://docs.oracle.com/iaas/Content/Archive/Concepts/archivestorageoverview.htm). +// + +package objectstorage + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// WorkRequestSummary A summary of the status of a work request. +type WorkRequestSummary struct { + + // The type of work request. + OperationType WorkRequestSummaryOperationTypeEnum `mandatory:"false" json:"operationType,omitempty"` + + // The status of a specified work request. + Status WorkRequestSummaryStatusEnum `mandatory:"false" json:"status,omitempty"` + + // The id of the work request. + Id *string `mandatory:"false" json:"id"` + + // The OCID (https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the compartment that contains the work request. Work + // requests are scoped to the same compartment as the resource the work request affects. + // If the work request affects multiple resources and those resources are not in the same compartment, the OCID of + // the primary resource is used. For example, you can copy an object in a bucket in one compartment to a bucket in + // another compartment. In this case, the OCID of the source compartment is used. + CompartmentId *string `mandatory:"false" json:"compartmentId"` + + Resources []WorkRequestResource `mandatory:"false" json:"resources"` + + // Percentage of the work request completed. + PercentComplete *float32 `mandatory:"false" json:"percentComplete"` + + // The date and time the work request was created, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeAccepted *common.SDKTime `mandatory:"false" json:"timeAccepted"` + + // The date and time the work request was started, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeStarted *common.SDKTime `mandatory:"false" json:"timeStarted"` + + // The date and time the work request was finished, as described in + // RFC 3339 (https://tools.ietf.org/html/rfc3339). + TimeFinished *common.SDKTime `mandatory:"false" json:"timeFinished"` +} + +func (m WorkRequestSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m WorkRequestSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if _, ok := GetMappingWorkRequestSummaryOperationTypeEnum(string(m.OperationType)); !ok && m.OperationType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for OperationType: %s. Supported values are: %s.", m.OperationType, strings.Join(GetWorkRequestSummaryOperationTypeEnumStringValues(), ","))) + } + if _, ok := GetMappingWorkRequestSummaryStatusEnum(string(m.Status)); !ok && m.Status != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Status: %s. Supported values are: %s.", m.Status, strings.Join(GetWorkRequestSummaryStatusEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// WorkRequestSummaryOperationTypeEnum Enum with underlying type: string +type WorkRequestSummaryOperationTypeEnum string + +// Set of constants representing the allowable values for WorkRequestSummaryOperationTypeEnum +const ( + WorkRequestSummaryOperationTypeCopyObject WorkRequestSummaryOperationTypeEnum = "COPY_OBJECT" + WorkRequestSummaryOperationTypeReencrypt WorkRequestSummaryOperationTypeEnum = "REENCRYPT" + WorkRequestSummaryOperationTypePrivateEndpointCreate WorkRequestSummaryOperationTypeEnum = "PRIVATE_ENDPOINT_CREATE" + WorkRequestSummaryOperationTypePrivateEndpointUpdate WorkRequestSummaryOperationTypeEnum = "PRIVATE_ENDPOINT_UPDATE" + WorkRequestSummaryOperationTypePrivateEndpointDelete WorkRequestSummaryOperationTypeEnum = "PRIVATE_ENDPOINT_DELETE" +) + +var mappingWorkRequestSummaryOperationTypeEnum = map[string]WorkRequestSummaryOperationTypeEnum{ + "COPY_OBJECT": WorkRequestSummaryOperationTypeCopyObject, + "REENCRYPT": WorkRequestSummaryOperationTypeReencrypt, + "PRIVATE_ENDPOINT_CREATE": WorkRequestSummaryOperationTypePrivateEndpointCreate, + "PRIVATE_ENDPOINT_UPDATE": WorkRequestSummaryOperationTypePrivateEndpointUpdate, + "PRIVATE_ENDPOINT_DELETE": WorkRequestSummaryOperationTypePrivateEndpointDelete, +} + +var mappingWorkRequestSummaryOperationTypeEnumLowerCase = map[string]WorkRequestSummaryOperationTypeEnum{ + "copy_object": WorkRequestSummaryOperationTypeCopyObject, + "reencrypt": WorkRequestSummaryOperationTypeReencrypt, + "private_endpoint_create": WorkRequestSummaryOperationTypePrivateEndpointCreate, + "private_endpoint_update": WorkRequestSummaryOperationTypePrivateEndpointUpdate, + "private_endpoint_delete": WorkRequestSummaryOperationTypePrivateEndpointDelete, +} + +// GetWorkRequestSummaryOperationTypeEnumValues Enumerates the set of values for WorkRequestSummaryOperationTypeEnum +func GetWorkRequestSummaryOperationTypeEnumValues() []WorkRequestSummaryOperationTypeEnum { + values := make([]WorkRequestSummaryOperationTypeEnum, 0) + for _, v := range mappingWorkRequestSummaryOperationTypeEnum { + values = append(values, v) + } + return values +} + +// GetWorkRequestSummaryOperationTypeEnumStringValues Enumerates the set of values in String for WorkRequestSummaryOperationTypeEnum +func GetWorkRequestSummaryOperationTypeEnumStringValues() []string { + return []string{ + "COPY_OBJECT", + "REENCRYPT", + "PRIVATE_ENDPOINT_CREATE", + "PRIVATE_ENDPOINT_UPDATE", + "PRIVATE_ENDPOINT_DELETE", + } +} + +// GetMappingWorkRequestSummaryOperationTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingWorkRequestSummaryOperationTypeEnum(val string) (WorkRequestSummaryOperationTypeEnum, bool) { + enum, ok := mappingWorkRequestSummaryOperationTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// WorkRequestSummaryStatusEnum Enum with underlying type: string +type WorkRequestSummaryStatusEnum string + +// Set of constants representing the allowable values for WorkRequestSummaryStatusEnum +const ( + WorkRequestSummaryStatusAccepted WorkRequestSummaryStatusEnum = "ACCEPTED" + WorkRequestSummaryStatusInProgress WorkRequestSummaryStatusEnum = "IN_PROGRESS" + WorkRequestSummaryStatusFailed WorkRequestSummaryStatusEnum = "FAILED" + WorkRequestSummaryStatusCompleted WorkRequestSummaryStatusEnum = "COMPLETED" + WorkRequestSummaryStatusCanceling WorkRequestSummaryStatusEnum = "CANCELING" + WorkRequestSummaryStatusCanceled WorkRequestSummaryStatusEnum = "CANCELED" +) + +var mappingWorkRequestSummaryStatusEnum = map[string]WorkRequestSummaryStatusEnum{ + "ACCEPTED": WorkRequestSummaryStatusAccepted, + "IN_PROGRESS": WorkRequestSummaryStatusInProgress, + "FAILED": WorkRequestSummaryStatusFailed, + "COMPLETED": WorkRequestSummaryStatusCompleted, + "CANCELING": WorkRequestSummaryStatusCanceling, + "CANCELED": WorkRequestSummaryStatusCanceled, +} + +var mappingWorkRequestSummaryStatusEnumLowerCase = map[string]WorkRequestSummaryStatusEnum{ + "accepted": WorkRequestSummaryStatusAccepted, + "in_progress": WorkRequestSummaryStatusInProgress, + "failed": WorkRequestSummaryStatusFailed, + "completed": WorkRequestSummaryStatusCompleted, + "canceling": WorkRequestSummaryStatusCanceling, + "canceled": WorkRequestSummaryStatusCanceled, +} + +// GetWorkRequestSummaryStatusEnumValues Enumerates the set of values for WorkRequestSummaryStatusEnum +func GetWorkRequestSummaryStatusEnumValues() []WorkRequestSummaryStatusEnum { + values := make([]WorkRequestSummaryStatusEnum, 0) + for _, v := range mappingWorkRequestSummaryStatusEnum { + values = append(values, v) + } + return values +} + +// GetWorkRequestSummaryStatusEnumStringValues Enumerates the set of values in String for WorkRequestSummaryStatusEnum +func GetWorkRequestSummaryStatusEnumStringValues() []string { + return []string{ + "ACCEPTED", + "IN_PROGRESS", + "FAILED", + "COMPLETED", + "CANCELING", + "CANCELED", + } +} + +// GetMappingWorkRequestSummaryStatusEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingWorkRequestSummaryStatusEnum(val string) (WorkRequestSummaryStatusEnum, bool) { + enum, ok := mappingWorkRequestSummaryStatusEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/.bumpversion.cfg b/vendor/github.com/tencentyun/cos-go-sdk-v5/.bumpversion.cfg new file mode 100644 index 00000000000..d2bac6df90e --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/.bumpversion.cfg @@ -0,0 +1,7 @@ +[bumpversion] +commit = True +tag = True +current_version = 0.7.0 + +[bumpversion:file:cos.go] + diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore b/vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore new file mode 100644 index 00000000000..5dbdb7424c5 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore @@ -0,0 +1,39 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test +.idea +.DS_Store + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +dist/ +cover.html +cover.out +covprofile +coverage.html +example/CI/media_process/test* +example/CI/workflow_and_job/test* +example/CI/metainsight/test* +example/CI/ai_recognition/test* +example/CI/image_process/test* +example/CI/doc_preview/test* +example/CI/content_auditing/test* +.vscode diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/.travis.yml b/vendor/github.com/tencentyun/cos-go-sdk-v5/.travis.yml new file mode 100644 index 00000000000..6d3e2842e19 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/.travis.yml @@ -0,0 +1,32 @@ +language: go +go: +- master +sudo: false +before_install: +- go get -u github.com/mattn/goveralls +- go get -u github.com/stretchr/testify +install: +- go get +- go build +- go build github.com/mattn/goveralls +script: +- if [[ ! -n "$COS_SECRETID" ]]; then exit 0 + ; fi +- make test +- make ci-test +- go test -coverprofile=cover.out github.com/toranger/cos-go-sdk-v5 +- "${TRAVIS_HOME}/gopath/bin/goveralls -service=travis-ci -coverprofile=cover.out" +matrix: + allow_failures: + - go: 1.7 + - go: master +env: + global: + - secure: XXB/cFVnJcAzhOZ2/zplwjhhhireQQGGRbNscPgQ0kpUQCyPZ6oIHvJMafuP4TVTJHEdMiaDxm0HNvgARuopXVaQNmK2UZj6xw40Ud7OT7ZUnw88xkQkXOI5GwG8oz9LqxIXUSItHegKXRLW0e1PoBdjZNv6lxGFAtuOcl9ekAg/q2lGIIQFefz6NK7gCmGYULKe+4J15VFldoYNM0JesxxxArTvtv8+k+U53oUwy9dex6z5oIA1zGIeKLcOD2xXgbjid/Ett3t0B2w3GfJWoM9rGV0eHgveOAUGe5tQkMKvl5LK1hj+93ZmU0MAG7x7t9jYKrFPqU/eDNJRMb4Ro6L7lIXVEKaBUkLx28PnwFQ5D043GBVtQGqYNcldZXIfbyYEHQZlD/BWFOt5YqTpGg+7Wm4NC3Yffqsurzk54juT7FftzVy0A8MFkqO+c5RHrOSUlm01pWXkGLHgZhUP5gEZEuUaoluSQTZksmAUJZ7F8DxwpE4SYBqfN27PZ87rWDNyOqNv1w1trzwx2IfdHHA+vfCZ7UM5e85gxFWUO2tJCUai2q21v3gBrcAgBOb6BwVzbWAorM2zY20f0l21XxOWMakA+r4JJA3s3EmcczcQeeL6pkFIAh+qKdFEPuyQTjH1mGpPzYFNbWtvPXijQo5PqyGrKL8W1t3ovwXMXoE= + - secure: bep0PPD/oYW5zY0QpeeC+WgFIya5DNRVmR92MO+e5BdFlSJPhstoG8bRh91EeftzC/Hyd3PUEIglPqTgZPxwysqW/81plsU95wV3qJi9gPi7+ZtYXH4xZTnaqgZsTr7jsKSVoKHSu7XqCtbSytW8YMN9wRWzG19/9hX2Z79Q6yNy5l9856Oyj1E2IXDjdZLPsWDhnZ8Vvk1wAVy2fc2esqKzHAZwm8n9vee2yR8vz7GXUszzpKvn4R43eNzdlFEHCmN0ANmxLJZmnYDpZHHfNf4slts+0S6I7awFXppuXUDaJPBRCia4XoFeSw+01IW1Vi0kAwvGLhxjJCWc4M/4ZU0byXDT11tDFvWa19NmnbYiizWiXNVecn1oNWYJqIKe7TTAMAtHSXAPmLX0rXuXKzwM09W6yrLFufCxyix9IOnenEbe9WwSdBbhmeLF3Wu/uVGkDog/FsXJM75sk956vV9UKh9zF4B9/NR8szJMF7shEs0Fbru5UUWheqg4AadPl3dhAWuj2+6NANa1LpH3JVD3II9dlXeMmMvsSwDvrYUaX/S8tf6JwZG0zCJK0TYp05rjxH+NIzWaMUTY7+HwYqqK3pOW3San0SlZiMq8N7GSnKUZ7WRQXYSB4gXHrg+mWyeVC7XnqiRtCwVi+LtPMu+YUbg7dwVi0vtKjYZYIUY= + - secure: Ob28vrOuHMKNKEtChkWbsaVv2SwLhcxXMnvGe4XN+y3mFvdhYnwpt6NdgThF8OCZ0761tvTRmvALfiZnO0uORjTtoHKkVPrnVIxlCcode0NVJZNHGn2fqjemdLKCnSeX7hm+9zeLpCnIvC+Sp3iZ3t2AH4AzgFx6nirWO3HwT5l9rNL9Q1CfwlOpNJJ36r9JTHwQnXmOfOmszUNoZ3rtiFXJ8dCi+BgY0lsiIRSiDkAH7KAPf86REM+ww81AaXG4/RuYx1Vj5zQCtZN7XEOViSXEbqqb8SrIFOccDu5FV12djg+4QS7FSjLVGrdIUcn4oI6pS24Et3oXf8xFx6JLYyGGhgZ2BsyJEx5vLQvkTWnMTrwZVRtCQ+g6lMUQpJhL2rBrmVBUqBFb5IH69O7corQm53n5qLM8IiosAQLfbOtML/1PyEpKCG2aOx1377Fx2yzxXW3ucP1PBqCzli0oCM2T52LfiNvZTzkIU6XJebBnzkZXepzOIFSur86kxgvQFElw9ro2X6XXPKU5S25xVaUSvaN1kmqLSkToJ9S1rmDYXnJR4aH0R2GcLw+EkMHFJJoAjnRHxrB4/1vOJbzmfS+qy6ShRhUMSD8gk4YJ6Y7o9h7oekuWOEn+XGhl29U9T5OApzHfoPEGZwLnpHxAiKJtQtv/TNhBIOFCjigsF7U= +notifications: + email: + recipients: + - wjielai@tencent.com + - fysntian@tencent.com diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md b/vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md new file mode 100644 index 00000000000..50eac96f61d --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md @@ -0,0 +1,1165 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). + +## [v0.7.65](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.64...v0.7.65) - 2025-04-07 + +1、CI 支持上传时和云上图片人车通用识别功能,支持文件处理的参数。 +2、CI 支持开通桶的文件处理、ASR处理、AI处理、图片处理、文档预览的功能。 +2、COS 修复url为nil是抛出错误。删除对象时增加可选query,更新跨区域复制API。 + +### Merged + +- 更新 bucket replication api [`#313`](https://github.com/tencentyun/cos-go-sdk-v5/pull/313) +- Feature wanjiewu ca27a7eb [`#312`](https://github.com/tencentyun/cos-go-sdk-v5/pull/312) +- Feature jojoliang 5d02f80b [`#311`](https://github.com/tencentyun/cos-go-sdk-v5/pull/311) +- Feature jojoliang a3a5e08e [`#310`](https://github.com/tencentyun/cos-go-sdk-v5/pull/310) +- 不允许请求url为空 [`#309`](https://github.com/tencentyun/cos-go-sdk-v5/pull/309) +- 支持上传时和云上图⽚⼈⻋通⽤识别功能 [`#308`](https://github.com/tencentyun/cos-go-sdk-v5/pull/308) + +### Commits + +- 开通各个桶的功能 [`58e0f87`](https://github.com/tencentyun/cos-go-sdk-v5/commit/58e0f87e8beb8da341ddd33d042859e78333af1e) +- Updated CHANGELOG.md [`dd9e6c8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/dd9e6c87963434ea1f1951a78e9c95b031674070) +- delete object增加query [`1f9da7b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1f9da7b7f22c5d1d6312135b18933bd6aaf3ccb0) +- 支持文件处理的参数 [`de8e055`](https://github.com/tencentyun/cos-go-sdk-v5/commit/de8e0557b2ad5c6e74a12384edab1c64e42e5281) + +## [v0.7.64](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.63...v0.7.64) - 2025-03-26 + +1、增加 PutFromURL 接口 +2、统一Transport 接口 +3、兼容 bucket origin 参数 + +### Merged + +- Feature jojoliang 7228e310 [`#307`](https://github.com/tencentyun/cos-go-sdk-v5/pull/307) +- Feature jojoliang bbd92f3d [`#306`](https://github.com/tencentyun/cos-go-sdk-v5/pull/306) +- 兼容origin 老api [`#305`](https://github.com/tencentyun/cos-go-sdk-v5/pull/305) + +### Commits + +- 增加put_from_url接口 [`49f4c8b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/49f4c8b9f549b6cf4a94e597276f94b711bcd6b0) +- 统一Transport接口 [`73a066d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/73a066dd66b7b10f2733fe8de7de4dfa0f72a628) +- Updated CHANGELOG.md [`c20803b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c20803bdb3cd3dfd187f22adc6a9ec532a16e8f2) + +## [v0.7.63](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.62...v0.7.63) - 2025-03-21 + +1、预签名修复路径合并,用户传什么路径做什么签名,如: ../ 不会合并成 / +2、证书接口增加证书ID + +### Merged + +- Feature jojoliang bf495f4b [`#303`](https://github.com/tencentyun/cos-go-sdk-v5/pull/303) +- 预签名文件路径不合并,如../不合并成/ [`#302`](https://github.com/tencentyun/cos-go-sdk-v5/pull/302) + +### Commits + +- Updated CHANGELOG.md [`e2423be`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e2423bebcf86fbf162ef04cf8c46b186ff05f593) +- add certid to certificate [`73e4427`](https://github.com/tencentyun/cos-go-sdk-v5/commit/73e4427d0e6001abe0234c21716e90bbf495f4b1) + +## [v0.7.62](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.61...v0.7.62) - 2025-02-25 + +支持严格签名 + +### Merged + +- Feature jojoliang c58c97cc [`#301`](https://github.com/tencentyun/cos-go-sdk-v5/pull/301) +- 严格签名修复Content-Length [`#300`](https://github.com/tencentyun/cos-go-sdk-v5/pull/300) +- 将x-cos-security-token签入到签名 [`#299`](https://github.com/tencentyun/cos-go-sdk-v5/pull/299) + +### Commits + +- 签入content-length [`1f1f7c2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1f1f7c25af7d46c49074a0be8cee911bf5f1ff0e) +- Updated CHANGELOG.md [`a9d70c2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a9d70c24800bc308cb909f41b1a587d44fcb6b03) +- update bucket policy sign content-length [`2fc78aa`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2fc78aaa613b2e634ec9d18e09d673dc58c97ccb) + +## [v0.7.61](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.60...v0.7.61) - 2025-02-06 + +1、CI 支持调用获取cibuckets接口设置region参数,CreateDataset支持SceneType参数。 +2、CI 支持签入x-ci 头部 + +### Merged + +- update version [`#298`](https://github.com/tencentyun/cos-go-sdk-v5/pull/298) +- Feature jojoliang 6aaae605 [`#296`](https://github.com/tencentyun/cos-go-sdk-v5/pull/296) +- add SceneType [`#295`](https://github.com/tencentyun/cos-go-sdk-v5/pull/295) +- Feature jojoliang 3db4866b [`#294`](https://github.com/tencentyun/cos-go-sdk-v5/pull/294) + +### Commits + +- Updated CHANGELOG.md [`9e12be0`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9e12be0af0b140fa9bf63c9bfc367577312c5879) +- update CreateDataset [`2ee3975`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2ee39750388eee7a5cd0e50cfb861487e002c149) +- 支持x-ci的header头 [`d97656d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d97656d9f511b1ea9c4d10c06f2d6260929ee65a) +- update ut [`8441c5c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8441c5cb1f3062ec7ea32a88cb6ead958cd32204) +- update demo [`c1895a3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c1895a31bacf56b671101c1a63acc3191778ca75) +- 支持调用获取cibuckets接口设置region参数 [`a2cee6a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a2cee6ac991c4e43c6cfe8196d508c73f1519fa3) + +## [v0.7.60](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.59...v0.7.60) - 2024-12-25 + +CI支持调用获取cibuckets接口 + +### Merged + +- update version [`#293`](https://github.com/tencentyun/cos-go-sdk-v5/pull/293) +- Feature jojoliang eb6f4953 [`#292`](https://github.com/tencentyun/cos-go-sdk-v5/pull/292) + +### Commits + +- 支持调用获取cibuckets接口 [`f4be7fd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f4be7fd92b10b5c7344323bd506dce702ac04135) +- Updated CHANGELOG.md [`1e509e2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1e509e2617cd2285c897f2b1a79213f63c7e6dbd) + +## [v0.7.59](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.58...v0.7.59) - 2024-11-20 + +初始化兼容URL校验;CI.GetMediaInfo方法兼容以/开头的key。 + +### Merged + +- 兼容URL [`#289`](https://github.com/tencentyun/cos-go-sdk-v5/pull/289) +- Feature jojoliang 02517980 [`#288`](https://github.com/tencentyun/cos-go-sdk-v5/pull/288) +- Feature jojoliang 8e02db5a [`#287`](https://github.com/tencentyun/cos-go-sdk-v5/pull/287) + +### Commits + +- 语音识别热词相关接口 [`4518f8f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4518f8fce8b8841fec4513516be10889f6d21a73) +- Updated CHANGELOG.md [`243b2d8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/243b2d893baf776f49f5f8232845294cc6be3cfc) +- 兼容key中包含/问题 [`233d628`](https://github.com/tencentyun/cos-go-sdk-v5/commit/233d62822f24c86935a8aa4a10bcddad832ceaa6) + +## [v0.7.58](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.57...v0.7.58) - 2024-11-11 + +修复context不生效的问题,URL校验兼容 + +### Merged + +- 兼容url校验带path [`#286`](https://github.com/tencentyun/cos-go-sdk-v5/pull/286) + +### Commits + +- Updated CHANGELOG.md [`1aa1a55`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1aa1a55c44765da795bae721b933026c7e62a498) + +## [v0.7.57](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.56...v0.7.57) - 2024-11-04 + +COS ServiceURL和BatchURL检验兼容Bucket格式,GetPresignedURL3兼容path全urlencode + +### Merged + +- 更新GetPresignedURL3, 兼容trpc-go url格式 [`#284`](https://github.com/tencentyun/cos-go-sdk-v5/pull/284) + +### Commits + +- Updated CHANGELOG.md [`43fbd84`](https://github.com/tencentyun/cos-go-sdk-v5/commit/43fbd84ff1e729589191d1894fdf660ebb910503) + +## [v0.7.56](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.55...v0.7.56) - 2024-11-01 + +1、COS 3xx默认不跟随,COS域名会检验BaseURL格式。 +2、CI 新增边转边播多任务创建接口,播放列表任务批量接口 + +### Merged + +- Feature jojoliang b8918773 [`#283`](https://github.com/tencentyun/cos-go-sdk-v5/pull/283) +- Feature jojoliang 1a086920 [`#282`](https://github.com/tencentyun/cos-go-sdk-v5/pull/282) + +### Commits + +- 默认不跟随,检验URL [`2a003a6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2a003a69bd7c0f5321384b828f69a70b60fa78fe) +- 支持边转边播播放列表任务批量接口 [`1f64e94`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1f64e947b9d79f428e5f56062e7270cef09b8aac) +- 新增边转边播多任务创建接口 [`b335033`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b335033a313cbc736e4f5102895d6bfa3c2979af) +- Updated CHANGELOG.md [`08b4159`](https://github.com/tencentyun/cos-go-sdk-v5/commit/08b415932672abe067aee56666e614183c7612db) +- fix ci test [`9677c2b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9677c2b34dcb41f57313abcec1b399cb89187730) + +## [v0.7.55](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.54...v0.7.55) - 2024-09-12 + +1、COS增加DeleteReferer方法,PutSymlink内部对SymlinkTarget做urlencode,更新demo规范,更加GetMeta接口和intelligent-tiering v2接口。 +2、CI 支持多合一ai识别接口,metainsight增加mode字段,更新VideoTargetRec,支持盲水印3.0和极智压缩,支持kafka回调通知能力,解决jwt库版本安全问题。 + +### Merged + +- Feature jojoliang 2e155105 [`#280`](https://github.com/tencentyun/cos-go-sdk-v5/pull/280) +- Feature jojoliang 0aa53fe3 [`#279`](https://github.com/tencentyun/cos-go-sdk-v5/pull/279) +- Feature jojoliang 8dfdf213 [`#278`](https://github.com/tencentyun/cos-go-sdk-v5/pull/278) +- Feature jojoliang 3f696cf3 [`#277`](https://github.com/tencentyun/cos-go-sdk-v5/pull/277) +- fix FileProcessJobsDetail [`#276`](https://github.com/tencentyun/cos-go-sdk-v5/pull/276) +- Feature jojoliang b4436de4 [`#275`](https://github.com/tencentyun/cos-go-sdk-v5/pull/275) +- 增加domain header [`#274`](https://github.com/tencentyun/cos-go-sdk-v5/pull/274) +- 更新 demo [`#273`](https://github.com/tencentyun/cos-go-sdk-v5/pull/273) +- update bucket referer [`#271`](https://github.com/tencentyun/cos-go-sdk-v5/pull/271) + +### Commits + +- 增加GetMeta接口,增加intelligent-tiering v2接口 [`b3a9f08`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b3a9f08a223c83ebf985ddf816895ccb014fe217) +- 更新demo [`8ce4837`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8ce483740aadf37b0bd05a3681e8bcb88a52298f) +- 支持盲水印3.0和极智压缩 [`ae68c1f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ae68c1f8d835e5aa6e2773c1811f340634016481) +- 支持多合一ai识别接口 [`ce30d02`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ce30d02fc9f5cf2ccd2202e7c125ef5e186df1a8) +- 支持kafka回调通知能力 [`debfcd1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/debfcd14317f4ed401794aa4600d59ae9a0bdbf2) +- 解决jwt库的版本安全问题 [`26d3550`](https://github.com/tencentyun/cos-go-sdk-v5/commit/26d3550b9c425e2f3ff3a019d8d5f2906f2e2bfe) +- update VideoTargetRec [`8670f9c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8670f9cbfaf628e28b8ab42d82f8cb51f28b1045) +- update presignedurl demo [`4257d33`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4257d33afb6b106145d2ab1b7443b180cc516355) +- 修复demo中问题 [`41bf4a3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/41bf4a34ed41bd1ae97afa63f6ef2491829b282d) +- Updated CHANGELOG.md [`6468769`](https://github.com/tencentyun/cos-go-sdk-v5/commit/64687693995512ca14bfd8796596032937fdbe7e) +- update go.mod [`74f414d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/74f414d5126bb8d25d349288ae260ac2e1551055) +- metainsight add mode [`b002c8b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b002c8b0ff1e81fdfacf9e7e5d80e8133f02d28e) +- 支持极智压缩状态参数 [`38b6730`](https://github.com/tencentyun/cos-go-sdk-v5/commit/38b6730e503ac6aa826dab2a3cc52cc3064f3b0b) +- x-cos-symlink-target内部做urlencode [`66ce357`](https://github.com/tencentyun/cos-go-sdk-v5/commit/66ce3574c92d8d649d51d055e72edc4b44320d36) + +## [v0.7.54](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.53...v0.7.54) - 2024-07-11 + +1、COS download方法允许分块可以超过10000, +2、增加sts签名方式并自动更新临时密钥 + +### Merged + +- download分块可以超过10000, 增加sts签名方式 [`#270`](https://github.com/tencentyun/cos-go-sdk-v5/pull/270) + +### Commits + +- Updated CHANGELOG.md [`7b3b630`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7b3b630a1d9fab65f66804aec8f3b2c43893c06b) + +## [v0.7.53](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.52...v0.7.53) - 2024-07-11 + +1、COS upload接口透传参数到compelete,upload part支持上传0字节,设置软链接x-cos-symlink-target头部做urlencode。 +2、CI 增加人像抠图接口。 + +### Merged + +- x-cos-symlink-target内部做urlencode [`#269`](https://github.com/tencentyun/cos-go-sdk-v5/pull/269) +- Feature jojoliang 9ca80bb5 [`#268`](https://github.com/tencentyun/cos-go-sdk-v5/pull/268) +- upload part 支持上传0字节 [`#267`](https://github.com/tencentyun/cos-go-sdk-v5/pull/267) +- Feature jojoliang c9b129da [`#266`](https://github.com/tencentyun/cos-go-sdk-v5/pull/266) + +### Commits + +- 支持人像抠图和通用抠图接口 [`0f45101`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f45101e8f9af144ebc77bebb512aa26ff4a07ad) +- sdk update [`055592b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/055592be590c940af040d35c3f4a30b8791daeea) +- Updated CHANGELOG.md [`3e334a4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/3e334a46a4f30228ac3667fe14ce6260c13e1001) +- Updated CHANGELOG.md [`f196bf7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f196bf7747485266dab094f5c69a22b0d9008012) +- upload接口透传参数到complete [`9906bd9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9906bd932c94e3dec6cabb105e936f397b63fd79) +- update ZipPreview test [`0f07c52`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f07c529b834448079ace3a8ceb629dc9b129daa) + +## [v0.7.52](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.51...v0.7.52) - 2024-07-01 + +1、更新lifecycle、policy、intelligent参数 +2、增加重试标识,Upload传递自定义头部 + +### Merged + +- update lifecycle,policy,intelligent params, 增加重试标识,增加upload时自定义参数传递 [`#264`](https://github.com/tencentyun/cos-go-sdk-v5/pull/264) + +### Commits + +- Updated CHANGELOG.md [`55bbddb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/55bbddbd4b891a108dd376d55a70f8a0681db683) + +## [v0.7.51](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.50...v0.7.51) - 2024-06-24 + +1、CI 支持 meta insight +2、abort multipart 校验key + +### Merged + +- 检查abort multi的路径 [`#262`](https://github.com/tencentyun/cos-go-sdk-v5/pull/262) +- Feature jojoliang e16e7c98 [`#261`](https://github.com/tencentyun/cos-go-sdk-v5/pull/261) + +### Commits + +- 支持metainsight [`cbd9ea9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cbd9ea9c5c3811d39fa8157d40836e9747cb011d) +- 忽略测试文件 [`119d6ff`](https://github.com/tencentyun/cos-go-sdk-v5/commit/119d6ff6b73440dff6aa061270e16c00cad1a1bd) +- 支持metainsight单测 [`a2547fc`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a2547fc092227ce413e64a898dbaf0da9aa8cd33) +- metainsight1.1 sdk [`2bd433a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2bd433a7ab37427f8a548601f9358180ee8562ab) +- 优化边转边播示例 [`c5f0e59`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c5f0e59566799a4b68f1b9142bf5dffb7cc529b3) +- 新增图片搜索和人脸搜索单测 [`0f9a4e8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f9a4e83213cf0b5b875699dc394a802d76ca768) +- Updated CHANGELOG.md [`f585425`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f585425752d4d1c44b4a657253e9d0f7b63136c4) + +## [v0.7.50](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.49...v0.7.50) - 2024-06-12 + +COS 预签名URL不对/做编码 + +### Merged + +- 预签名URL不编码 [`#259`](https://github.com/tencentyun/cos-go-sdk-v5/pull/259) + +### Commits + +- 预签名URL不编码/ [`99de629`](https://github.com/tencentyun/cos-go-sdk-v5/commit/99de62963ec569abbabcf37384912690b77e2846) +- Updated CHANGELOG.md [`d09d568`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d09d568e871486662bbee1c36a6cff96e88f458a) + +## [v0.7.49](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.48...v0.7.49) - 2024-06-04 + +1、修复MultiCopy分块是sourceurl编码 +2、CI 审核14.3 SDK,支持长短边开关 + +### Merged + +- multicopy source url编码 [`#257`](https://github.com/tencentyun/cos-go-sdk-v5/pull/257) +- Feature jojoliang b462cc0f [`#256`](https://github.com/tencentyun/cos-go-sdk-v5/pull/256) +- 审核14.3 sdk [`#255`](https://github.com/tencentyun/cos-go-sdk-v5/pull/255) + +### Commits + +- Updated CHANGELOG.md [`bd0557e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/bd0557e60c3a0de768996d5ad6d3ac78db581730) +- 支持长短边开关 [`531dec3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/531dec3dd22e719170ab4eab13084f6f75cd8373) + +## [v0.7.48](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.47...v0.7.48) - 2024-05-22 + +1、增加Download接口进度,修复copy接口sourceURL存在VersionId问题,增加历史版本恢复demo。简单上传允许5GB文件,更新MultiCopy 5GB文件采用Copy接口。 +2、CI DocPreviewHTMLOptions 增加weboffice_url和tokenuid参数,支持开通媒体桶接口,支持视频标签多模态接口,支持边转边播,新增crf参数。 +3、增加COS和CI的单元测试,当前覆盖率接近91%。 + +### Merged + +- Feature jojoliang 2dababd3 [`#254`](https://github.com/tencentyun/cos-go-sdk-v5/pull/254) +- Feature jojoliang 5a15001b [`#252`](https://github.com/tencentyun/cos-go-sdk-v5/pull/252) +- Feature jojoliang c307996b [`#251`](https://github.com/tencentyun/cos-go-sdk-v5/pull/251) +- Feature jojoliang 74fd0658 [`#250`](https://github.com/tencentyun/cos-go-sdk-v5/pull/250) +- Feature jojoliang 85b92bed [`#248`](https://github.com/tencentyun/cos-go-sdk-v5/pull/248) +- Feature jojoliang 5e79ea1b [`#246`](https://github.com/tencentyun/cos-go-sdk-v5/pull/246) +- Feature jojoliang 81564773 [`#244`](https://github.com/tencentyun/cos-go-sdk-v5/pull/244) +- Feature jojoliang b21eefa1 [`#242`](https://github.com/tencentyun/cos-go-sdk-v5/pull/242) +- Feature jojoliang e76fab9d [`#241`](https://github.com/tencentyun/cos-go-sdk-v5/pull/241) +- Feature jojoliang 1e58093b [`#240`](https://github.com/tencentyun/cos-go-sdk-v5/pull/240) +- DocPreviewHTMLOptions 增加weboffice_url和tokenuid参数 [`#239`](https://github.com/tencentyun/cos-go-sdk-v5/pull/239) + +### Commits + +- 下载校验key,增加ut [`7af5453`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7af54534c8c380149ac7dedb0709a5f85b92bed1) +- 支持边转边播 [`8e69739`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8e69739607592f4c364e6947eeea1ff3e3bad7c4) +- 新增单测用例 [`241cd5a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/241cd5a3d80d294a098789d365a9b26d3e393bcb) +- 新增单测 [`e3785be`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e3785be3f63959057c782a67bc3bfadbb689c212) +- 增加历史版本恢复demo [`413e910`](https://github.com/tencentyun/cos-go-sdk-v5/commit/413e910d57b30e6efdc122b28ebcaf65e79ea1b9) +- 修复copy sourceURL存在versionId问题,增加Download进度,默认不切换 [`9265a98`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9265a98076f849905e5590c6921d29432f1f32b7) +- 新增方法 [`9762204`](https://github.com/tencentyun/cos-go-sdk-v5/commit/97622042d1aa5beef3d2c3ac42aecf8e6d3b1e67) +- 完善单元测试 [`0411781`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0411781fc635d522ef7acc8864c5e9bee8730764) +- 支持开通媒体桶接口 [`54de4fd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/54de4fd0b462620d0e3ceb6ffdb65e2db76806f3) +- cdn场景如何生成Url [`a209897`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a209897a36eda6ebc75dfa736be629fe4c7e0552) +- Updated CHANGELOG.md [`2f05c98`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2f05c9814f68f14af9edc3e124286348709d5496) +- 支持视频标签多模态接口 [`0268b78`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0268b78d0bfd5914b2a32115f60eb0de4a308ee8) +- demo边转边播场景ci-process参数 [`fddf7c4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/fddf7c41a80f4817a1e4080945b132851658c128) +- 简单上传允许上传刚好5GB文件 [`9992cbb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9992cbb1853c2b260522d4f078cd6372dababd3f) +- 更新MultiCopy [`29884e8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/29884e8626c2af72b51a3df0b2c51d0d888fbbcb) +- 新增crf参数 [`24cb28b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/24cb28b9b0de52d3b0f3597ed587c015161cc202) +- 直接拼接参数 [`ace1c70`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ace1c707150fdda400bd0705d7902bc26a1406a7) + +## [v0.7.47](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.46...v0.7.47) - 2024-03-01 + +1、更新预签名做urlencode,添加ACL常量,兼容key非法时分块上传返回xml解析失败。 +2、GetService增加地域过滤,增加BucketType +2、CI支持Dataset接口,FileMetaIndex接口 + +### Merged + +- Feature jojoliang 5a030823 [`#236`](https://github.com/tencentyun/cos-go-sdk-v5/pull/236) +- add ACL enum demo [`#235`](https://github.com/tencentyun/cos-go-sdk-v5/pull/235) +- 更新ACL常量,兼容key非法时分块上传返回xml解析失败 [`#234`](https://github.com/tencentyun/cos-go-sdk-v5/pull/234) +- update GetPresignedURL [`#232`](https://github.com/tencentyun/cos-go-sdk-v5/pull/232) + +### Commits + +- 支持9个接口 [`623c33c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/623c33c18d441fc6210fe692d08f739d0c7d7f32) +- 支持dataindex的14个接口 [`ddf959a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ddf959ae97bc00c6f9e434e02bdbb450daeb2753) +- Updated CHANGELOG.md [`92a2e31`](https://github.com/tencentyun/cos-go-sdk-v5/commit/92a2e311df0af3cfb9b080d80d6dd64f4fa94a10) +- format 文件 [`f709661`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f70966132a774bb3a389d1ef30b2602dfc767141) +- 忽略桶信息 [`ed8db26`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ed8db265e7796532764fc7cf316b5e75ab9fc610) +- getservice增加地域过滤,增加BucketType [`9b29d2f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9b29d2f72a0ce5b323f1ebb6c4864ca753bf3433) +- 增加忽略文件 [`4363cb6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4363cb6aaff05646df6db9a0755263877f436ee4) + +## [v0.7.46](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.45...v0.7.46) - 2024-01-09 + +1、COS 增加对象软链接,对象操作增加重试,更新cors,更新GetPresignedURL。 +2、CI 更新文档对比、商品抠图、充拼接接口、ai1.4补充、pic-operations算到签名里。 + +### Merged + +- 更新预签名 [`#230`](https://github.com/tencentyun/cos-go-sdk-v5/pull/230) +- update bucket cors, add x-cos-tagging in putbucket, update Presignurl [`#229`](https://github.com/tencentyun/cos-go-sdk-v5/pull/229) +- update cos-website [`#228`](https://github.com/tencentyun/cos-go-sdk-v5/pull/228) +- Feature jojoliang 07c6039e [`#227`](https://github.com/tencentyun/cos-go-sdk-v5/pull/227) +- update domain [`#226`](https://github.com/tencentyun/cos-go-sdk-v5/pull/226) +- Feature lilang 49f346d6 [`#224`](https://github.com/tencentyun/cos-go-sdk-v5/pull/224) +- Feature jojoliang 4df53093 [`#223`](https://github.com/tencentyun/cos-go-sdk-v5/pull/223) +- Feature lilang d38c66dd [`#222`](https://github.com/tencentyun/cos-go-sdk-v5/pull/222) +- Feature lilang 4cee3f5c [`#220`](https://github.com/tencentyun/cos-go-sdk-v5/pull/220) +- 填充拼接接口新增模式和参考索引参数 [`#218`](https://github.com/tencentyun/cos-go-sdk-v5/pull/218) +- add object symlink [`#217`](https://github.com/tencentyun/cos-go-sdk-v5/pull/217) +- Feature jojoliang 2a0e39c7 [`#216`](https://github.com/tencentyun/cos-go-sdk-v5/pull/216) +- Feature lilang 1c333bc2 [`#215`](https://github.com/tencentyun/cos-go-sdk-v5/pull/215) +- 修改demo [`#213`](https://github.com/tencentyun/cos-go-sdk-v5/pull/213) + +### Commits + +- add retry for put object [`b037b1d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b037b1d3efc0b10f9d7ba56f31667b313f931572) +- ai1.4补充 [`6c34926`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6c34926a6bc1e35ce26e50de37ef88d6227679d2) +- CI17 [`0d8107c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0d8107c396f3ed7fb99178ff3df4c5594e3a42e7) +- 文档对比 [`caaca46`](https://github.com/tencentyun/cos-go-sdk-v5/commit/caaca46dbc273207cc3a9ccd912e40400b9b794a) +- 支持查询播放key [`6c43b9f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6c43b9fd45793ea67d3c3f9c0eedc8c5f9195ac7) +- update bucket cors, add x-cos-tagging in putbucket, update GetPresignedURL [`35b83ed`](https://github.com/tencentyun/cos-go-sdk-v5/commit/35b83ed71e7879f647779aac3233409662e13188) +- 添加方法 [`8b6c807`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8b6c8070c61915c8fb1d7b9b08b6011b1c178eb6) +- update [`b110e20`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b110e2021fa245b614ce844299e519b07c6039eb) +- Updated CHANGELOG.md [`500a8f6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/500a8f60f324e44ce67f4bac4c81cd5c6e4d6528) +- 支持xml [`5c51c3a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5c51c3ae8866835a74121eb3a96bad21c333bc22) +- update retry [`2c500a8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2c500a86ed9b1f5997e589824cd72b11544065be) +- appid隐藏 [`2a08bcb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2a08bcb5fb86ef9a0b80a693a5f1bf662df3e8ae) +- pic-operations算到签名里 [`cd1d04e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cd1d04e326cceda488ee93172072ae144f601de8) +- 商品抠图新增detect-url参数 [`776c1b2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/776c1b2c85860c676173f3901cb10d08be3f985a) + +## [v0.7.45](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.44...v0.7.45) - 2023-10-18 + +更新bucket origin接口,更新Copy接口。 + +### Merged + +- fix copy object, update bucket origin [`#212`](https://github.com/tencentyun/cos-go-sdk-v5/pull/212) +- Feature lilang 8d637ca2 [`#211`](https://github.com/tencentyun/cos-go-sdk-v5/pull/211) + +### Commits + +- generate_token demo [`0fc7f23`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0fc7f231da7096341a0a71e8bff57894c206c6b5) +- Updated CHANGELOG.md [`2d08098`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2d08098de11e75468b20925cf12e7619aa9dfcb1) +- generate_token [`66a66a1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/66a66a1d183d3c6f2e804dd0cf43ac1eed444bab) + +## [v0.7.44](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.43...v0.7.44) - 2023-10-09 + +1、增加GetPresignedURL接口。 +2、CI 更新文件处理参数、媒体参数,增加AI检测接口,增加黑产检查同步接口。 + +### Merged + +- add getPresignedURL2 [`#210`](https://github.com/tencentyun/cos-go-sdk-v5/pull/210) +- Feature jojoliang 3259afb9 [`#208`](https://github.com/tencentyun/cos-go-sdk-v5/pull/208) + +### Commits + +- 添加方法 [`69f446a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/69f446a7a0009b5ac9e0f470ff55eef544d3e907) +- 参数补充 [`b598e3c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b598e3c860e2574c9c2474c3d31185a40cd7d860) +- 黑产检查同步接口 [`d3e671c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d3e671c1360d24edc34ce7fa209bf11d8b5f09d0) +- ai1.4 [`697a287`](https://github.com/tencentyun/cos-go-sdk-v5/commit/697a287ee214e48b560cf58eb49d91bc808397e3) +- 媒体参数补充 [`9f2c7d7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9f2c7d77301e91e9400a5bb4d92003a76a5fa775) +- 文件处理1.2 [`1a47db9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1a47db9ea5e44258b67c7eb42e7df3f7dc703c05) +- Updated CHANGELOG.md [`ceda434`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ceda43486b032a0a2d88afb28dc1adc3a0af7321) + +## [v0.7.43](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.42...v0.7.43) - 2023-09-05 + +1、增加客户端加密KMS请求重试。 +2、增加对象锁定功能,更新静态网站字段,更新ACL允许header和body同时设置。 +3、CI 更新请求参数。 + +### Merged + +- update bucket acl [`#206`](https://github.com/tencentyun/cos-go-sdk-v5/pull/206) +- update bucket website [`#205`](https://github.com/tencentyun/cos-go-sdk-v5/pull/205) +- Feature jojoliang 1038d35f [`#204`](https://github.com/tencentyun/cos-go-sdk-v5/pull/204) +- Feature jojoliang bcf65425 [`#203`](https://github.com/tencentyun/cos-go-sdk-v5/pull/203) + +### Commits + +- 参数补充 [`e7ef3e5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e7ef3e55e8e9735594681f2415dfeddc14547751) +- crypto add kms request retry [`9b4c409`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9b4c409f7663c5a12dcd4984ef09fc8c2b2f69e0) +- add Put ObjectRetention [`13ccff3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/13ccff3ee377461da10b5ef4abb1e604ce5066c4) +- Updated CHANGELOG.md [`0ef69db`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0ef69dbdef58d337733fa8951972eabb90954a0a) +- 添加参数 [`05212d8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/05212d89d32455c87c7af85e791a421c2dd9d634) +- 添加字段 [`b74737f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b74737fa7bb5dfb00953d5eb4570a4dd576c9209) +- 删除queue id [`f019b7c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f019b7c95d47a5f9465d309d43b7ba55a2c25422) + +## [v0.7.42](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.41...v0.7.42) - 2023-06-29 + +1、增加UT测试,更新tencentcloud-sdk-go 版本到 v1.0.563。 +2、增加PostInventory接口,增加object lock,增加DeleteBatchJob。 +3、CI 文件处理接口、文档浏览、视频质量打分任务、审核等参数变更。 +4、CI支持倍速转码、AI人体检测接口、海报合成任务、地图拼接、内容识别、闲时转码标记位等。 + +### Merged + +- Feature jojoliang 6a39e426 [`#201`](https://github.com/tencentyun/cos-go-sdk-v5/pull/201) +- Feature jojoliang 985bbfa3 [`#200`](https://github.com/tencentyun/cos-go-sdk-v5/pull/200) +- Feature jojoliang 51a2f385 [`#199`](https://github.com/tencentyun/cos-go-sdk-v5/pull/199) +- Feature lilang d8d6b147 [`#198`](https://github.com/tencentyun/cos-go-sdk-v5/pull/198) +- update getservice [`#197`](https://github.com/tencentyun/cos-go-sdk-v5/pull/197) +- Feature jojoliang d0d7edf5 [`#195`](https://github.com/tencentyun/cos-go-sdk-v5/pull/195) +- add GetService params [`#194`](https://github.com/tencentyun/cos-go-sdk-v5/pull/194) +- add restore versionid [`#193`](https://github.com/tencentyun/cos-go-sdk-v5/pull/193) +- add object lock [`#192`](https://github.com/tencentyun/cos-go-sdk-v5/pull/192) +- Feature jojoliang 64cbd1f5 [`#191`](https://github.com/tencentyun/cos-go-sdk-v5/pull/191) +- 支持原图下载 [`#189`](https://github.com/tencentyun/cos-go-sdk-v5/pull/189) +- Feature jojoliang 3e3dda77 [`#188`](https://github.com/tencentyun/cos-go-sdk-v5/pull/188) +- Feature jojoliang 3762ef4f [`#187`](https://github.com/tencentyun/cos-go-sdk-v5/pull/187) +- Feature jojoliang aa6c7cad [`#185`](https://github.com/tencentyun/cos-go-sdk-v5/pull/185) +- update ut [`#184`](https://github.com/tencentyun/cos-go-sdk-v5/pull/184) +- update ut [`#183`](https://github.com/tencentyun/cos-go-sdk-v5/pull/183) + +### Commits + +- demo优化 [`4d341bb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4d341bbaf14bec3b9f12d3f35188deea603cf65d) +- 修改demo [`b40dd06`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b40dd06977d9344df521437462515939c72c0559) +- 单元测试补充 [`e6c9884`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e6c98845f37d1ae3d75d171c8324948a1d764583) +- 补充单元测试 [`a7288cd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a7288cdc4f21cab561d8acdab9b00fa2ea34d6f5) +- 单元测试补充 [`87de5ef`](https://github.com/tencentyun/cos-go-sdk-v5/commit/87de5efc42fb939898ef6dfe5b6291009cd5becc) +- 内容识别 [`7bdcb1d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7bdcb1d2629fe0ff8d8491b8123fc0eb85ff54b2) +- 万象sdk 补充 [`200e93b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/200e93b73f8095347133897213f2655e28002feb) +- 内容识别&ut [`7a45ecb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7a45ecbfc547a90ecf5760d90108b86409d3442a) +- 万象15期需求 [`c3b96c0`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c3b96c0ac52fe51689bef854adb9115625e1530f) +- 海报合成任务 [`dbc50da`](https://github.com/tencentyun/cos-go-sdk-v5/commit/dbc50daa74594217c69d4ecd11af1a8c47a3d2a9) +- ut [`a994d4a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a994d4a2cc7e2cec4ad6cb16a42f3c5616401deb) +- 补充单元测试 [`9b90a6b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9b90a6bb75b827790cc96bc50576e108074718d0) +- 单元测试补充 [`b528bb6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b528bb6faf4fe9ba0ff11675999d61a2911b1213) +- add post bucket inventory [`492db1b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/492db1bb1490f32188c757504fa7221be99a63ed) +- 地图拼接需求 [`6ac0209`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6ac02098fd4d25c165b17030988316ed3036bfed) +- ai人体检测接口 [`544f5ad`](https://github.com/tencentyun/cos-go-sdk-v5/commit/544f5adf6b66433c9d85d35be8e520695c93dc52) +- TDCRefresh [`af06387`](https://github.com/tencentyun/cos-go-sdk-v5/commit/af06387eb0e16c83175ec7a18625ea5b341128fc) +- ut [`dbe46a4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/dbe46a4056417d7daba2cb03aea34d1d8d6b1477) +- 文件处理1.1 [`3292425`](https://github.com/tencentyun/cos-go-sdk-v5/commit/329242519c53bc7c71cd98d47ea79f868d9f62ac) +- add delete batch job [`6a05212`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6a052122fda04ed5c65c7a72d98b4b1ac27bb8f5) + +## [v0.7.41](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.40...v0.7.41) - 2023-01-09 + +1、CI 质量评分新增参数、质量评分新增参数、新增审核冻结参数、直播审核转存参数 +2、CI 文档处理接口及UT测试、更新直播审核转存参数、审核冻结参数 +3、新增客户端加密kms endpoint配置 +4、修改GetObjectVersions返回的Size类型为int64 + +### Commits + +- 文件处理接口 [`839e8b7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/839e8b7cfdd44a5001be08d187005b6763b3f5ef) +- 文件处理单应测试 [`30100a6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/30100a64814ac28a7ec00c20e45308198cb8589e) +- 审核冻结参数;直播审核转存参数 [`1380145`](https://github.com/tencentyun/cos-go-sdk-v5/commit/13801459296a102662d32a4c4b5e53d3274e5414) +- 修改字段 [`0f76128`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f7612855ca6c4c5a8b173f7a4d1bfbe267a6067) +- update crypto kms endpoint [`c57d309`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c57d3099f00309629ddc2f74fff86168c33452ff) +- 商品抠图新增参数 [`b6a81ed`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b6a81ed5066f210601468dea70eb43a57897ed0e) +- 向前兼容 [`929ab55`](https://github.com/tencentyun/cos-go-sdk-v5/commit/929ab556b385065c4208b88f9989ab727070126a) +- Updated CHANGELOG.md [`d427a5c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d427a5c87caa137515d9a6fd1ade3cdaa28a1228) +- 质量评分新增参数 [`49c83ae`](https://github.com/tencentyun/cos-go-sdk-v5/commit/49c83ae8610a69c5381f14d7210c8355ede5e369) +- 修改GetObjectVersions返回的Size类型为int64 [`525b389`](https://github.com/tencentyun/cos-go-sdk-v5/commit/525b389ee6a1dc4fa44865d86d6e6e0423e37a66) + +## [v0.7.40](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.39...v0.7.40) - 2022-11-15 + +1、upload file with contentlength,update crc log, add optional header +2、支持启用工作流和暂停工作流接口 + +### Commits + +- add optional header [`c996f66`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c996f66c8d02a04fc4de4e494872f74878238e31) +- 支持启用工作流和暂停工作流接口 [`a187403`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a187403769e561d54f492d8324775dfa1ebd47ff) +- Updated CHANGELOG.md [`2631285`](https://github.com/tencentyun/cos-go-sdk-v5/commit/26312858daba267fedbfd0e4e19713138c2d9cb6) +- update crc [`3ee574e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/3ee574e09c844561dd4152e9b2b95ea19711f945) +- upload file with contentlength [`86fec59`](https://github.com/tencentyun/cos-go-sdk-v5/commit/86fec599e274e4d49025d0e2e3d42d1de1334c4d) + +## [v0.7.39](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.38...v0.7.39) - 2022-10-12 + +1、update multicopy retry、Delete Bucket option +2、CI 媒体处理能力补齐、hls解密服务、审核黑白名单和音频审核新增字段 + +### Commits + +- 媒体处理能力补齐(截止CI13.0) [`fce8da8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/fce8da84ef58a04aa3d778647b2944696384a29c) +- 审核黑白名单和音频审核新增字段 [`24dc798`](https://github.com/tencentyun/cos-go-sdk-v5/commit/24dc798f24071e4b4e3b07f9b9d8daaf984fbbc3) +- 新加post截图存cos方法 [`8a247a4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8a247a4eef17d1a80afdf4b30987b468d750046a) +- 合并master [`7310792`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7310792df68b9ba6eb3219e678e86c5975fa7b88) +- hls解密服务 [`924c051`](https://github.com/tencentyun/cos-go-sdk-v5/commit/924c051b10f5e21f97c4077543a05efea3554991) +- 添加拼接参数 [`fa34c0b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/fa34c0b3a5ed7800223e0339f08863407d3da44f) +- add delete bucket opt [`5389852`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5389852aef138d8bc70dba4ccd90d8f5b2ec733f) +- 合并冲突 [`81cefb0`](https://github.com/tencentyun/cos-go-sdk-v5/commit/81cefb0a3f4067a734cc53a3e20b4bce27f19151) +- update multicopy [`ff4eda3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ff4eda38bf525d672cc0052e810f261d86d2200f) +- Updated CHANGELOG.md [`8a39be1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8a39be1701f871987d3107cd405688238946765a) +- update partcopy [`f99b506`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f99b5068270f7446b26e3ee6e7c653149232323f) +- update multicopy retry [`6f08b8b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6f08b8b4719a7a6dd6a67c361b2077433d990741) +- 忽略.vscode [`8b5ddb7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8b5ddb7aaa1832d784e7cc79a7f2f3af15497f9c) + +## [v0.7.38](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.37...v0.7.38) - 2022-08-25 + +1、增加创建bucket的ofs类型 +2、copy返回详细错误信息 + +### Commits + +- add BucketArchConfig to PutBucket, update copy error return [`3f30427`](https://github.com/tencentyun/cos-go-sdk-v5/commit/3f30427a955141b9e64238b8bcf3d5ebf6e85651) +- Updated CHANGELOG.md [`8659476`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8659476ebaa8e9b6edfbefe7c8d656e9cd28e0f3) + +## [v0.7.37](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.36...v0.7.37) - 2022-08-25 + +1、增加证书接口,增加bucketGet自定义头部 +2、CI 商品抠图、文档预览 + +### Commits + +- 文档预览 [`01fad12`](https://github.com/tencentyun/cos-go-sdk-v5/commit/01fad12d9589dfc88c29ffa807352a73f159d108) +- add certificate [`563f286`](https://github.com/tencentyun/cos-go-sdk-v5/commit/563f286c94f781dc958f865624d5ba80a607af7e) +- 商品抠图 [`e3215ad`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e3215ad71d11ee0a4bdf84911bdc2b5e600f4a90) +- Updated CHANGELOG.md [`2f8b126`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2f8b126733c0fa0e754370c1ad29c958054faef7) +- add optional header to bucketGet [`44c947e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/44c947ebaa7a803e382b9dfc57e63468e70aa7ce) +- update copy [`26ba46d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/26ba46da9a962c7aebaf6b2df849731ea9f72ba8) + +## [v0.7.36](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.35...v0.7.36) - 2022-07-27 + +1、CI 更新内容审核、支持直播流审核、自定义文本库 +2、CI 更新基础图片处理、盲水印、样式、压缩、二维码识别、生成 +图片质量评估、ocr +3、增加可选header在lifecycle and object tagging接口、更新crc校验报错信息 + +### Commits + +- 基础图片处理、盲水印、样式、压缩、二维码识别、生成 [`7c596d6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7c596d60b7da7d79d34b778e95eab817728c15b9) +- 人脸核身 [`5bbe2a2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5bbe2a2324dbdd8678eda557170febfa25c8530c) +- 图片处理3期 sdk补充 [`f53f4c6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f53f4c68cf6147db5335a44a435f64a1ebe88333) +- add optional header in lifecycle and object tagging [`8acf953`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8acf953c9b56b25caa2573e5c006bbdb374e6ff5) +- 人脸检测 [`2552041`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2552041c2289f1efe952e2e168069f962d8a0604) +- 内容审核用户业务字段 [`0df9871`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0df9871fd8eefaf1308c925c0c883900a1f75be8) +- add proxy demo [`453ff54`](https://github.com/tencentyun/cos-go-sdk-v5/commit/453ff547abbf2500ce9163559b9d2e5337471f57) +- Updated CHANGELOG.md [`678489e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/678489e159f24255eaf2b91945a1afe30fc8a568) +- badcase反馈接口 [`ec2afa4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ec2afa454f3c481dcf78119472d2d6618b254a20) +- 统一结构体定义 [`77384a5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/77384a5599dce7f47fd3fc2ca00eab04730fe3e6) +- 自定义文本库 [`e3243c6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e3243c64ffb418b629563c13fd5939373b7ffef5) +- 支持直播流审核 [`2fec043`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2fec043151b4fd921aa049853eef0503f095d31c) +- export UserAgent [`88d6fa9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/88d6fa98c4f445316ef03184fee0d2bc0e00dbe1) +- 规避图片cgi不支持chunked的问题 [`223f7b7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/223f7b7ee7033f20dfe2f400d8ee444922a2f43c) +- 任务新增userdata字段 [`07fea3a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/07fea3a13fd60557f783b7cd4e93f0a4e0cfc8c9) +- 任务新增userdata字段 [`770bb9a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/770bb9a8019ab997c26d36cdf3e8e8c218d245ec) +- 图片审核结果增加Category [`6ac42c6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6ac42c68bf504d49675768f69bfc9ebbb5627d23) +- update crc64 errmsg [`ad06e7a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ad06e7a6a0e54d4ab0fb7e6edf23ba89631dfadc) +- check crc print err [`5210297`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5210297a6d2e51109999443f5ecd053e57b08acb) +- update ci [`70a554b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/70a554bc4de9f7029afbff6815bd86388d778789) + +## [v0.7.35](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.34...v0.7.35) - 2022-05-20 + +### Merged + +- Cos v4 dev [`#175`](https://github.com/tencentyun/cos-go-sdk-v5/pull/175) + +### Commits + +- 新增模板类型 [`26c0bd6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/26c0bd63c4f196bb829f34e374977b581aa82c90) +- 添加模板类型 [`11b0b48`](https://github.com/tencentyun/cos-go-sdk-v5/commit/11b0b48ad5d653455d5fa281913787c2d114bc05) +- 补充任务类型 [`84d9be2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/84d9be24bbaf475d38cd98a096800fcd0cb0f009) +- 新增转码模板 [`2fb8865`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2fb8865ea0f70b61c1427862ae71252ba0437797) +- workflow [`3d28a02`](https://github.com/tencentyun/cos-go-sdk-v5/commit/3d28a0212353a5d0d6ff7e64e26e18fdfb4fd8a7) +- 工作流增删改查 [`c176883`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c176883a7412c29a649d9d1d39e9dca689babfe2) +- 修改demo中的bucket和appid [`0ce8af7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0ce8af7f4057bb6d53077aee0a507dc960438cf7) +- 批量处理任务 [`7427269`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7427269d2d82a1a7111331714a234bd4213dc191) +- ci 图片处理任务demo提交 [`cc07430`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cc074303295e9e548c49ddd4403982b0db079db6) +- check bucketname, dns scatter [`77a1232`](https://github.com/tencentyun/cos-go-sdk-v5/commit/77a1232edd98478846b4c059fca7b7a0c3b3f2fa) +- add get_signature [`51699c6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/51699c658095753a6875a8391986b55c8bde0876) +- 支持流抽取任务和增加3个color值 [`ee129a9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ee129a9d8764f1969cc9e110460e5a5fb60a2ce1) +- 添加工作流相关结构体 [`2b70cbc`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2b70cbc7903d1c74f6fdd50ebc34a6566600563e) +- 支持转封装加密和同步媒体信息struct复用异步任务的结构 [`6000c57`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6000c5725a7dace8eae163dd5b26668d2140a974) +- update ci ImageProcessResult, update ut [`55f2349`](https://github.com/tencentyun/cos-go-sdk-v5/commit/55f2349736555d4d8037087cd40b3e03e4a44382) +- 支持媒体信息任务 [`449f4e4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/449f4e42bb478ee1b1a609fa81f5f86911925e52) +- add opt header to GetObjectVersion [`85bc4ea`](https://github.com/tencentyun/cos-go-sdk-v5/commit/85bc4eaea499b16be69f8c5f07e5eaf4d6e9693c) +- check delete behavior [`07068b5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/07068b576885309547668d0ba23383aa9600175b) +- 删除调试信息 [`a60f7dd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a60f7dd035755c20a29c11bd4254185e9961c9b8) +- update dns scatter [`c0527ad`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c0527adfff89c13144f5f53c3dd1396df60c9723) + +## [v0.7.34](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.33...v0.7.34) - 2022-03-01 + +### Merged + +- Cos v4 dev [`#167`](https://github.com/tencentyun/cos-go-sdk-v5/pull/167) + +### Commits + +- 完善任务接口 [`619bc6b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/619bc6be68d0e00530cbd4bf75e1debb2101b4ec) +- 完善工作流实例查询接口 [`091e4df`](https://github.com/tencentyun/cos-go-sdk-v5/commit/091e4dffa3918e531444465a978d8c34e60eb9de) +- add:支持md5和进度 [`b4c4a90`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b4c4a906a608bcb3776adbcf3fda4fb60643ea8e) +- add credential [`72d8904`](https://github.com/tencentyun/cos-go-sdk-v5/commit/72d8904b4cff8746c867b127cc0cb16cba4b27c1) +- 新增语音识别任务 [`99c1f41`](https://github.com/tencentyun/cos-go-sdk-v5/commit/99c1f410afd665f6e24fcc42b10a9195e8670662) +- 云查毒接口 [`9c253bb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9c253bbe18f56928b32bdb00fa2829ce84c7a365) +- 图片审核增加大图压缩参数 [`8be801b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8be801ba2a617ee56dfb722d8d2388ef8e3f2a36) +- 完善工作流实例查询接口 [`89bf394`](https://github.com/tencentyun/cos-go-sdk-v5/commit/89bf394df434e1c93ab8891b39996794176b8e13) +- add:支持万象域名下媒体接口 [`117b5d3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/117b5d3a28a6de35d1ffbc80a4e41bad5836bf9b) +- Updated CHANGELOG.md [`cb64742`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cb64742158e726119a541f156faa3216fbdf5e85) +- Updated CHANGELOG.md [`f2dc7ef`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f2dc7efdce50c2114520941df06bdc49e15214cd) +- add opt header in bucket head [`33a7ea2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/33a7ea2683e7608d794011143ad1a01943760a66) +- update download [`0f3c6f4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f3c6f4ac1709b11823356704c3c6f0225d754aa) +- update multicopy [`1a1a581`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1a1a5810b308feec05fc92ef67d5a298149efef1) +- update fetch demo [`9cc16ad`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9cc16ad671b723472287ce003acee48b34228e00) +- 网页审核dataid参数 [`b408223`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b408223459252423a7385a447bb5454e60478897) +- update bucket inventory [`18ecdbd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/18ecdbde98e03b80826d7f10ba8d3b783dbdd845) +- update ut [`108941e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/108941e6ae203e6e138d38009012866adad429f1) +- 图片和视频审核增加未成年人场景 [`df7e3f9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/df7e3f9740ed5e387038b0b27f5378b16c0ab712) +- 图片审核兼容terrorism拼法 [`8fcaab6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8fcaab682ef9645d6de255d154879740d056e8eb) + +## [v0.7.33](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.32...v0.7.33) - 2021-12-07 + +### Merged + +- Cos v4 dev [`#164`](https://github.com/tencentyun/cos-go-sdk-v5/pull/164) +- update presignurl [`#161`](https://github.com/tencentyun/cos-go-sdk-v5/pull/161) + +### Commits + +- update auth [`b5482a8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b5482a8a4b3a87aa136e3be493b0b7b97f3ffcc8) +- 内容审核网页审核接口 [`47bfeab`](https://github.com/tencentyun/cos-go-sdk-v5/commit/47bfeabd2ec0c88af9a1acb09eb116ebd3b4ce73) +- 内容审核RequestId参数 [`1900e2c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1900e2cc80447edbb3ad0e8f01993529fa23d413) +- update demo [`803cdd8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/803cdd823383fa19d990c04f03152b7c580eaa06) +- update demo [`3d30e27`](https://github.com/tencentyun/cos-go-sdk-v5/commit/3d30e2772f174f51354140cf3962e87274f0657d) +- update PresignedURL && add batchGet demo [`4c06894`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4c068949a6a9b71c8e8b282be606e62bc1a8533f) +- 图片批量审核接口 [`55968d8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/55968d88111aa86ebb189bcd0c8cc0d2a2bc9783) +- Updated CHANGELOG.md [`cdb5d3c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cdb5d3c23d38068c896b7bcbb79021d8d4113a5a) +- 音频审核查询结果分片返回多个 [`4d05757`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4d05757ff4ee42c63191fa6b782f6bc1757b8eb3) +- add params check [`03ccac5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/03ccac5f6d5715e0814d7c825bfd9c6879d52018) +- 内容审核DataId参数 [`5eabaa9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5eabaa9b4148e072da7223f2420bb9cdc1373b85) + +## [v0.7.32](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.31...v0.7.32) - 2021-10-28 + +### Merged + +- add ut [`#160`](https://github.com/tencentyun/cos-go-sdk-v5/pull/160) +- add CI 媒体处理接口 [`#159`](https://github.com/tencentyun/cos-go-sdk-v5/pull/159) +- Cos v4 dev [`#158`](https://github.com/tencentyun/cos-go-sdk-v5/pull/158) +- update auth signed header [`#157`](https://github.com/tencentyun/cos-go-sdk-v5/pull/157) +- Cos v4 dev [`#156`](https://github.com/tencentyun/cos-go-sdk-v5/pull/156) +- update PresignedURL [`#155`](https://github.com/tencentyun/cos-go-sdk-v5/pull/155) +- Cos v4 dev [`#154`](https://github.com/tencentyun/cos-go-sdk-v5/pull/154) +- Cos v4 dev [`#153`](https://github.com/tencentyun/cos-go-sdk-v5/pull/153) +- Cos v4 dev [`#152`](https://github.com/tencentyun/cos-go-sdk-v5/pull/152) +- Cos v4 dev [`#151`](https://github.com/tencentyun/cos-go-sdk-v5/pull/151) +- add:增加截图任务参数 [`#150`](https://github.com/tencentyun/cos-go-sdk-v5/pull/150) + +### Commits + +- add fetch task api && add cvm role [`d2e9d91`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d2e9d919bdd6dba423ac39f0aa2d882ff85a4963) +- 内容审核六期接口 [`87f4943`](https://github.com/tencentyun/cos-go-sdk-v5/commit/87f49432d0514158982bdccda4a15c6504c98701) +- add retry options [`b0532f5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b0532f56c62b132897e0a3b333cbc43f1f5393da) +- add:解析回调body [`52bf0c7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/52bf0c72b54bfad999edd9a542c9b44af61a2b58) +- add:支持多任务接口 [`84a85a1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/84a85a159760405704c61e1085e790f378a3bf24) +- add:支持雪碧图任务 [`1f98f78`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1f98f7857cd2cc5b70dbb1ae60628f4310c0c5c3) +- ci 分段任务struct demo提交 [`6b85e7b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6b85e7b9e72f223fab3eb9d5b1eea4b61bf7740c) +- add:支持动图任务 [`96b7f6d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/96b7f6d79015704a4cae2bcf153eb601b290cf0c) +- fix:调整指针数组为实例十足 [`54fa46a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/54fa46a83631caba6570d9276fe287ea4420d6bf) +- update ci doc [`48d7d86`](https://github.com/tencentyun/cos-go-sdk-v5/commit/48d7d868fe7dec6040a597a07ca3babef41e83b9) +- update [`d7b154b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d7b154bab1506ffa2b7ddbd834b64bfbc082a6a2) +- add:xml可见性 [`0263d6a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0263d6a6394a80c87a7c1c1507e048bdeffb15d5) +- update demo [`e9c0af3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e9c0af3ad1eb0582e9517c4f80af922e0e181469) +- update demo [`6372b2e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6372b2ef3cbc66be72e77e222e3d49c0d3ced254) +- fix:截图时输出文件是多个 [`134713e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/134713eac32327ff6b09aaa57f95ec53fca28221) + +## [v0.7.31](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.30...v0.7.31) - 2021-09-07 + +### Merged + +- 更新ci内容审核接口 [`#149`](https://github.com/tencentyun/cos-go-sdk-v5/pull/149) +- update upload/download opt [`#148`](https://github.com/tencentyun/cos-go-sdk-v5/pull/148) +- Cos v4 dev [`#146`](https://github.com/tencentyun/cos-go-sdk-v5/pull/146) +- Cos v4 dev [`#145`](https://github.com/tencentyun/cos-go-sdk-v5/pull/145) + +### Commits + +- update download retry && bucket domain [`a63f617`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a63f6174b609f6b593cc274566b50aa5174705e6) +- add:支持拼接任务 [`ee4f335`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ee4f335957f295497adbcf81a8e34bf38ba5e106) +- add:格式话 [`81d6170`](https://github.com/tencentyun/cos-go-sdk-v5/commit/81d6170a01b6bb50140cd738e7b91e812c2e641e) +- Updated CHANGELOG.md [`4c0eb2d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4c0eb2d7b78c5d58c7a9495111fefb8bf854b31a) +- update ci_media [`17cf1d4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/17cf1d43003ba5998f23381437df03fa98a27f17) +- update upload/download [`fd0f5ed`](https://github.com/tencentyun/cos-go-sdk-v5/commit/fd0f5ed75aa97ed7719bbfd0da5913a825621094) + +## [v0.7.30](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.29...v0.7.30) - 2021-08-25 + +### Merged + +- Cos v4 dev [`#144`](https://github.com/tencentyun/cos-go-sdk-v5/pull/144) + +### Commits + +- add append && add retry [`6d06f34`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6d06f3452d0a8b6f1f8f719edf2d80e0fcce4823) +- add put with transport [`35642e5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/35642e50731639c982bf3302e1088fc7963ae9bb) +- Updated CHANGELOG.md [`a505960`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a505960fe4cbb12bbf081315a73f97b880deeb1e) +- update append [`df29a44`](https://github.com/tencentyun/cos-go-sdk-v5/commit/df29a448ac33860036422075a1e64d0bf3120c45) + +## [v0.7.29](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.28...v0.7.29) - 2021-07-27 + +### Commits + +- Updated CHANGELOG.md [`4d84465`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4d84465313582d4cd13c6138f8a510c26c419678) +- update version [`8d03ad4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8d03ad45904c733ba1b04926672e8a1cffc98b44) + +## [v0.7.28](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.27...v0.7.28) - 2021-07-27 + +### Merged + +- update context [`#143`](https://github.com/tencentyun/cos-go-sdk-v5/pull/143) +- update ctx [`#141`](https://github.com/tencentyun/cos-go-sdk-v5/pull/141) + +### Commits + +- update CHANGELOG.md [`eb5f276`](https://github.com/tencentyun/cos-go-sdk-v5/commit/eb5f27672a70f8a8621d763a19a9b24427007480) +- Updated CHANGELOG.md [`100cdb8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/100cdb8ab8576d3a56c20b7e4c27993275adfdd3) +- Updated CHANGELOG.md [`925081a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/925081ac2523e9e92ddd17c27fc5ab965b8e3648) +- update auth [`9795208`](https://github.com/tencentyun/cos-go-sdk-v5/commit/979520893c8ec4a1ce581261f7793849ff3afc5d) + +## [v0.7.27](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.26...v0.7.27) - 2021-06-25 + +### Commits + +- Updated CHANGELOG.md [`43e7b7b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/43e7b7bec2538083b9e48936ce8b1b4a45ba08a6) +- update to v0.7.27 [`152b063`](https://github.com/tencentyun/cos-go-sdk-v5/commit/152b0634ca147d5695644361eaa966e81e875e73) + +## [v0.7.26](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.25...v0.7.26) - 2021-06-25 + +### Merged + +- update go.mod [`#139`](https://github.com/tencentyun/cos-go-sdk-v5/pull/139) +- add header to restore [`#137`](https://github.com/tencentyun/cos-go-sdk-v5/pull/137) +- update bucket get [`#136`](https://github.com/tencentyun/cos-go-sdk-v5/pull/136) +- add get object url [`#135`](https://github.com/tencentyun/cos-go-sdk-v5/pull/135) +- Complete unit tests in ci_media.go and fix several issues in ci_media.go [`#134`](https://github.com/tencentyun/cos-go-sdk-v5/pull/134) +- update test [`#131`](https://github.com/tencentyun/cos-go-sdk-v5/pull/131) +- update bucket lifecycle [`#128`](https://github.com/tencentyun/cos-go-sdk-v5/pull/128) +- add cse-kms [`#127`](https://github.com/tencentyun/cos-go-sdk-v5/pull/127) + +### Commits + +- add ces-kms [`7134982`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7134982d66a52575ec5133d7a01d718175baf719) +- 补全object.go, ci.go, ci_doc.go的单元测试 [`205ee11`](https://github.com/tencentyun/cos-go-sdk-v5/commit/205ee119e9c7f7592e95286915eed785c443d589) +- add Crypto UserAgent and versionid [`6ddd327`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6ddd32755c16dcbcf89cecb785b23d32d0199ea5) +- Complete unit tests in ci_media.go and fix several issues in ci_media.go. [`d1c9ff5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d1c9ff5808b601b7a918b152c8fba7ac2d5976c4) +- prepare crypto [`6097da8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6097da89694493508c7dba2e6ab5a59c5ab66fa9) +- cse-kms done [`05379cf`](https://github.com/tencentyun/cos-go-sdk-v5/commit/05379cf3101c3f44b59dbbf1bcc14517a8c2f922) +- update go.sum [`15022ae`](https://github.com/tencentyun/cos-go-sdk-v5/commit/15022aea2ec57f3a68f4a0d6f72dcfe1d85c2fd2) +- Updated CHANGELOG.md [`efd7866`](https://github.com/tencentyun/cos-go-sdk-v5/commit/efd7866989a308b05f8834e7cfc1682fceb8b088) +- Updated CHANGELOG.md [`8e62f33`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8e62f335d477bf2d83db9f73236627b8362fbd84) +- Updated CHANGELOG.md [`ba44de1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ba44de1b0fe5fe66b89314a90ca3a7277d8345c9) +- update crypto demo [`70b911b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/70b911ba7ef0775d3ca6d3e966cc1c2bea52fd0c) +- update crypto test [`0edf665`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0edf665bf13714f57397b920ac613221a9da4209) +- update ces-kms [`3094fa7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/3094fa72e8d1985528cfc0c8835ac0f01e15b2c7) +- Fix ci_media.go and example/CI/media_process/media_process.go [`ef23bab`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ef23bab44479fc5a1960b9357b64e556402527d8) +- update crypto wrap meta [`06f101d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/06f101d9e3de4cf038c2a50fc87c4f2830e397fe) +- update crypto sample [`d7608ad`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d7608ad3bc2e46f2213e4c2faaf466cd802cf24a) +- update [`e89b7b0`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e89b7b088ab69340ef04cd3ab4bb53ad7b4dc40c) + +## [v0.7.25](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.24...v0.7.25) - 2021-05-10 + +### Merged + +- fix demo [`#126`](https://github.com/tencentyun/cos-go-sdk-v5/pull/126) +- add ci && download checkpoint [`#124`](https://github.com/tencentyun/cos-go-sdk-v5/pull/124) +- update bucket lifecycle,presignedURL,error format [`#120`](https://github.com/tencentyun/cos-go-sdk-v5/pull/120) +- Cos dev v5 [`#117`](https://github.com/tencentyun/cos-go-sdk-v5/pull/117) + +### Commits + +- add ci guetzli && test [`caee386`](https://github.com/tencentyun/cos-go-sdk-v5/commit/caee386405df2603c860bf08f6e39bc0d76663fe) +- add CI QRCode && Update CI [`e2bf821`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e2bf82118033b3d0317afdde8c7f0da6e767e003) +- add multidownload [`f54cbf1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f54cbf13a574974f5916c7ac3af46a41ac7fd4e8) +- add example [`4cc93a9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4cc93a9ebd3649100363d59c40934bdf56250eb4) +- add AudioAuditing [`1b22189`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1b221890652deff58fb0d7e31cf679ce3de412f8) +- download checkpoint [`4d15821`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4d158217c8b79af01b00916b1715f0c982862373) +- update download and put bucket [`da7dafc`](https://github.com/tencentyun/cos-go-sdk-v5/commit/da7dafccbdb6ae9f9809c4d0243b70976a437cdb) +- update multidownload [`2a64ad4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2a64ad473b82f4b621fa35ddc5655297c0c73955) +- deliver init header to complete in upload [`f398b20`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f398b20eeeb6c847c11a863a39e81c89bf285645) +- add directory demo [`4af950f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4af950f313b3a12aeed3c928efad4bf1dac8c03e) +- Updated CHANGELOG.md [`ab8e9e6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ab8e9e6980206a19433a7b133c68eb77e9278853) + +## [v0.7.24](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.23...v0.7.24) - 2021-03-27 + +### Merged + +- Cos v4 dev [`#116`](https://github.com/tencentyun/cos-go-sdk-v5/pull/116) + +### Commits + +- add req close options & update upload simple upload threshold [`f2a0dc3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f2a0dc3aad8f8e684d44e5d350670cc20a9ad329) +- update PutFromFile [`5672500`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5672500b2d0570e06166d21285f384567d03c27d) +- Updated CHANGELOG.md [`8a9f014`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8a9f014dd5890ca47f9ff8fa9c384c1d8067cee1) +- PutFromFile add retry [`7a8d337`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7a8d337d5c6aee90294b2a86937df92287ca34e2) +- update upload [`228fb17`](https://github.com/tencentyun/cos-go-sdk-v5/commit/228fb17936e5a3618a631e16a36fdc7769821228) + +## [v0.7.23](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.22...v0.7.23) - 2021-03-23 + +### Merged + +- latest 0.7.23 stable [`#113`](https://github.com/tencentyun/cos-go-sdk-v5/pull/113) + +### Commits + +- update latest 0.7.23 stable [`17c220d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/17c220d588c93afcdfce86154245daf44b196e0c) +- Updated CHANGELOG.md [`f42ee97`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f42ee9765b9267fc64345d4bb5ca389ed0528c07) + +## [v0.7.22](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.21...v0.7.22) - 2021-03-12 + +### Merged + +- Cos v4 dev [`#111`](https://github.com/tencentyun/cos-go-sdk-v5/pull/111) +- update [`#109`](https://github.com/tencentyun/cos-go-sdk-v5/pull/109) + +### Commits + +- Updated CHANGELOG.md [`d58178d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d58178d869994363c70a4e1b846b4f8ff87ccb84) +- update crc [`23ad6e2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/23ad6e2c72a815f790345446045db132abdec0dd) + +## [v0.7.21](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.20...v0.7.21) - 2021-03-08 + +### Merged + +- Cos v4 dev [`#108`](https://github.com/tencentyun/cos-go-sdk-v5/pull/108) +- Cos v4 dev [`#107`](https://github.com/tencentyun/cos-go-sdk-v5/pull/107) +- Cos v4 dev [`#106`](https://github.com/tencentyun/cos-go-sdk-v5/pull/106) + +### Commits + +- add:支持媒体处理任务接口 [`917abd1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/917abd14626ac6b1dd08c21d46b9a9988f537b1a) +- add:redeme里增加链接 [`d795d20`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d795d20dca35ef730c8b58ba8a1e7e27fd9810d3) +- update ci [`33b02c0`](https://github.com/tencentyun/cos-go-sdk-v5/commit/33b02c0be26631712f47c410e6d1f32f6fae477b) +- update ci put & select [`62fb57e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/62fb57e373a9b86dafbd356820c0e96b20da9ba2) +- add upload verification [`2bfb93f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2bfb93f7d05ffdd4db0a21cbec410f97f2d51cb6) +- Updated CHANGELOG.md [`e0e66ae`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e0e66ae920c8611459d505d9f847e16e62cb666f) +- add:redeme里增加链接 [`a060fa0`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a060fa03a93c6b7bb2e303e7c270fa0df8895e24) +- update [`45e6cb6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/45e6cb65c3d9758743bba26342ec02ad38f75d22) +- update [`685c58a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/685c58af29276c23ff69aee377b03ed31c7eb856) +- update ci [`deaede4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/deaede440c412277e93e9c0a891089ddb92381f3) + +## [v0.7.20](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.19...v0.7.20) - 2021-02-25 + +### Merged + +- fix multicopy and multiupload send on closed channel panic [`#104`](https://github.com/tencentyun/cos-go-sdk-v5/pull/104) +- update DividePart to 64M [`#103`](https://github.com/tencentyun/cos-go-sdk-v5/pull/103) +- update test [`#102`](https://github.com/tencentyun/cos-go-sdk-v5/pull/102) + +### Commits + +- Updated CHANGELOG.md [`eb667d9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/eb667d9ed9fae2a338bee4fffc84381d00dec897) + +## [v0.7.19](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.18...v0.7.19) - 2021-02-01 + +### Merged + +- add get object optional and test [`#101`](https://github.com/tencentyun/cos-go-sdk-v5/pull/101) + +### Commits + +- Updated CHANGELOG.md [`d2273eb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d2273eb6855df9c5db147ae4e1477eefc2490403) + +## [v0.7.18](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.17...v0.7.18) - 2021-01-11 + +### Merged + +- update upload [`#100`](https://github.com/tencentyun/cos-go-sdk-v5/pull/100) + +### Commits + +- Updated CHANGELOG.md [`5172396`](https://github.com/tencentyun/cos-go-sdk-v5/commit/51723968313c10a106ecf7fdb5227c41247ec066) + +## [v0.7.17](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.16...v0.7.17) - 2020-12-29 + +### Merged + +- add MultiCopy [`#99`](https://github.com/tencentyun/cos-go-sdk-v5/pull/99) + +### Commits + +- Updated CHANGELOG.md [`91fc87b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/91fc87ba8af042adb0d0bf147f8fe6aa49057976) + +## [v0.7.16](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.15...v0.7.16) - 2020-12-24 + +### Merged + +- Cos v4 dev [`#98`](https://github.com/tencentyun/cos-go-sdk-v5/pull/98) + +### Commits + +- Add Bucket Accelerate [`c07e497`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c07e49771c809fab640ac9f2c31d776de9dea23d) +- update upload progress && single object length [`72e7751`](https://github.com/tencentyun/cos-go-sdk-v5/commit/72e77516044f833f60577906800a638ebb31dc83) +- Updated CHANGELOG.md [`5057561`](https://github.com/tencentyun/cos-go-sdk-v5/commit/50575619064fbd54e69745b1884756e6f6222a99) +- update version [`6da3d40`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6da3d4094cd8ca8e6840dedcb8b540c14e1f4c93) + +## [v0.7.15](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.14...v0.7.15) - 2020-12-11 + +### Merged + +- update ci [`#96`](https://github.com/tencentyun/cos-go-sdk-v5/pull/96) + +### Commits + +- Updated CHANGELOG.md [`b8afb3f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b8afb3f85050cee4884a46c8ed49d26bf76d10a4) + +## [v0.7.14](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.13...v0.7.14) - 2020-12-09 + +### Merged + +- update version [`#95`](https://github.com/tencentyun/cos-go-sdk-v5/pull/95) +- fix bucket lifecycle [`#94`](https://github.com/tencentyun/cos-go-sdk-v5/pull/94) + +### Commits + +- Updated CHANGELOG.md [`e3a89ee`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e3a89ee58b4f524c7ad5f2b1f0bdc688a2e39c32) + +## [v0.7.13](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.12...v0.7.13) - 2020-12-08 + +### Merged + +- Cos v4 dev [`#93`](https://github.com/tencentyun/cos-go-sdk-v5/pull/93) + +### Commits + +- add ci doc [`dad5b1f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/dad5b1f3fbbf30958d3d8ae930b06abcaf8db5ac) +- add progress [`2afc5e1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2afc5e192cd9bc8d6630fa929e10028ec79bde8e) +- Updated CHANGELOG.md [`e39f3e3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e39f3e3585e0478abe50b33962e1e3981a2d432c) +- update test [`4899c22`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4899c226f70ccc1bb4ac8489a2b8ff000003bc97) +- add auto changelog workflow [`ca3ea38`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ca3ea38770afcd11e50570a835090c68a377157f) + +## [v0.7.12](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.11...v0.7.12) - 2020-11-25 + +### Merged + +- fix ci_test [`#89`](https://github.com/tencentyun/cos-go-sdk-v5/pull/89) +- update version [`#92`](https://github.com/tencentyun/cos-go-sdk-v5/pull/92) +- update presignedurl && copy [`#91`](https://github.com/tencentyun/cos-go-sdk-v5/pull/91) + +## [v0.7.11](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.10...v0.7.11) - 2020-11-15 + +### Merged + +- Cos v4 dev [`#90`](https://github.com/tencentyun/cos-go-sdk-v5/pull/90) + +### Commits + +- add select, and x-cos-traffic-limit [`e6f823c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e6f823c7c1ee66fe68de4aafd45b009dee4b1ac2) +- add ListMultiUploads && 断点续传 [`64d31f3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/64d31f318a223866ac16c64bbe9effcd168b696d) +- ci 内容审核 [`695c446`](https://github.com/tencentyun/cos-go-sdk-v5/commit/695c4466f5cec17acd5143777d4eae90f389f119) +- add checkpoint multi upload [`287669a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/287669a677af36153d645aabd4b296114aea75fe) +- add ci post [`dd7c41c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/dd7c41ca0824b607633e6a7bd0d3a838d52a91fd) +- add CI图片审核 [`98eab28`](https://github.com/tencentyun/cos-go-sdk-v5/commit/98eab2886c628a3fbbbf581aeea56759ff38700c) +- fix list uploads [`5e69c19`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5e69c19d3450d06c3da270ca12e43647432d0ca4) +- add decodeURIComponent [`f6c91c9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f6c91c92d6e46869c8f7acf000eccce2d351051b) +- add checkpoint multi upload: update [`52c110b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/52c110b7ede92af97e3685d4afd73a128ddd443b) + +## [v0.7.10](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.9...v0.7.10) - 2020-09-29 + +### Merged + +- ACL转换 [`#87`](https://github.com/tencentyun/cos-go-sdk-v5/pull/87) +- fix bucket encryption & test [`#86`](https://github.com/tencentyun/cos-go-sdk-v5/pull/86) + +### Commits + +- fix MultiUpload when filesize=0 [`cb662cd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cb662cdad5225cf92be335911d1805a29e445d14) +- 多版本删除 [`0e9536d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0e9536d989b8e47b71fa02d12cb75d8ffda8b5fc) +- update travis.yml [`b0a399e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b0a399e92dd143fb55b1ed173497644e51450835) +- update version [`5804e86`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5804e86747f587402b962dcb680ebc0d7c04035d) + +## [v0.7.9](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.8...v0.7.9) - 2020-09-14 + +### Merged + +- add bucket intelligenttiering [`#85`](https://github.com/tencentyun/cos-go-sdk-v5/pull/85) + +## [v0.7.8](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.7...v0.7.8) - 2020-08-31 + +### Merged + +- x-cos-copy-source urlencode修正 [`#83`](https://github.com/tencentyun/cos-go-sdk-v5/pull/83) +- Common dev [`#82`](https://github.com/tencentyun/cos-go-sdk-v5/pull/82) + +### Commits + +- add host to signature [`f9f6178`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f9f617878dad23f915ecea978f065aa70486843c) + +## [v0.7.7](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.6...v0.7.7) - 2020-06-04 + +### Merged + +- add object tagging && bucket origin && add stsv3 demo [`#80`](https://github.com/tencentyun/cos-go-sdk-v5/pull/80) + +## [v0.7.6](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.5...v0.7.6) - 2020-05-20 + +### Merged + +- add GetBucketObjectVersions & update tips when failed [`#78`](https://github.com/tencentyun/cos-go-sdk-v5/pull/78) + +### Commits + +- update version [`bcc1ed2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/bcc1ed2b8317cea8a32ab193ffad0a6482d63560) + +## [v0.7.5](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.4...v0.7.5) - 2020-05-14 + +### Merged + +- update tag 0.7.5 [`#77`](https://github.com/tencentyun/cos-go-sdk-v5/pull/77) +- feat: Object.Delete 增加 optHeader 传递 [`#75`](https://github.com/tencentyun/cos-go-sdk-v5/pull/75) + +### Commits + +- feat: 改为可选参数,向下兼容 [`2eee514`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2eee5149d727a045e80d28729bb60c90614e8275) + +## [v0.7.4](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.3...v0.7.4) - 2020-04-12 + +### Merged + +- add encryption and referer [`#74`](https://github.com/tencentyun/cos-go-sdk-v5/pull/74) + +### Commits + +- version 0.7.4 [`da7722b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/da7722b10af59762b8e4f687891850650f0100a9) + +## v0.7.3 - 2020-04-02 + +### Merged + +- update ci and error [`#73`](https://github.com/tencentyun/cos-go-sdk-v5/pull/73) +- add policy and IsNoSuchKeyError function [`#72`](https://github.com/tencentyun/cos-go-sdk-v5/pull/72) +- add restore object for batch [`#69`](https://github.com/tencentyun/cos-go-sdk-v5/pull/69) +- Addbatch [`#68`](https://github.com/tencentyun/cos-go-sdk-v5/pull/68) +- inventory/logging/replication/versioning/tagging [`#66`](https://github.com/tencentyun/cos-go-sdk-v5/pull/66) +- add content-language [`#65`](https://github.com/tencentyun/cos-go-sdk-v5/pull/65) +- add host [`#64`](https://github.com/tencentyun/cos-go-sdk-v5/pull/64) +- update MultiUpload [`#63`](https://github.com/tencentyun/cos-go-sdk-v5/pull/63) +- add bucket website and domain interface [`#53`](https://github.com/tencentyun/cos-go-sdk-v5/pull/53) +- 改进:增加对Upload part - copy API的支持 [`#54`](https://github.com/tencentyun/cos-go-sdk-v5/pull/54) +- add sts policy describe [`#60`](https://github.com/tencentyun/cos-go-sdk-v5/pull/60) +- update the sts example [`#59`](https://github.com/tencentyun/cos-go-sdk-v5/pull/59) +- Automatic partitioning for MultiUpload [`#58`](https://github.com/tencentyun/cos-go-sdk-v5/pull/58) +- add sse-c and optional header for put object [`#57`](https://github.com/tencentyun/cos-go-sdk-v5/pull/57) +- fix object upload copy versionid [`#56`](https://github.com/tencentyun/cos-go-sdk-v5/pull/56) +- Fix the multiupload property [`#50`](https://github.com/tencentyun/cos-go-sdk-v5/pull/50) +- Fix the mulupload out of index panic [`#49`](https://github.com/tencentyun/cos-go-sdk-v5/pull/49) +- fix the example of get, reorder the import package [`#48`](https://github.com/tencentyun/cos-go-sdk-v5/pull/48) +- spec the test bucket only used for test [`#47`](https://github.com/tencentyun/cos-go-sdk-v5/pull/47) +- reopen the coverage report [`#46`](https://github.com/tencentyun/cos-go-sdk-v5/pull/46) +- Fix the ci test [`#45`](https://github.com/tencentyun/cos-go-sdk-v5/pull/45) +- add Server Side Encryption Option to ObjectPutHeaderOptions and fixed testing [`#44`](https://github.com/tencentyun/cos-go-sdk-v5/pull/44) +- Fix the outindex of the resp addr in head object [`#42`](https://github.com/tencentyun/cos-go-sdk-v5/pull/42) +- Add the check for anonymous user [`#41`](https://github.com/tencentyun/cos-go-sdk-v5/pull/41) +- Change the param type in listParts [`#38`](https://github.com/tencentyun/cos-go-sdk-v5/pull/38) +- Fix the options param to listparts interface [`#37`](https://github.com/tencentyun/cos-go-sdk-v5/pull/37) +- Add the error when return 200OK but body contains the error [`#34`](https://github.com/tencentyun/cos-go-sdk-v5/pull/34) +- cgi already compact, so remove the sprit [`#32`](https://github.com/tencentyun/cos-go-sdk-v5/pull/32) +- fix the blink in prefix which lead the wrong auth [`#31`](https://github.com/tencentyun/cos-go-sdk-v5/pull/31) +- Support Versioning, Replication, Inventory and Logging API [`#30`](https://github.com/tencentyun/cos-go-sdk-v5/pull/30) +- fix the panic of getting out of index with response header [`#28`](https://github.com/tencentyun/cos-go-sdk-v5/pull/28) +- According the versionid to head and get object, add the opt header of copy object [`#26`](https://github.com/tencentyun/cos-go-sdk-v5/pull/26) +- rm the panic in interface [`#24`](https://github.com/tencentyun/cos-go-sdk-v5/pull/24) +- Add presigned url and demo use it to get object [`#23`](https://github.com/tencentyun/cos-go-sdk-v5/pull/23) +- Check delete object param and fix restore name [`#22`](https://github.com/tencentyun/cos-go-sdk-v5/pull/22) +- Add PostObjectRestore interface [`#21`](https://github.com/tencentyun/cos-go-sdk-v5/pull/21) +- Add vendor files [`#19`](https://github.com/tencentyun/cos-go-sdk-v5/pull/19) +- Add the comment to declare the out of memory issue when put large loc… [`#17`](https://github.com/tencentyun/cos-go-sdk-v5/pull/17) +- Need to improve the interface in the future [`#16`](https://github.com/tencentyun/cos-go-sdk-v5/pull/16) +- Add ci test with the testify and travis, Add get/put by localfile. [`#15`](https://github.com/tencentyun/cos-go-sdk-v5/pull/15) +- url encode without / [`#14`](https://github.com/tencentyun/cos-go-sdk-v5/pull/14) +- solve the oom when send the big file with the debug request header option [`#10`](https://github.com/tencentyun/cos-go-sdk-v5/pull/10) +- remove the content-type when the request body is empty [`#9`](https://github.com/tencentyun/cos-go-sdk-v5/pull/9) +- fix format [`#6`](https://github.com/tencentyun/cos-go-sdk-v5/pull/6) +- fix format of doc [`#5`](https://github.com/tencentyun/cos-go-sdk-v5/pull/5) +- update the comment for godoc [`#4`](https://github.com/tencentyun/cos-go-sdk-v5/pull/4) +- fix test [`#3`](https://github.com/tencentyun/cos-go-sdk-v5/pull/3) +- update rm the append interface [`#2`](https://github.com/tencentyun/cos-go-sdk-v5/pull/2) + +### Commits + +- fix the vendor files [`a5b3ad3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a5b3ad37d64c5aa82b12a57a6fdb0d2dba5ca1a8) +- first to commit project [`6ad265f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6ad265fc0c275a4b1615c0f4702a7a992d8d299c) +- add batch [`c57ac81`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c57ac81a16da82605cc42bf9e0c8fd3af2cf62c5) +- Support Versioning, Replication, Inventory and Logging api [`c131870`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c131870916d7c29eb8c4a9512ea59ed7d7b09e18) +- fix path [`121a7d8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/121a7d861c8e0fb048aac5a8bc1a644414b16dc3) +- fix the vendor file [`830b5c5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/830b5c54a51d38b91e1432c7b216350a5c479ad0) +- update bucket inventory/logging/replication/versioning/tagging and test [`d37fd23`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d37fd23cdfe570886024c2c0586a2f14429a10ed) +- Add ci test with the testify and travis, test the working [`4cc9e08`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4cc9e08da1a0ce670cf6d20567059b7529b440d5) +- Add ci test with the testify and travis, test the working [`c323f1b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c323f1b90cd97b98708216a72c666d89bdbcad8b) +- rm inventory and logging example [`7739e84`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7739e84d42b7a33121b16817f25129050db93db5) +- add policy [`b427226`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b427226ae44b1c0f25b8681147e828f4603a9014) +- update batch [`156deae`](https://github.com/tencentyun/cos-go-sdk-v5/commit/156deaea3caacc5249050ae1e7378ae8af909c5d) +- update bucket domain and website struct [`b97a490`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b97a490e28370fecc475bf8b1a82df0d5a52a424) +- presigned url, and demo [`0c2d28c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0c2d28caf108cff2a95507a9ff286be679d7925b) +- fix ci_test [`c17efed`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c17efed0aedee60e819d3e9504720ff47958da14) +- fix [`9ebd645`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9ebd6456b6aa788d0d2e97f4a8fb652c1b9a1976) +- update batch [`699fef2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/699fef215987bcf7f2459b9843ce8641900135f7) +- Add the comment to declare the out of memory issue when put large local file [`6c894b8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6c894b8e4d5f0bb1ca24d444a9f8e18f95027cde) +- go module support [`54101f9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/54101f9739b3e59f201092f79d683a0cf377d7d0) +- optional header for complete upload part [`44546a4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/44546a40372260158652ddc6d805ddfc19f13fa3) diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/LICENSE b/vendor/github.com/tencentyun/cos-go-sdk-v5/LICENSE new file mode 100644 index 00000000000..8ff7942e203 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 mozillazg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/Makefile b/vendor/github.com/tencentyun/cos-go-sdk-v5/Makefile new file mode 100644 index 00000000000..108cfa34464 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/Makefile @@ -0,0 +1,22 @@ +help: + @echo "test run test" + @echo "lint run lint" + @echo "example run examples" + +.PHONY: test +test: + go test -v -cover -coverprofile cover.out + go tool cover -html cover.out -o cover.html + +.PHONY: lint +lint: + gofmt -s -w . + goimports -w . + golint . + go vet + +.PHONY: example +example: + cd example && sh test.sh +ci-test: + cd costesting && go test -v diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/README.md b/vendor/github.com/tencentyun/cos-go-sdk-v5/README.md new file mode 100644 index 00000000000..72b2b888c06 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/README.md @@ -0,0 +1,106 @@ +# cos-go-sdk-v5 + +腾讯云对象存储服务 COS(Cloud Object Storage) Go SDK(API 版本:V5 版本的 XML API)。 + +## Install + +`go get -u github.com/tencentyun/cos-go-sdk-v5` + + +## Usage + +```go +package main + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "time" + + "github.com/tencentyun/cos-go-sdk-v5" +) + +func main() { + //将修改为真实的信息 + //bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式 + u, _ := url.Parse("https://.cos..myqcloud.com") + b := &cos.BaseURL{BucketURL: u} + c := cos.NewClient(b, &http.Client{ + //设置超时时间 + Timeout: 100 * time.Second, + Transport: &cos.AuthorizationTransport{ + //如实填写账号和密钥,也可以设置为环境变量 + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + }, + }) + + name := "test/hello.txt" + resp, err := c.Object.Get(context.Background(), name, nil) + if err != nil { + panic(err) + } + bs, _ := ioutil.ReadAll(resp.Body) + resp.Body.Close() + fmt.Printf("%s\n", string(bs)) +} +``` + +所有的 API 在 [example](./example/) 目录下都有对应的使用示例。 + +Service API: + +* [x] Get Service(使用示例:[service/get.go](./example/service/get.go)) + +Bucket API: + +* [x] Get Bucket(使用示例:[bucket/get.go](./example/bucket/get.go)) +* [x] Get Bucket ACL(使用示例:[bucket/getACL.go](./example/bucket/getACL.go)) +* [x] Get Bucket CORS(使用示例:[bucket/getCORS.go](./example/bucket/getCORS.go)) +* [x] Get Bucket Location(使用示例:[bucket/getLocation.go](./example/bucket/getLocation.go)) +* [x] Get Buket Lifecycle(使用示例:[bucket/getLifecycle.go](./example/bucket/getLifecycle.go)) +* [x] Get Bucket Tagging(使用示例:[bucket/getTagging.go](./example/bucket/getTagging.go)) +* [x] Put Bucket(使用示例:[bucket/put.go](./example/bucket/put.go)) +* [x] Put Bucket ACL(使用示例:[bucket/putACL.go](./example/bucket/putACL.go)) +* [x] Put Bucket CORS(使用示例:[bucket/putCORS.go](./example/bucket/putCORS.go)) +* [x] Put Bucket Lifecycle(使用示例:[bucket/putLifecycle.go](./example/bucket/putLifecycle.go)) +* [x] Put Bucket Tagging(使用示例:[bucket/putTagging.go](./example/bucket/putTagging.go)) +* [x] Delete Bucket(使用示例:[bucket/delete.go](./example/bucket/delete.go)) +* [x] Delete Bucket CORS(使用示例:[bucket/deleteCORS.go](./example/bucket/deleteCORS.go)) +* [x] Delete Bucket Lifecycle(使用示例:[bucket/deleteLifecycle.go](./example/bucket/deleteLifecycle.go)) +* [x] Delete Bucket Tagging(使用示例:[bucket/deleteTagging.go](./example/bucket/deleteTagging.go)) +* [x] Head Bucket(使用示例:[bucket/head.go](./example/bucket/head.go)) +* [x] List Multipart Uploads(使用示例:[bucket/listMultipartUploads.go](./example/bucket/listMultipartUploads.go)) + +Object API: + +* [x] Get Object(使用示例:[object/get.go](./example/object/get.go)) +* [x] Get Object ACL(使用示例:[object/getACL.go](./example/object/getACL.go)) +* [x] Put Object(使用示例:[object/put.go](./example/object/put.go)) +* [x] Put Object ACL(使用示例:[object/putACL.go](./example/object/putACL.go)) +* [x] Put Object Copy(使用示例:[object/copy.go](./example/object/copy.go)) +* [x] Delete Object(使用示例:[object/delete.go](./example/object/delete.go)) +* [x] Delete Multiple Object(使用示例:[object/deleteMultiple.go](./example/object/deleteMultiple.go)) +* [x] Head Object(使用示例:[object/head.go](./example/object/head.go)) +* [x] Options Object(使用示例:[object/options.go](./example/object/options.go)) +* [x] Initiate Multipart Upload(使用示例:[object/initiateMultipartUpload.go](./example/object/initiateMultipartUpload.go)) +* [x] Upload Part(使用示例:[object/uploadPart.go](./example/object/uploadPart.go)) +* [x] List Parts(使用示例:[object/listParts.go](./example/object/listParts.go)) +* [x] Complete Multipart Upload(使用示例:[object/completeMultipartUpload.go](./example/object/completeMultipartUpload.go)) +* [x] Abort Multipart Upload(使用示例:[object/abortMultipartUpload.go](./example/object/abortMultipartUpload.go)) +* [x] Mutipart Upload(使用示例:[object/MutiUpload.go](./example/object/MutiUpload.go)) + + +数据处理 API: + +* [x] 媒体处理(使用示例:[media_process.go](./example/CI/media_process/media_process.go)) +* [x] 文档处理(使用示例:[ci_doc_process.go](./example/CI/doc_process/ci_doc_process.go)) + + +内容审核 API: + +* [x] 视频审核(使用示例:[ci_video_auditing_job.go](./example/CI/content_auditing/ci_video_auditing_job.go)) diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go new file mode 100644 index 00000000000..cd612e1169b --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go @@ -0,0 +1,767 @@ +package cos + +import ( + "context" + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "encoding/json" + "fmt" + "hash" + "io" + "io/ioutil" + math_rand "math/rand" + "net" + "net/http" + "net/url" + "regexp" + "sort" + "strings" + "sync" + "time" +) + +const ( + sha1SignAlgorithm = "sha1" + privateHeaderPrefix = "x-cos-" + privateCIHeaderPrefix = "x-ci-" + defaultAuthExpire = time.Hour +) + +var ( + defaultTmpAuthExpire = int64(600) + defaultCVMSchema = "http" + defaultCVMMetaHost = "metadata.tencentyun.com" + defaultCVMCredURI = "latest/meta-data/cam/security-credentials" + internalHost = regexp.MustCompile(`^.*cos-internal\.[a-z-1]+\.tencentcos\.cn$`) + defaultStsHost = "sts.tencentcloudapi.com" + defaultStsSchema = "https" +) + +var DNSScatterDialContext = DNSScatterDialContextFunc + +var DNSScatterTransport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: DNSScatterDialContext, + MaxIdleConns: 100, + IdleConnTimeout: 60 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, +} + +func init() { + math_rand.Seed(time.Now().UnixNano()) +} + +func DNSScatterDialContextFunc(ctx context.Context, network string, addr string) (conn net.Conn, err error) { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + ips, err := net.DefaultResolver.LookupIPAddr(ctx, host) + if err != nil { + return nil, err + } + dialer := &net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + } + // DNS 打散 + start := math_rand.Intn(len(ips)) + for i := start; i < len(ips); i++ { + conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ips[i].IP.String(), port)) + if err == nil { + return + } + } + for i := 0; i < start; i++ { + conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ips[i].IP.String(), port)) + if err == nil { + break + } + } + return +} + +// 需要校验的 Headers 列表 +var NeedSignHeaders = map[string]bool{ + "host": true, + "range": true, + "x-cos-acl": true, + "x-cos-grant-read": true, + "x-cos-grant-write": true, + "x-cos-grant-full-control": true, + "cache-control": true, + "content-disposition": true, + "content-encoding": true, + "content-type": true, + "content-length": true, + "content-md5": true, + "transfer-encoding": true, + "expect": true, + "expires": true, + "x-cos-content-sha1": true, + "x-cos-storage-class": true, + "if-match": true, + "if-modified-since": true, + "if-none-match": true, + "if-unmodified-since": true, + "origin": true, + "access-control-request-method": true, + "access-control-request-headers": true, + "x-cos-object-type": true, + "pic-operations": true, +} + +// 非线程安全,只能在进程初始化(而不是Client初始化)时做设置 +func SetNeedSignHeaders(key string, val bool) { + NeedSignHeaders[key] = val +} + +func safeURLEncode(s string) string { + s = encodeURIComponent(s) + s = strings.Replace(s, "!", "%21", -1) + s = strings.Replace(s, "'", "%27", -1) + s = strings.Replace(s, "(", "%28", -1) + s = strings.Replace(s, ")", "%29", -1) + s = strings.Replace(s, "*", "%2A", -1) + return s +} + +type valuesSignMap map[string][]string + +func (vs valuesSignMap) Add(key, value string) { + key = strings.ToLower(safeURLEncode(key)) + vs[key] = append(vs[key], value) +} + +func (vs valuesSignMap) Encode() string { + var keys []string + for k := range vs { + keys = append(keys, k) + } + sort.Strings(keys) + + var pairs []string + for _, k := range keys { + items := vs[k] + sort.Strings(items) + for _, val := range items { + pairs = append( + pairs, + fmt.Sprintf("%s=%s", k, safeURLEncode(val))) + } + } + return strings.Join(pairs, "&") +} + +// AuthTime 用于生成签名所需的 q-sign-time 和 q-key-time 相关参数 +type AuthTime struct { + SignStartTime time.Time + SignEndTime time.Time + KeyStartTime time.Time + KeyEndTime time.Time +} + +// NewAuthTime 生成 AuthTime 的便捷函数 +// +// expire: 从现在开始多久过期. +func NewAuthTime(expire time.Duration) *AuthTime { + signStartTime := time.Now() + keyStartTime := signStartTime + signEndTime := signStartTime.Add(expire) + keyEndTime := signEndTime + return &AuthTime{ + SignStartTime: signStartTime, + SignEndTime: signEndTime, + KeyStartTime: keyStartTime, + KeyEndTime: keyEndTime, + } +} + +// signString return q-sign-time string +func (a *AuthTime) signString() string { + return fmt.Sprintf("%d;%d", a.SignStartTime.Unix(), a.SignEndTime.Unix()) +} + +// keyString return q-key-time string +func (a *AuthTime) keyString() string { + return fmt.Sprintf("%d;%d", a.KeyStartTime.Unix(), a.KeyEndTime.Unix()) +} + +// newAuthorization 通过一系列步骤生成最终需要的 Authorization 字符串 +func newAuthorization(secretID, secretKey string, req *http.Request, authTime *AuthTime, signHost bool) string { + signTime := authTime.signString() + keyTime := authTime.keyString() + signKey := calSignKey(secretKey, keyTime) + + if signHost { + req.Header.Set("Host", req.Host) + } + formatHeaders := *new(string) + signedHeaderList := *new([]string) + formatHeaders, signedHeaderList = genFormatHeaders(req.Header) + formatParameters, signedParameterList := genFormatParameters(req.URL.Query()) + formatString := genFormatString(req.Method, *req.URL, formatParameters, formatHeaders) + + stringToSign := calStringToSign(sha1SignAlgorithm, keyTime, formatString) + signature := calSignature(signKey, stringToSign) + + return genAuthorization( + secretID, signTime, keyTime, signature, signedHeaderList, + signedParameterList, + ) +} + +// AddAuthorizationHeader 给 req 增加签名信息 +func AddAuthorizationHeader(secretID, secretKey string, sessionToken string, req *http.Request, authTime *AuthTime) { + if secretID == "" { + return + } + if len(sessionToken) > 0 { + req.Header.Set("x-cos-security-token", sessionToken) + } + auth := newAuthorization(secretID, secretKey, req, + authTime, true, + ) + req.Header.Set("Authorization", auth) +} + +// calSignKey 计算 SignKey +func calSignKey(secretKey, keyTime string) string { + digest := calHMACDigest(secretKey, keyTime, sha1SignAlgorithm) + return fmt.Sprintf("%x", digest) +} + +// calStringToSign 计算 StringToSign +func calStringToSign(signAlgorithm, signTime, formatString string) string { + h := sha1.New() + h.Write([]byte(formatString)) + return fmt.Sprintf("%s\n%s\n%x\n", signAlgorithm, signTime, h.Sum(nil)) +} + +// calSignature 计算 Signature +func calSignature(signKey, stringToSign string) string { + digest := calHMACDigest(signKey, stringToSign, sha1SignAlgorithm) + return fmt.Sprintf("%x", digest) +} + +// genAuthorization 生成 Authorization +func genAuthorization(secretID, signTime, keyTime, signature string, signedHeaderList, signedParameterList []string) string { + return strings.Join([]string{ + "q-sign-algorithm=" + sha1SignAlgorithm, + "q-ak=" + secretID, + "q-sign-time=" + signTime, + "q-key-time=" + keyTime, + "q-header-list=" + strings.Join(signedHeaderList, ";"), + "q-url-param-list=" + strings.Join(signedParameterList, ";"), + "q-signature=" + signature, + }, "&") +} + +// genFormatString 生成 FormatString +func genFormatString(method string, uri url.URL, formatParameters, formatHeaders string) string { + formatMethod := strings.ToLower(method) + formatURI := uri.Path + + return fmt.Sprintf("%s\n%s\n%s\n%s\n", formatMethod, formatURI, + formatParameters, formatHeaders, + ) +} + +// genFormatParameters 生成 FormatParameters 和 SignedParameterList +// instead of the url.Values{} +func genFormatParameters(parameters url.Values) (formatParameters string, signedParameterList []string) { + ps := valuesSignMap{} + for key, values := range parameters { + for _, value := range values { + ps.Add(key, value) + signedParameterList = append(signedParameterList, strings.ToLower(safeURLEncode(key))) + } + } + //formatParameters = strings.ToLower(ps.Encode()) + formatParameters = ps.Encode() + sort.Strings(signedParameterList) + return +} + +// genFormatHeaders 生成 FormatHeaders 和 SignedHeaderList +func genFormatHeaders(headers http.Header) (formatHeaders string, signedHeaderList []string) { + hs := valuesSignMap{} + for key, values := range headers { + if isSignHeader(strings.ToLower(key)) { + for _, value := range values { + hs.Add(key, value) + signedHeaderList = append(signedHeaderList, strings.ToLower(safeURLEncode(key))) + } + } + } + formatHeaders = hs.Encode() + sort.Strings(signedHeaderList) + return +} + +// HMAC 签名 +func calHMACDigest(key, msg, signMethod string) []byte { + var hashFunc func() hash.Hash + switch signMethod { + case "sha1": + hashFunc = sha1.New + default: + hashFunc = sha1.New + } + h := hmac.New(hashFunc, []byte(key)) + h.Write([]byte(msg)) + return h.Sum(nil) +} + +func isSignHeader(key string) bool { + for k, v := range NeedSignHeaders { + if key == k && v { + return true + } + } + if strings.HasPrefix(key, privateCIHeaderPrefix) { + return true + } + return strings.HasPrefix(key, privateHeaderPrefix) +} + +type TransportIface interface { + GetCredential() (string, string, string, error) +} + +// AuthorizationTransport 给请求增加 Authorization header +type AuthorizationTransport struct { + SecretID string + SecretKey string + SessionToken string + rwLocker sync.RWMutex + // 签名多久过期 + Expire time.Duration + Transport http.RoundTripper +} + +// SetCredential update the SecretID(ak), SercretKey(sk), sessiontoken +func (t *AuthorizationTransport) SetCredential(ak, sk, token string) { + t.rwLocker.Lock() + defer t.rwLocker.Unlock() + t.SecretID = ak + t.SecretKey = sk + t.SessionToken = token +} + +// GetCredential get the ak, sk, token +func (t *AuthorizationTransport) GetCredential() (string, string, string, error) { + t.rwLocker.RLock() + defer t.rwLocker.RUnlock() + return t.SecretID, t.SecretKey, t.SessionToken, nil +} + +// RoundTrip implements the RoundTripper interface. +func (t *AuthorizationTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req = cloneRequest(req) // per RoundTrip contract + + ak, sk, token, _ := t.GetCredential() + if strings.HasPrefix(ak, " ") || strings.HasSuffix(ak, " ") { + return nil, fmt.Errorf("SecretID is invalid") + } + if strings.HasPrefix(sk, " ") || strings.HasSuffix(sk, " ") { + return nil, fmt.Errorf("SecretKey is invalid") + } + + // 增加 Authorization header + authTime := NewAuthTime(defaultAuthExpire) + AddAuthorizationHeader(ak, sk, token, req, authTime) + + resp, err := t.transport(req).RoundTrip(req) + return resp, err +} + +func (t *AuthorizationTransport) transport(req *http.Request) http.RoundTripper { + if t.Transport != nil { + return t.Transport + } + // 内部域名默认使用DNS打散 + if rc := internalHost.MatchString(req.URL.Hostname()); rc { + return DNSScatterTransport + } + return http.DefaultTransport +} + +type CVMSecurityCredentials struct { + TmpSecretId string `json:",omitempty"` + TmpSecretKey string `json:",omitempty"` + ExpiredTime int64 `json:",omitempty"` + Expiration string `json:",omitempty"` + Token string `json:",omitempty"` + Code string `json:",omitempty"` +} + +type CVMCredentialTransport struct { + RoleName string + Transport http.RoundTripper + secretID string + secretKey string + sessionToken string + expiredTime int64 + rwLocker sync.RWMutex +} + +func (t *CVMCredentialTransport) GetRoles() ([]string, error) { + urlname := fmt.Sprintf("%s://%s/%s", defaultCVMSchema, defaultCVMMetaHost, defaultCVMCredURI) + resp, err := http.Get(urlname) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode > 299 { + bs, _ := ioutil.ReadAll(resp.Body) + return nil, fmt.Errorf("get cvm security-credentials role failed, StatusCode: %v, Body: %v", resp.StatusCode, string(bs)) + } + bs, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + roles := strings.Split(strings.TrimSpace(string(bs)), "\n") + if string(bs) == "" || len(roles) == 0 { + return nil, fmt.Errorf("get cvm security-credentials role failed, No valid cam role was found") + } + return roles, nil +} + +// https://cloud.tencent.com/document/product/213/4934 +func (t *CVMCredentialTransport) UpdateCredential(now int64) (string, string, string, error) { + t.rwLocker.Lock() + defer t.rwLocker.Unlock() + if t.expiredTime > now+defaultTmpAuthExpire { + return t.secretID, t.secretKey, t.sessionToken, nil + } + roleName := t.RoleName + if roleName == "" { + roles, err := t.GetRoles() + if err != nil { + return t.secretID, t.secretKey, t.sessionToken, err + } + roleName = roles[0] + } + urlname := fmt.Sprintf("%s://%s/%s/%s", defaultCVMSchema, defaultCVMMetaHost, defaultCVMCredURI, roleName) + resp, err := http.Get(urlname) + if err != nil { + return t.secretID, t.secretKey, t.sessionToken, err + } + defer resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode > 299 { + bs, _ := ioutil.ReadAll(resp.Body) + return t.secretID, t.secretKey, t.sessionToken, fmt.Errorf("call cvm security-credentials failed, StatusCode: %v, Body: %v", resp.StatusCode, string(bs)) + } + var cred CVMSecurityCredentials + err = json.NewDecoder(resp.Body).Decode(&cred) + if err != nil { + return t.secretID, t.secretKey, t.sessionToken, err + } + if cred.Code != "Success" { + return t.secretID, t.secretKey, t.sessionToken, fmt.Errorf("call cvm security-credentials failed, Code:%v", cred.Code) + } + t.secretID, t.secretKey, t.sessionToken, t.expiredTime = cred.TmpSecretId, cred.TmpSecretKey, cred.Token, cred.ExpiredTime + return t.secretID, t.secretKey, t.sessionToken, nil +} + +func (t *CVMCredentialTransport) GetCredential() (string, string, string, error) { + now := time.Now().Unix() + t.rwLocker.RLock() + // 提前 defaultTmpAuthExpire 获取重新获取临时密钥 + if t.expiredTime <= now+defaultTmpAuthExpire { + expiredTime := t.expiredTime + t.rwLocker.RUnlock() + secretID, secretKey, secretToken, err := t.UpdateCredential(now) + // 获取临时密钥失败但密钥未过期 + if err != nil && now < expiredTime { + err = nil + } + return secretID, secretKey, secretToken, err + } + defer t.rwLocker.RUnlock() + return t.secretID, t.secretKey, t.sessionToken, nil +} + +func (t *CVMCredentialTransport) RoundTrip(req *http.Request) (*http.Response, error) { + ak, sk, token, err := t.GetCredential() + if err != nil { + return nil, err + } + req = cloneRequest(req) + // 增加 Authorization header + authTime := NewAuthTime(defaultAuthExpire) + AddAuthorizationHeader(ak, sk, token, req, authTime) + + resp, err := t.transport().RoundTrip(req) + return resp, err +} + +func (t *CVMCredentialTransport) transport() http.RoundTripper { + if t.Transport != nil { + return t.Transport + } + return http.DefaultTransport +} + +type CredentialTransport struct { + Transport http.RoundTripper + Credential CredentialIface +} + +func (t *CredentialTransport) GetCredential() (string, string, string, error) { + return t.Credential.GetSecretId(), t.Credential.GetSecretKey(), t.Credential.GetToken(), nil +} + +func (t *CredentialTransport) RoundTrip(req *http.Request) (*http.Response, error) { + ak, sk, token := t.Credential.GetSecretId(), t.Credential.GetSecretKey(), t.Credential.GetToken() + + req = cloneRequest(req) + // 增加 Authorization header + authTime := NewAuthTime(defaultAuthExpire) + AddAuthorizationHeader(ak, sk, token, req, authTime) + + resp, err := t.transport().RoundTrip(req) + return resp, err +} + +func (t *CredentialTransport) transport() http.RoundTripper { + if t.Transport != nil { + return t.Transport + } + return http.DefaultTransport +} + +type CredentialIface interface { + GetSecretId() string + GetToken() string + GetSecretKey() string +} + +func NewTokenCredential(secretId, secretKey, token string) *Credential { + return &Credential{ + SecretID: secretId, + SecretKey: secretKey, + SessionToken: token, + } +} + +func (c *Credential) GetSecretKey() string { + return c.SecretKey +} + +func (c *Credential) GetSecretId() string { + return c.SecretID +} + +func (c *Credential) GetToken() string { + return c.SessionToken +} + +// 通过sts访问 +type Credentials struct { + TmpSecretID string `json:"TmpSecretId,omitempty"` + TmpSecretKey string `json:"TmpSecretKey,omitempty"` + SessionToken string `json:"Token,omitempty"` +} +type CredentialError struct { + Code string `json:"Code,omitempty"` + Message string `json:"Message,omitempty"` + RequestId string `json:"RequestId,omitempty"` +} + +func (e *CredentialError) Error() string { + return fmt.Sprintf("Code: %v, Message: %v, RequestId: %v", e.Code, e.Message, e.RequestId) +} + +type CredentialResult struct { + Credentials *Credentials `json:"Credentials,omitempty"` + ExpiredTime int64 `json:"ExpiredTime,omitempty"` + RequestId string `json:"RequestId,omitempty"` + Error *CredentialError `json:"Error,omitempty"` +} + +type CredentialCompleteResult struct { + Response *CredentialResult `json:"Response"` +} + +type CredentialPolicyStatement struct { + Action []string `json:"action,omitempty"` + Effect string `json:"effect,omitempty"` + Resource []string `json:"resource,omitempty"` + Condition map[string]map[string]interface{} `json:"condition,omitempty"` +} + +type CredentialPolicy struct { + Version string `json:"version,omitempty"` + Statement []CredentialPolicyStatement `json:"statement,omitempty"` +} + +type StsCredentialTransport struct { + Transport http.RoundTripper + SecretID string + SecretKey string + Policy *CredentialPolicy + Host string + Region string + expiredTime int64 + credential Credentials + rwLocker sync.RWMutex +} + +func (t *StsCredentialTransport) UpdateCredential(now int64) (string, string, string, error) { + t.rwLocker.Lock() + defer t.rwLocker.Unlock() + if t.expiredTime > now+defaultTmpAuthExpire { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, nil + } + region := t.Region + if region == "" { + region = "ap-guangzhou" + } + policy, err := getPolicy(t.Policy) + if err != nil { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, err + } + params := map[string]interface{}{ + "SecretId": t.SecretID, + "Policy": url.QueryEscape(policy), + "DurationSeconds": 1800, + "Region": region, + "Timestamp": time.Now().Unix(), + "Nonce": math_rand.Int(), + "Name": "cos-sts-sdk", + "Action": "GetFederationToken", + "Version": "2018-08-13", + } + resp, err := t.sendRequest(params) + if err != nil { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, err + } + defer resp.Body.Close() + if resp.StatusCode > 299 { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, fmt.Errorf("sts StatusCode error: %v", resp.StatusCode) + } + result := &CredentialCompleteResult{} + err = json.NewDecoder(resp.Body).Decode(result) + if err == io.EOF { + err = nil // ignore EOF errors caused by empty response body + } + if err != nil { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, err + } + if result.Response != nil && result.Response.Error != nil { + result.Response.Error.RequestId = result.Response.RequestId + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, result.Response.Error + } + if result.Response != nil && result.Response.Credentials != nil { + t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, t.expiredTime = result.Response.Credentials.TmpSecretID, result.Response.Credentials.TmpSecretKey, result.Response.Credentials.SessionToken, result.Response.ExpiredTime + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, nil + } + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, fmt.Errorf("GetCredential failed, result: %v", result.Response) +} + +func (t *StsCredentialTransport) GetCredential() (string, string, string, error) { + now := time.Now().Unix() + t.rwLocker.RLock() + // 提前 defaultTmpAuthExpire 获取重新获取临时密钥 + if t.expiredTime <= now+defaultTmpAuthExpire { + expiredTime := t.expiredTime + t.rwLocker.RUnlock() + secretID, secretKey, secretToken, err := t.UpdateCredential(now) + // 获取临时密钥失败但密钥未过期 + if err != nil && now < expiredTime { + err = nil + } + return secretID, secretKey, secretToken, err + } + defer t.rwLocker.RUnlock() + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, nil +} + +func (t *StsCredentialTransport) RoundTrip(req *http.Request) (*http.Response, error) { + ak, sk, token, err := t.GetCredential() + if err != nil { + return nil, err + } + req = cloneRequest(req) + // 增加 Authorization header + authTime := NewAuthTime(defaultAuthExpire) + AddAuthorizationHeader(ak, sk, token, req, authTime) + + resp, err := t.transport().RoundTrip(req) + return resp, err +} + +func (t *StsCredentialTransport) transport() http.RoundTripper { + if t.Transport != nil { + return t.Transport + } + return http.DefaultTransport +} + +func (t *StsCredentialTransport) sendRequest(params map[string]interface{}) (*http.Response, error) { + paramValues := url.Values{} + for k, v := range params { + paramValues.Add(fmt.Sprintf("%v", k), fmt.Sprintf("%v", v)) + } + sign := t.signed("POST", params) + paramValues.Add("Signature", sign) + + host := defaultStsHost + if t.Host != "" { + host = t.Host + } + resp, err := http.DefaultClient.PostForm(defaultStsSchema+"://"+host, paramValues) + return resp, err +} + +func (t *StsCredentialTransport) signed(method string, params map[string]interface{}) string { + host := defaultStsHost + if t.Host != "" { + host = t.Host + } + source := method + host + "/?" + makeFlat(params) + + hmacObj := hmac.New(sha1.New, []byte(t.SecretKey)) + hmacObj.Write([]byte(source)) + + sign := base64.StdEncoding.EncodeToString(hmacObj.Sum(nil)) + + return sign +} + +func getPolicy(policy *CredentialPolicy) (string, error) { + if policy == nil { + return "", nil + } + res := policy + if policy.Version == "" { + res = &CredentialPolicy{ + Version: "2.0", + Statement: policy.Statement, + } + } + bs, err := json.Marshal(res) + if err != nil { + return "", err + } + return string(bs), nil +} + +func makeFlat(params map[string]interface{}) string { + keys := make([]string, 0, len(params)) + for k, _ := range params { + keys = append(keys, k) + } + sort.Strings(keys) + + var plainParms string + for _, k := range keys { + plainParms += fmt.Sprintf("&%v=%v", k, params[k]) + } + return plainParms[1:] +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/batch.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/batch.go new file mode 100644 index 00000000000..acfa7786dc4 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/batch.go @@ -0,0 +1,291 @@ +package cos + +import ( + "context" + "encoding/xml" + "fmt" + "net/http" +) + +type BatchService service + +type BatchRequestHeaders struct { + XCosAppid int `header:"x-cos-appid" xml:"-" url:"-"` + ContentLength string `header:"Content-Length,omitempty" xml:"-" url:"-"` + ContentType string `header:"Content-Type,omitempty" xml:"-" url:"-"` + Headers *http.Header `header:"-" xml:"-" url:"-"` +} + +// BatchProgressSummary +type BatchProgressSummary struct { + NumberOfTasksFailed int `xml:"NumberOfTasksFailed" header:"-" url:"-"` + NumberOfTasksSucceeded int `xml:"NumberOfTasksSucceeded" header:"-" url:"-"` + TotalNumberOfTasks int `xml:"TotalNumberOfTasks" header:"-" url:"-"` +} + +// BatchJobReport +type BatchJobReport struct { + Bucket string `xml:"Bucket" header:"-" url:"-"` + Enabled string `xml:"Enabled" header:"-" url:"-"` + Format string `xml:"Format" header:"-" url:"-"` + Prefix string `xml:"Prefix,omitempty" header:"-" url:"-"` + ReportScope string `xml:"ReportScope" header:"-" url:"-"` +} + +// BatchJobOperationCopy +type BatchCOSTag struct { + Key string `xml:"Key,omitempty" header:"-" url:"-"` + Value string `xml:"Value,omitempty" header:"-" url:"-"` +} +type BatchNewObjectTagging struct { + COSTag []BatchCOSTag `xml:"COSTag,omitempty" header:"-" url:"-"` +} + +type BatchMetadata struct { + Key string `xml:"Key" header:"-" url:"-"` + Value string `xml:"Value" header:"-" url:"-"` +} +type BatchNewObjectMetadata struct { + CacheControl string `xml:"CacheControl,omitempty" header:"-" url:"-"` + ContentDisposition string `xml:"ContentDisposition,omitempty" header:"-" url:"-"` + ContentEncoding string `xml:"ContentEncoding,omitempty" header:"-" url:"-"` + ContentType string `xml:"ContentType,omitempty" header:"-" url:"-"` + HttpExpiresDate string `xml:"HttpExpiresDate,omitempty" header:"-" url:"-"` + SSEAlgorithm string `xml:"SSEAlgorithm,omitempty" header:"-" url:"-"` + UserMetadata []BatchMetadata `xml:"UserMetadata>member,omitempty" header:"-" url:"-"` +} +type BatchGrantee struct { + DisplayName string `xml:"DisplayName,omitempty" header:"-" url:"-"` + Identifier string `xml:"Identifier" header:"-" url:"-"` + TypeIdentifier string `xml:"TypeIdentifier" header:"-" url:"-"` +} +type BatchCOSGrant struct { + Grantee *BatchGrantee `xml:"Grantee" header:"-" url:"-"` + Permission string `xml:"Permission" header:"-" url:"-"` +} +type BatchAccessControlGrants struct { + COSGrants *BatchCOSGrant `xml:"COSGrant,omitempty" header:"-" url:"-"` +} +type BatchJobOperationCopy struct { + AccessControlDirective string `xml:"AccessControlDirective,omitempty" header:"-" url:"-"` + AccessControlGrants *BatchAccessControlGrants `xml:"AccessControlGrants,omitempty" header:"-" url:"-"` + CannedAccessControlList string `xml:"CannedAccessControlList,omitempty" header:"-" url:"-"` + PrefixReplace bool `xml:"PrefixReplace,omitempty" header:"-" url:"-"` + ResourcesPrefix string `xml:"ResourcesPrefix,omitempty" header:"-" url:"-"` + TargetKeyPrefix string `xml:"TargetKeyPrefix,omitempty" header:"-" url:"-"` + MetadataDirective string `xml:"MetadataDirective,omitempty" header:"-" url:"-"` + ModifiedSinceConstraint int64 `xml:"ModifiedSinceConstraint,omitempty" header:"-" url:"-"` + UnModifiedSinceConstraint int64 `xml:"UnModifiedSinceConstraint,omitempty" header:"-" url:"-"` + NewObjectMetadata *BatchNewObjectMetadata `xml:"NewObjectMetadata,omitempty" header:"-" url:"-"` + TaggingDirective string `xml:"TaggingDirective,omitempty" header:"-" url:"-"` + NewObjectTagging *BatchNewObjectTagging `xml:"NewObjectTagging,omitempty" header:"-" url:"-"` + StorageClass string `xml:"StorageClass,omitempty" header:"-" url:"-"` + TargetResource string `xml:"TargetResource" header:"-" url:"-"` +} + +// BatchInitiateRestoreObject +type BatchInitiateRestoreObject struct { + ExpirationInDays int `xml:"ExpirationInDays"` + JobTier string `xml:"JobTier"` +} + +// BatchJobOperation +type BatchJobOperation struct { + PutObjectCopy *BatchJobOperationCopy `xml:"COSPutObjectCopy,omitempty" header:"-" url:"-"` + RestoreObject *BatchInitiateRestoreObject `xml:"COSInitiateRestoreObject,omitempty" header:"-" url:"-"` +} + +// BatchJobManifest +type BatchJobManifestLocation struct { + ETag string `xml:"ETag" header:"-" url:"-"` + ObjectArn string `xml:"ObjectArn" header:"-" url:"-"` + ObjectVersionId string `xml:"ObjectVersionId,omitempty" header:"-" url:"-"` +} +type BatchJobManifestSpec struct { + Fields []string `xml:"Fields>member,omitempty" header:"-" url:"-"` + Format string `xml:"Format" header:"-" url:"-"` +} +type BatchJobManifest struct { + Location *BatchJobManifestLocation `xml:"Location" header:"-" url:"-"` + Spec *BatchJobManifestSpec `xml:"Spec" header:"-" url:"-"` +} + +type BatchCreateJobOptions struct { + XMLName xml.Name `xml:"CreateJobRequest" header:"-" url:"-"` + ClientRequestToken string `xml:"ClientRequestToken" header:"-" url:"-"` + ConfirmationRequired string `xml:"ConfirmationRequired,omitempty" header:"-" url:"-"` + Description string `xml:"Description,omitempty" header:"-" url:"-"` + Manifest *BatchJobManifest `xml:"Manifest" header:"-" url:"-"` + Operation *BatchJobOperation `xml:"Operation" header:"-" url:"-"` + Priority int `xml:"Priority" header:"-" url:"-"` + Report *BatchJobReport `xml:"Report" header:"-" url:"-"` + RoleArn string `xml:"RoleArn" header:"-" url:"-"` +} + +type BatchCreateJobResult struct { + XMLName xml.Name `xml:"CreateJobResult"` + JobId string `xml:"JobId,omitempty"` +} + +func (s *BatchService) CreateJob(ctx context.Context, opt *BatchCreateJobOptions, headers *BatchRequestHeaders) (*BatchCreateJobResult, *Response, error) { + var res BatchCreateJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BatchURL, + uri: "/jobs", + method: http.MethodPost, + optHeader: headers, + body: opt, + result: &res, + } + + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type BatchJobFailureReasons struct { + FailureCode string `xml:"FailureCode" header:"-" url:"-"` + FailureReason string `xml:"FailureReason" header:"-" url:"-"` +} + +type BatchDescribeJob struct { + ConfirmationRequired string `xml:"ConfirmationRequired,omitempty" header:"-" url:"-"` + CreationTime string `xml:"CreationTime,omitempty" header:"-" url:"-"` + Description string `xml:"Description,omitempty" header:"-" url:"-"` + FailureReasons *BatchJobFailureReasons `xml:"FailureReasons>JobFailure,omitempty" header:"-" url:"-"` + JobId string `xml:"JobId" header:"-" url:"-"` + Manifest *BatchJobManifest `xml:"Manifest" header:"-" url:"-"` + Operation *BatchJobOperation `xml:"Operation" header:"-" url:"-"` + Priority int `xml:"Priority" header:"-" url:"-"` + ProgressSummary *BatchProgressSummary `xml:"ProgressSummary" header:"-" url:"-"` + Report *BatchJobReport `xml:"Report,omitempty" header:"-" url:"-"` + RoleArn string `xml:"RoleArn,omitempty" header:"-" url:"-"` + Status string `xml:"Status,omitempty" header:"-" url:"-"` + StatusUpdateReason string `xml:"StatusUpdateReason,omitempty" header:"-" url:"-"` + SuspendedCause string `xml:"SuspendedCause,omitempty" header:"-" url:"-"` + SuspendedDate string `xml:"SuspendedDate,omitempty" header:"-" url:"-"` + TerminationDate string `xml:"TerminationDate,omitempty" header:"-" url:"-"` +} +type BatchDescribeJobResult struct { + XMLName xml.Name `xml:"DescribeJobResult"` + Job *BatchDescribeJob `xml:"Job,omitempty"` +} + +func (s *BatchService) DescribeJob(ctx context.Context, id string, headers *BatchRequestHeaders) (*BatchDescribeJobResult, *Response, error) { + var res BatchDescribeJobResult + u := fmt.Sprintf("/jobs/%s", id) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BatchURL, + uri: u, + method: http.MethodGet, + optHeader: headers, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type BatchListJobsOptions struct { + JobStatuses string `url:"jobStatuses,omitempty" header:"-" xml:"-"` + MaxResults int `url:"maxResults,omitempty" header:"-" xml:"-"` + NextToken string `url:"nextToken,omitempty" header:"-" xml:"-"` +} + +type BatchListJobsMember struct { + CreationTime string `xml:"CreationTime,omitempty" header:"-" url:"-"` + Description string `xml:"Description,omitempty" header:"-" url:"-"` + JobId string `xml:"JobId,omitempty" header:"-" url:"-"` + Operation string `xml:"Operation,omitempty" header:"-" url:"-"` + Priority int `xml:"Priority,omitempty" header:"-" url:"-"` + ProgressSummary *BatchProgressSummary `xml:"ProgressSummary,omitempty" header:"-" url:"-"` + Status string `xml:"Status,omitempty" header:"-" url:"-"` + TerminationDate string `xml:"TerminationDate,omitempty" header:"-" url:"-"` +} +type BatchListJobs struct { + Members []BatchListJobsMember `xml:"member,omitempty" header:"-" url:"-"` +} +type BatchListJobsResult struct { + XMLName xml.Name `xml:"ListJobsResult"` + Jobs *BatchListJobs `xml:"Jobs,omitempty"` + NextToken string `xml:"NextToken,omitempty"` +} + +func (s *BatchService) ListJobs(ctx context.Context, opt *BatchListJobsOptions, headers *BatchRequestHeaders) (*BatchListJobsResult, *Response, error) { + var res BatchListJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BatchURL, + uri: "/jobs", + method: http.MethodGet, + optQuery: opt, + optHeader: headers, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type BatchUpdatePriorityOptions struct { + JobId string `url:"-" header:"-" xml:"-"` + Priority int `url:"priority" header:"-" xml:"-"` +} +type BatchUpdatePriorityResult struct { + XMLName xml.Name `xml:"UpdateJobPriorityResult"` + JobId string `xml:"JobId,omitempty"` + Priority int `xml:"Priority,omitempty"` +} + +func (s *BatchService) UpdateJobPriority(ctx context.Context, opt *BatchUpdatePriorityOptions, headers *BatchRequestHeaders) (*BatchUpdatePriorityResult, *Response, error) { + u := fmt.Sprintf("/jobs/%s/priority", opt.JobId) + var res BatchUpdatePriorityResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BatchURL, + uri: u, + method: http.MethodPost, + optQuery: opt, + optHeader: headers, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type BatchUpdateStatusOptions struct { + JobId string `header:"-" url:"-" xml:"-"` + RequestedJobStatus string `url:"requestedJobStatus" header:"-" xml:"-"` + StatusUpdateReason string `url:"statusUpdateReason,omitempty" header:"-" xml:"-"` +} +type BatchUpdateStatusResult struct { + XMLName xml.Name `xml:"UpdateJobStatusResult"` + JobId string `xml:"JobId,omitempty"` + Status string `xml:"Status,omitempty"` + StatusUpdateReason string `xml:"StatusUpdateReason,omitempty"` +} + +func (s *BatchService) UpdateJobStatus(ctx context.Context, opt *BatchUpdateStatusOptions, headers *BatchRequestHeaders) (*BatchUpdateStatusResult, *Response, error) { + u := fmt.Sprintf("/jobs/%s/status", opt.JobId) + var res BatchUpdateStatusResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BatchURL, + uri: u, + method: http.MethodPost, + optQuery: opt, + optHeader: headers, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *BatchService) DeleteJob(ctx context.Context, id string, headers *BatchRequestHeaders) (*Response, error) { + if len(id) == 0 { + return nil, fmt.Errorf("Id is invalid") + } + u := fmt.Sprintf("/jobs/%s", id) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BatchURL, + uri: u, + method: http.MethodDelete, + optHeader: headers, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go new file mode 100644 index 00000000000..65995aeba7e --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go @@ -0,0 +1,366 @@ +package cos + +import ( + "bytes" + "context" + "encoding/xml" + "errors" + "net/http" +) + +// BucketService 相关 API +type BucketService service + +// BucketGetResult is the result of GetBucket +type BucketGetResult struct { + XMLName xml.Name `xml:"ListBucketResult"` + Name string + Prefix string `xml:"Prefix,omitempty"` + Marker string `xml:"Marker,omitempty"` + NextMarker string `xml:"NextMarker,omitempty"` + Delimiter string `xml:"Delimiter,omitempty"` + MaxKeys int + IsTruncated bool + Contents []Object `xml:"Contents,omitempty"` + CommonPrefixes []string `xml:"CommonPrefixes>Prefix,omitempty"` + EncodingType string `xml:"EncodingType,omitempty"` +} + +// BucketGetOptions is the option of GetBucket +type BucketGetOptions struct { + Prefix string `url:"prefix,omitempty" header:"-" xml:"-"` + Delimiter string `url:"delimiter,omitempty" header:"-" xml:"-"` + EncodingType string `url:"encoding-type,omitempty" header:"-" xml:"-"` + Marker string `url:"marker,omitempty" header:"-" xml:"-"` + MaxKeys int `url:"max-keys,omitempty" header:"-" xml:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// Get Bucket请求等同于 List Object请求,可以列出该Bucket下部分或者所有Object,发起该请求需要拥有Read权限。 +// +// https://www.qcloud.com/document/product/436/7734 +func (s *BucketService) Get(ctx context.Context, opt *BucketGetOptions) (*BucketGetResult, *Response, error) { + var res BucketGetResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/", + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +// BucketPutOptions is same to the ACLHeaderOptions +type BucketPutOptions struct { + XCosACL string `header:"x-cos-acl,omitempty" url:"-" xml:"-"` + XCosGrantRead string `header:"x-cos-grant-read,omitempty" url:"-" xml:"-"` + XCosGrantWrite string `header:"x-cos-grant-write,omitempty" url:"-" xml:"-"` + XCosGrantFullControl string `header:"x-cos-grant-full-control,omitempty" url:"-" xml:"-"` + XCosGrantReadACP string `header:"x-cos-grant-read-acp,omitempty" url:"-" xml:"-"` + XCosGrantWriteACP string `header:"x-cos-grant-write-acp,omitempty" url:"-" xml:"-"` + XCosTagging string `header:"x-cos-tagging,omitempty" url:"-" xml:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` + CreateBucketConfiguration *CreateBucketConfiguration `header:"-" url:"-" xml:"-"` +} +type CreateBucketConfiguration struct { + XMLName xml.Name `xml:"CreateBucketConfiguration"` + BucketAZConfig string `xml:"BucketAZConfig,omitempty"` + BucketArchConfig string `xml:"BucketArchConfig,omitempty"` +} + +// Put Bucket请求可以在指定账号下创建一个Bucket。 +// +// https://www.qcloud.com/document/product/436/7738 +func (s *BucketService) Put(ctx context.Context, opt *BucketPutOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/", + method: http.MethodPut, + optHeader: opt, + } + if opt != nil && opt.CreateBucketConfiguration != nil { + sendOpt.body = opt.CreateBucketConfiguration + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +type BucketDeleteOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// Delete Bucket请求可以在指定账号下删除Bucket,删除之前要求Bucket为空。 +// +// https://www.qcloud.com/document/product/436/7732 +func (s *BucketService) Delete(ctx context.Context, opt ...*BucketDeleteOptions) (*Response, error) { + var dopt *BucketDeleteOptions + if len(opt) > 0 { + dopt = opt[0] + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/", + method: http.MethodDelete, + optHeader: dopt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +type BucketHeadOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// Head Bucket请求可以确认是否存在该Bucket,是否有权限访问,Head的权限与Read一致。 +// +// 当其存在时,返回 HTTP 状态码200; +// 当无权限时,返回 HTTP 状态码403; +// 当不存在时,返回 HTTP 状态码404。 +// +// https://www.qcloud.com/document/product/436/7735 +func (s *BucketService) Head(ctx context.Context, opt ...*BucketHeadOptions) (*Response, error) { + var hopt *BucketHeadOptions + if len(opt) > 0 { + hopt = opt[0] + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/", + method: http.MethodHead, + optHeader: hopt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +func (s *BucketService) IsExist(ctx context.Context) (bool, error) { + _, err := s.Head(ctx) + if err == nil { + return true, nil + } + if IsNotFoundError(err) { + return false, nil + } + return false, err +} + +// Bucket is the meta info of Bucket +type Bucket struct { + Name string + Region string `xml:"Location,omitempty"` + CreationDate string `xml:",omitempty"` + BucketType string `xml:",omitempty"` +} + +type BucketGetObjectVersionsOptions struct { + Prefix string `url:"prefix,omitempty" header:"-"` + Delimiter string `url:"delimiter,omitempty" header:"-"` + EncodingType string `url:"encoding-type,omitempty" header:"-"` + KeyMarker string `url:"key-marker,omitempty" header:"-"` + VersionIdMarker string `url:"version-id-marker,omitempty" header:"-"` + MaxKeys int `url:"max-keys,omitempty" header:"-"` + XOptionHeader *http.Header `url:"-" header:"-,omitempty" xml:"-"` +} + +type BucketGetObjectVersionsResult struct { + XMLName xml.Name `xml:"ListVersionsResult"` + Name string `xml:"Name,omitempty"` + EncodingType string `xml:"EncodingType,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + KeyMarker string `xml:"KeyMarker,omitempty"` + VersionIdMarker string `xml:"VersionIdMarker,omitempty"` + MaxKeys int `xml:"MaxKeys,omitempty"` + Delimiter string `xml:"Delimiter,omitempty"` + IsTruncated bool `xml:"IsTruncated,omitempty"` + NextKeyMarker string `xml:"NextKeyMarker,omitempty"` + NextVersionIdMarker string `xml:"NextVersionIdMarker,omitempty"` + CommonPrefixes []string `xml:"CommonPrefixes>Prefix,omitempty"` + Version []ListVersionsResultVersion `xml:"Version,omitempty"` + DeleteMarker []ListVersionsResultDeleteMarker `xml:"DeleteMarker,omitempty"` +} + +type ListVersionsResultVersion struct { + Key string `xml:"Key,omitempty"` + VersionId string `xml:"VersionId,omitempty"` + IsLatest bool `xml:"IsLatest,omitempty"` + LastModified string `xml:"LastModified,omitempty"` + ETag string `xml:"ETag,omitempty"` + Size int64 `xml:"Size,omitempty"` + StorageClass string `xml:"StorageClass,omitempty"` + Owner *Owner `xml:"Owner,omitempty"` +} + +type ListVersionsResultDeleteMarker struct { + Key string `xml:"Key,omitempty"` + VersionId string `xml:"VersionId,omitempty"` + IsLatest bool `xml:"IsLatest,omitempty"` + LastModified string `xml:"LastModified,omitempty"` + Owner *Owner `xml:"Owner,omitempty"` +} + +func (s *BucketService) GetObjectVersions(ctx context.Context, opt *BucketGetObjectVersionsOptions) (*BucketGetObjectVersionsResult, *Response, error) { + var res BucketGetObjectVersionsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?versions", + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +type BucketGetMetadataResult struct { + BucketUrl string + BucketName string + Location string + MAZ bool + OFS bool + Encryption *BucketGetEncryptionResult + ACL *BucketGetACLResult + Website *BucketGetWebsiteResult + Logging *BucketGetLoggingResult + CORS *BucketGetCORSResult + Versioning *BucketGetVersionResult + Lifecycle *BucketGetLifecycleResult + IntelligentTiering *ListIntelligentTieringConfigurations + Tagging *BucketGetTaggingResult + ObjectLock *BucketGetObjectLockResult + Replication *BucketGetReplicationResult +} + +func (s *BucketService) GetMeta(ctx context.Context, bucket ...string) (*BucketGetMetadataResult, *Response, error) { + if s.client.BaseURL.BucketURL == nil { + return nil, nil, errors.New("BucketURL is empty") + } + var customDomain bool + if !hostPrefix.MatchString(s.client.BaseURL.BucketURL.String()) { + customDomain = true + if len(bucket) == 0 || !bucketChecker.MatchString(bucket[0]) { + return nil, nil, errors.New("you must provide bucket-appid param in using custom domain") + } + } + var err error + var resp *Response + var res BucketGetMetadataResult + + resp, err = s.Head(ctx) + if err != nil { + return nil, resp, err + } + // 非自定义域名 + if !customDomain { + res.BucketName, res.Location = GetBucketRegionFromUrl(s.client.BaseURL.BucketURL) + } else { + res.BucketName, res.Location = bucket[0], resp.Header.Get("X-Cos-Bucket-Region") + } + w := bytes.NewBuffer(nil) + bucketURLTemplate.Execute(w, struct { + Schema string + BucketName string + Region string + }{"https", res.BucketName, res.Location}) + res.BucketUrl = w.String() + + if resp.Header.Get("X-Cos-Bucket-Az-Type") == "MAZ" { + res.MAZ = true + } + if resp.Header.Get("X-Cos-Bucket-Arch") == "OFS" { + res.OFS = true + } + + res.Encryption, resp, err = s.GetEncryption(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Encryption = nil + } else { + return nil, resp, err + } + } + res.ACL, resp, err = s.GetACL(ctx) + if err != nil { + if IsNotFoundError(err) { + res.ACL = nil + } else { + return nil, resp, err + } + } + res.Website, resp, err = s.GetWebsite(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Website = nil + } else { + return nil, resp, err + } + } + res.Logging, resp, err = s.GetLogging(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Logging = nil + } else { + return nil, resp, err + } + } + res.CORS, resp, err = s.GetCORS(ctx) + if err != nil { + if IsNotFoundError(err) { + res.CORS = nil + } else { + return nil, resp, err + } + } + res.Versioning, resp, err = s.GetVersioning(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Versioning = nil + } else { + return nil, resp, err + } + } + res.Lifecycle, resp, err = s.GetLifecycle(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Lifecycle = nil + } else { + return nil, resp, err + } + } + res.IntelligentTiering, resp, err = s.ListIntelligentTiering(ctx) + if err != nil { + if IsNotFoundError(err) { + res.IntelligentTiering = nil + } else { + return nil, resp, err + } + } + res.Tagging, resp, err = s.GetTagging(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Tagging = nil + } else { + return nil, resp, err + } + } + res.ObjectLock, resp, err = s.GetObjectLockConfiguration(ctx) + if err != nil { + if IsNotFoundError(err) { + res.ObjectLock = nil + } else { + return nil, resp, err + } + } + res.Replication, resp, err = s.GetBucketReplication(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Replication = nil + } else { + return nil, resp, err + } + } + return &res, resp, nil +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_accelerate.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_accelerate.go new file mode 100644 index 00000000000..48192db2f72 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_accelerate.go @@ -0,0 +1,37 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type BucketPutAccelerateOptions struct { + XMLName xml.Name `xml:"AccelerateConfiguration"` + Status string `xml:"Status,omitempty"` + Type string `xml:"Type,omitempty"` +} +type BucketGetAccelerateResult BucketPutAccelerateOptions + +func (s *BucketService) PutAccelerate(ctx context.Context, opt *BucketPutAccelerateOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?accelerate", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetAccelerate(ctx context.Context) (*BucketGetAccelerateResult, *Response, error) { + var res BucketGetAccelerateResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?accelerate", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go new file mode 100644 index 00000000000..d2069cfa3a5 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go @@ -0,0 +1,62 @@ +package cos + +import ( + "context" + "net/http" +) + +// BucketGetACLResult is same to the ACLXml +type BucketGetACLResult = ACLXml + +// GetACL 使用API读取Bucket的ACL表,只有所有者有权操作。 +// +// https://www.qcloud.com/document/product/436/7733 +func (s *BucketService) GetACL(ctx context.Context) (*BucketGetACLResult, *Response, error) { + var res BucketGetACLResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?acl", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + if err == nil { + decodeACL(resp, &res) + } + return &res, resp, err +} + +// BucketPutACLOptions is the option of PutBucketACL +type BucketPutACLOptions struct { + Header *ACLHeaderOptions `url:"-" xml:"-"` + Body *ACLXml `url:"-" header:"-"` +} + +// PutACL 使用API写入Bucket的ACL表,您可以通过Header:"x-cos-acl","x-cos-grant-read", +// "x-cos-grant-write","x-cos-grant-full-control"传入ACL信息,也可以通过body以XML格式传入ACL信息, +// +// 但是只能选择Header和Body其中一种,否则返回冲突。 +// +// Put Bucket ACL是一个覆盖操作,传入新的ACL将覆盖原有ACL。只有所有者有权操作。 +// +// "x-cos-acl":枚举值为public-read,private;public-read意味这个Bucket有公有读私有写的权限, +// private意味这个Bucket有私有读写的权限。 +// +// "x-cos-grant-read":意味被赋予权限的用户拥有该Bucket的读权限 +// "x-cos-grant-write":意味被赋予权限的用户拥有该Bucket的写权限 +// "x-cos-grant-full-control":意味被赋予权限的用户拥有该Bucket的读写权限 +// +// https://www.qcloud.com/document/product/436/7737 +func (s *BucketService) PutACL(ctx context.Context, opt *BucketPutACLOptions) (*Response, error) { + header := opt.Header + body := opt.Body + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?acl", + method: http.MethodPut, + body: body, + optHeader: header, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go new file mode 100644 index 00000000000..29f085fedfa --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go @@ -0,0 +1,73 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +// BucketCORSRule is the rule of BucketCORS +type BucketCORSRule struct { + ID string `xml:"ID,omitempty"` + AllowedMethods []string `xml:"AllowedMethod"` + AllowedOrigins []string `xml:"AllowedOrigin"` + AllowedHeaders []string `xml:"AllowedHeader,omitempty"` + MaxAgeSeconds int `xml:"MaxAgeSeconds,omitempty"` + ExposeHeaders []string `xml:"ExposeHeader,omitempty"` +} + +// BucketGetCORSResult is the result of GetBucketCORS +type BucketGetCORSResult struct { + XMLName xml.Name `xml:"CORSConfiguration"` + Rules []BucketCORSRule `xml:"CORSRule,omitempty"` + ResponseVary string `xml:"ResponseVary,omitempty"` +} + +// GetCORS 实现 Bucket 跨域访问配置读取。 +// +// https://www.qcloud.com/document/product/436/8274 +func (s *BucketService) GetCORS(ctx context.Context) (*BucketGetCORSResult, *Response, error) { + var res BucketGetCORSResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?cors", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +// BucketPutCORSOptions is the option of PutBucketCORS +type BucketPutCORSOptions struct { + XMLName xml.Name `xml:"CORSConfiguration"` + Rules []BucketCORSRule `xml:"CORSRule,omitempty"` + ResponseVary string `xml:"ResponseVary,omitempty"` +} + +// PutCORS 实现 Bucket 跨域访问设置,您可以通过传入XML格式的配置文件实现配置,文件大小限制为64 KB。 +// +// https://www.qcloud.com/document/product/436/8279 +func (s *BucketService) PutCORS(ctx context.Context, opt *BucketPutCORSOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?cors", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +// DeleteCORS 实现 Bucket 跨域访问配置删除。 +// +// https://www.qcloud.com/document/product/436/8283 +func (s *BucketService) DeleteCORS(ctx context.Context) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?cors", + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go new file mode 100644 index 00000000000..fe23f14a44e --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go @@ -0,0 +1,133 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type BucketDomainRule struct { + Status string `xml:"Status,omitempty"` + Name string `xml:"Name,omitempty"` + Type string `xml:"Type,omitempty"` + ForcedReplacement string `xml:"ForcedReplacement,omitempty"` +} + +type BucketPutDomainOptions struct { + XMLName xml.Name `xml:"DomainConfiguration"` + Rules []BucketDomainRule `xml:"DomainRule,omitempty"` +} +type BucketGetDomainResult BucketPutDomainOptions + +func (s *BucketService) PutDomain(ctx context.Context, opt *BucketPutDomainOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domain", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +type BucketGetDomainOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +func (s *BucketService) GetDomain(ctx context.Context, opt ...*BucketGetDomainOptions) (*BucketGetDomainResult, *Response, error) { + var gopt *BucketGetDomainOptions + if len(opt) > 0 { + gopt = opt[0] + } + var res BucketGetDomainResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domain", + method: http.MethodGet, + result: &res, + optHeader: gopt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +type BucketDeleteDomainOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +func (s *BucketService) DeleteDomain(ctx context.Context, opt ...*BucketDeleteDomainOptions) (*Response, error) { + var dopt *BucketDeleteDomainOptions + if len(opt) > 0 { + dopt = opt[0] + } + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domain", + method: http.MethodDelete, + optHeader: dopt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +type BucketPutDomainCertificateOptions struct { + XMLName xml.Name `xml:"DomainCertificate"` + CertificateInfo *BucketDomainCertificateInfo `xml:"CertificateInfo"` + DomainList []string `xml:"DomainList>DomainName"` +} + +type BucketDomainCertificateInfo struct { + CertType string `xml:"CertType,omitempty"` + CustomCert *BucketDomainCustomCert `xml:"CustomCert,omitempty"` +} +type BucketDomainCustomCert struct { + CertId string `xml:"CertId,omitempty"` + Cert string `xml:"Cert,omitempty"` + PrivateKey string `xml:"PrivateKey,omitempty"` +} + +func (s *BucketService) PutDomainCertificate(ctx context.Context, opt *BucketPutDomainCertificateOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domaincertificate", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +type BucketGetDomainCertificateResult struct { + XMLName xml.Name `xml:"DomainCertificate"` + Status string `xml:"Status,omitempty"` +} + +type BucketGetDomainCertificateOptions struct { + DomainName string `url:"domainname"` +} + +type BucketDeleteDomainCertificateOptions BucketGetDomainCertificateOptions + +func (s *BucketService) GetDomainCertificate(ctx context.Context, opt *BucketGetDomainCertificateOptions) (*BucketGetDomainCertificateResult, *Response, error) { + var res BucketGetDomainCertificateResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domaincertificate", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +func (s *BucketService) DeleteDomainCertificate(ctx context.Context, opt *BucketDeleteDomainCertificateOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domaincertificate", + method: http.MethodDelete, + optQuery: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go new file mode 100644 index 00000000000..2fa2f98902b --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go @@ -0,0 +1,52 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type BucketEncryptionConfiguration struct { + SSEAlgorithm string `xml:"SSEAlgorithm"` + KMSMasterKeyID string `xml:"KMSMasterKeyID,omitempty"` +} + +type BucketPutEncryptionOptions struct { + XMLName xml.Name `xml:"ServerSideEncryptionConfiguration"` + Rule *BucketEncryptionConfiguration `xml:"Rule>ApplyServerSideEncryptionByDefault"` +} + +type BucketGetEncryptionResult BucketPutEncryptionOptions + +func (s *BucketService) PutEncryption(ctx context.Context, opt *BucketPutEncryptionOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?encryption", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetEncryption(ctx context.Context) (*BucketGetEncryptionResult, *Response, error) { + var res BucketGetEncryptionResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?encryption", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +func (s *BucketService) DeleteEncryption(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?encryption", + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go new file mode 100644 index 00000000000..d5967a8a70c --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go @@ -0,0 +1,142 @@ +package cos + +import ( + "context" + "encoding/xml" + "errors" + "net/http" +) + +type BucketIntelligentTieringFilterAnd struct { + Prefix string `xml:"Prefix,omitempty" header:"-"` + Tag []*BucketTaggingTag `xml:"Tag,omitempty" header:"-"` +} + +type BucketIntelligentTieringFilter struct { + And *BucketIntelligentTieringFilterAnd `xml:"And,omitempty" header:"-"` + Prefix string `xml:"Prefix,omitempty" header:"-"` + Tag []*BucketTaggingTag `xml:"Tag,omitempty" header:"-"` +} + +type BucketIntelligentTieringTransition struct { + AccessTier string `xml:"AccessTier,omitempty" header:"-"` + Days int `xml:"Days,omitempty" header:"-"` + RequestFrequent int `xml:"RequestFrequent,omitempty" header:"-"` +} + +type BucketPutIntelligentTieringOptions struct { + XMLName xml.Name `xml:"IntelligentTieringConfiguration" header:"-"` + Status string `xml:"Status,omitempty" header:"-"` + Transition *BucketIntelligentTieringTransition `xml:"Transition,omitempty" header:"-"` + + // V2 + Id string `xml:"Id,omitempty" header:"-"` + Tiering []*BucketIntelligentTieringTransition `xml:"Tiering,omitempty" header:"-"` + Filter *BucketIntelligentTieringFilter `xml:"Filter,omitempty" header:"-"` + + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +type BucketGetIntelligentTieringResult BucketPutIntelligentTieringOptions + +type BucketGetIntelligentTieringOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +type IntelligentTieringConfiguration struct { + Id string `xml:"Id"` + Status string `xml:"Status"` + Tiering []*BucketIntelligentTieringTransition `xml:"Tiering"` + Filter *BucketIntelligentTieringFilter `xml:"Filter,omitempty"` +} + +type ListIntelligentTieringConfigurations struct { + XMLName xml.Name `xml:"ListBucketIntelligentTieringConfigurationsOutput"` + Configurations []*IntelligentTieringConfiguration `xml:"IntelligentTieringConfiguration,omitempty"` +} + +func (s *BucketService) PutIntelligentTiering(ctx context.Context, opt *BucketPutIntelligentTieringOptions) (*Response, error) { + if opt != nil && opt.Transition != nil { + opt.Transition.RequestFrequent = 1 + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligenttiering", + method: http.MethodPut, + optHeader: opt, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +func (s *BucketService) GetIntelligentTiering(ctx context.Context, opt ...*BucketGetIntelligentTieringOptions) (*BucketGetIntelligentTieringResult, *Response, error) { + var optHeader *BucketGetIntelligentTieringOptions + if len(opt) > 0 { + optHeader = opt[0] + } + var res BucketGetIntelligentTieringResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligenttiering", + method: http.MethodGet, + optHeader: optHeader, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +func (s *BucketService) PutIntelligentTieringV2(ctx context.Context, opt *BucketPutIntelligentTieringOptions) (*Response, error) { + if opt == nil || opt.Id == "" { + return nil, errors.New("id is empty") + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering&id=" + opt.Id, + method: http.MethodPut, + optHeader: opt, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +func (s *BucketService) GetIntelligentTieringV2(ctx context.Context, id string, opt ...*BucketGetIntelligentTieringOptions) (*BucketGetIntelligentTieringResult, *Response, error) { + var optHeader *BucketGetIntelligentTieringOptions + if len(opt) > 0 { + optHeader = opt[0] + } + var res BucketGetIntelligentTieringResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering&id=" + id, + method: http.MethodGet, + optHeader: optHeader, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +func (s *BucketService) ListIntelligentTiering(ctx context.Context) (*ListIntelligentTieringConfigurations, *Response, error) { + var res ListIntelligentTieringConfigurations + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +func (s *BucketService) DeleteIntelligentTiering(ctx context.Context, id string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering&id=" + id, + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go new file mode 100644 index 00000000000..747086f4b51 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go @@ -0,0 +1,154 @@ +package cos + +import ( + "context" + "encoding/xml" + "fmt" + "net/http" +) + +// Notice bucket_inventory only for test. can not use + +// BucketGetInventoryResult same struct to options +type BucketGetInventoryResult BucketPutInventoryOptions + +// BucketListInventoryConfiguartion same struct to options +type BucketListInventoryConfiguartion BucketPutInventoryOptions + +type BucketInventoryFilterPeriod struct { + StartTime int64 `xml:"StartTime,omitempty"` + EndTime int64 `xml:"EndTime,omitempty"` +} + +// BucketInventoryFilter ... +type BucketInventoryFilter struct { + Prefix string `xml:"And>Prefix,omitempty"` + Tags []ObjectTaggingTag `xml:"And>Tag,omitempty"` + StorageClass string `xml:"And>StorageClass,omitempty"` + Period *BucketInventoryFilterPeriod `xml:"Period,omitempty"` +} + +// BucketInventoryOptionalFields ... +type BucketInventoryOptionalFields struct { + BucketInventoryFields []string `xml:"Field,omitempty"` +} + +// BucketInventorySchedule ... +type BucketInventorySchedule struct { + Frequency string `xml:"Frequency"` +} + +// BucketInventoryEncryption ... +type BucketInventoryEncryption struct { + SSECOS string `xml:"SSE-COS"` +} + +// BucketInventoryDestination ... +type BucketInventoryDestination struct { + Bucket string `xml:"Bucket"` + AccountId string `xml:"AccountId,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + Format string `xml:"Format"` + Encryption *BucketInventoryEncryption `xml:"Encryption,omitempty"` +} + +// BucketPutInventoryOptions ... +type BucketPutInventoryOptions struct { + XMLName xml.Name `xml:"InventoryConfiguration"` + ID string `xml:"Id"` + IsEnabled string `xml:"IsEnabled"` + IncludedObjectVersions string `xml:"IncludedObjectVersions"` + Filter *BucketInventoryFilter `xml:"Filter,omitempty"` + OptionalFields *BucketInventoryOptionalFields `xml:"OptionalFields,omitempty"` + Schedule *BucketInventorySchedule `xml:"Schedule"` + Destination *BucketInventoryDestination `xml:"Destination>COSBucketDestination"` +} + +type BucketPostInventoryOptions struct { + XMLName xml.Name `xml:"InventoryConfiguration"` + ID string `xml:"Id"` + IncludedObjectVersions string `xml:"IncludedObjectVersions"` + Filter *BucketInventoryFilter `xml:"Filter,omitempty"` + OptionalFields *BucketInventoryOptionalFields `xml:"OptionalFields,omitempty"` + Destination *BucketInventoryDestination `xml:"Destination>COSBucketDestination"` +} + +// ListBucketInventoryConfigResult result of ListBucketInventoryConfiguration +type ListBucketInventoryConfigResult struct { + XMLName xml.Name `xml:"ListInventoryConfigurationResult"` + InventoryConfigurations []BucketListInventoryConfiguartion `xml:"InventoryConfiguration,omitempty"` + IsTruncated bool `xml:"IsTruncated,omitempty"` + ContinuationToken string `xml:"ContinuationToken,omitempty"` + NextContinuationToken string `xml:"NextContinuationToken,omitempty"` +} + +// PutBucketInventory https://cloud.tencent.com/document/product/436/33707 +func (s *BucketService) PutInventory(ctx context.Context, id string, opt *BucketPutInventoryOptions) (*Response, error) { + u := fmt.Sprintf("/?inventory&id=%s", id) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err + +} + +// GetBucketInventory https://cloud.tencent.com/document/product/436/33705 +func (s *BucketService) GetInventory(ctx context.Context, id string) (*BucketGetInventoryResult, *Response, error) { + u := fmt.Sprintf("/?inventory&id=%s", id) + var res BucketGetInventoryResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +// DeleteBucketInventory https://cloud.tencent.com/document/product/436/33704 +func (s *BucketService) DeleteInventory(ctx context.Context, id string) (*Response, error) { + u := fmt.Sprintf("/?inventory&id=%s", id) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +// ListBucketInventoryConfigurations https://cloud.tencent.com/document/product/436/33706 +func (s *BucketService) ListInventoryConfigurations(ctx context.Context, token string) (*ListBucketInventoryConfigResult, *Response, error) { + var res ListBucketInventoryConfigResult + var u string + if token == "" { + u = "/?inventory" + } else { + u = fmt.Sprintf("/?inventory&continuation-token=%s", encodeURIComponent(token)) + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err + +} +func (s *BucketService) PostInventory(ctx context.Context, id string, opt *BucketPostInventoryOptions) (*Response, error) { + u := fmt.Sprintf("/?inventory&id=%s", id) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPost, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go new file mode 100644 index 00000000000..64f4b06b04e --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go @@ -0,0 +1,137 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type BucketLifecycleAndOperator struct { + Prefix string `xml:"Prefix,omitempty" header:"-"` + Tag []BucketTaggingTag `xml:"Tag,omitempty" header:"-"` + PrefixNotEquals string `xml:"PrefixNotEquals,omitempty" header:"-"` + ObjectSizeGreaterThan int64 `xml:"ObjectSizeGreaterThan,omitempty" header:"-"` + ObjectSizeLessThan int64 `xml:"ObjectSizeLessThan,omitempty" header:"-"` +} + +// BucketLifecycleFilter is the param of BucketLifecycleRule +type BucketLifecycleFilter struct { + Prefix string `xml:"Prefix,omitempty" header:"-"` + Tag *BucketTaggingTag `xml:"Tag,omitempty" header:"-"` + And *BucketLifecycleAndOperator `xml:"And,omitempty" header:"-"` +} + +// BucketLifecycleExpiration is the param of BucketLifecycleRule +type BucketLifecycleExpiration struct { + Date string `xml:"Date,omitempty" header:"-"` + Days int `xml:"Days,omitempty" header:"-"` + ExpiredObjectDeleteMarker bool `xml:"ExpiredObjectDeleteMarker,omitempty" header:"-"` +} + +type BucketAccessFrequency struct { + AccessCountLessThan int `xml:"AccessCountLessThan,omitempty" header:"-"` + RecentDays int `xml:"RecentDays,omitempty" header:"-"` +} + +// BucketLifecycleTransition is the param of BucketLifecycleRule +type BucketLifecycleTransition struct { + Date string `xml:"Date,omitempty" header:"-"` + Days int `xml:"Days,omitempty" header:"-"` + StorageClass string `xml:"StorageClass,omitempty" header:"-"` + AccessFrequency *BucketAccessFrequency `xml:"AccessFrequency,omitempty" header:"-"` +} + +type BucketLifecycleNoncurrentVersion struct { + NoncurrentDays int `xml:"NoncurrentDays,omitempty" header:"-"` + StorageClass string `xml:"StorageClass,omitempty" header:"-"` + AccessFrequency *BucketAccessFrequency `xml:"AccessFrequency,omitempty" header:"-"` +} + +// BucketLifecycleAbortIncompleteMultipartUpload is the param of BucketLifecycleRule +type BucketLifecycleAbortIncompleteMultipartUpload struct { + DaysAfterInitiation int `xml:"DaysAfterInitiation,omitempty" header:"-"` +} + +// BucketLifecycleRule is the rule of BucketLifecycle +type BucketLifecycleRule struct { + ID string `xml:"ID,omitempty" header:"-"` + Status string `xml:"Status,omitempty" header:"-"` + Filter *BucketLifecycleFilter `xml:"Filter,omitempty" header:"-"` + Transition []BucketLifecycleTransition `xml:"Transition,omitempty" header:"-"` + Expiration *BucketLifecycleExpiration `xml:"Expiration,omitempty" header:"-"` + AbortIncompleteMultipartUpload *BucketLifecycleAbortIncompleteMultipartUpload `xml:"AbortIncompleteMultipartUpload,omitempty" header:"-"` + NoncurrentVersionTransition []BucketLifecycleNoncurrentVersion `xml:"NoncurrentVersionTransition,omitempty" header:"-"` + NoncurrentVersionExpiration *BucketLifecycleNoncurrentVersion `xml:"NoncurrentVersionExpiration,omitempty" header:"-"` +} + +// BucketGetLifecycleResult is the result of BucketGetLifecycle +type BucketGetLifecycleResult struct { + XMLName xml.Name `xml:"LifecycleConfiguration" header:"-"` + Rules []BucketLifecycleRule `xml:"Rule,omitempty" header:"-"` +} + +type BucketGetLifecycleOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// GetLifecycle 请求实现读取生命周期管理的配置。当配置不存在时,返回404 Not Found。 +// https://www.qcloud.com/document/product/436/8278 +func (s *BucketService) GetLifecycle(ctx context.Context, opt ...*BucketGetLifecycleOptions) (*BucketGetLifecycleResult, *Response, error) { + var optHeader *BucketGetLifecycleOptions + if len(opt) > 0 { + optHeader = opt[0] + } + var res BucketGetLifecycleResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?lifecycle", + method: http.MethodGet, + optHeader: optHeader, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +// BucketPutLifecycleOptions is the option of PutBucketLifecycle +type BucketPutLifecycleOptions struct { + XMLName xml.Name `xml:"LifecycleConfiguration" header:"-"` + Rules []BucketLifecycleRule `xml:"Rule,omitempty" header:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// PutLifecycle 请求实现设置生命周期管理的功能。您可以通过该请求实现数据的生命周期管理配置和定期删除。 +// 此请求为覆盖操作,上传新的配置文件将覆盖之前的配置文件。生命周期管理对文件和文件夹同时生效。 +// https://www.qcloud.com/document/product/436/8280 +func (s *BucketService) PutLifecycle(ctx context.Context, opt *BucketPutLifecycleOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?lifecycle", + method: http.MethodPut, + optHeader: opt, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +type BucketDeleteLifecycleOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// DeleteLifecycle 请求实现删除生命周期管理。 +// https://www.qcloud.com/document/product/436/8284 +func (s *BucketService) DeleteLifecycle(ctx context.Context, opt ...*BucketDeleteLifecycleOptions) (*Response, error) { + var optHeader *BucketDeleteLifecycleOptions + if len(opt) > 0 { + optHeader = opt[0] + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?lifecycle", + optHeader: optHeader, + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go new file mode 100644 index 00000000000..d449f96d251 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go @@ -0,0 +1,28 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +// BucketGetLocationResult is the result of BucketGetLocation +type BucketGetLocationResult struct { + XMLName xml.Name `xml:"LocationConstraint"` + Location string `xml:",chardata"` +} + +// GetLocation 接口获取Bucket所在地域信息,只有Bucket所有者有权限读取信息。 +// +// https://www.qcloud.com/document/product/436/8275 +func (s *BucketService) GetLocation(ctx context.Context) (*BucketGetLocationResult, *Response, error) { + var res BucketGetLocationResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?location", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_logging.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_logging.go new file mode 100644 index 00000000000..88a1a95432d --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_logging.go @@ -0,0 +1,50 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +// Notice bucket logging function is testing, can not use. + +// BucketLoggingEnabled main struct of logging +type BucketLoggingEnabled struct { + TargetBucket string `xml:"TargetBucket"` + TargetPrefix string `xml:"TargetPrefix"` +} + +// BucketPutLoggingOptions is the options of PutBucketLogging +type BucketPutLoggingOptions struct { + XMLName xml.Name `xml:"BucketLoggingStatus"` + LoggingEnabled *BucketLoggingEnabled `xml:"LoggingEnabled,omitempty"` +} + +// BucketGetLoggingResult is the result of GetBucketLogging +type BucketGetLoggingResult BucketPutLoggingOptions + +// PutBucketLogging https://cloud.tencent.com/document/product/436/17054 +func (s *BucketService) PutLogging(ctx context.Context, opt *BucketPutLoggingOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?logging", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +// GetBucketLogging https://cloud.tencent.com/document/product/436/17053 +func (s *BucketService) GetLogging(ctx context.Context) (*BucketGetLoggingResult, *Response, error) { + var res BucketGetLoggingResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?logging", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err + +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go new file mode 100644 index 00000000000..662181190cf --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go @@ -0,0 +1,82 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type ObjectLockRule struct { + Days int `xml:"DefaultRetention>Days,omitempty"` +} + +type BucketPutObjectLockOptions struct { + XMLName xml.Name `xml:"ObjectLockConfiguration"` + ObjectLockEnabled string `xml:"ObjectLockEnabled,omitempty"` + Rule *ObjectLockRule `xml:"Rule,omitempty"` +} + +type BucketGetObjectLockResult BucketPutObjectLockOptions + +func (s *BucketService) PutObjectLockConfiguration(ctx context.Context, opt *BucketPutObjectLockOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?object-lock", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetObjectLockConfiguration(ctx context.Context) (*BucketGetObjectLockResult, *Response, error) { + var res BucketGetObjectLockResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?object-lock", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +type ObjectGetRetentionOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +type ObjectGetRetentionResult struct { + XMLName xml.Name `xml:"Retention"` + RetainUntilDate string `xml:"RetainUntilDate,omitempty"` + Mode string `xml:"Mode,omitempty"` +} + +func (s *ObjectService) GetRetention(ctx context.Context, key string, opt *ObjectGetRetentionOptions) (*ObjectGetRetentionResult, *Response, error) { + var res ObjectGetRetentionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(key) + "?retention", + method: http.MethodGet, + optHeader: opt, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +type ObjectPutRetentionOptions struct { + XMLName xml.Name `xml:"Retention"` + RetainUntilDate string `xml:"RetainUntilDate,omitempty"` + Mode string `xml:"Mode,omitempty"` +} + +func (s *ObjectService) PutRetention(ctx context.Context, key string, opt *ObjectPutRetentionOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(key) + "?retention", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go new file mode 100644 index 00000000000..a4af7214e48 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go @@ -0,0 +1,193 @@ +package cos + +import ( + "context" + "encoding/xml" + "fmt" + "github.com/clbanning/mxj" + "net/http" + "strconv" + "strings" +) + +type BucketPutOriginOptions struct { + XMLName xml.Name `xml:"OriginConfiguration"` + Rule []BucketOriginRule `xml:"OriginRule"` +} + +type BucketOriginRule struct { + RulePriority int `xml:"RulePriority,omitempty"` + OriginType string `xml:"OriginType,omitempty"` + OriginCondition *BucketOriginCondition `xml:"OriginCondition,omitempty"` + OriginParameter *BucketOriginParameter `xml:"OriginParameter,omitempty"` + OriginInfo *BucketOriginInfo `xml:"OriginInfo,omitempty"` +} + +type BucketOriginCondition struct { + HTTPStatusCode string `xml:"HTTPStatusCode,omitempty"` + Prefix string `xml:"Prefix,omitempty"` +} + +type BucketOriginParameter struct { + Protocol string `xml:"Protocol,omitempty"` + FollowQueryString *bool `xml:"FollowQueryString,omitempty"` + HttpHeader *BucketOriginHttpHeader `xml:"HttpHeader,omitempty"` + FollowRedirection *bool `xml:"FollowRedirection,omitempty"` + HttpRedirectCode string `xml:"HttpRedirectCode,omitempty"` + CopyOriginData *bool `xml:"CopyOriginData,omitempty"` +} + +type BucketOriginHttpHeader struct { + // 目前还不支持 FollowAllHeaders + FollowAllHeaders *bool `xml:"FollowAllHeaders,omitempty"` + NewHttpHeaders []OriginHttpHeader `xml:"NewHttpHeaders>Header,omitempty"` + FollowHttpHeaders []OriginHttpHeader `xml:"FollowHttpHeaders>Header,omitempty"` + ForbidFollowHeaders []OriginHttpHeader `xml:"ForbidFollowHeaders>Header,omitempty"` +} + +type OriginHttpHeader struct { + Key string `xml:"Key,omitempty"` + Value string `xml:"Value,omitempty"` +} + +type BucketOriginInfo struct { + HostInfo *BucketOriginHostInfo `xml:"HostInfo,omitempty"` + FileInfo *BucketOriginFileInfo `xml:"FileInfo,omitempty"` +} + +type BucketOriginHostInfo struct { + HostName string + Weight int64 + StandbyHostName_N []string +} + +type BucketOriginFileInfo struct { + // 兼容旧版本 + PrefixDirective bool `xml:"PrefixDirective,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + Suffix string `xml:"Suffix,omitempty"` + // 新版本 + PrefixConfiguration *OriginPrefixConfiguration `xml:"PrefixConfiguration,omitempty"` + SuffixConfiguration *OriginSuffixConfiguration `xml:"SuffixConfiguration,omitempty"` + FixedFileConfiguration *OriginFixedFileConfiguration `xml:"FixedFileConfiguration,omitempty"` +} + +type OriginPrefixConfiguration struct { + Prefix string `xml:"Prefix,omitempty"` +} + +type OriginSuffixConfiguration struct { + Suffix string `xml:"Suffix,omitempty"` +} + +type OriginFixedFileConfiguration struct { + FixedFilePath string `xml:"FixedFilePath,omitempty"` +} + +type BucketGetOriginResult BucketPutOriginOptions + +func (this *BucketOriginHostInfo) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if this == nil { + return nil + } + err := e.EncodeToken(start) + if err != nil { + return err + } + if this.HostName != "" { + err = e.EncodeElement(this.HostName, xml.StartElement{Name: xml.Name{Local: "HostName"}}) + if err != nil { + return err + } + } + if this.Weight != 0 { + err = e.EncodeElement(this.Weight, xml.StartElement{Name: xml.Name{Local: "Weight"}}) + if err != nil { + return err + } + } + for index, standByHostName := range this.StandbyHostName_N { + err = e.EncodeElement(standByHostName, xml.StartElement{Name: xml.Name{Local: fmt.Sprintf("StandbyHostName_%v", index+1)}}) + if err != nil { + return err + } + } + return e.EncodeToken(xml.EndElement{Name: start.Name}) +} + +func (this *BucketOriginHostInfo) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var val struct { + XMLName xml.Name + Inner []byte `xml:",innerxml"` + } + err := d.DecodeElement(&val, &start) + if err != nil { + return err + } + str := "" + string(val.Inner) + "" + myMxjMap, err := mxj.NewMapXml([]byte(str)) + if err != nil { + return err + } + myMap, ok := myMxjMap["HostInfo"].(map[string]interface{}) + if !ok { + return fmt.Errorf("XML HostInfo Parse failed") + } + + var total int + for key, value := range myMap { + if key == "HostName" { + this.HostName = value.(string) + } + if key == "Weight" { + v := value.(string) + this.Weight, err = strconv.ParseInt(v, 10, 64) + if err != nil { + return err + } + } + if strings.HasPrefix(key, "StandbyHostName_") { + total++ + } + } + // 按顺序执行 + for i := 1; i <= total; i++ { + key := fmt.Sprintf("StandbyHostName_%v", i) + this.StandbyHostName_N = append(this.StandbyHostName_N, myMap[key].(string)) + } + + return nil +} + +func (s *BucketService) PutOrigin(ctx context.Context, opt *BucketPutOriginOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?origin", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetOrigin(ctx context.Context) (*BucketGetOriginResult, *Response, error) { + var res BucketGetOriginResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?origin", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +func (s *BucketService) DeleteOrigin(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?origin", + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go new file mode 100644 index 00000000000..85923cec794 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go @@ -0,0 +1,59 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +// ListMultipartUploadsResult is the result of ListMultipartUploads +type ListMultipartUploadsResult struct { + XMLName xml.Name `xml:"ListMultipartUploadsResult"` + Bucket string `xml:"Bucket"` + EncodingType string `xml:"Encoding-Type"` + KeyMarker string + UploadIDMarker string `xml:"UploadIdMarker"` + NextKeyMarker string + NextUploadIDMarker string `xml:"NextUploadIdMarker"` + MaxUploads int + IsTruncated bool + Uploads []struct { + Key string + UploadID string `xml:"UploadId"` + StorageClass string + Initiator *Initiator + Owner *Owner + Initiated string + } `xml:"Upload,omitempty"` + Prefix string + Delimiter string `xml:"delimiter,omitempty"` + CommonPrefixes []string `xml:"CommonPrefixs>Prefix,omitempty"` +} + +// ListMultipartUploadsOptions is the option of ListMultipartUploads +type ListMultipartUploadsOptions struct { + Delimiter string `url:"delimiter,omitempty"` + EncodingType string `url:"encoding-type,omitempty"` + Prefix string `url:"prefix,omitempty"` + MaxUploads int `url:"max-uploads,omitempty"` + KeyMarker string `url:"key-marker,omitempty"` + UploadIDMarker string `url:"upload-id-marker,omitempty"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// ListMultipartUploads 用来查询正在进行中的分块上传。单次最多列出1000个正在进行中的分块上传。 +// +// https://www.qcloud.com/document/product/436/7736 +func (s *BucketService) ListMultipartUploads(ctx context.Context, opt *ListMultipartUploadsOptions) (*ListMultipartUploadsResult, *Response, error) { + var res ListMultipartUploadsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?uploads", + method: http.MethodGet, + result: &res, + optQuery: opt, + optHeader: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go new file mode 100644 index 00000000000..97c55509c80 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go @@ -0,0 +1,77 @@ +package cos + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "strings" +) + +type BucketStatement struct { + Principal map[string][]string `json:"principal,omitempty"` + Action []string `json:"action,omitempty"` + Effect string `json:"effect,omitempty"` + Resource []string `json:"resource,omitempty"` + Condition map[string]map[string]interface{} `json:"condition,omitempty"` + Sid string `json:"sid,omitempty"` +} + +type BucketPutPolicyOptions struct { + Statement []BucketStatement `json:"statement,omitempty"` + Version string `json:"version,omitempty"` + Principal map[string][]string `json:"principal,omitempty"` +} + +type BucketGetPolicyResult BucketPutPolicyOptions + +func (s *BucketService) PutPolicy(ctx context.Context, opt *BucketPutPolicyOptions) (*Response, error) { + var f *strings.Reader + var body string + if opt != nil { + bs, err := json.Marshal(opt) + if err != nil { + return nil, err + } + body = string(bs) + f = strings.NewReader(body) + } + header := &commonHeader{ + ContentLength: int64(len(body)), + } + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?policy", + method: http.MethodPut, + body: f, + optHeader: header, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetPolicy(ctx context.Context) (*BucketGetPolicyResult, *Response, error) { + var bs bytes.Buffer + var res BucketGetPolicyResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?policy", + method: http.MethodGet, + result: &bs, + } + resp, err := s.client.doRetry(ctx, sendOpt) + if err == nil { + err = json.Unmarshal(bs.Bytes(), &res) + } + return &res, resp, err +} + +func (s *BucketService) DeletePolicy(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?policy", + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go new file mode 100644 index 00000000000..52e7a247393 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go @@ -0,0 +1,58 @@ +package cos + +import ( + "context" + "encoding/base64" + "encoding/xml" + "net/http" +) + +type BucketPutRefererOptions struct { + XMLName xml.Name `xml:"RefererConfiguration"` + Status string `xml:"Status"` + RefererType string `xml:"RefererType"` + DomainList []string `xml:"DomainList>Domain"` + EmptyReferConfiguration string `xml:"EmptyReferConfiguration,omitempty"` + VerifySignatureURL string `xml:"VerifySignatureURL,omitempty"` +} + +type BucketGetRefererResult BucketPutRefererOptions + +func (s *BucketService) PutReferer(ctx context.Context, opt *BucketPutRefererOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?referer", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetReferer(ctx context.Context) (*BucketGetRefererResult, *Response, error) { + var res BucketGetRefererResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?referer", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +// Put空 +func (s *BucketService) DeleteReferer(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?referer", + method: http.MethodPut, + optHeader: &struct { + Md5 string `header:"Content-Md5"` + }{ + Md5: base64.StdEncoding.EncodeToString(calMD5Digest([]byte(""))), + }, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go new file mode 100644 index 00000000000..3dc6235ff08 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go @@ -0,0 +1,87 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type DeleteMarkerReplication struct { + Status string `xml:"Status"` +} + +// ReplicationDestination is the sub struct of BucketReplicationRule +type ReplicationDestination struct { + Bucket string `xml:"Bucket"` + StorageClass string `xml:"StorageClass,omitempty"` +} + +type ReplicationFilterAnd struct { + Prefix string `xml:"Prefix"` + Tag []ObjectTaggingTag `xml:"Tag,omitempty"` +} + +type ReplicationFilter struct { + And *ReplicationFilterAnd `xml:"And,omitempty"` + Prefix string `xml:"Prefix,omitempty"` +} + +// BucketReplicationRule is the main param of replication +type BucketReplicationRule struct { + ID string `xml:"ID,omitempty"` + Status string `xml:"Status"` + Priority int `xml:"Priority,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + Filter *ReplicationFilter `xml:"Filter,omitempty"` + Destination *ReplicationDestination `xml:"Destination"` + DeleteMarkerReplication *DeleteMarkerReplication `xml:"DeleteMarkerReplication,omitempty"` +} + +// PutBucketReplicationOptions is the options of PutBucketReplication +type PutBucketReplicationOptions struct { + XMLName xml.Name `xml:"ReplicationConfiguration"` + Role string `xml:"Role"` + Rule []BucketReplicationRule `xml:"Rule"` +} + +// GetBucketReplicationResult is the result of GetBucketReplication +type GetBucketReplicationResult PutBucketReplicationOptions +type BucketGetReplicationResult = GetBucketReplicationResult + +// PutBucketReplication https://cloud.tencent.com/document/product/436/19223 +func (s *BucketService) PutBucketReplication(ctx context.Context, opt *PutBucketReplicationOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?replication", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err + +} + +// GetBucketReplication https://cloud.tencent.com/document/product/436/19222 +func (s *BucketService) GetBucketReplication(ctx context.Context) (*GetBucketReplicationResult, *Response, error) { + var res GetBucketReplicationResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?replication", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err + +} + +// DeleteBucketReplication https://cloud.tencent.com/document/product/436/19221 +func (s *BucketService) DeleteBucketReplication(ctx context.Context) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?replication", + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_tagging.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_tagging.go new file mode 100644 index 00000000000..e223ee10b70 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_tagging.go @@ -0,0 +1,69 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +// BucketTaggingTag is the tag of BucketTagging +type BucketTaggingTag struct { + Key string + Value string +} + +// BucketGetTaggingResult is the result of BucketGetTagging +type BucketGetTaggingResult struct { + XMLName xml.Name `xml:"Tagging"` + TagSet []BucketTaggingTag `xml:"TagSet>Tag,omitempty"` +} + +// GetTagging 接口实现获取指定Bucket的标签。 +// +// https://www.qcloud.com/document/product/436/8277 +func (s *BucketService) GetTagging(ctx context.Context) (*BucketGetTaggingResult, *Response, error) { + var res BucketGetTaggingResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?tagging", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +// BucketPutTaggingOptions is the option of BucketPutTagging +type BucketPutTaggingOptions struct { + XMLName xml.Name `xml:"Tagging"` + TagSet []BucketTaggingTag `xml:"TagSet>Tag,omitempty"` +} + +// PutTagging 接口实现给用指定Bucket打标签。用来组织和管理相关Bucket。 +// +// 当该请求设置相同Key名称,不同Value时,会返回400。请求成功,则返回204。 +// +// https://www.qcloud.com/document/product/436/8281 +func (s *BucketService) PutTagging(ctx context.Context, opt *BucketPutTaggingOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?tagging", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +// DeleteTagging 接口实现删除指定Bucket的标签。 +// +// https://www.qcloud.com/document/product/436/8286 +func (s *BucketService) DeleteTagging(ctx context.Context) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?tagging", + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_version.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_version.go new file mode 100644 index 00000000000..c540af89d52 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_version.go @@ -0,0 +1,42 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +// BucketPutVersionOptions is the options of PutBucketVersioning +type BucketPutVersionOptions struct { + XMLName xml.Name `xml:"VersioningConfiguration"` + Status string `xml:"Status"` +} + +// BucketGetVersionResult is the result of GetBucketVersioning +type BucketGetVersionResult BucketPutVersionOptions + +// PutVersion https://cloud.tencent.com/document/product/436/19889 +// Status has Suspended\Enabled +func (s *BucketService) PutVersioning(ctx context.Context, opt *BucketPutVersionOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?versioning", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +// GetVersion https://cloud.tencent.com/document/product/436/19888 +func (s *BucketService) GetVersioning(ctx context.Context) (*BucketGetVersionResult, *Response, error) { + var res BucketGetVersionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?versioning", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go new file mode 100644 index 00000000000..9a97e9c7aaa --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go @@ -0,0 +1,77 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type WebsiteRoutingRule struct { + ConditionErrorCode string `xml:"Condition>HttpErrorCodeReturnedEquals,omitempty"` + ConditionPrefix string `xml:"Condition>KeyPrefixEquals,omitempty"` + + RedirectProtocol string `xml:"Redirect>Protocol,omitempty"` + RedirectReplaceKey string `xml:"Redirect>ReplaceKeyWith,omitempty"` + RedirectReplaceKeyPrefix string `xml:"Redirect>ReplaceKeyPrefixWith,omitempty"` +} + +type WebsiteRoutingRules struct { + Rules []WebsiteRoutingRule `xml:"RoutingRule,omitempty"` +} + +type AutoAddressing struct { + Status string `xml:"Status,omitempty"` +} + +type ErrorDocument struct { + Key string `xml:"Key,omitempty"` + OriginalHttpStatus string `xml:"OriginalHttpStatus,omitempty"` +} + +type RedirectRequestsProtocol struct { + Protocol string `xml:"Protocol,omitempty"` +} + +type BucketPutWebsiteOptions struct { + XMLName xml.Name `xml:"WebsiteConfiguration"` + Index string `xml:"IndexDocument>Suffix"` + RedirectProtocol *RedirectRequestsProtocol `xml:"RedirectAllRequestsTo,omitempty"` + AutoAddressing *AutoAddressing `xml:"AutoAddressing,omitempty"` + Error *ErrorDocument `xml:"ErrorDocument,omitempty"` + RoutingRules *WebsiteRoutingRules `xml:"RoutingRules,omitempty"` +} + +type BucketGetWebsiteResult BucketPutWebsiteOptions + +func (s *BucketService) PutWebsite(ctx context.Context, opt *BucketPutWebsiteOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?website", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetWebsite(ctx context.Context) (*BucketGetWebsiteResult, *Response, error) { + var res BucketGetWebsiteResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?website", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +func (s *BucketService) DeleteWebsite(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?website", + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go new file mode 100644 index 00000000000..94508a8fc42 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go @@ -0,0 +1,2875 @@ +package cos + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "hash/crc64" + "io" + "net/http" + "net/url" + "os" + "strconv" +) + +type CIService service + +type PicOperations struct { + IsPicInfo int `json:"is_pic_info,omitempty"` + Rules []PicOperationsRules `json:"rules,omitemtpy"` +} +type PicOperationsRules struct { + Bucket string `json:"bucket,omitempty"` + FileId string `json:"fileid"` + Rule string `json:"rule"` +} + +func EncodePicOperations(pic *PicOperations) string { + if pic == nil { + return "" + } + bs, err := json.Marshal(pic) + if err != nil { + return "" + } + return string(bs) +} + +type ImageProcessResult struct { + XMLName xml.Name `xml:"UploadResult"` + OriginalInfo *PicOriginalInfo `xml:"OriginalInfo,omitempty"` + ProcessResults []PicProcessObject `xml:"ProcessResults>Object,omitempty"` + ImgTargetRecResult *ImgTargetRecResult `xml:"ImgTargetRecResult,omitempty"` + // 历史兼容考虑不建议抽象单独struct防止客户使用影响 + ProcessResultsText string `xml:"ProcessResults>Text,omitempty"` + ProcessResultsWatermarkStatusCode int `xml:"ProcessResults>WatermarkStatusCode,omitempty"` +} +type PicOriginalInfo struct { + Key string `xml:"Key,omitempty"` + Location string `xml:"Location,omitempty"` + ImageInfo *PicImageInfo `xml:"ImageInfo,omitempty"` + ETag string `xml:"ETag,omitempty"` +} +type PicImageInfo struct { + Format string `xml:"Format,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` + Quality int `xml:"Quality,omitempty"` + Ave string `xml:"Ave,omitempty"` + Orientation int `xml:"Orientation,omitempty"` +} +type PicProcessObject struct { + Key string `xml:"Key,omitempty"` + Location string `xml:"Location,omitempty"` + Format string `xml:"Format,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` + Size int `xml:"Size,omitempty"` + Quality int `xml:"Quality,omitempty"` + ETag string `xml:"ETag,omitempty"` + WatermarkStatus int `xml:"WatermarkStatus,omitempty"` + CodeStatus int `xml:"CodeStatus,omitempty"` + QRcodeInfo []QRcodeInfo `xml:"QRcodeInfo,omitempty"` + FrameCount int `xml:"FrameCount,omitempty"` + Md5 string `xml:"Md5,omitempty"` + BitDepth int `xml:"BitDepth,omitempty"` +} +type QRcodeInfo struct { + CodeUrl string `xml:"CodeUrl,omitempty"` + CodeLocation *CodeLocation `xml:"CodeLocation,omitempty"` +} +type CodeLocation struct { + Point []string `xml:"Point,omitempty"` +} + +type picOperationsHeader struct { + PicOperations string `header:"Pic-Operations" xml:"-" url:"-"` +} + +type ImageProcessOptions = PicOperations + +// 云上数据处理 https://cloud.tencent.com/document/product/460/18147 +func (s *CIService) ImageProcess(ctx context.Context, name string, opt *ImageProcessOptions) (*ImageProcessResult, *Response, error) { + header := &picOperationsHeader{ + PicOperations: EncodePicOperations(opt), + } + var res ImageProcessResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?image_process", + method: http.MethodPost, + optHeader: header, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// ImageRecognitionOptions is the option of ImageAuditing +type ImageRecognitionOptions struct { + CIProcess string `url:"ci-process,omitempty"` + DetectType string `url:"detect-type,omitempty"` + DetectUrl string `url:"detect-url,omitempty"` + Interval int `url:"interval,omitempty"` + MaxFrames int `url:"max-frames,omitempty"` + BizType string `url:"biz-type,omitempty"` + LargeImageDetect int `url:"large-image-detect,omitempty"` + DataId string `url:"dataid,omitempty"` + Async int `url:"async,omitempty"` + Callback string `url:"callback,omitempty"` +} + +type UserListInfo struct { + ListResults []UserListResults `xml:",omitempty"` +} + +// AuditingMaskInfo 审核马赛克信息 +type AuditingMaskInfo struct { + RecordInfo *AuditingMaskRecordInfo `xml:",omitempty"` + LiveInfo *AuditingMaskLiveInfo `xml:",omitempty"` +} + +// AuditingMaskInfo 审核马赛克信息 +type AuditingMaskRecordInfo struct { + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + Output *struct { + Region string `xml:"Region,omitempty"` + Bucket string `xml:"Bucket,omitempty"` + Object string `xml:"Object,omitempty"` + } `xml:"Output,omitempty"` +} + +// AuditingMaskInfo 审核马赛克信息 +type AuditingMaskLiveInfo struct { + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` + Output string `xml:"Output,omitempty"` +} + +// UserListResults 命中账号黑白名单信息 +type UserListResults struct { + ListType *int `xml:",omitempty"` + ListName string `xml:",omitempty"` + Entity string `xml:",omitempty"` +} + +// ImageRecognitionResult is the result of ImageRecognition/ImageAuditing +type ImageRecognitionResult struct { + XMLName xml.Name `xml:"RecognitionResult"` + JobId string `xml:"JobId,omitempty"` + State string `xml:"State,omitempty"` + Object string `xml:"Object,omitempty"` + Url string `xml:"Url,omitempty"` + Text string `xml:"Text,omitempty"` + Label string `xml:"Label,omitempty"` + Result int `xml:"Result,omitempty"` + Score int `xml:"Score,omitempty"` + Category string `xml:"Category,omitempty"` + SubLabel string `xml:"SubLabel,omitempty"` + PornInfo *RecognitionInfo `xml:"PornInfo,omitempty"` + TerroristInfo *RecognitionInfo `xml:"TerroristInfo,omitempty"` + PoliticsInfo *RecognitionInfo `xml:"PoliticsInfo,omitempty"` + AdsInfo *RecognitionInfo `xml:"AdsInfo,omitempty"` + TeenagerInfo *RecognitionInfo `xml:"TeenagerInfo,omitempty"` + TerrorismInfo *RecognitionInfo `xml:"TerrorismInfo,omitempty"` + CompressionResult int `xml:"CompressionResult,omitempty"` + DataId string `xml:"DataId,omitempty"` +} + +// RecognitionInfo is the result of auditing scene +type RecognitionInfo struct { + Code int `xml:"Code,omitempty"` + Msg string `xml:"Msg,omitempty"` + HitFlag int `xml:"HitFlag,omitempty"` + Score int `xml:"Score,omitempty"` + Label string `xml:"Label,omitempty"` + Count int `xml:"Count,omitempty"` + Category string `xml:"Category,omitempty"` + SubLabel string `xml:"SubLabel,omitempty"` + Keywords []string `xml:"Keywords,omitempty"` + OcrResults []OcrResult `xml:"OcrResults,omitempty"` + ObjectResults []ObjectResult `xml:"ObjectResults,omitempty"` + LibResults []LibResult `xml:"LibResults,omitempty"` + SpeakerResults []LanguageResult `xml:"SpeakerResults,omitempty"` + RecognitionResults []LanguageResult `xml:"RecognitionResults,omitempty"` +} + +// 图片审核 https://cloud.tencent.com/document/product/460/37318 +func (s *CIService) ImageRecognition(ctx context.Context, name string, reserved string) (*ImageRecognitionResult, *Response, error) { + opt := &ImageRecognitionOptions{ + CIProcess: "sensitive-content-recognition", + } + var res ImageRecognitionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name), + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// 图片审核 支持detect-url等全部参数 +func (s *CIService) ImageAuditing(ctx context.Context, name string, opt *ImageRecognitionOptions) (*ImageRecognitionResult, *Response, error) { + var res ImageRecognitionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name), + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UserExtraInfo is user defined information +type UserExtraInfo struct { + TokenId string `xml:",omitempty"` + Nickname string `xml:",omitempty"` + DeviceId string `xml:",omitempty"` + AppId string `xml:",omitempty"` + Room string `xml:",omitempty"` + IP string `xml:",omitempty"` + Type string `xml:",omitempty"` + ReceiveTokenId string `xml:",omitempty"` + Gender string `xml:",omitempty"` + Level string `xml:",omitempty"` + Role string `xml:",omitempty"` +} + +// Encryption is user defined information +type Encryption struct { + Algorithm string `xml:",omitempty"` + Key string `xml:",omitempty"` + IV string `xml:",omitempty"` + KeyId string `xml:",omitempty"` + KeyType int `xml:",omitempty"` +} + +// FreezeConf is auto freeze options +type FreezeConf struct { + PornScore string `xml:",omitempty"` + IllegalScore string `xml:",omitempty"` + TerrorismScore string `xml:",omitempty"` + PoliticsScore string `xml:",omitempty"` + AdsScore string `xml:",omitempty"` + AbuseScore string `xml:",omitempty"` + TeenagerScore string `xml:",omitempty"` +} + +// AuditingMask is auto Mask options +type AuditingMask struct { + Images []AuditingMaskImages `xml:",omitempty"` + Audios []AuditingMaskAudios `xml:",omitempty"` + CosOutput *AuditingMaskCosOutput `xml:",omitempty"` + LiveOutput *AuditingMaskLiveOutput `xml:",omitempty"` +} + +// AuditingMaskImages 审核马赛克相关参数 +type AuditingMaskImages struct { + Label string `xml:",omitempty"` + Type string `xml:",omitempty"` + Url string `xml:",omitempty"` +} + +// AuditingMaskAudios 审核马赛克相关参数 +type AuditingMaskAudios struct { + Label string `xml:",omitempty"` + Type string `xml:",omitempty"` +} + +// AuditingMaskCosOutput 审核马赛克相关参数 +type AuditingMaskCosOutput struct { + Region string `xml:"Region,omitempty"` + Bucket string `xml:"Bucket,omitempty"` + Object string `xml:"Object,omitempty"` + Transcode *Transcode `xml:",omitempty"` +} + +// AuditingMaskLiveOutput 审核马赛克相关参数 +type AuditingMaskLiveOutput struct { + Url string `xml:"Url,omitempty"` + Transcode *Transcode `xml:",omitempty"` +} + +// ImageAuditingInputOptions is the option of BatchImageAuditingOptions +type ImageAuditingInputOptions struct { + DataId string `xml:",omitempty"` + Object string `xml:",omitempty"` + Url string `xml:",omitempty"` + Content string `xml:",omitempty"` + Interval int `xml:",omitempty"` + MaxFrames int `xml:",omitempty"` + LargeImageDetect int `xml:",omitempty"` + UserInfo *UserExtraInfo `xml:",omitempty"` +} + +// ImageAuditingJobConf is the config of BatchImageAuditingOptions +type ImageAuditingJobConf struct { + DetectType string `xml:",omitempty"` + BizType string `xml:",omitempty"` + Async int `xml:",omitempty"` + Callback string `xml:",omitempty"` + Freeze *FreezeConf `xml:",omitempty"` +} + +// BatchImageAuditingOptions is the option of BatchImageAuditing +type BatchImageAuditingOptions struct { + XMLName xml.Name `xml:"Request"` + Input []ImageAuditingInputOptions `xml:"Input,omitempty"` + Conf *ImageAuditingJobConf `xml:"Conf"` +} + +// ImageAuditingResult is the result of BatchImageAuditingJobResult +type ImageAuditingResult struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + State string `xml:",omitempty"` + DataId string `xml:",omitempty"` + Object string `xml:",omitempty"` + Url string `xml:",omitempty"` + Text string `xml:",omitempty"` + Label string `xml:",omitempty"` + Result int `xml:",omitempty"` + Score int `xml:",omitempty"` + Category string `xml:",omitempty"` + SubLabel string `xml:",omitempty"` + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` + TeenagerInfo *RecognitionInfo `xml:",omitempty"` + CompressionResult int `xml:",omitempty"` + UserInfo *UserExtraInfo `xml:",omitempty"` + Encryption *Encryption `xml:",omitempty"` + ListInfo *UserListInfo `xml:",omitempty"` + ForbidState int `xml:",omitempty"` +} + +// BatchImageAuditingJobResult is the result of BatchImageAuditing +type BatchImageAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail []ImageAuditingResult `xml:",omitempty"` + RequestId string `xml:",omitempty"` +} + +// 图片批量审核接口 +func (s *CIService) BatchImageAuditing(ctx context.Context, opt *BatchImageAuditingOptions) (*BatchImageAuditingJobResult, *Response, error) { + var res BatchImageAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/image/auditing", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetImageAuditingJobResult is the result of GetImageAuditingJob +type GetImageAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *ImageAuditingResult `xml:",omitempty"` + RequestId string `xml:",omitempty"` +} + +// 图片审核-查询任务 +func (s *CIService) GetImageAuditingJob(ctx context.Context, jobid string) (*GetImageAuditingJobResult, *Response, error) { + var res GetImageAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/image/auditing/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// PutVideoAuditingJobOptions is the option of PutVideoAuditingJob +type PutVideoAuditingJobOptions struct { + XMLName xml.Name `xml:"Request"` + InputObject string `xml:"Input>Object,omitempty"` + InputUrl string `xml:"Input>Url,omitempty"` + InputDataId string `xml:"Input>DataId,omitempty"` + InputUserInfo *UserExtraInfo `xml:"Input>UserInfo,omitempty"` + Encryption *Encryption `xml:",omitempty"` + Conf *VideoAuditingJobConf `xml:"Conf"` + Type string `xml:"Type,omitempty"` + StorageConf *StorageConf `xml:"StorageConf,omitempty"` +} + +// VideoAuditingJobConf is the config of PutVideoAuditingJobOptions +type VideoAuditingJobConf struct { + DetectType string `xml:",omitempty"` + Snapshot *PutVideoAuditingJobSnapshot `xml:",omitempty"` + Callback string `xml:",omitempty"` + CallbackVersion string `xml:",omitempty"` + CallbackType int `xml:",omitempty"` + BizType string `xml:",omitempty"` + DetectContent int `xml:",omitempty"` + Freeze *FreezeConf `xml:",omitempty"` + Mask *AuditingMask `xml:",omitempty"` +} + +// PutVideoAuditingJobSnapshot is the snapshot config of VideoAuditingJobConf +type PutVideoAuditingJobSnapshot struct { + Mode string `xml:",omitempty"` + Count int `xml:",omitempty"` + TimeInterval float32 `xml:",omitempty"` +} + +// StorageConf is live video storage config of PutVideoAuditingJobOptions +type StorageConf struct { + Path string `xml:",omitempty"` +} + +// PutVideoAuditingJobResult is the result of PutVideoAuditingJob +type PutVideoAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail struct { + JobId string `xml:"JobId,omitempty"` + State string `xml:"State,omitempty"` + CreationTime string `xml:"CreationTime,omitempty"` + Object string `xml:"Object,omitempty"` + Url string `xml:"Url,omitempty"` + } `xml:"JobsDetail,omitempty"` + RequestId string `xml:"RequestId,omitempty"` +} + +// 视频审核-创建任务 https://cloud.tencent.com/document/product/460/46427 +func (s *CIService) PutVideoAuditingJob(ctx context.Context, opt *PutVideoAuditingJobOptions) (*PutVideoAuditingJobResult, *Response, error) { + var res PutVideoAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/video/auditing", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetVideoAuditingJobResult is the result of GetVideoAuditingJob +type GetVideoAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *AuditingJobDetail `xml:",omitempty"` + RequestId string `xml:",omitempty"` +} + +// AuditingJobDetail is the detail of GetVideoAuditingJobResult +type AuditingJobDetail struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + State string `xml:",omitempty"` + CreationTime string `xml:",omitempty"` + Object string `xml:",omitempty"` + Url string `xml:",omitempty"` + DataId string `xml:",omitempty"` + SnapshotCount string `xml:",omitempty"` + Label string `xml:",omitempty"` + SubLabel string `xml:",omitempty"` + Result int `xml:",omitempty"` + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` + TeenagerInfo *RecognitionInfo `xml:",omitempty"` + Snapshot []GetVideoAuditingJobSnapshot `xml:",omitempty"` + AudioSection []AudioSectionResult `xml:",omitempty"` + UserInfo *UserExtraInfo `xml:",omitempty"` + Type string `xml:",omitempty"` + ListInfo *UserListInfo `xml:",omitempty"` + ForbidState int `xml:",omitempty"` + MaskInfo *AuditingMaskInfo `xml:",omitempty"` +} + +// GetVideoAuditingJobSnapshot is the snapshot result of AuditingJobDetail +type GetVideoAuditingJobSnapshot struct { + Url string `xml:",omitempty"` + Text string `xml:",omitempty"` + SnapshotTime int `xml:",omitempty"` + Label string `xml:",omitempty"` + Result int `xml:",omitempty"` + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` + TeenagerInfo *RecognitionInfo `xml:",omitempty"` +} + +// AudioSectionResult is the audio section result of AuditingJobDetail/AudioAuditingJobDetail +type AudioSectionResult struct { + Url string `xml:",omitempty"` + Text string `xml:",omitempty"` + OffsetTime int `xml:",omitempty"` + Duration int `xml:",omitempty"` + Label string `xml:",omitempty"` + SubLabel string `xml:",omitempty"` + Result int `xml:",omitempty"` + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` + TeenagerInfo *RecognitionInfo `xml:",omitempty"` + LanguageResults []LanguageResult `xml:",omitempty"` +} + +// 视频审核-查询任务 https://cloud.tencent.com/document/product/460/46926 +func (s *CIService) GetVideoAuditingJob(ctx context.Context, jobid string) (*GetVideoAuditingJobResult, *Response, error) { + var res GetVideoAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/video/auditing/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// 视频审核-取消直播流审核任务 +func (s *CIService) PostVideoAuditingCancelJob(ctx context.Context, jobid string) (*PutVideoAuditingJobResult, *Response, error) { + var res PutVideoAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/video/cancel_auditing/" + jobid, + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// PutAudioAuditingJobOptions is the option of PutAudioAuditingJob +type PutAudioAuditingJobOptions struct { + XMLName xml.Name `xml:"Request"` + InputObject string `xml:"Input>Object,omitempty"` + InputUrl string `xml:"Input>Url,omitempty"` + InputDataId string `xml:"Input>DataId,omitempty"` + InputUserInfo *UserExtraInfo `xml:"Input>UserInfo,omitempty"` + Conf *AudioAuditingJobConf `xml:"Conf"` +} + +// AudioAuditingJobConf is the config of PutAudioAuditingJobOptions +type AudioAuditingJobConf struct { + DetectType string `xml:",omitempty"` + Callback string `xml:",omitempty"` + CallbackVersion string `xml:",omitempty"` + CallbackType int `xml:",omitempty"` + BizType string `xml:",omitempty"` + Freeze *FreezeConf `xml:",omitempty"` +} + +// PutAudioAuditingJobResult is the result of PutAudioAuditingJob +type PutAudioAuditingJobResult PutVideoAuditingJobResult + +// 音频审核-创建任务 https://cloud.tencent.com/document/product/460/53395 +func (s *CIService) PutAudioAuditingJob(ctx context.Context, opt *PutAudioAuditingJobOptions) (*PutAudioAuditingJobResult, *Response, error) { + var res PutAudioAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/audio/auditing", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetAudioAuditingJobResult is the result of GetAudioAuditingJob +type GetAudioAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *AudioAuditingJobDetail `xml:",omitempty"` + RequestId string `xml:",omitempty"` +} + +// AudioAuditingJobDetail is the detail of GetAudioAuditingJobResult +type AudioAuditingJobDetail struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + State string `xml:",omitempty"` + CreationTime string `xml:",omitempty"` + Object string `xml:",omitempty"` + Url string `xml:",omitempty"` + DataId string `xml:",omitempty"` + AudioText string `xml:",omitempty"` + Label string `xml:",omitempty"` + Result int `xml:",omitempty"` + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` + TeenagerInfo *RecognitionInfo `xml:",omitempty"` + LanguageResults []LanguageResult `xml:",omitempty"` + Section []AudioSectionResult `xml:",omitempty"` + UserInfo *UserExtraInfo `xml:",omitempty"` + ListInfo *UserListInfo `xml:",omitempty"` + ForbidState int `xml:",omitempty"` +} + +// LanguageResult 语种识别结果 +type LanguageResult struct { + Label string `xml:"Label"` + Score uint32 `xml:"Score"` + StartTime *int64 `xml:"StartTime,omitempty"` + EndTime *int64 `xml:"EndTime,omitempty"` +} + +// 音频审核-查询任务 https://cloud.tencent.com/document/product/460/53396 +func (s *CIService) GetAudioAuditingJob(ctx context.Context, jobid string) (*GetAudioAuditingJobResult, *Response, error) { + var res GetAudioAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/audio/auditing/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// PutTextAuditingJobOptions is the option of PutTextAuditingJob +type PutTextAuditingJobOptions struct { + XMLName xml.Name `xml:"Request"` + InputObject string `xml:"Input>Object,omitempty"` + InputUrl string `xml:"Input>Url,omitempty"` + InputContent string `xml:"Input>Content,omitempty"` + InputDataId string `xml:"Input>DataId,omitempty"` + InputUserInfo *UserExtraInfo `xml:"Input>UserInfo,omitempty"` + Conf *TextAuditingJobConf `xml:"Conf"` +} + +// TextAuditingJobConf is the config of PutAudioAuditingJobOptions +type TextAuditingJobConf struct { + DetectType string `xml:",omitempty"` + Callback string `xml:",omitempty"` + CallbackVersion string `xml:",omitempty"` + BizType string `xml:",omitempty"` + CallbackType int `xml:",omitempty"` + Freeze *FreezeConf `xml:",omitempty"` +} + +// PutTextAuditingJobResult is the result of PutTextAuditingJob +type PutTextAuditingJobResult GetTextAuditingJobResult + +// 文本审核-创建任务 https://cloud.tencent.com/document/product/436/56289 +func (s *CIService) PutTextAuditingJob(ctx context.Context, opt *PutTextAuditingJobOptions) (*PutTextAuditingJobResult, *Response, error) { + var res PutTextAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/text/auditing", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetTextAuditingJobResult is the result of GetTextAuditingJob +type GetTextAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *TextAuditingJobDetail `xml:",omitempty"` + RequestId string `xml:",omitempty"` +} + +// TextAuditingJobDetail is the detail of GetTextAuditingJobResult +type TextAuditingJobDetail struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + State string `xml:",omitempty"` + CreationTime string `xml:",omitempty"` + Object string `xml:",omitempty"` + Url string `xml:",omitempty"` + DataId string `xml:",omitempty"` + Content string `xml:",omitempty"` + SectionCount int `xml:",omitempty"` + Label string `xml:",omitempty"` + Result int `xml:",omitempty"` + PornInfo *TextRecognitionInfo `xml:",omitempty"` + TerrorismInfo *TextRecognitionInfo `xml:",omitempty"` + PoliticsInfo *TextRecognitionInfo `xml:",omitempty"` + AdsInfo *TextRecognitionInfo `xml:",omitempty"` + IllegalInfo *TextRecognitionInfo `xml:",omitempty"` + AbuseInfo *TextRecognitionInfo `xml:",omitempty"` + Section []TextSectionResult `xml:",omitempty"` + UserInfo *UserExtraInfo `xml:",omitempty"` + ListInfo *UserListInfo `xml:",omitempty"` + ForbidState int `xml:",omitempty"` + ValueInfo *TextRecognitionInfo `xml:",omitempty"` + SpamInfo *TextRecognitionInfo `xml:",omitempty"` +} + +// TextLibResult +type TextLibResult struct { + LibType int32 `xml:"LibType,omitempty"` + LibName string `xml:"LibName,omitempty"` + Keywords []string `xml:"Keywords,omitempty"` +} + +// TextRecognitionInfo +type TextRecognitionInfo struct { + Code int `xml:",omitempty"` + HitFlag int `xml:",omitempty"` + Score int `xml:",omitempty"` + Count int `xml:",omitempty"` + Keywords string `xml:",omitempty"` + LibResults []TextLibResult `xml:",omitempty"` + SubLabel string `xml:",omitempty"` +} + +// TextSectionResult is the section result of TextAuditingJobDetail +type TextSectionResult struct { + StartByte int `xml:",omitempty"` + Label string `xml:",omitempty"` + Result int `xml:",omitempty"` + PornInfo *TextRecognitionInfo `xml:",omitempty"` + TerrorismInfo *TextRecognitionInfo `xml:",omitempty"` + PoliticsInfo *TextRecognitionInfo `xml:",omitempty"` + AdsInfo *TextRecognitionInfo `xml:",omitempty"` + IllegalInfo *TextRecognitionInfo `xml:",omitempty"` + AbuseInfo *TextRecognitionInfo `xml:",omitempty"` + ValueInfo *TextRecognitionInfo `xml:",omitempty"` + SpamInfo *TextRecognitionInfo `xml:",omitempty"` +} + +// 文本审核-查询任务 https://cloud.tencent.com/document/product/436/56288 +func (s *CIService) GetTextAuditingJob(ctx context.Context, jobid string) (*GetTextAuditingJobResult, *Response, error) { + var res GetTextAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/text/auditing/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// PutDocumentAuditingJobOptions is the option of PutDocumentAuditingJob +type PutDocumentAuditingJobOptions struct { + XMLName xml.Name `xml:"Request"` + InputObject string `xml:"Input>Object,omitempty"` + InputUrl string `xml:"Input>Url,omitempty"` + InputType string `xml:"Input>Type,omitempty"` + InputDataId string `xml:"Input>DataId,omitempty"` + InputUserInfo *UserExtraInfo `xml:"Input>UserInfo,omitempty"` + Conf *DocumentAuditingJobConf `xml:"Conf"` +} + +// DocumentAuditingJobConf is the config of PutDocumentAuditingJobOptions +type DocumentAuditingJobConf struct { + DetectType string `xml:",omitempty"` + Callback string `xml:",omitempty"` + BizType string `xml:",omitempty"` + CallbackType int `xml:",omitempty"` + Freeze *FreezeConf `xml:",omitempty"` +} + +// PutDocumentAuditingJobResult is the result of PutDocumentAuditingJob +type PutDocumentAuditingJobResult PutVideoAuditingJobResult + +// 文档审核-创建任务 https://cloud.tencent.com/document/product/436/59381 +func (s *CIService) PutDocumentAuditingJob(ctx context.Context, opt *PutDocumentAuditingJobOptions) (*PutDocumentAuditingJobResult, *Response, error) { + var res PutDocumentAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/document/auditing", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetDocumentAuditingJobResult is the result of GetDocumentAuditingJob +type GetDocumentAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *DocumentAuditingJobDetail `xml:",omitempty"` + RequestId string `xml:",omitempty"` +} + +// DocumentAuditingJobDetail is the detail of GetDocumentAuditingJobResult +type DocumentAuditingJobDetail struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + State string `xml:",omitempty"` + CreationTime string `xml:",omitempty"` + Object string `xml:",omitempty"` + Url string `xml:",omitempty"` + DataId string `xml:",omitempty"` + PageCount int `xml:",omitempty"` + Label string `xml:",omitempty"` + Suggestion int `xml:",omitempty"` + Labels *DocumentResultInfo `xml:",omitempty"` + PageSegment *DocumentPageSegmentInfo `xml:",omitempty"` + UserInfo *UserExtraInfo `xml:",omitempty"` + ListInfo *UserListInfo `xml:",omitempty"` + ForbidState int `xml:",omitempty"` +} + +// DocumentResultInfo +type DocumentResultInfo struct { + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` +} + +// DocumentPageSegmentInfo +type DocumentPageSegmentInfo struct { + Results []DocumentPageSegmentResultResult `xml:",omitempty"` +} + +// DocumentPageSegmentResultResult +type DocumentPageSegmentResultResult struct { + Url string `xml:",omitempty"` + Text string `xml:",omitempty"` + PageNumber int `xml:",omitempty"` + SheetNumber int `xml:",omitempty"` + Label string `xml:",omitempty"` + Suggestion int `xml:",omitempty"` + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` +} + +// OcrResult +type OcrResult struct { + Text string `xml:"Text,omitempty"` + Keywords []string `xml:"Keywords,omitempty"` + SubLabel string `xml:"SubLabel,omitempty"` + Location *Location `xml:"Location,omitempty"` +} + +// ObjectResult +type ObjectResult struct { + Name string `xml:"Name,omitempty"` + SubLabel string `xml:"SubLabel,omitempty"` + Location *Location `xml:"Location,omitempty"` +} + +// LibResult +type LibResult struct { + ImageId string `xml:"ImageId,omitempty"` + Score uint32 `xml:"Score,omitempty"` + TextLibResult +} + +// Location +type Location struct { + X float64 `xml:"X,omitempty"` // 左上角横坐标 + Y float64 `xml:"Y,omitempty"` // 左上角纵坐标 + Width float64 `xml:"Width,omitempty"` // 宽度 + Height float64 `xml:"Height,omitempty"` // 高度 + Rotate float64 `xml:"Rotate,omitempty"` // 检测框的旋转角度 +} + +// 文档审核-查询任务 https://cloud.tencent.com/document/product/436/59382 +func (s *CIService) GetDocumentAuditingJob(ctx context.Context, jobid string) (*GetDocumentAuditingJobResult, *Response, error) { + var res GetDocumentAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/document/auditing/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// PutWebpageAuditingJobOptions is the option of PutWebpageAuditingJob +type PutWebpageAuditingJobOptions struct { + XMLName xml.Name `xml:"Request"` + InputUrl string `xml:"Input>Url,omitempty"` + InputDataId string `xml:"Input>DataId,omitempty"` + InputUserInfo *UserExtraInfo `xml:"Input>UserInfo,omitempty"` + Conf *WebpageAuditingJobConf `xml:"Conf"` +} + +// WebpageAuditingJobConf is the config of PutWebpageAuditingJobOptions +type WebpageAuditingJobConf struct { + DetectType string `xml:",omitempty"` + Callback string `xml:",omitempty"` + ReturnHighlightHtml bool `xml:",omitempty"` + BizType string `xml:",omitempty"` + CallbackType int `xml:",omitempty"` +} + +// PutWebpageAuditingJobResult is the result of PutWebpageAuditingJob +type PutWebpageAuditingJobResult PutVideoAuditingJobResult + +// 网页审核-创建任务 https://cloud.tencent.com/document/product/436/63958 +func (s *CIService) PutWebpageAuditingJob(ctx context.Context, opt *PutWebpageAuditingJobOptions) (*PutWebpageAuditingJobResult, *Response, error) { + var res PutWebpageAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/webpage/auditing", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetWebpageAuditingJobResult is the result of GetWebpageAuditingJob +type GetWebpageAuditingJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *WebpageAuditingJobDetail `xml:",omitempty"` +} + +// WebpageAuditingJobDetail is the detail of GetWebpageAuditingJobResult +type WebpageAuditingJobDetail struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + State string `xml:",omitempty"` + CreationTime string `xml:",omitempty"` + Url string `xml:",omitempty"` + Labels *WebpageResultInfo `xml:",omitempty"` + PageCount int `xml:",omitempty"` + Suggestion int `xml:",omitempty"` + ImageResults *WebpageImageResults `xml:",omitempty"` + TextResults *WebpageTextResults `xml:",omitempty"` + HighlightHtml string `xml:",omitempty"` + DataId string `xml:",omitempty"` + UserInfo *UserExtraInfo `xml:",omitempty"` + ListInfo *UserListInfo `xml:",omitempty"` + Label string `xml:",omitempty"` +} + +// WebpageResultInfo +type WebpageResultInfo struct { + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` + IllegalInfo *RecognitionInfo `xml:",omitempty"` + AbuseInfo *RecognitionInfo `xml:",omitempty"` +} + +// WebpageImageResults +type WebpageImageResults struct { + Results []WebpageImageResult `xml:",omitempty"` +} + +// WebpageImageResult +type WebpageImageResult struct { + Url string `xml:",omitempty"` + Text string `xml:",omitempty"` + Label string `xml:",omitempty"` + PageNumber int `xml:",omitempty"` + SheetNumber int `xml:",omitempty"` + Suggestion int `xml:",omitempty"` + PornInfo *RecognitionInfo `xml:",omitempty"` + TerrorismInfo *RecognitionInfo `xml:",omitempty"` + PoliticsInfo *RecognitionInfo `xml:",omitempty"` + AdsInfo *RecognitionInfo `xml:",omitempty"` +} + +// WebpageTextResults +type WebpageTextResults struct { + Results []WebpageTextResult `xml:",omitempty"` +} + +// WebpageTextResult +type WebpageTextResult struct { + Text string `xml:",omitempty"` + Label string `xml:",omitempty"` + Result int `xml:",omitempty"` + PageNumber int `xml:",omitempty"` + SheetNumber int `xml:",omitempty"` + Suggestion int `xml:",omitempty"` + PornInfo *TextRecognitionInfo `xml:",omitempty"` + TerrorismInfo *TextRecognitionInfo `xml:",omitempty"` + PoliticsInfo *TextRecognitionInfo `xml:",omitempty"` + AdsInfo *TextRecognitionInfo `xml:",omitempty"` + IllegalInfo *TextRecognitionInfo `xml:",omitempty"` + AbuseInfo *TextRecognitionInfo `xml:",omitempty"` +} + +// 网页审核-查询任务 https://cloud.tencent.com/document/product/436/63959 +func (s *CIService) GetWebpageAuditingJob(ctx context.Context, jobid string) (*GetWebpageAuditingJobResult, *Response, error) { + var res GetWebpageAuditingJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/webpage/auditing/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// ReportBadcaseOptions +type ReportBadcaseOptions struct { + XMLName xml.Name `xml:"Request"` + ContentType int `xml:",omitempty"` + Text string `xml:",omitempty"` + Url string `xml:",omitempty"` + Label string `xml:",omitempty"` + SuggestedLabel string `xml:",omitempty"` + JobId string `xml:",omitempty"` + ModerationTime string `xml:",omitempty"` +} + +// ReportBadcaseResult +type ReportBadcaseResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:",omitempty"` +} + +// 提交Badcase +func (s *CIService) ReportBadcase(ctx context.Context, opt *ReportBadcaseOptions) (*ReportBadcaseResult, *Response, error) { + var res ReportBadcaseResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/report/badcase", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// PutVirusDetectJobOptions is the option of PutVirusDetectJob +type PutVirusDetectJobOptions struct { + XMLName xml.Name `xml:"Request"` + InputObject string `xml:"Input>Object,omitempty"` + InputUrl string `xml:"Input>Url,omitempty"` + Conf *VirusDetectJobConf `xml:"Conf"` +} + +// VirusDetectJobConf is the config of PutVirusDetectJobOptions +type VirusDetectJobConf struct { + DetectType string `xml:",omitempty"` + Callback string `xml:",omitempty"` +} + +// PutVirusDetectJobResult is the result of PutVirusDetectJob +type PutVirusDetectJobResult PutVideoAuditingJobResult + +// 云查毒接口-提交病毒检测任务 https://cloud.tencent.com/document/product/436/63961 +func (s *CIService) PutVirusDetectJob(ctx context.Context, opt *PutVirusDetectJobOptions) (*PutVirusDetectJobResult, *Response, error) { + var res PutVirusDetectJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/virus/detect", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetVirusDetectJobResult is the result of GetVirusDetectJob +type GetVirusDetectJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *VirusDetectJobDetail `xml:",omitempty"` + RequestId string `xml:",omitempty"` +} + +// VirusDetectJobDetail is the detail of GetVirusDetectJobResult +type VirusDetectJobDetail struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + State string `xml:",omitempty"` + CreationTime string `xml:",omitempty"` + Object string `xml:",omitempty"` + Url string `xml:",omitempty"` + Suggestion string `xml:",omitempty"` + DetectDetail *VirusResults `xml:",omitempty"` +} + +// VirusResults +type VirusResults struct { + Result []VirusInfo `xml:",omitempty"` +} + +// VirusInfo +type VirusInfo struct { + FileName string `xml:",omitempty"` + VirusName string `xml:",omitempty"` +} + +// 云查毒接口-查询病毒检测任务结果 https://cloud.tencent.com/document/product/436/63962 +func (s *CIService) GetVirusDetectJob(ctx context.Context, jobid string) (*GetVirusDetectJobResult, *Response, error) { + var res GetVirusDetectJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/virus/detect/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// 图片持久化处理-上传时处理 https://cloud.tencent.com/document/product/460/18147 +// 盲水印-上传时添加 https://cloud.tencent.com/document/product/460/19017 +// 二维码识别-上传时识别 https://cloud.tencent.com/document/product/460/37513 +func (s *CIService) Put(ctx context.Context, name string, r io.Reader, uopt *ObjectPutOptions) (*ImageProcessResult, *Response, error) { + if r == nil { + return nil, nil, fmt.Errorf("reader is nil") + } + if err := CheckReaderLen(r); err != nil { + return nil, nil, err + } + opt := CloneObjectPutOptions(uopt) + totalBytes, err := GetReaderLen(r) + if err != nil && opt != nil && opt.Listener != nil { + if opt.ContentLength == 0 { + return nil, nil, err + } + totalBytes = opt.ContentLength + } + if err == nil { + // 与 go http 保持一致, 非bytes.Buffer/bytes.Reader/strings.Reader由用户指定ContentLength, 或使用 Chunk 上传 + // if opt != nil && opt.ContentLength == 0 && IsLenReader(r) { + // opt.ContentLength = totalBytes + // } + // lilang : 2022-07-04 + // 图片cgi不设置content-length的话,读不到body。图片处理cgi暂时不支持chunked,后面会修复。 + if opt != nil && opt.ContentLength == 0 { + opt.ContentLength = totalBytes + } + + } + reader := TeeReader(r, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + } + if opt != nil && opt.Listener != nil { + reader.listener = opt.Listener + } + + var res ImageProcessResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name), + method: http.MethodPut, + body: reader, + optHeader: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + + return &res, resp, err +} + +// ci put object from local file +func (s *CIService) PutFromFile(ctx context.Context, name string, filePath string, opt *ObjectPutOptions) (*ImageProcessResult, *Response, error) { + fd, err := os.Open(filePath) + if err != nil { + return nil, nil, err + } + defer fd.Close() + + return s.Put(ctx, name, fd, opt) +} + +// 基本图片处理 https://cloud.tencent.com/document/product/460/36540 +// 盲水印-下载时添加 https://cloud.tencent.com/document/product/460/19017 +func (s *CIService) Get(ctx context.Context, name string, operation string, opt *ObjectGetOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&%s", encodeURIComponent(name), id[0], encodeURIComponent(operation)) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?%s", encodeURIComponent(name), encodeURIComponent(operation)) + } else { + return nil, errors.New("wrong params") + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + + if opt != nil && opt.Listener != nil { + if err == nil && resp != nil { + if totalBytes, e := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64); e == nil { + resp.Body = TeeReader(resp.Body, nil, totalBytes, opt.Listener) + } + } + } + return resp, err +} + +func (s *CIService) GetToFile(ctx context.Context, name, localpath, operation string, opt *ObjectGetOptions, id ...string) (*Response, error) { + resp, err := s.Get(ctx, name, operation, opt, id...) + if err != nil { + return resp, err + } + defer resp.Body.Close() + + // If file exist, overwrite it + fd, err := os.OpenFile(localpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660) + if err != nil { + return resp, err + } + + _, err = io.Copy(fd, resp.Body) + fd.Close() + if err != nil { + return resp, err + } + + return resp, nil +} + +type GetQRcodeResult struct { + XMLName xml.Name `xml:"Response"` + CodeStatus int `xml:"CodeStatus,omitempty"` + QRcodeInfo *QRcodeInfo `xml:"QRcodeInfo,omitempty"` + ResultImage string `xml:"ResultImage,omitempty"` +} + +// 二维码识别-下载时识别 https://cloud.tencent.com/document/product/436/54070 +func (s *CIService) GetQRcode(ctx context.Context, name string, cover int, opt *ObjectGetOptions, id ...string) (*GetQRcodeResult, *Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&ci-process=QRcode&cover=%v", encodeURIComponent(name), id[0], cover) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?ci-process=QRcode&cover=%v", encodeURIComponent(name), cover) + } else { + return nil, nil, errors.New("wrong params") + } + + var res GetQRcodeResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type GetQRcodeResultV2 struct { + XMLName xml.Name `xml:"Response"` + CodeStatus int `xml:"CodeStatus,omitempty"` + QRcodeInfo []QRcodeInfo `xml:"QRcodeInfo,omitempty"` + ResultImage string `xml:"ResultImage,omitempty"` +} + +// GetQRcodeV2 二维码识别-下载时识别 https://cloud.tencent.com/document/product/436/54070 +func (s *CIService) GetQRcodeV2(ctx context.Context, name string, cover int, opt *ObjectGetOptions, id ...string) (*GetQRcodeResultV2, *Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&ci-process=QRcode&cover=%v", encodeURIComponent(name), id[0], cover) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?ci-process=QRcode&cover=%v", encodeURIComponent(name), cover) + } else { + return nil, nil, errors.New("wrong params") + } + + var res GetQRcodeResultV2 + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type GenerateQRcodeOptions struct { + QRcodeContent string `url:"qrcode-content,omitempty"` + Mode int `url:"mode,omitempty"` + Width int `url:"width,omitempty"` +} +type GenerateQRcodeResult struct { + XMLName xml.Name `xml:"Response"` + ResultImage string `xml:"ResultImage,omitempty"` +} + +// 二维码生成 https://cloud.tencent.com/document/product/436/54071 +func (s *CIService) GenerateQRcode(ctx context.Context, opt *GenerateQRcodeOptions) (*GenerateQRcodeResult, *Response, error) { + var res GenerateQRcodeResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?ci-process=qrcode-generate", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *CIService) GenerateQRcodeToFile(ctx context.Context, filePath string, opt *GenerateQRcodeOptions) (*GenerateQRcodeResult, *Response, error) { + res, resp, err := s.GenerateQRcode(ctx, opt) + if err != nil { + return res, resp, err + } + + // If file exist, overwrite it + fd, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660) + if err != nil { + return res, resp, err + } + defer fd.Close() + + bs, err := base64.StdEncoding.DecodeString(res.ResultImage) + if err != nil { + return res, resp, err + } + fb := bytes.NewReader(bs) + _, err = io.Copy(fd, fb) + + return res, resp, err +} + +// 开通 Guetzli 压缩 https://cloud.tencent.com/document/product/460/30112 +func (s *CIService) PutGuetzli(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?guetzli", + method: http.MethodPut, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +type GetGuetzliResult struct { + XMLName xml.Name `xml:"GuetzliStatus"` + GuetzliStatus string `xml:",chardata"` +} + +// 查询 Guetzli 状态 https://cloud.tencent.com/document/product/460/30111 +func (s *CIService) GetGuetzli(ctx context.Context) (*GetGuetzliResult, *Response, error) { + var res GetGuetzliResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?guetzli", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +// 关闭 Guetzli 压缩 https://cloud.tencent.com/document/product/460/30113 +func (s *CIService) DeleteGuetzli(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?guetzli", + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +type AddStyleOptions struct { + XMLName xml.Name `xml:"AddStyle"` + StyleName string `xml:"StyleName,omitempty"` + StyleBody string `xml:"StyleBody,omitempty"` +} + +type GetStyleOptions struct { + XMLName xml.Name `xml:"GetStyle"` + StyleName string `xml:"StyleName,omitempty"` +} + +type GetStyleResult struct { + XMLName xml.Name `xml:"StyleList"` + StyleRule []StyleRule `xml:"StyleRule,omitempty"` +} + +type StyleRule struct { + StyleName string `xml:"StyleName,omitempty"` + StyleBody string `xml:"StyleBody,omitempty"` +} + +type DeleteStyleOptions struct { + XMLName xml.Name `xml:"DeleteStyle"` + StyleName string `xml:"StyleName,omitempty"` +} + +func (s *CIService) AddStyle(ctx context.Context, opt *AddStyleOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodPut, + uri: "/?style", + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *CIService) GetStyle(ctx context.Context, opt *GetStyleOptions) (*GetStyleResult, *Response, error) { + var res GetStyleResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodGet, + uri: "/?style", + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *CIService) DeleteStyle(ctx context.Context, opt *DeleteStyleOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodDelete, + uri: "/?style", + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +type ImageQualityResult struct { + XMLName xml.Name `xml:"Response"` + LongImage bool `xml:"LongImage,omitempty"` + BlackAndWhite bool `xml:"BlackAndWhite,omitempty"` + SmallImage bool `xml:"SmallImage,omitempty"` + BigImage bool `xml:"BigImage,omitempty"` + PureImage bool `xml:"PureImage,omitempty"` + ClarityScore int `xml:"ClarityScore,omitempty"` + AestheticScore int `xml:"AestheticScore,omitempty"` + RequestId string `xml:"RequestId,omitempty"` +} + +// ImageQuality 图片质量评估 +func (s *CIService) ImageQuality(ctx context.Context, obj string) (*ImageQualityResult, *Response, error) { + var res ImageQualityResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(obj) + "?ci-process=AssessQuality", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +// ImageQualityOptions is the option of ImageQualityWithOpt +type ImageQualityOptions struct { + CIProcess string `url:"ci-process,omitempty"` + DetectUrl string `url:"detect-url,omitempty"` + EnableClarity string `url:"enable_clarity,omitempty"` + EnableAesthetics string `url:"enable_aesthetics,omitempty"` + EnableLowquality string `url:"enable_lowquality,omitempty"` +} + +// ImageQualityWithOpt 图片质量评估 +func (s *CIService) ImageQualityWithOpt(ctx context.Context, obj string, opt *ImageQualityOptions) (*ImageQualityResult, *Response, error) { + var res ImageQualityResult + opt.CIProcess = "AssessQuality" + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(obj), + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type OcrRecognitionOptions struct { + Type string `url:"type,omitempty"` + LanguageType string `url:"language-type,omitempty"` + Ispdf bool `url:"ispdf,omitempty"` + PdfPageNumber int `url:"pdf-pagenumber,omitempty"` + Isword bool `url:"isword,omitempty"` + EnableWordPolygon bool `url:"enable-word-polygon,omitempty"` +} + +type OcrRecognitionResult struct { + XMLName xml.Name `xml:"Response"` + TextDetections []TextDetections `xml:"TextDetections,omitempty"` + Language string `xml:"Language,omitempty"` + Angel float64 `xml:"Angel,omitempty"` + PdfPageSize int `xml:"PdfPageSize,omitempty"` + RequestId string `xml:"RequestId,omitempty"` +} + +type TextDetections struct { + DetectedText string `xml:"DetectedText,omitempty"` + Confidence int `xml:"Confidence,omitempty"` + Polygon []Polygon `xml:"Polygon,omitempty"` + ItemPolygon []ItemPolygon `xml:"ItemPolygon,omitempty"` + Words []Words `xml:"Words,omitempty"` + WordPolygon []WordPolygon `xml:"WordPolygon,omitempty"` +} + +type Polygon struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` +} + +// ItemPolygon TODO +type ItemPolygon struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` +} + +type Words struct { + Confidence int `xml:"Confidence,omitempty"` + Character string `xml:"Character,omitempty"` + WordCoordPoint *WordCoordPoint `xml:"WordCoordPoint,omitempty"` +} + +type WordCoordPoint struct { + WordCoordinate []Polygon `xml:"WordCoordinate,omitempty"` +} + +type WordPolygon struct { + LeftTop *Polygon `xml:"LeftTop,omitempty"` + RightTop *Polygon `xml:"RightTop,omitempty"` + RightBottom *Polygon `xml:"RightBottom,omitempty"` + LeftBottom *Polygon `xml:"LeftBottom,omitempty"` +} + +// OcrRecognition OCR通用文字识别 +func (s *CIService) OcrRecognition(ctx context.Context, obj string, opt *OcrRecognitionOptions) (*OcrRecognitionResult, *Response, error) { + var res OcrRecognitionResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(obj) + "?ci-process=OCR", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type DetectCarResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + CarTags []CarTags `xml:"CarTags,omitempty"` +} + +type CarTags struct { + Serial string `xml:"Serial,omitempty"` + Brand string `xml:"Brand,omitempty"` + Type string `xml:"Type,omitempty"` + Color string `xml:"Color,omitempty"` + Confidence int `xml:"Confidence,omitempty"` + Year int `xml:"Year,omitempty"` + CarLocation []CarLocation `xml:"CarLocation,omitempty"` + PlateContent []PlateContent `xml:"PlateContent,omitempty"` +} + +type CarLocation struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` +} + +type PlateContent struct { + Plate string `xml:"Plate,omitempty"` + Color string `xml:"Color,omitempty"` + Type string `xml:"Type,omitempty"` + PlateLocation *PlateLocation `xml:"PlateLocation,omitempty"` +} + +type PlateLocation struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` +} + +// DetectCar 车辆车牌检测 +func (s *CIService) DetectCar(ctx context.Context, obj string) (*DetectCarResult, *Response, error) { + var res DetectCarResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(obj) + "?ci-process=DetectCar", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type CIServiceResult struct { + XMLName xml.Name `xml:"CIStatus"` + CIStatus string `xml:",chardata"` +} + +func (s *CIService) OpenCIService(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodPut, + uri: "/", + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *CIService) GetCIService(ctx context.Context) (*CIServiceResult, *Response, error) { + var res CIServiceResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodGet, + uri: "/", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *CIService) CloseCIService(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodPut, + uri: "/?unbind", + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +type HotLinkOptions struct { + XMLName xml.Name `xml:"Hotlink"` + Url []string `xml:"Url,omitempty"` + Type string `xml:"Type,omitempty"` +} + +type HotLinkResult struct { + XMLName xml.Name `xml:"Hotlink"` + Status string `xml:"Status,omitempty"` + Type string `xml:"Type,omitempty"` + Url []string `xml:"Url,omitempty"` +} + +func (s *CIService) SetHotLink(ctx context.Context, opt *HotLinkOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodPut, + uri: "/?hotlink", + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *CIService) GetHotLink(ctx context.Context) (*HotLinkResult, *Response, error) { + var res HotLinkResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodGet, + uri: "/?hotlink", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type OriginProtectResult struct { + XMLName xml.Name `xml:"OriginProtectStatus"` + OriginProtectStatus string `xml:",chardata"` +} + +func (s *CIService) OpenOriginProtect(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodPut, + uri: "/?origin-protect", + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *CIService) GetOriginProtect(ctx context.Context) (*OriginProtectResult, *Response, error) { + var res OriginProtectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodGet, + uri: "/?origin-protect", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *CIService) CloseOriginProtect(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodDelete, + uri: "/?origin-protect", + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +type PicTagResult struct { + XMLName xml.Name `xml:"RecognitionResult"` + Labels []PicTag `xml:"Labels,omitempty"` +} + +type PicTag struct { + Confidence int `xml:"Confidence,omitempty"` + Name string `xml:"Name,omitempty"` +} + +func (s *CIService) PicTag(ctx context.Context, obj string) (*PicTagResult, *Response, error) { + var res PicTagResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=detect-label", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type DetectFaceOptions struct { + MaxFaceNum int `url:"max-face-num,omitempty"` +} + +type DetectFaceResult struct { + XMLName xml.Name `xml:"Response"` + ImageWidth int `xml:"ImageWidth,omitempty"` + ImageHeight int `xml:"ImageHeight,omitempty"` + FaceModelVersion string `xml:"FaceModelVersion,omitempty"` + RequestId string `xml:"RequestId,omitempty"` + FaceInfos []FaceInfos `xml:"FaceInfos,omitempty"` +} + +type FaceInfos struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` +} + +func (s *CIService) DetectFace(ctx context.Context, obj string, opt *DetectFaceOptions) (*DetectFaceResult, *Response, error) { + var res DetectFaceResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=DetectFace", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type FaceEffectOptions struct { + Type string `url:"type,omitempty"` + Whitening int `url:"whitening,omitempty"` + Smoothing int `url:"smoothing,omitempty"` + FaceLifting int `url:"faceLifting,omitempty"` + EyeEnlarging int `url:"eyeEnlarging,omitempty"` + Gender int `url:"gender,omitempty"` + Age int `url:"age,omitempty"` +} + +type FaceEffectResult struct { + XMLName xml.Name `xml:"Response"` + ResultImage string `xml:"ResultImage,omitempty"` + ResultMask string `xml:"ResultMask,omitempty"` +} + +func (s *CIService) FaceEffect(ctx context.Context, obj string, opt *FaceEffectOptions) (*FaceEffectResult, *Response, error) { + var res FaceEffectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=face-effect", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type PetEffectResult struct { + XMLName xml.Name `xml:"Response"` + ResultInfo []struct { + Score int `xml:"Score,omitempty"` + Name string `xml:"Name,omitempty"` + Location struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Height int `xml:"Height,omitempty"` + Width int `xml:"Width,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"ResultInfo,omitempty"` +} + +func (s *CIService) EffectPet(ctx context.Context, obj string) (*PetEffectResult, *Response, error) { + var res PetEffectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=detect-pet", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type PetDetectOption struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +type PetDetectResult struct { + XMLName xml.Name `xml:"Response"` + ResultInfo []struct { + Score int `xml:"Score,omitempty"` + Name string `xml:"Name,omitempty"` + Location struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Height int `xml:"Height,omitempty"` + Width int `xml:"Width,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"ResultInfo,omitempty"` +} + +func (s *CIService) DetectPet(ctx context.Context, obj string, opt *PetDetectOption) (*PetDetectResult, *Response, error) { + var res PetDetectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=detect-pet", + result: &res, + optQuery: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type AILicenseRecOptions struct { + DetectUrl string `url:"detect-url,omitempty"` + CardType string `url:"CardType,omitempty"` +} + +type AILicenseRecResult struct { + XMLName xml.Name `xml:"Response"` + Status int `xml:"Status,omitempty"` + IdInfo []struct { + Name string `xml:"Name,omitempty"` + DetectedText string `xml:"DetectedText,omitempty"` + Score int `xml:"Score,omitempty"` + Location struct { + Point []string `xml:"Point,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"IdInfo,omitempty"` +} + +func (s *CIService) AILicenseRec(ctx context.Context, obj string, opt *AILicenseRecOptions) (*AILicenseRecResult, *Response, error) { + var res AILicenseRecResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=AILicenseRec", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type AIObjectDetectOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +type AIObjectDetectResult struct { + XMLName xml.Name `xml:"RecognitionResult"` + Status int `xml:"Status,omitempty"` + DetectMultiObj []struct { + Name string `xml:"Name,omitempty"` + Confidence int `xml:"Confidence,omitempty"` + Location struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"DetectMultiObj,omitempty"` +} + +func (s *CIService) AIObjectDetect(ctx context.Context, obj string, opt *AIObjectDetectOptions) (*AIObjectDetectResult, *Response, error) { + var res AIObjectDetectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=AIObjectDetect", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type IdCardOCROptions struct { + CardSide string `url:"CardSide,omitempty"` + Config *IdCardOCROptionsConfig `url:"Config,omitempty"` +} + +type IdCardOCROptionsConfig struct { + CropIdCard bool `json:"CropIdCard,omitempty"` + CropPortrait bool `json:"CropPortrait,omitempty"` + CopyWarn bool `json:"CopyWarn,omitempty"` + BorderCheckWarn bool `json:"BorderCheckWarn,omitempty"` + ReshootWarn bool `json:"ReshootWarn,omitempty"` + DetectPsWarn bool `json:"DetectPsWarn,omitempty"` + TempIdWarn bool `json:"TempIdWarn,omitempty"` + InvalidDateWarn bool `json:"InvalidDateWarn,omitempty"` + Quality bool `json:"Quality,omitempty"` + MultiCardDetect bool `json:"MultiCardDetect,omitempty"` +} + +func (c *IdCardOCROptionsConfig) EncodeValues(key string, v *url.Values) error { + config, err := json.Marshal(c) + if err != nil { + return err + } + v.Add("Config", string(config)) + + return nil +} + +type IdCardOCRResult struct { + XMLName xml.Name `xml:"Response"` + IdInfo *IdCardInfo `xml:"IdInfo,omitempty"` + AdvancedInfo *IdCardAdvancedInfo `xml:"AdvancedInfo,omitempty"` +} + +type IdCardInfo struct { + Name string `xml:"Name,omitempty"` + Sex string `xml:"Sex,omitempty"` + Nation string `xml:"Nation,omitempty"` + Birth string `xml:"Birth,omitempty"` + Address string `xml:"Address,omitempty"` + IdNum string `xml:"IdNum,omitempty"` + Authority string `xml:"Authority,omitempty"` + ValidDate string `xml:"ValidDate,omitempty"` +} + +type IdCardAdvancedInfo struct { + IdCard string `xml:"IdCard,omitempty"` + Portrait string `xml:"Portrait,omitempty"` + Quality string `xml:"Quality,omitempty"` + BorderCodeValue string `xml:"BorderCodeValue,omitempty"` + WarnInfos []string `xml:"WarnInfos,omitempty"` +} + +func (s *CIService) IdCardOCRWhenCloud(ctx context.Context, obj string, query *IdCardOCROptions) (*IdCardOCRResult, *Response, error) { + var res IdCardOCRResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=IDCardOCR", + optQuery: query, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *CIService) IdCardOCRWhenUpload(ctx context.Context, obj, filePath string, query *IdCardOCROptions, header *ObjectPutOptions) (*IdCardOCRResult, *Response, error) { + fd, err := os.Open(filePath) + if err != nil { + return nil, nil, err + } + defer fd.Close() + + if err := CheckReaderLen(fd); err != nil { + return nil, nil, err + } + opt := CloneObjectPutOptions(header) + totalBytes, err := GetReaderLen(fd) + if err != nil && opt != nil && opt.Listener != nil { + if opt.ContentLength == 0 { + return nil, nil, err + } + totalBytes = opt.ContentLength + } + if err == nil { + // 与 go http 保持一致, 非bytes.Buffer/bytes.Reader/strings.Reader由用户指定ContentLength, 或使用 Chunk 上传 + // if opt != nil && opt.ContentLength == 0 && IsLenReader(r) { + // opt.ContentLength = totalBytes + // } + // lilang : 2022-07-04 + // 图片cgi不设置content-length的话,读不到body。图片处理cgi暂时不支持chunked,后面会修复。 + if opt != nil && opt.ContentLength == 0 { + opt.ContentLength = totalBytes + } + + } + reader := TeeReader(fd, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + } + if opt != nil && opt.Listener != nil { + reader.listener = opt.Listener + } + + var res IdCardOCRResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(obj) + "?ci-process=IDCardOCR", + method: http.MethodPut, + optQuery: query, + body: reader, + optHeader: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + + return &res, resp, err +} + +type GetLiveCodeResult struct { + XMLName xml.Name `xml:"Response"` + LiveCode string `xml:"LiveCode,omitempty"` +} + +func (s *CIService) GetLiveCode(ctx context.Context) (*GetLiveCodeResult, *Response, error) { + var res GetLiveCodeResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/?ci-process=GetLiveCode", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type GetActionSequenceResult struct { + XMLName xml.Name `xml:"Response"` + ActionSequence string `xml:"ActionSequence,omitempty"` +} + +func (s *CIService) GetActionSequence(ctx context.Context) (*GetActionSequenceResult, *Response, error) { + var res GetActionSequenceResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/?ci-process=GetActionSequence", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type LivenessRecognitionOptions struct { + IdCard string `url:"IdCard,omitempty"` + Name string `url:"Name,omitempty"` + LivenessType string `url:"LivenessType,omitempty"` + ValidateData string `url:"ValidateData,omitempty"` + BestFrameNum int `url:"BestFrameNum,omitempty"` +} + +type LivenessRecognitionResult struct { + XMLName xml.Name `xml:"Response"` + BestFrameBase64 string `xml:"BestFrameBase64,omitempty"` + Sim float64 `xml:"Sim,omitempty"` + BestFrameList []string `xml:"BestFrameList,omitempty"` +} + +func (s *CIService) LivenessRecognitionWhenCloud(ctx context.Context, obj string, query *LivenessRecognitionOptions) (*LivenessRecognitionResult, *Response, error) { + var res LivenessRecognitionResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=LivenessRecognition", + optQuery: query, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *CIService) LivenessRecognitionWhenUpload(ctx context.Context, obj, filePath string, query *LivenessRecognitionOptions, header *ObjectPutOptions) (*LivenessRecognitionResult, *Response, error) { + fd, err := os.Open(filePath) + if err != nil { + return nil, nil, err + } + defer fd.Close() + + if err := CheckReaderLen(fd); err != nil { + return nil, nil, err + } + opt := CloneObjectPutOptions(header) + totalBytes, err := GetReaderLen(fd) + if err != nil && opt != nil && opt.Listener != nil { + if opt.ContentLength == 0 { + return nil, nil, err + } + totalBytes = opt.ContentLength + } + if err == nil { + // 与 go http 保持一致, 非bytes.Buffer/bytes.Reader/strings.Reader由用户指定ContentLength, 或使用 Chunk 上传 + // if opt != nil && opt.ContentLength == 0 && IsLenReader(r) { + // opt.ContentLength = totalBytes + // } + // lilang : 2022-07-04 + // 图片cgi不设置content-length的话,读不到body。图片处理cgi暂时不支持chunked,后面会修复。 + if opt != nil && opt.ContentLength == 0 { + opt.ContentLength = totalBytes + } + + } + reader := TeeReader(fd, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + } + if opt != nil && opt.Listener != nil { + reader.listener = opt.Listener + } + + var res LivenessRecognitionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(obj) + "?ci-process=LivenessRecognition", + method: http.MethodPut, + optQuery: query, + body: reader, + optHeader: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + + return &res, resp, err +} + +type GoodsMattingptions struct { + CenterLayout string `url:"center-layout,omitempty"` + PaddingLayout string `url:"padding-layout,omitempty"` + DetectUrl string `url:"detect-url,omitempty"` +} + +// GoodsMatting 商品抠图 +func (s *CIService) GoodsMatting(ctx context.Context, key string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(key) + "?ci-process=GoodsMatting", + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// GoodsMattingWithOpt 商品抠图 +func (s *CIService) GoodsMattingWithOpt(ctx context.Context, key string, opt *GoodsMattingptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(key) + "?ci-process=GoodsMatting", + optQuery: opt, + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type PedestrianLocation CodeLocation + +type PedestrianInfo struct { + Name string `xml:"Name,omitempty"` + Score int `xml:"Score,omitempty"` + Location *PedestrianLocation `xml:"Location,omitempty"` +} + +type AIBodyRecognitionResult struct { + XMLName xml.Name `xml:"RecognitionResult"` + Status int `xml:"Status,omitempty"` + PedestrianInfo []PedestrianInfo `xml:"PedestrianInfo,omitempty"` +} + +// AIBodyRecognitionOptions is the option of AIBodyRecognitionWithOpt +type AIBodyRecognitionOptions struct { + CIProcess string `url:"ci-process,omitempty"` + DetectUrl string `url:"detect-url,omitempty"` +} + +// 人体识别 https://cloud.tencent.com/document/product/436/83728 +func (s *CIService) AIBodyRecognition(ctx context.Context, key string, opt *AIBodyRecognitionOptions) (*AIBodyRecognitionResult, *Response, error) { + var res AIBodyRecognitionResult + opt.CIProcess = "AIBodyRecognition" + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(key), + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// 海报合成 +// PosterproductionInput TODO +type PosterproductionInput struct { + Object string `xml:"Object,omitempty"` +} + +// PosterproductionTemplateOptions TODO +type PosterproductionTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Input *PosterproductionInput `xml:"Input,omitempty"` + Name string `xml:"Name,omitempty"` + CategoryIds string `xml:"CategoryIds,omitempty"` +} + +// DescribePosterproductionTemplateOptions TODO +type DescribePosterproductionTemplateOptions struct { + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` + CategoryIds string `url:"categoryIds,omitempty"` + Type string `url:"type,omitempty"` +} + +// PosterproductionTemplateResult TODO +type PosterproductionTemplateResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + Template interface{} `xml:"Template,omitempty"` +} + +// PosterproductionTemplateResult TODO +type PosterproductionTemplateResults struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount string `xml:"TotalCount,omitempty"` + PageNumber string `xml:"PageNumber,omitempty"` + PageSize string `xml:"PageSize,omitempty"` + TemplateList interface{} `xml:"TemplateList,omitempty"` +} + +func (s *CIService) PutPosterproductionTemplate(ctx context.Context, opt *PosterproductionTemplateOptions) (*PosterproductionTemplateResult, *Response, error) { + var res PosterproductionTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/posterproduction/template", + method: http.MethodPost, + optQuery: nil, + body: &opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *CIService) GetPosterproductionTemplate(ctx context.Context, tplId string) (*PosterproductionTemplateResult, *Response, error) { + var res PosterproductionTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/posterproduction/template/" + tplId, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *CIService) GetPosterproductionTemplates(ctx context.Context, opt *DescribePosterproductionTemplateOptions) (*PosterproductionTemplateResults, *Response, error) { + var res PosterproductionTemplateResults + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/posterproduction/template", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetOriginImage https://cloud.tencent.com/document/product/460/90744 +func (s *CIService) GetOriginImage(ctx context.Context, name string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=originImage", + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// GetAIImageColoring https://https://cloud.tencent.com/document/product/460/83794 +func (s *CIService) GetAIImageColoring(ctx context.Context, name string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AIImageColoring", + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// AIImageColoringOptions TODO +type AIImageColoringOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +// GetAIImageColoringV2 todo +func (s *CIService) GetAIImageColoringV2(ctx context.Context, name string, opt *AIImageColoringOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AIImageColoring", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// GetAISuperResolution https://cloud.tencent.com/document/product/460/83793 +func (s *CIService) GetAISuperResolution(ctx context.Context, name string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AISuperResolution", + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// AISuperResolutionOptions TODO +type AISuperResolutionOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +// GetAISuperResolutionV2 https://cloud.tencent.com/document/product/460/83793 +func (s *CIService) GetAISuperResolutionV2(ctx context.Context, name string, opt *AISuperResolutionOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AISuperResolution", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// GetAIEnhanceImage https://cloud.tencent.com/document/product/460/83792 +func (s *CIService) GetAIEnhanceImage(ctx context.Context, name string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AIEnhanceImage", + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// AIEnhanceImageOptions 图像增强选项 +type AIEnhanceImageOptions struct { + DetectUrl string `url:"detect-url,omitempty"` + Senoise int `url:"denoise,omitempty"` + Sharpen int `url:"sharpen,omitempty"` + IgnoreError int `url:"ignore-error,omitempty"` +} + +// GetAIEnhanceImageV2 https://cloud.tencent.com/document/product/460/83792 +func (s *CIService) GetAIEnhanceImageV2(ctx context.Context, name string, opt *AIEnhanceImageOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AIEnhanceImage", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// AIImageCropOptions 图像智能裁剪选项 +type AIImageCropOptions struct { + DetectUrl string `url:"detect-url,omitempty"` + Width int `url:"width,omitempty"` + Height int `url:"height,omitempty"` + Fixed int `url:"fixed,omitempty"` + IgnoreError int `url:"ignore-error,omitempty"` +} + +// GetAIImageCrop https://cloud.tencent.com/document/product/460/83791 +func (s *CIService) GetAIImageCrop(ctx context.Context, name string, opt *AIImageCropOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AIImageCrop", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// AutoTranslationBlockOptions 实时文字翻译 +type AutoTranslationBlockOptions struct { + InputText string `url:"InputText,omitempty"` + SourceLang string `url:"SourceLang,omitempty"` + TargetLang string `url:"TargetLang,omitempty"` + TextDomain string `url:"TextDomain,omitempty"` + TextStyle string `url:"TextStyle,omitempty"` +} + +// AutoTranslationBlockResults 实时文字翻译选项 +type AutoTranslationBlockResults struct { + XMLName xml.Name `xml:"TranslationResult"` + TranslationResult string `xml:",chardata"` +} + +// GetAIImageCrop https://cloud.tencent.com/document/product/460/83547 +func (s *CIService) GetAutoTranslationBlock(ctx context.Context, opt *AutoTranslationBlockOptions) (*AutoTranslationBlockResults, *Response, error) { + var res AutoTranslationBlockResults + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?ci-process=AutoTranslationBlock", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// ImageRepairOptions 图像修复选项 +type ImageRepairOptions struct { + DetectUrl string `url:"detect-url,omitempty"` + MaskPic string `url:"MaskPic,omitempty"` + MaskPoly string `url:"MaskPoly,omitempty"` +} + +// GetImageRepair https://cloud.tencent.com/document/product/460/79042 +func (s *CIService) GetImageRepair(ctx context.Context, name string, opt *ImageRepairOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=ImageRepair", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// RecognizeLogoOptions Logo识别选项 +type RecognizeLogoOptions struct { + DetectUrl string `url:"detect-url,omitempty"` + IgnoreError int `url:"ignore-error,omitempty"` +} + +// RecognizeLogoResults Logo识别结果 +type RecognizeLogoResults struct { + XMLName xml.Name `xml:"RecognitionResult"` + Status int `xml:"Status"` + LogoInfo []struct { + Name string `xml:"Name,omitempty"` + Sorce string `xml:"Sorce,omitempty"` + Location struct { + Point []string `xml:"Point,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"LogoInfo,omitempty"` +} + +// GetRecognizeLogo https://cloud.tencent.com/document/product/460/79736 +func (s *CIService) GetRecognizeLogo(ctx context.Context, name string, opt *RecognizeLogoOptions) (*RecognizeLogoResults, *Response, error) { + var res RecognizeLogoResults + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=RecognizeLogo", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// AssessQualityResults Logo识别结果 +type AssessQualityResults struct { + XMLName xml.Name `xml:"Response"` + LongImage bool `xml:"LongImage"` + BlackAndWhite bool `xml:"BlackAndWhite"` + SmallImage bool `xml:"SmallImage"` + BigImage bool `xml:"BigImage"` + PureImage bool `xml:"PureImage"` + ClarityScore int `xml:"ClarityScore"` + AestheticScore int `xml:"AestheticScore"` + RequestId string `xml:"RequestId"` +} + +// GetAssessQuality https://cloud.tencent.com/document/product/460/63228 +func (s *CIService) GetAssessQuality(ctx context.Context, name string) (*AssessQualityResults, *Response, error) { + var res AssessQualityResults + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AssessQuality", + method: http.MethodGet, + disableCloseBody: true, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *CIService) TDCRefresh(ctx context.Context, name string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/" + encodeURIComponent(name) + "?TDCRefresh", + method: http.MethodPost, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type AIGameRecOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +type AIGameRecResult struct { + XMLName xml.Name `xml:"RecognitionResult"` + GameLabels *struct { + Confidence int `xml:"Confidence,omitempty"` + FirstCategory string `xml:"FirstCategory,omitempty"` + SecondCategory string `xml:"SecondCategory,omitempty"` + GameName string `xml:"GameName,omitempty"` + } `xml:"GameLabels,omitempty"` +} + +// AIGameRec 游戏识别 +func (s *CIService) AIGameRec(ctx context.Context, obj string, opt *AIGameRecOptions) (*AIGameRecResult, *Response, error) { + var res AIGameRecResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=AIGameRec", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type AIPicMattingOptions struct { + DetectUrl string `url:"detect-url, omitempty" json:"-"` // 您可以通过填写 detect-url 处理任意公网可访问的图片链接。不填写 detect-url 时,后台会默认处理 ObjectKey ,填写了 detect-url 时,后台会处理 detect-url 链接,无需再填写 ObjectKey detect-url 示例:http://www.example.com/abc.jpg ,需要进行 UrlEncode,处理后为http%25253A%25252F%25252Fwww.example.com%25252Fabc.jpg。 + CenterLayout int `url:"center-layout, omitempty" json:"-"` // 抠图主体居中显示;值为1时居中显示,值为0不做处理,默认为0 + PaddingLayout string `url:"padding-layout, omitempty" json:"-"` // 将处理后的图片四边进行留白,形式为 padding-layout=x,左右两边各进行 dx 像素的留白,上下两边各进行 dy 像素的留白,例如:padding-layout=20x10默认不进行留白操作,dx、dy 最大值为1000像素。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +// AIPicMatting 通用抠图 +// https://cloud.tencent.com/document/product/460/106750 +func (s *CIService) AIPicMatting(ctx context.Context, ObjectKey string, opt *AIPicMattingOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(ObjectKey) + "?ci-process=AIPicMatting", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type AIPortraitMattingOptions struct { + DetectUrl string `url:"detect-url, omitempty" json:"-"` // 您可以通过填写 detect-url 处理任意公网可访问的图片链接。不填写 detect-url 时,后台会默认处理 ObjectKey ,填写了 detect-url 时,后台会处理 detect-url 链接,无需再填写 ObjectKey。 detect-url 示例:http://www.example.com/abc.jpg,需要进行 UrlEncode,处理后为http%25253A%25252F%25252Fwww.example.com%25252Fabc.jpg。 + CenterLayout int `url:"center-layout, omitempty" json:"-"` // 抠图主体居中显示;值为1时居中显示,值为0不做处理,默认为0 + PaddingLayout string `url:"padding-layout, omitempty" json:"-"` // 将处理后的图片四边进行留白,形式为 padding-layout=x,左右两边各进行 dx 像素的留白,上下两边各进行 dy 像素的留白,例如:padding-layout=20x10默认不进行留白操作,dx、dy最大值为1000像素。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +// AIPortraitMatting 人像抠图 +// https://cloud.tencent.com/document/product/460/106751 +func (s *CIService) AIPortraitMatting(ctx context.Context, ObjectKey string, opt *AIPortraitMattingOptions) (*Response, error) { + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(ObjectKey) + "?ci-process=AIPortraitMatting", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type AIRecognitionResult struct { + XMLName xml.Name `xml:"Response" json:"response,omitempty"` + // BodyJointsDetect struct { + // BodyJointsResults []struct { + // BodyJoints []struct { + // KeyPointType string `xml:"KeyPointType"` + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"BodyJoints" json:"bodyjoints,omitempty"` + // BoundBox struct { + // Height string `xml:"Height"` + // Width string `xml:"Width"` + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"BoundBox" json:"boundbox,omitempty"` + // Confidence string `xml:"Confidence"` + // } `xml:"BodyJointsResults" json:"bodyjointsresults,omitempty"` + // RequestId string `xml:"RequestId"` + // } `xml:"BodyJointsDetect" json:"bodyjointsdetect,omitempty"` + // DetectLabel struct { + // Labels []struct { + // Confidence string `xml:"Confidence"` + // Name string `xml:"Name"` + // } `xml:"Labels" json:"labels,omitempty"` + // } `xml:"DetectLabel" json:"detectlabel,omitempty"` + // OCR struct { + // Angel string `xml:"Angel"` + // Language string `xml:"Language"` + // PdfPageSize string `xml:"PdfPageSize"` + // RequestId string `xml:"RequestId"` + // TextDetections []struct { + // Confidence string `xml:"Confidence"` + // DetectedText string `xml:"DetectedText"` + // ItemPolygon struct { + // Height string `xml:"Height"` + // Width string `xml:"Width"` + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"ItemPolygon" json:"itempolygon,omitempty"` + // Polygon []struct { + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"Polygon" json:"polygon,omitempty"` + // Words string `xml:"Words"` + // } `xml:"TextDetections" json:"textdetections,omitempty"` + // } `xml:"OCR" json:"ocr,omitempty"` + // EnhanceImage struct { + // EnhancedImage string `xml:"EnhancedImage"` + // } `xml:"EnhanceImage" json:"enhanceimage,omitempty"` + DetectVehicle struct { + Vehicles []struct { + Location struct { + Height int `xml:"Height"` + Width int `xml:"Width"` + X int `xml:"X"` + Y int `xml:"Y"` + } `xml:"Location" json:"location,omitempty"` + Name string `xml:"Name"` + Score int `xml:"Score"` + } `xml:"Vehicles" json:"vehicles,omitempty"` + } `xml:"DetectVehicle" json:"detectvehicle,omitempty"` + DetectPedestrian struct { + Pedestrians []struct { + Location struct { + Height int `xml:"Height"` + Width int `xml:"Width"` + X int `xml:"X"` + Y int `xml:"Y"` + } `xml:"Location" json:"location,omitempty"` + Name string `xml:"Name"` + Score int `xml:"Score"` + } `xml:"Pedestrians" json:"pedestrians,omitempty"` + } `xml:"DetectPedestrian" json:"detectpedestrian,omitempty"` + DetectPet struct { + Pets []struct { + Location struct { + Height int `xml:"Height"` + Width int `xml:"Width"` + X int `xml:"X"` + Y int `xml:"Y"` + } `xml:"Location" json:"location,omitempty"` + Name string `xml:"Name"` + Score int `xml:"Score"` + } `xml:"Pets" json:"pets,omitempty"` + } `xml:"DetectPet" json:"detectpet,omitempty"` +} + +type AIRecognitionOptions struct { + DetectType string `url:"detect-type, omitempty" json:"-"` + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +// AIRecognition 多AI接口合一 +func (s *CIService) AIRecognition(ctx context.Context, ObjectKey string, opt *AIRecognitionOptions) (*AIRecognitionResult, *Response, error) { + var res AIRecognitionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(ObjectKey) + "?ci-process=ai-recognition", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type ImageSlimSuffixs struct { + Suffix []string `xml:"Suffix,omitempty"` +} + +type ImageSlim struct { + XMLName xml.Name `xml:"ImageSlim"` + SlimMode string `xml:"SlimMode,omitempty"` + Suffixs *ImageSlimSuffixs `xml:"Suffixs,omitempty"` +} + +type ImageSlimResult struct { + XMLName xml.Name `xml:"ImageSlim"` + SlimMode string `xml:"SlimMode,omitempty"` + Status string `xml:"Status,omitempty"` + Suffixs *ImageSlimSuffixs `xml:"Suffixs,omitempty"` +} + +type ImageSlimOptions ImageSlim + +// PutImageSlim 开通 极智压缩ImageSlim https://cloud.tencent.com/document/product/460/95042 +func (s *CIService) PutImageSlim(ctx context.Context, opt *ImageSlimOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?image-slim", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +// GetImageSlim 查询 极智压缩ImageSlim https://cloud.tencent.com/document/product/460/95043 +func (s *CIService) GetImageSlim(ctx context.Context) (*ImageSlimResult, *Response, error) { + var res ImageSlimResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?image-slim", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +// DeleteImageSlim 关闭 极智压缩ImageSlim https://cloud.tencent.com/document/product/460/95044 +func (s *CIService) DeleteImageSlim(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?image-slim", + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +// DescribeCIBucketsOptions is the option of CIBuckets +type DescribeCIBucketsOptions struct { + BucketName string `url:"bucketName,omitempty"` + TagKey string `url:"tagKey,omitempty"` + Region string `url:"region,omitempty"` + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` +} + +// CIBucketList is the result of CIBuckets +type CIBucketList struct { + BucketId string `xml:"BucketId,omitempty"` + BucketName string `xml:"BucketName,omitempty"` + AppId string `xml:"AppId,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + Region string `xml:"Region,omitempty"` + Status string `xml:"Status,omitempty"` +} + +// CIBucketsResult is the result of CIBuckets +type CIBucketsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount string `xml:"TotalCount,omitempty"` + PageNumber string `xml:"PageNumber,omitempty"` + PageSize string `xml:"PageSize,omitempty"` + CIBucketList []CIBucketList `xml:"CIBucketList,omitempty"` +} + +// DescribeCIBuckets 查询CI桶列表 +func (s *CIService) DescribeCIBuckets(ctx context.Context, opt *DescribeCIBucketsOptions) (*CIBucketsResult, *Response, error) { + var res CIBucketsResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/cibuckets", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +// ImgTargetRecResult 图片识别结果 +type ImgTargetRecResult struct { + BodyDetailInfos struct { + BodyDetailInfo []struct { + X string `xml:"X"` + Y string `xml:"Y"` + Width string `xml:"Width"` + Height string `xml:"Height"` + } `xml:"BodyDetailInfo"` + } `xml:"BodyDetailInfos"` + CarDetailInfos struct { + CarDetailInfo []struct { + X string `xml:"X"` + Y string `xml:"Y"` + Width string `xml:"Width"` + Height string `xml:"Height"` + } `xml:"CarDetailInfo"` + } `xml:"CarDetailInfos"` + FaceDetailInfos struct { + FaceDetailInfo []struct { + X string `xml:"X"` + Y string `xml:"Y"` + Width string `xml:"Width"` + Height string `xml:"Height"` + } `xml:"FaceDetailInfo"` + } `xml:"FaceDetailInfos"` + PlateDetailInfos struct { + PlateDetailInfo []struct { + X string `xml:"X"` + Y string `xml:"Y"` + Width string `xml:"Width"` + Height string `xml:"Height"` + } `xml:"PlateDetailInfo"` + } `xml:"PlateDetailInfos"` +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go new file mode 100644 index 00000000000..6a538429a50 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go @@ -0,0 +1,434 @@ +package cos + +import ( + "bytes" + "context" + "encoding/json" + "encoding/xml" + "io" + "net/http" + "net/url" +) + +type DocProcessJobInput struct { + Object string `xml:"Object,omitempty"` +} + +type DocProcessJobOutput struct { + Region string `xml:"Region,omitempty"` + Bucket string `xml:"Bucket,omitempty"` + Object string `xml:"Object,omitempty"` +} + +type DocProcessJobDocProcess struct { + SrcType string `xml:"SrcType,omitempty"` + TgtType string `xml:"TgtType,omitempty"` + SheetId int `xml:"SheetId,omitempty"` + StartPage int `xml:"StartPage,omitempty"` + EndPage int `xml:"EndPage,omitempty"` + ImageParams string `xml:"ImageParams,omitempty"` + DocPassword string `xml:"DocPassword,omitempty"` + Comments int `xml:"Comments,omitempty"` + PaperDirection int `xml:"PaperDirection,omitempty"` + Quality int `xml:"Quality,omitempty"` + Zoom int `xml:"Zoom,omitempty"` + PaperSize int `xml:"PaperSize,omitempty"` + ImageDpi int `xml:"ImageDpi,omitempty"` + PicPagination int `xml:"PicPagination,omitempty"` +} + +type DocProcessJobDocProcessResult struct { + FailPageCount int `xml:",omitempty"` + SuccPageCount int `xml:"SuccPageCount,omitempty"` + TaskId string `xml:"TaskId,omitempty"` + TgtType string `xml:"TgtType,omitempty"` + TotalPageCount int `xml:"TotalPageCount,omitempty"` + TotalSheetCount int `xml:"TotalSheetCount,omitempty"` + PageInfo []struct { + PageNo int `xml:"PageNo,omitempty"` + TgtUri string `xml:"TgtUri,omitempty"` + XSheetPics int `xml:"X-SheetPics,omitempty"` + PicIndex int `xml:"PicIndex,omitempty"` + PicNum int `xml:"PicNum,omitempty"` + } `xml:"PageInfo,omitempty"` +} + +type DocProcessJobOperation struct { + Output *DocProcessJobOutput `xml:"Output,omitempty"` + DocProcess *DocProcessJobDocProcess `xml:"DocProcess,omitempty"` + DocProcessResult *DocProcessJobDocProcessResult `xml:"DocProcessResult,omitempty"` +} + +type DocProcessJobDetail struct { + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + JobId string `xml:"JobId,omitempty"` + Tag string `xml:"Tag,omitempty"` + State string `xml:"State,omitempty"` + CreationTime string `xml:"CreationTime,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + Input *DocProcessJobInput `xml:"Input,omitempty"` + Operation *DocProcessJobOperation `xml:"Operation,omitempty"` +} + +type CreateDocProcessJobsOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *DocProcessJobInput `xml:"Input,omitempty"` + Operation *DocProcessJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` +} + +type CreateDocProcessJobsResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail DocProcessJobDetail `xml:"JobsDetail,omitempty"` +} + +// CreateDocProcessJobs 创建文档预览任务 https://cloud.tencent.com/document/product/436/54056 +func (s *CIService) CreateDocProcessJobs(ctx context.Context, opt *CreateDocProcessJobsOptions) (*CreateDocProcessJobsResult, *Response, error) { + var res CreateDocProcessJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/doc_jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type DescribeDocProcessJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *DocProcessJobDetail `xml:"JobsDetail,omitempty"` + NonExistJobIds string `xml:"NonExistJobIds,omitempty"` +} + +// DescribeDocProcessJob 查询文档预览任务 https://cloud.tencent.com/document/product/436/54095 +func (s *CIService) DescribeDocProcessJob(ctx context.Context, jobid string) (*DescribeDocProcessJobResult, *Response, error) { + var res DescribeDocProcessJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/doc_jobs/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type DescribeDocProcessJobsOptions struct { + QueueId string `url:"queueId,omitempty"` + Tag string `url:"tag,omitempty"` + OrderByTime string `url:"orderByTime,omitempty"` + NextToken string `url:"nextToken,omitempty"` + Size int `url:"size,omitempty"` + States string `url:"states,omitempty"` + StartCreationTime string `url:"startCreationTime,omitempty"` + EndCreationTime string `url:"endCreationTime,omitempty"` +} + +type DescribeDocProcessJobsResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail []DocProcessJobDetail `xml:"JobsDetail,omitempty"` + NextToken string `xml:"NextToken,omitempty"` +} + +// DescribeDocProcessJobs 拉取符合条件的文档预览任务 https://cloud.tencent.com/document/product/436/54096 +func (s *CIService) DescribeDocProcessJobs(ctx context.Context, opt *DescribeDocProcessJobsOptions) (*DescribeDocProcessJobsResult, *Response, error) { + var res DescribeDocProcessJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/doc_jobs", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type DescribeDocProcessQueuesOptions struct { + QueueIds string `url:"queueIds,omitempty"` + State string `url:"state,omitempty"` + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` +} + +type DescribeDocProcessQueuesResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + QueueList []DocProcessQueue `xml:"QueueList,omitempty"` + NonExistPIDs []string `xml:"NonExistPIDs,omitempty"` +} + +type DocProcessQueue struct { + QueueId string `xml:"QueueId,omitempty"` + Name string `xml:"Name,omitempty"` + State string `xml:"State,omitempty"` + MaxSize int `xml:"MaxSize,omitempty"` + MaxConcurrent int `xml:"MaxConcurrent,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + NotifyConfig *DocProcessQueueNotifyConfig `xml:"NotifyConfig,omitempty"` +} + +type DocProcessQueueNotifyConfig struct { + Url string `xml:"Url,omitempty"` + State string `xml:"State,omitempty"` + Type string `xml:"Type,omitempty"` + Event string `xml:"Event,omitempty"` +} + +// DescribeDocProcessQueues 查询文档预览队列 https://cloud.tencent.com/document/product/436/54055 +func (s *CIService) DescribeDocProcessQueues(ctx context.Context, opt *DescribeDocProcessQueuesOptions) (*DescribeDocProcessQueuesResult, *Response, error) { + var res DescribeDocProcessQueuesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/docqueue", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type UpdateDocProcessQueueOptions struct { + XMLName xml.Name `xml:"Request"` + Name string `xml:"Name,omitempty"` + QueueID string `xml:"QueueID,omitempty"` + State string `xml:"State,omitempty"` + NotifyConfig *DocProcessQueueNotifyConfig `xml:"NotifyConfig,omitempty"` +} + +type UpdateDocProcessQueueResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId"` + Queue *DocProcessQueue `xml:"Queue"` +} + +// UpdateDocProcessQueue 更新文档预览队列 https://cloud.tencent.com/document/product/436/54094 +func (s *CIService) UpdateDocProcessQueue(ctx context.Context, opt *UpdateDocProcessQueueOptions) (*UpdateDocProcessQueueResult, *Response, error) { + var res UpdateDocProcessQueueResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/docqueue/" + opt.QueueID, + body: opt, + method: http.MethodPut, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type DescribeDocProcessBucketsOptions struct { + Regions string `url:"regions,omitempty"` + BucketNames string `url:"bucketNames,omitempty"` + BucketName string `url:"bucketName,omitempty"` + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` +} + +type DescribeDocProcessBucketsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + DocBucketList []DocProcessBucket `xml:"DocBucketList,omitempty"` +} +type DocProcessBucket struct { + BucketId string `xml:"BucketId,omitempty"` + Name string `xml:"Name,omitempty"` + Region string `xml:"Region,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + AliasBucketId string `xml:"AliasBucketId,omitempty"` +} + +// DescribeDocProcessBuckets 开通文档预览功能 https://cloud.tencent.com/document/product/460/103608 +func (s *CIService) DescribeDocProcessBuckets(ctx context.Context, opt *DescribeDocProcessBucketsOptions) (*DescribeDocProcessBucketsResult, *Response, error) { + var res DescribeDocProcessBucketsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/docbucket", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type CreateDocProcessBucketOptions struct { +} + +type CreateDocProcessBucketResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + DocBucket DocProcessBucket `xml:"DocBucket,omitempty"` +} + +// CreateDocProcessBucket 查询文档预览开通状态 https://cloud.tencent.com/document/product/436/54057 +func (s *CIService) CreateDocProcessBucket(ctx context.Context, opt *CreateDocProcessBucketOptions) (*CreateDocProcessBucketResult, *Response, error) { + var res CreateDocProcessBucketResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/docbucket", + optQuery: opt, + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type DocPreviewOptions struct { + SrcType string `url:"srcType,omitempty"` + Page int `url:"page,omitempty"` + ImageParams string `url:"ImageParams,omitempty"` + Sheet int `url:"sheet,omitempty"` + DstType string `url:"dstType,omitempty"` + Password string `url:"password,omitempty"` + Comment int `url:"comment,omitempty"` + ExcelPaperDirection int `url:"excelPaperDirection,omitempty"` + Quality int `url:"quality,omitempty"` + Zoom int `url:"zoom,omitempty"` + ExcelRow int `url:"excelRow,omitempty"` + ExcelCol int `url:"excelCol,omitempty"` + ExcelPaperSize int `url:"excelPaperSize,omitempty"` + TxtPagination bool `url:"txtPagination,omitempty"` + Scale int `url:"scale,omitempty"` + ImageDpi int `url:"imageDpi,omitempty"` +} + +// DocPreview 同步请求接口 https://cloud.tencent.com/document/product/436/54058 +func (s *CIService) DocPreview(ctx context.Context, name string, opt *DocPreviewOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=doc-preview", + optQuery: opt, + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type CIDocCompareOptions struct { + Object string `url:"object,omitempty"` + ComparePath string `url:"comparePath,omitempty"` + CompareUrl string `url:"compareUrl,omitempty"` + SrcType string `url:"srcType,omitempty"` + TgtUri string `url:"tgtUri,omitempty"` +} + +type CIDocCompareResult struct { + XMLName xml.Name `xml:"Response"` + Code string `xml:"Code,omitempty" json:"code,omitempty"` + ETag string `xml:"ETag,omitempty" json:"eTag,omitempty"` + Msg string `xml:"Msg,omitempty" json:"msg,omitempty"` + ResultPath string `xml:"ResultPath,omitempty" json:"resultPath,omitempty"` +} + +// 优先 json +func (w *CIDocCompareResult) Write(p []byte) (n int, err error) { + err = json.Unmarshal(p, w) + if err != nil { + err = xml.NewDecoder(bytes.NewReader(p)).Decode(w) + if err == nil { + return len(p), nil + } + if err == io.EOF { + err = nil // ignore EOF errors caused by empty response body + } + return 0, err + } + return len(p), nil +} + +// CIDocCompare TODO +func (s *CIService) CIDocCompare(ctx context.Context, opt *CIDocCompareOptions) (*Response, *CIDocCompareResult, error) { + var res CIDocCompareResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/doccompare", + optQuery: opt, + method: http.MethodGet, + disableCloseBody: true, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, &res, err +} + +type DocPreviewHTMLOptions struct { + DstType string `url:"dstType,omitempty"` + SrcType string `url:"srcType,omitempty"` + WebofficeUrl string `url:"weboffice_url,omitempty"` + TokenUid string `url:"tokenuid,omitempty"` + Sign string `url:"sign,omitempty"` + Copyable string `url:"copyable,omitempty"` + HtmlParams *HtmlParams `url:"htmlParams,omitempty"` + Htmlwaterword string `url:"htmlwaterword,omitempty"` + Htmlfillstyle string `url:"htmlfillstyle,omitempty"` + Htmlfront string `url:"htmlfront,omitempty"` + Htmlrotate string `url:"htmlrotate,omitempty"` + Htmlhorizontal string `url:"htmlhorizontal,omitempty"` + Htmlvertical string `url:"htmlvertical,omitempty"` +} + +func (c *HtmlParams) EncodeValues(key string, v *url.Values) error { + config, err := json.Marshal(c) + if err != nil { + return err + } + v.Add("htmlParams", string(config)) + return nil +} + +type HtmlParams struct { + CommonOptions *HtmlCommonParams `json:"commonOptions,omitempty"` + WordOptions *HtmlWordParams `json:"wordOptions,omitempty"` + PdfOptions *HtmlPdfParams `json:"pdfOptions,omitempty"` + PptOptions *HtmlPptParams `json:"pptOptions,omitempty"` +} + +type HtmlCommonParams struct { + IsShowTopArea bool `json:"isShowTopArea"` + IsShowHeader bool `json:"isShowHeader"` + IsBrowserViewFullscreen bool `json:"isBrowserViewFullscreen"` + IsIframeViewFullscreen bool `json:"isIframeViewFullscreen"` +} + +type HtmlWordParams struct { + IsShowDocMap bool `json:"isShowDocMap"` + IsBestScale bool `json:"isBestScale"` + IsShowBottomStatusBar bool `json:"isShowBottomStatusBar"` +} + +type HtmlPdfParams struct { + IsShowComment bool `json:"isShowComment"` + IsInSafeMode bool `json:"isInSafeMode"` + IsShowBottomStatusBar bool `json:"isShowBottomStatusBar"` +} + +type HtmlPptParams struct { + IsShowBottomStatusBar bool `json:"isShowBottomStatusBar"` +} + +// DocPreviewHTML 文档转html https://cloud.tencent.com/document/product/460/52518 +func (s *CIService) DocPreviewHTML(ctx context.Context, name string, opt *DocPreviewHTMLOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=doc-preview", + optQuery: opt, + method: http.MethodGet, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go new file mode 100644 index 00000000000..d737cae05f5 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go @@ -0,0 +1,207 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type FileHashCodeConfig struct { + Type string `xml:",omitempty"` + AddToHeader bool `xml:",omitempty"` +} + +type FileHashCodeResult struct { + MD5 string `xml:",omitempty"` + SHA1 string `xml:",omitempty"` + SHA256 string `xml:",omitempty"` + FileSize int `xml:",omitempty"` + LastModified string `xml:",omitempty"` + Etag string `xml:",omitempty"` +} + +type FileUncompressConfig struct { + Prefix string `xml:",omitempty"` + PrefixReplaced string `xml:",omitempty"` + UnCompressKey string `xml:",omitempty"` + Mode string `xml:",omitempty"` + DownloadConfig *FileUncompressDownloadConfig `xml:",omitempty"` +} + +type FileUncompressDownloadConfig struct { + Prefix string `xml:",omitempty"` + Key []string `xml:",omitempty"` +} + +type FileUncompressResult struct { + Region string `xml:",omitempty"` + Bucket string `xml:",omitempty"` + FileCount string `xml:",omitempty"` +} + +type KeyConfig struct { + Key string `xml:",omitempty"` + Folder string `xml:",omitempty"` + Rename string `xml:",omitempty"` + ImageParams string `xml:",omitempty"` +} + +type FileCompressConfig struct { + Flatten string `xml:",omitempty"` + Format string `xml:",omitempty"` + UrlList string `xml:",omitempty"` + Prefix string `xml:",omitempty"` + Key []string `xml:",omitempty"` + Type string `xml:",omitempty"` + CompressKey string `xml:",omitempty"` + IgnoreError string `xml:",omitempty"` + KeyConfig []KeyConfig `xml:",omitempty"` +} + +type FileCompressResult struct { + Region string `xml:",omitempty"` + Bucket string `xml:",omitempty"` + Object string `xml:",omitempty"` + CompressFileCount int `xml:",omitempty"` + ErrorCount int `xml:",omitempty"` + ErrorDetail *ErrorDetail `xml:",omitempty"` +} + +type ErrorDetail struct { + ErrorCount string `xml:",omitempty"` + ErrorFile []string `xml:",omitempty"` +} + +type FileProcessInput FileCompressResult +type FileProcessOutput FileCompressResult + +type FileProcessJobOperation struct { + FileHashCodeConfig *FileHashCodeConfig `xml:",omitempty"` + FileHashCodeResult *FileHashCodeResult `xml:",omitempty"` + FileUncompressConfig *FileUncompressConfig `xml:",omitempty"` + FileUncompressResult *FileUncompressResult `xml:",omitempty"` + FileCompressConfig *FileCompressConfig `xml:",omitempty"` + FileCompressResult *FileCompressResult `xml:",omitempty"` + Output *FileProcessOutput `xml:",omitempty"` + UserData string `xml:",omitempty"` +} + +type FileProcessJobOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:",omitempty"` + Input *FileProcessInput `xml:",omitempty"` + Operation *FileProcessJobOperation `xml:",omitempty"` + QueueId string `xml:",omitempty"` + CallBackFormat string `xml:",omitempty"` + CallBackType string `xml:",omitempty"` + CallBack string `xml:",omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:",omitempty"` +} + +type FileProcessJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *FileProcessJobsDetail `xml:",omitempty"` +} + +type FileProcessJobsDetail struct { + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + JobId string `xml:",omitempty"` + Tag string `xml:",omitempty"` + State string `xml:",omitempty"` + CreationTime string `xml:",omitempty"` + StartTime string `xml:",omitempty"` + EndTime string `xml:",omitempty"` + QueueId string `xml:",omitempty"` + Progress int `xml:",omitempty"` + Input *FileProcessInput `xml:",omitempty"` + Operation *FileProcessJobOperation `xml:",omitempty"` +} + +// 提交哈希值计算任务 https://cloud.tencent.com/document/product/436/83108 +// 提交文件解压任务 https://cloud.tencent.com/document/product/436/83110 +// 提交多文件打包压缩任务 https://cloud.tencent.com/document/product/436/83112 +func (s *CIService) CreateFileProcessJob(ctx context.Context, opt *FileProcessJobOptions) (*FileProcessJobResult, *Response, error) { + var res FileProcessJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/file_jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// 查询哈希值计算结果 https://cloud.tencent.com/document/product/436/83109 +// 查询文件解压结果 https://cloud.tencent.com/document/product/436/83111 +// 查询多文件打包压缩结果 https://cloud.tencent.com/document/product/436/83113 +func (s *CIService) DescribeFileProcessJob(ctx context.Context, jobid string) (*FileProcessJobResult, *Response, error) { + var res FileProcessJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/file_jobs/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetFileHashOptions is the option of GetFileHash +type GetFileHashOptions struct { + CIProcess string `url:"ci-process,omitempty"` + Type string `url:"type,omitempty"` + AddToHeader bool `url:"addtoheader,omitempty"` +} + +// GetFileHashResult is the result of GetFileHash +type GetFileHashResult struct { + XMLName xml.Name `xml:"Response"` + FileHashCodeResult *FileHashCodeResult `xml:",omitempty"` + Input *FileProcessInput `xml:",omitempty"` +} + +// 哈希值计算同步请求 https://cloud.tencent.com/document/product/436/83107 +func (s *CIService) GetFileHash(ctx context.Context, name string, opt *GetFileHashOptions) (*GetFileHashResult, *Response, error) { + var res GetFileHashResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name), + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// ZipPreviewResult 压缩包预览结果 +type ZipPreviewResult struct { + XMLName xml.Name `xml:"Response"` + FileNumber int `xml:"FileNumber,omitempty"` + IsTruncated bool `xml:"IsTruncated,omitempty"` + Contents []*struct { + Key string `xml:"Key,omitempty"` + LastModified string `xml:"LastModified,omitempty"` + UncompressedSize int `xml:"UncompressedSize,omitempty"` + } `xml:"Contents,omitempty"` +} + +// ZipPreview 压缩包预览 +func (s *CIService) ZipPreview(ctx context.Context, name, uncompress_key string) (*ZipPreviewResult, *Response, error) { + var res ZipPreviewResult + uriStr := "/" + encodeURIComponent(name) + "?ci-process=zippreview" + if uncompress_key != "" { + uriStr += "&uncompress-key=" + encodeURIComponent(uncompress_key) + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: uriStr, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go new file mode 100644 index 00000000000..ddf4bddc515 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go @@ -0,0 +1,4461 @@ +package cos + +import ( + "bytes" + "context" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "net/http" + "sort" + "strings" + "time" + + "github.com/clbanning/mxj" + "github.com/mitchellh/mapstructure" +) + +type VodInfo struct { + FileId string `xml:"FileId,omitempty"` + SubAppId string `xml:"SubAppId,omitempty"` +} + +// JobInput TODO +type JobInput struct { + Object string `xml:"Object,omitempty"` + Lang string `xml:"Lang,omitempty"` + Type string `xml:"Type,omitempty"` + BasicType string `xml:"BasicType,omitempty"` + CosHeaders []struct { + Key string `xml:"Key"` + Value string `xml:"Value"` + } `xml:"CosHeaders"` + Url string `xml:"Url,omitempty"` + Vod *VodInfo `xml:"Vod,omitempty"` +} + +// StreamExtract TODO +type StreamExtract struct { + Index string `xml:"Index,omitempty"` + Object string `xml:"Object,omitempty"` +} + +// JobOutput TODO +type JobOutput struct { + Region string `xml:"Region,omitempty"` + Bucket string `xml:"Bucket,omitempty"` + Object string `xml:"Object,omitempty"` + SpriteObject string `xml:"SpriteObject,omitempty"` + AuObject string `xml:"AuObject,omitempty"` + BassObject string `xml:"BassObject,omitempty"` + DrumObject string `xml:"DrumObject,omitempty"` + StreamExtract []StreamExtract `xml:"StreamExtract,omitempty"` +} + +// ClipConfig TODO +type ClipConfig struct { + Duration string `xml:"Duration"` +} + +// Container TODO +type Container struct { + Format string `xml:"Format,omitempty"` + ClipConfig *ClipConfig `xml:"ClipConfig,omitempty"` +} + +// Video TODO +type Video struct { + Codec string `xml:"Codec"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Fps string `xml:"Fps,omitempty"` + Remove string `xml:"Remove,omitempty"` + Profile string `xml:"Profile,omitempty"` + Bitrate string `xml:"Bitrate,omitempty"` + Crf string `xml:"Crf,omitempty"` + Gop string `xml:"Gop,omitempty"` + Preset string `xml:"Preset,omitempty"` + Bufsize string `xml:"Bufsize,omitempty"` + Maxrate string `xml:"Maxrate,omitempty"` + HlsTsTime string `xml:"HlsTsTime,omitempty"` + DashSegment string `xml:"DashSegment,omitempty"` + Pixfmt string `xml:"Pixfmt,omitempty"` + LongShortMode string `xml:"LongShortMode,omitempty"` + Rotate string `xml:"Rotate,omitempty"` + AnimateOnlyKeepKeyFrame string `xml:"AnimateOnlyKeepKeyFrame,omitempty"` + AnimateTimeIntervalOfFrame string `xml:"AnimateTimeIntervalOfFrame,omitempty"` + AnimateFramesPerSecond string `xml:"AnimateFramesPerSecond,omitempty"` + Quality string `xml:"Quality,omitempty"` + Roi string `xml:"Roi,omitempty"` + Crop string `xml:"Crop,omitempty"` + Interlaced string `xml:"Interlaced,omitempty"` + ColorParam *VideoColorParam `xml:"ColorParam,omitempty"` +} + +type VideoColorParam struct { + ColorRange string `xml:"ColorRange,omitempty"` + ColorSpace string `xml:"ColorSpace,omitempty"` + ColorTrc string `xml:"ColorTrc,omitempty"` + ColorPrimaries string `xml:"ColorPrimaries,omitempty"` +} + +// TranscodeProVideo TODO +type TranscodeProVideo struct { + Codec string `xml:"Codec,omitempty"` + Profile string `xml:"Profile,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Interlaced string `xml:"Interlaced,omitempty"` + Fps string `xml:"Fps,omitempty"` + Bitrate string `xml:"Bitrate,omitempty"` + Rotate string `xml:"Rotate,omitempty"` +} + +// TimeInterval TODO +type TimeInterval struct { + Start string `xml:"Start,omitempty"` + Duration string `xml:"Duration,omitempty"` +} + +// Audio TODO +type Audio struct { + Codec string `xml:"Codec,omitempty"` + Samplerate string `xml:"Samplerate,omitempty"` + Bitrate string `xml:"Bitrate,omitempty"` + Channels string `xml:"Channels,omitempty"` + Remove string `xml:"Remove,omitempty"` + KeepTwoTracks string `xml:"KeepTwoTracks,omitempty"` + SwitchTrack string `xml:"SwitchTrack,omitempty"` + SampleFormat string `xml:"SampleFormat,omitempty"` +} + +// TranscodeProAudio TODO +type TranscodeProAudio struct { + Codec string `xml:"Codec,omitempty"` + Remove string `xml:"Remove,omitempty"` +} + +// TransConfig TODO +type TransConfig struct { + AdjDarMethod string `xml:"AdjDarMethod,omitempty"` + IsCheckReso string `xml:"IsCheckReso,omitempty"` + ResoAdjMethod string `xml:"ResoAdjMethod,omitempty"` + IsCheckVideoBitrate string `xml:"IsCheckVideoBitrate,omitempty"` + VideoBitrateAdjMethod string `xml:"VideoBitrateAdjMethod,omitempty"` + IsCheckAudioBitrate string `xml:"IsCheckAudioBitrate,omitempty"` + AudioBitrateAdjMethod string `xml:"AudioBitrateAdjMethod,omitempty"` + DeleteMetadata string `xml:"DeleteMetadata,omitempty"` + IsHdr2Sdr string `xml:"IsHdr2Sdr,omitempty"` + HlsEncrypt *HlsEncrypt `xml:"HlsEncrypt,omitempty"` +} + +// Transcode TODO +type Transcode struct { + Container *Container `xml:"Container,omitempty"` + Video *Video `xml:"Video,omitempty"` + TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` + Audio *Audio `xml:"Audio,omitempty"` + TransConfig *TransConfig `xml:"TransConfig,omitempty"` + AudioMix *AudioMix `xml:"AudioMix,omitempty"` + AudioMixArray []AudioMix `xml:"AudioMixArray,omitempty"` +} + +// TranscodePro TODO +type TranscodePro struct { + Container *Container `xml:"Container,omitempty"` + Video *TranscodeProVideo `xml:"Video,omitempty"` + Audio *TranscodeProAudio `xml:"Audio,omitempty"` + TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` + TransConfig *TransConfig `xml:"TransConfig,omitempty"` +} + +// WatermarkSlideConfig TODO +type WatermarkSlideConfig struct { + SlideMode string `xml:"SlideMode,omitempty"` + XSlideSpeed string `xml:"XSlideSpeed,omitempty"` + YSlideSpeed string `xml:"YSlideSpeed,omitempty"` +} + +// Image TODO +type Image struct { + Url string `xml:"Url,omitempty"` + Mode string `xml:"Mode,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Transparency string `xml:"Transparency,omitempty"` + Background string `xml:"Background,omitempty"` +} + +// Text TODO +type Text struct { + FontSize string `xml:"FontSize,omitempty"` + FontType string `xml:"FontType,omitempty"` + FontColor string `xml:"FontColor,omitempty"` + Transparency string `xml:"Transparency,omitempty"` + Text string `xml:"Text,omitempty"` +} + +// TtsTpl TODO +type TtsTpl struct { + Mode string `xml:"Mode,omitempty"` + Codec string `xml:"Codec,omitempty"` + VoiceType string `xml:"VoiceType,omitempty"` + Volume string `xml:"Volume,omitempty"` + Speed string `xml:"Speed,omitempty"` +} + +// TtsConfig TODO +type TtsConfig struct { + Input string `xml:"Input,omitempty"` + InputType string `xml:"InputType,omitempty"` +} + +// Translation TODO +type Translation struct { + Lang string `xml:"Lang,omitempty"` + Type string `xml:"Type,omitempty"` +} + +// WordsGeneralize TODO +type WordsGeneralize struct { + NerMethod string `xml:"NerMethod,omitempty"` + SegMethod string `xml:"SegMethod,omitempty"` +} + +// WordsGeneralizeResult TODO +type WordsGeneralizeResult struct { + WordsGeneralizeLable []WordsGeneralizeResulteLable `xml:"WordsGeneralizeLable,omitempty"` + WordsGeneralizeToken []WordsGeneralizeResulteToken `xml:"WordsGeneralizeToken,omitempty"` +} + +// WordsGeneralizeResulteLable TODO +type WordsGeneralizeResulteLable struct { + Category string `xml:"Category,omitempty"` + Word string `xml:"Word,omitempty"` +} + +// WordsGeneralizeResulteToken TODO +type WordsGeneralizeResulteToken struct { + Length string `xml:"Length,omitempty"` + Offset string `xml:"Offset,omitempty"` + Pos string `xml:"Pos,omitempty"` + Word string `xml:"Word,omitempty"` +} + +// Watermark TODO +type Watermark struct { + Type string `xml:"Type,omitempty"` + Pos string `xml:"Pos,omitempty"` // TopLeft:左上; Top:上居中; TopRight:右上; Left:左居中; Center:正中心; Right:右居中; BottomLeft:左下; Bottom:下居中; BottomRight:右下 + LocMode string `xml:"LocMode,omitempty"` + Dx string `xml:"Dx,omitempty"` + Dy string `xml:"Dy,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` + SlideConfig *WatermarkSlideConfig `xml:"SlideConfig,omitempty"` + Image *Image `xml:"Image,omitempty"` + Text *Text `xml:"Text,omitempty"` +} + +// EffectConfig TODO +type EffectConfig struct { + EnableStartFadein string `xml:"EnableStartFadein,omitempty"` + StartFadeinTime string `xml:"StartFadeinTime,omitempty"` + EnableEndFadeout string `xml:"EnableEndFadeout,omitempty"` + EndFadeoutTime string `xml:"EndFadeoutTime,omitempty"` + EnableBgmFade string `xml:"EnableBgmFade,omitempty"` + BgmFadeTime string `xml:"BgmFadeTime,omitempty"` +} + +// AudioMix TODO +type AudioMix struct { + AudioSource string `xml:"AudioSource,omitempty"` + MixMode string `xml:"MixMode,omitempty"` + Replace string `xml:"Replace,omitempty"` + EffectConfig *EffectConfig `xml:"EffectConfig,omitempty"` +} + +// ConcatFragment TODO +type ConcatFragment struct { + Url string `xml:"Url,omitempty"` + Mode string `xml:"Mode,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` + FragmentIndex string `xml:"FragmentIndex,omitempty"` + Duration string `xml:"Duration,omitempty"` +} + +// ConcatTemplate TODO +type ConcatTemplate struct { + ConcatFragment []ConcatFragment `xml:"ConcatFragment,omitempty"` + Audio *Audio `xml:"Audio,omitempty"` + Video *Video `xml:"Video,omitempty"` + Container *Container `xml:"Container,omitempty"` + Index string `xml:"Index,omitempty"` + AudioMix *AudioMix `xml:"AudioMix,omitempty"` + AudioMixArray []AudioMix `xml:"AudioMixArray,omitempty"` + SceneChangeInfo *SceneChangeInfo `xml:"SceneChangeInfo,omitempty"` + DirectConcat string `xml:"DirectConcat,omitempty"` +} + +// SceneChangeInfo 转场参数 +type SceneChangeInfo struct { + Mode string `xml:"Mode,omitempty"` + Time string `xml:"Time,omitempty"` + TransitionType string `xml:"TransitionType,omitempty"` +} + +// SpriteSnapshotConfig TODO +type SpriteSnapshotConfig struct { + CellHeight string `xml:"CellHeight,omitempty"` + CellWidth string `xml:"CellWidth,omitempty"` + Color string `xml:"Color,omitempty"` + Columns string `xml:"Columns,omitempty"` + Lines string `xml:"Lines,omitempty"` + Margin string `xml:"Margin,omitempty"` + Padding string `xml:"Padding,omitempty"` + ScaleMethod string `xml:"ScaleMethod,omitempty"` +} + +// Snapshot TODO +type Snapshot struct { + Mode string `xml:"Mode,omitempty"` + Start string `xml:"Start,omitempty"` + TimeInterval string `xml:"TimeInterval,omitempty"` + Count string `xml:"Count,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + CIParam string `xml:"CIParam,omitempty"` + IsCheckCount bool `xml:"IsCheckCount,omitempty"` + IsCheckBlack bool `xml:"IsCheckBlack,omitempty"` + BlackLevel string `xml:"BlackLevel,omitempty"` + PixelBlackThreshold string `xml:"PixelBlackThreshold,omitempty"` + SnapshotOutMode string `xml:"SnapshotOutMode,omitempty"` + SpriteSnapshotConfig *SpriteSnapshotConfig `xml:"SpriteSnapshotConfig,omitempty"` +} + +// AnimationVideo TODO +// 有意和转码区分,两种任务关注的参数不一样避免干扰 +type AnimationVideo struct { + Codec string `xml:"Codec,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Fps string `xml:"Fps,omitempty"` + AnimateOnlyKeepKeyFrame string `xml:"AnimateOnlyKeepKeyFrame,omitempty"` + AnimateTimeIntervalOfFrame string `xml:"AnimateTimeIntervalOfFrame,omitempty"` + AnimateFramesPerSecond string `xml:"AnimateFramesPerSecond,omitempty"` + Quality string `xml:"Quality,omitempty"` +} + +// Animation TODO +type Animation struct { + Container *Container `xml:"Container,omitempty"` + Video *AnimationVideo `xml:"Video,omitempty"` + TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` +} + +// HlsEncrypt TODO +type HlsEncrypt struct { + IsHlsEncrypt bool `xml:"IsHlsEncrypt,omitempty"` + UriKey string `xml:"UriKey,omitempty"` +} + +// Segment TODO +type Segment struct { + Format string `xml:"Format,omitempty"` + Duration string `xml:"Duration,omitempty"` + TranscodeIndex string `xml:"TranscodeIndex,omitempty"` + HlsEncrypt *HlsEncrypt `xml:"HlsEncrypt,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` +} + +// VideoMontageVideo TODO +type VideoMontageVideo struct { + Codec string `xml:"Codec"` + Width string `xml:"Width"` + Height string `xml:"Height"` + Fps string `xml:"Fps"` + Remove string `xml:"Remove,omitempty"` + Bitrate string `xml:"Bitrate"` + Crf string `xml:"Crf"` +} + +// VideoMontage TODO +type VideoMontage struct { + Container *Container `xml:"Container,omitempty"` + Video *VideoMontageVideo `xml:"Video,omitempty"` + Audio *Audio `xml:"Audio,omitempty"` + Duration string `xml:"Duration,omitempty"` + Scene string `xml:"Scene,omitempty"` + AudioMix *AudioMix `xml:"AudioMix,omitempty"` + AudioMixArray []AudioMix `xml:"AudioMixArray,omitempty"` +} + +// AudioConfig TODO +type AudioConfig struct { + Codec string `xml:"Codec"` + Samplerate string `xml:"Samplerate"` + Bitrate string `xml:"Bitrate"` + Channels string `xml:"Channels"` +} + +// VoiceSeparate TODO +type VoiceSeparate struct { + AudioMode string `xml:"AudioMode,omitempty"` // IsAudio 人声, IsBackground 背景声, AudioAndBackground 人声和背景声 + AudioConfig *AudioConfig `xml:"AudioConfig,omitempty"` +} + +// ColorEnhance TODO +type ColorEnhance struct { + Enable string `xml:"Enable,omitempty"` + Contrast string `xml:"Contrast,omitempty"` + Correction string `xml:"Correction,omitempty"` + Saturation string `xml:"Saturation,omitempty"` +} + +// MsSharpen TODO +type MsSharpen struct { + Enable string `xml:"Enable,omitempty"` + SharpenLevel string `xml:"SharpenLevel,omitempty"` +} + +// VideoProcess TODO +type VideoProcess struct { + ColorEnhance *ColorEnhance `xml:"ColorEnhance,omitempty"` + MsSharpen *MsSharpen `xml:"MsSharpen,omitempty"` +} + +// SDRtoHDR TODO +type SDRtoHDR struct { + HdrMode string `xml:"HdrMode,omitempty"` // HLG、HDR10 +} + +// SuperResolution TODO +type SuperResolution struct { + Resolution string `xml:"Resolution,omitempty"` // sdtohd、hdto4k + EnableScaleUp string `xml:"EnableScaleUp,omitempty"` + Version string `xml:"Version,omitempty"` +} + +// DigitalWatermark TODO +type DigitalWatermark struct { + Message string `xml:"Message"` + Type string `xml:"Type"` + Version string `xml:"Version"` +} + +// ExtractDigitalWatermark TODO +type ExtractDigitalWatermark struct { + Type string `xml:"Type"` + Version string `xml:"Version"` +} + +// Subtitles TODO +type Subtitles struct { + Subtitle []Subtitle `xml:"Subtitle,omitempty"` +} + +// Subtitle TODO +type Subtitle struct { + Url string `xml:"Url,omitempty"` + Embed string `xml:"Embed,omitempty"` + FontType string `xml:"FontType,omitempty"` + FontSize string `xml:"FontSize,omitempty"` + FontColor string `xml:"FontColor,omitempty"` + OutlineColor string `xml:"OutlineColor,omitempty"` + VMargin string `xml:"VMargin,omitempty"` +} + +// VideoTag TODO +type VideoTag struct { + Scenario string `xml:"Scenario,omitempty"` // 1. Stream 2. ShortVideo + Text string `xml:"Text,omitempty"` +} + +// VideoTagResult TODO +type VideoTagResult struct { + StreamData *VideoTagResultStreamData `xml:"StreamData,omitempty"` +} + +// VideoTagResultStreamData TODO +type VideoTagResultStreamData struct { + SubErrCode string `xml:"SubErrCode,omitempty"` + SubErrMsg string `xml:"SubErrMsg,omitempty"` + Data *VideoTagResultStreamDataData `xml:"Data,omitempty"` +} + +// VideoTagResultStreamDataData TODO +type VideoTagResultStreamDataData struct { + Tags []VideoTagResultStreamDataDataTags `xml:"Tags,omitempty"` + PersonTags []VideoTagResultStreamDataDataPersonTags `xml:"PersonTags,omitempty"` + PlaceTags []VideoTagResultStreamDataDataPlaceTags `xml:"PlaceTags,omitempty"` + ActionTags []VideoTagResultStreamDataDataActionTags `xml:"ActionTags,omitempty"` + ObjectTags []VideoTagResultStreamDataDataObjectTags `xml:"ObjectTags,omitempty"` + Labels []VideoTagResultStreamDataDataLabels `xml:"Labels,omitempty"` +} + +// VideoTagResultStreamDataDataTags TODO +type VideoTagResultStreamDataDataTags struct { + Tag string `xml:"Tag,omitempty"` + TagCls string `xml:"TagCls,omitempty"` + Confidence float64 `xml:"Confidence,omitempty"` +} + +// VideoTagResultStreamDataDataPersonTags TODO +type VideoTagResultStreamDataDataPersonTags struct { + Name string `xml:"Name,omitempty"` + Confidence float64 `xml:"Confidence,omitempty"` + Count string `xml:"Count,omitempty"` + DetailPerSecond []VideoTagResultStreamDataDataPersonTagsDetailPerSecond `xml:"DetailPerSecond,omitempty"` +} + +// VideoTagResultStreamDataDataPersonTagsDetailPerSecond TODO +type VideoTagResultStreamDataDataPersonTagsDetailPerSecond struct { + TimeStamp string `xml:"TimeStamp,omitempty"` + Name string `xml:"Name,omitempty"` + Confidence float64 `xml:"Confidence,omitempty"` + BBox []VideoTagResultStreamDataDataPersonTagsDetailPerSecondBBox `xml:"BBox,omitempty"` +} + +// VideoTagResultStreamDataDataPersonTags TODO +type VideoTagResultStreamDataDataPersonTagsDetailPerSecondBBox struct { + X1 string `xml:"X1,omitempty"` + X2 string `xml:"X2,omitempty"` + Y1 string `xml:"Y1,omitempty"` + Y2 string `xml:"Y2,omitempty"` +} + +// VideoTagResultStreamDataDataPlaceTags TODO +type VideoTagResultStreamDataDataPlaceTags struct { + Tags []VideoTagResultStreamDataDataTags `xml:"Tags,omitempty"` + ClipFrameResult []string `xml:"ClipFrameResult,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` + StartIndex string `xml:"StartIndex,omitempty"` + EndIndex string `xml:"EndIndex,omitempty"` +} + +// VideoTagResultStreamDataDataActionTags TODO +type VideoTagResultStreamDataDataActionTags struct { + Tags []VideoTagResultStreamDataDataTags `xml:"Tags,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` +} + +// VideoTagResultStreamDataDataObjectTags TODO +type VideoTagResultStreamDataDataObjectTags struct { + Objects []VideoTagResultStreamDataDataPersonTagsDetailPerSecond `xml:"Objects,omitempty"` + TimeStamp string `xml:"TimeStamp,omitempty"` +} + +// VideoTagResultStreamDataDataLabels TODO +type VideoTagResultStreamDataDataLabels struct { + First string `xml:"First,omitempty"` + Second string `xml:"Second,omitempty"` + Confidence float64 `xml:"Confidence,omitempty"` +} + +// QualityEstimate TODO +type QualityEstimate struct { + Score string `xml:"Score,omitempty"` + VqaPlusResult struct { + NoAudio bool `xml:"NoAudio,omitempty"` + NoVideo bool `xml:"NoVideo,omitempty"` + DetailedResult []struct { + Type string `xml:"Type,omitempty"` + Items []struct { + Confidence int `xml:"Confidence,omitempty"` + StartTimeOffset float32 `xml:"StartTimeOffset,omitempty"` + EndTimeOffset float32 `xml:"EndTimeOffset,omitempty"` + AreaCoordSet []int `xml:"AreaCoordSet,omitempty"` + } `xml:"Items,omitempty"` + } `xml:"DetailedResult,omitempty"` + } `xml:"VqaPlusResult,omitempty"` +} + +// QualityEstimateConfig 视频质量检查的参数 +type QualityEstimateConfig struct { + Rotate string `xml:"Rotate,omitempty"` + Mode string `xml:"Mode,omitempty"` +} + +// MediaResult TODO +type MediaResult struct { + OutputFile struct { + Bucket string `xml:"Bucket,omitempty"` + Md5Info []struct { + Md5 string `xml:"Md5,omitempty"` + ObjectName string `xml:"ObjectName,omitempty"` + } `xml:"Md5Info,omitempty"` + ObjectName []string `xml:"ObjectName,omitempty"` + ObjectPrefix string `xml:"ObjectPrefix,omitempty"` + Region string `xml:"Region,omitempty"` + SpriteOutputFile struct { + Bucket string `xml:"Bucket,omitempty"` + Md5Info []struct { + Md5 string `xml:"Md5,omitempty"` + ObjectName string `xml:"ObjectName,omitempty"` + } `xml:"Md5Info,omitempty"` + ObjectName []string `xml:"ObjectName,omitempty"` + ObjectPrefix string `xml:"ObjectPrefix,omitempty"` + Region string `xml:"Region,omitempty"` + } `xml:"SpriteOutputFile,omitempty"` + } `xml:"OutputFile,omitempty"` +} + +// MediaInfo TODO +type MediaInfo struct { + Format struct { + Bitrate string `xml:"Bitrate"` + Duration string `xml:"Duration"` + FormatLongName string `xml:"FormatLongName"` + FormatName string `xml:"FormatName"` + NumProgram string `xml:"NumProgram"` + NumStream string `xml:"NumStream"` + Size string `xml:"Size"` + StartTime string `xml:"StartTime"` + } `xml:"Format"` + Stream struct { + Audio []struct { + Bitrate string `xml:"Bitrate"` + Channel string `xml:"Channel"` + ChannelLayout string `xml:"ChannelLayout"` + CodecLongName string `xml:"CodecLongName"` + CodecName string `xml:"CodecName"` + CodecTag string `xml:"CodecTag"` + CodecTagString string `xml:"CodecTagString"` + CodecTimeBase string `xml:"CodecTimeBase"` + Duration string `xml:"Duration"` + Index string `xml:"Index"` + Language string `xml:"Language"` + SampleFmt string `xml:"SampleFmt"` + SampleRate string `xml:"SampleRate"` + StartTime string `xml:"StartTime"` + Timebase string `xml:"Timebase"` + } `xml:"Audio"` + Subtitle string `xml:"Subtitle"` + Video []struct { + AvgFps string `xml:"AvgFps"` + Bitrate string `xml:"Bitrate"` + CodecLongName string `xml:"CodecLongName"` + CodecName string `xml:"CodecName"` + CodecTag string `xml:"CodecTag"` + CodecTagString string `xml:"CodecTagString"` + CodecTimeBase string `xml:"CodecTimeBase"` + Dar string `xml:"Dar"` + Duration string `xml:"Duration"` + Fps string `xml:"Fps"` + HasBFrame string `xml:"HasBFrame"` + Height string `xml:"Height"` + Index string `xml:"Index"` + Language string `xml:"Language"` + Level string `xml:"Level"` + NumFrames string `xml:"NumFrames"` + PixFormat string `xml:"PixFormat"` + Profile string `xml:"Profile"` + RefFrames string `xml:"RefFrames"` + Rotation string `xml:"Rotation"` + Sar string `xml:"Sar"` + StartTime string `xml:"StartTime"` + Timebase string `xml:"Timebase"` + Width string `xml:"Width"` + ColorRange string `xml:"ColorRange"` + ColorTransfer string `xml:"ColorTransfer"` + ColorPrimaries string `xml:"ColorPrimaries"` + } `xml:"Video"` + } `xml:"Stream"` +} + +// PicProcess TODO +type PicProcess struct { + IsPicInfo string `xml:"IsPicInfo,omitempty"` + ProcessRule string `xml:"ProcessRule,omitempty"` +} + +// PicProcessResult TODO +type PicProcessResult struct { + UploadResult struct { + OriginalInfo struct { + Key string `xml:"Key"` + Location string `xml:"Location"` + ETag string `xml:"ETag"` + ImageInfo struct { + Format string `xml:"Format"` + Width int32 `xml:"Width"` + Height int32 `xml:"Height"` + Quality int32 `xml:"Quality"` + Ave string `xml:"Ave"` + Orientation int32 `xml:"Orientation"` + } `xml:"ImageInfo"` + } `xml:"OriginalInfo"` + ProcessResults struct { + Object struct { + Key string `xml:"Key"` + Location string `xml:"Location"` + Format string `xml:"Format"` + Width int32 `xml:"Width"` + Height int32 `xml:"Height"` + Size int32 `xml:"Size"` + Quality int32 `xml:"Quality"` + Etag string `xml:"Etag"` + } `xml:"Object"` + } `xml:"ProcessResults"` + } `xml:"UploadResult"` +} + +// PosterProduction TODO +type PosterProduction struct { + TemplateId string `xml:"TemplateId,omitempty"` + Info interface{} `xml:"Info,omitempty"` +} + +// PicProcessJobOperation TODO +type PicProcessJobOperation struct { + TemplateId string `xml:"TemplateId,omitempty"` + PicProcess *PicProcess `xml:"PicProcess,omitempty"` + Output *JobOutput `xml:"Output,omitempty"` + UserData string `xml:"UserData,omitempty"` + JobLevel int `xml:"JobLevel,omitempty"` + PicProcessResult *PicProcessResult `xml:"PicProcessResult,omitempty"` + PosterProduction *PosterProduction `xml:"PosterProduction,omitempty"` +} + +// MediaProcessJobOperation TODO +type MediaProcessJobOperation struct { + Tag string `xml:"Tag,omitempty"` + Output *JobOutput `xml:"Output,omitempty"` + MediaResult *MediaResult `xml:"MediaResult,omitempty"` + MediaInfo *MediaInfo `xml:"MediaInfo,omitempty"` + Transcode *Transcode `xml:"Transcode,omitempty"` + Watermark []Watermark `xml:"Watermark,omitempty"` + TemplateId string `xml:"TemplateId,omitempty"` + WatermarkTemplateId []string `xml:"WatermarkTemplateId,omitempty"` + ConcatTemplate *ConcatTemplate `xml:"ConcatTemplate,omitempty"` + Snapshot *Snapshot `xml:"Snapshot,omitempty"` + Animation *Animation `xml:"Animation,omitempty"` + Segment *Segment `xml:"Segment,omitempty"` + VideoMontage *VideoMontage `xml:"VideoMontage,omitempty"` + VoiceSeparate *VoiceSeparate `xml:"VoiceSeparate,omitempty"` + VideoProcess *VideoProcess `xml:"VideoProcess,omitempty"` + TranscodeTemplateId string `xml:"TranscodeTemplateId,omitempty"` // 视频增强、超分、SDRtoHDR任务类型,可以选择转码模板相关参数 + SDRtoHDR *SDRtoHDR `xml:"SDRtoHDR,omitempty"` + SuperResolution *SuperResolution `xml:"SuperResolution,omitempty"` + DigitalWatermark *DigitalWatermark `xml:"DigitalWatermark,omitempty"` + ExtractDigitalWatermark *ExtractDigitalWatermark `xml:"ExtractDigitalWatermark,omitempty"` + VideoTag *VideoTag `xml:"VideoTag,omitempty"` + VideoTagResult *VideoTagResult `xml:"VideoTagResult,omitempty"` + SmartCover *NodeSmartCover `xml:"SmartCover,omitempty"` + UserData string `xml:"UserData,omitempty"` + JobLevel int `xml:"JobLevel,omitempty"` + QualityEstimate *QualityEstimate `xml:"QualityEstimate,omitempty"` + TtsTpl *TtsTpl `xml:"TtsTpl,omitempty"` + TtsConfig *TtsConfig `xml:"TtsConfig,omitempty"` + Translation *Translation `xml:"Translation,omitempty"` + WordsGeneralize *WordsGeneralize `xml:"WordsGeneralize,omitempty"` + WordsGeneralizeResult *WordsGeneralizeResult `xml:"WordsGeneralizeResult,omitempty"` + QualityEstimateConfig *QualityEstimateConfig `xml:"QualityEstimateConfig,omitempty"` + NoiseReduction *NoiseReduction `xml:"NoiseReduction,omitempty"` + SplitVideoParts *SplitVideoParts `xml:"SplitVideoParts,omitempty"` + SplitVideoInfoResult *SplitVideoInfoResult `xml:"SplitVideoInfoResult,omitempty"` + Subtitles *Subtitles `xml:"Subtitles,omitempty"` + VideoEnhance *VideoEnhance `xml:"VideoEnhance,omitempty"` + VideoTargetRec *VideoTargetRec `xml:"VideoTargetRec,omitempty"` + VideoTargetRecResult *VideoTargetRecResult `xml:"VideoTargetRecResult,omitempty"` + SegmentVideoBody *SegmentVideoBody `xml:"SegmentVideoBody,omitempty"` + FreeTranscode string `xml:"FreeTranscode,omitempty"` + PicProcess *PicProcess `xml:"PicProcess,omitempty"` + PicProcessResult *PicProcessResult `xml:"PicProcessResult,omitempty"` + PosterProduction *PosterProduction `xml:"PosterProduction,omitempty"` + SpeechRecognition *SpeechRecognition `xml:"SpeechRecognition,omitempty"` + SpeechRecognitionResult *SpeechRecognitionResult `xml:"SpeechRecognitionResult,omitempty"` + SoundHoundResult *SoundHoundResult `xml:"SoundHoundResult,omitempty"` + FillConcat *FillConcat `xml:"FillConcat,omitempty"` + VideoSynthesis *VideoSynthesis `xml:"VideoSynthesis,omitempty"` + DnaConfig *DnaConfig `xml:"DnaConfig,omitempty"` + DnaResult *DnaResult `xml:"DnaResult,omitempty"` + VocalScore *VocalScore `xml:"VocalScore,omitempty"` + VocalScoreResult *VocalScoreResult `xml:"VocalScoreResult,omitempty"` + ImageInspect *ImageInspect `xml:"ImageInspect,omitempty"` + ImageInspectResult *ImageInspectResult `xml:"ImageInspectResult,omitempty"` + SnapshotPrefix string `xml:"SnapshotPrefix,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty"` + Detection *ImageOCRDetection `xml:"Detection,omitempty"` + CustomId string `xml:"CustomId,omitempty"` +} + +// CreatePicJobsOptions TODO +type CreatePicJobsOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *PicProcessJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +// CreateAIJobsOptions TODO +type CreateAIJobsOptions CreateMediaJobsOptions + +// CreateMediaJobsOptions TODO +type CreateMediaJobsOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *MediaProcessJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +// NotifyConfigCallBackMqConfig TODO +type NotifyConfigCallBackMqConfig struct { + MqMode string `xml:"MqMode,omitempty"` + MqRegion string `xml:"MqRegion,omitempty"` + MqName string `xml:"MqName,omitempty"` +} + +// MediaProcessJobDetail TODO +type MediaProcessJobDetail struct { + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + JobId string `xml:"JobId,omitempty"` + Tag string `xml:"Tag,omitempty"` + Progress string `xml:"Progress,omitempty"` + State string `xml:"State,omitempty"` + CreationTime string `xml:"CreationTime,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *MediaProcessJobOperation `xml:"Operation,omitempty"` + SubTag string `xml:"SubTag,omitempty"` + Workflow []struct { + Name string `xml:"Name,omitempty"` + RunId string `xml:"RunId,omitempty"` + WorkflowId string `xml:"WorkflowId,omitempty"` + WorkflowName string `xml:"WorkflowName,omitempty"` + } `xml:"Workflow"` +} + +// CreatePicJobsResult TODO +type CreatePicJobsResult CreateMediaJobsResult + +// CreateAIJobsResult TODO +type CreateAIJobsResult CreateMediaJobsResult + +// CreateMediaJobsResult TODO +type CreateMediaJobsResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *MediaProcessJobDetail `xml:"JobsDetail,omitempty"` +} + +// CreateMultiMediaJobsOptions TODO +type CreateMultiMediaJobsOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation []MediaProcessJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +// CreateMultiMediaJobsResult TODO +type CreateMultiMediaJobsResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail []MediaProcessJobDetail `xml:"JobsDetail,omitempty"` +} + +// MediaProcessJobsNotifyBody TODO +type MediaProcessJobsNotifyBody struct { + XMLName xml.Name `xml:"Response"` + EventName string `xml:"EventName"` + JobsDetail *MediaProcessJobDetail `xml:"JobsDetail,omitempty"` +} + +// WorkflowExecutionNotifyBody TODO +type WorkflowExecutionNotifyBody struct { + XMLName xml.Name `xml:"Response"` + EventName string `xml:"EventName"` + WorkflowExecution struct { + RunId string `xml:"RunId"` + BucketId string `xml:"BucketId"` + Object string `xml:"Object"` + CosHeaders []struct { + Key string `xml:"Key"` + Value string `xml:"Value"` + } `xml:"CosHeaders"` + WorkflowId string `xml:"WorkflowId"` + WorkflowName string `xml:"WorkflowName"` + CreateTime string `xml:"CreateTime"` + State string `xml:"State"` + Tasks []struct { + Type string `xml:"Type"` + CreateTime string `xml:"CreateTime"` + EndTime string `xml:"EndTime"` + State string `xml:"State"` + JobId string `xml:"JobId"` + Name string `xml:"Name"` + TemplateId string `xml:"TemplateId"` + TemplateName string `xml:"TemplateName"` + TranscodeTemplateId string `xml:"TranscodeTemplateId,omitempty"` + TranscodeTemplateName string `xml:"TranscodeTemplateName,omitempty"` + HdrMode string `xml:"HdrMode,omitempty"` + ResultInfo struct { + ObjectCount int `xml:"ObjectCount"` + SpriteObjectCount int `xml:"SpriteObjectCount"` + ObjectInfo []struct { + ObjectName string `xml:"ObjectName"` + ObjectUrl string `xml:"ObjectUrl"` + InputObjectName string `xml:"InputObjectName"` + Code string `xml:"Code"` + Message string `xml:"Message"` + ImageOcrResult *ImageOCRDetection `xml:"ImageOcrResult,omitempty"` + } `xml:"ObjectInfo,omitempty"` + SpriteObjectInfo []struct { + ObjectName string `xml:"ObjectName"` + ObjectUrl string `xml:"ObjectUrl"` + InputObjectName string `xml:"InputObjectName"` + Code string `xml:"Code"` + Message string `xml:"Message"` + } `xml:"SpriteObjectInfo,omitempty"` + } `xml:"ResultInfo,omitempty"` + } `xml:"Tasks"` + } `xml:"WorkflowExecution"` +} + +// CreateMultiMediaJobs TODO +func (s *CIService) CreateMultiMediaJobs(ctx context.Context, opt *CreateMultiMediaJobsOptions) (*CreateMultiMediaJobsResult, *Response, error) { + var res CreateMultiMediaJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaJobs TODO +func (s *CIService) CreateMediaJobs(ctx context.Context, opt *CreateMediaJobsOptions) (*CreateMediaJobsResult, *Response, error) { + var res CreateMediaJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreatePicProcessJobs TODO +func (s *CIService) CreatePicProcessJobs(ctx context.Context, opt *CreatePicJobsOptions) (*CreatePicJobsResult, *Response, error) { + var res CreatePicJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/pic_jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateAIJobs TODO +func (s *CIService) CreateAIJobs(ctx context.Context, opt *CreateAIJobsOptions) (*CreateAIJobsResult, *Response, error) { + var res CreateAIJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/ai_jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribePicProcessJobResult TODO +type DescribePicProcessJobResult DescribeMediaProcessJobResult + +// DescribeAIJobResult TODO +type DescribeAIJobResult DescribeMediaProcessJobResult + +// DescribeMediaProcessJobResult TODO +type DescribeMediaProcessJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *MediaProcessJobDetail `xml:"JobsDetail,omitempty"` + NonExistJobIds string `xml:"NonExistJobIds,omitempty"` +} + +// DescribeMediaJob TODO +func (s *CIService) DescribeMediaJob(ctx context.Context, jobid string) (*DescribeMediaProcessJobResult, *Response, error) { + var res DescribeMediaProcessJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribePicProcessJob TODO +func (s *CIService) DescribePicProcessJob(ctx context.Context, jobid string) (*DescribePicProcessJobResult, *Response, error) { + var res DescribePicProcessJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/pic_jobs/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeAIJob TODO +func (s *CIService) DescribeAIJob(ctx context.Context, jobid string) (*DescribeAIJobResult, *Response, error) { + var res DescribeAIJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/ai_jobs/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeMutilMediaProcessJobResult TODO +type DescribeMutilMediaProcessJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail []MediaProcessJobDetail `xml:"JobsDetail,omitempty"` + NonExistJobIds []string `xml:"NonExistJobIds,omitempty"` +} + +// DescribeMultiMediaJob TODO +func (s *CIService) DescribeMultiMediaJob(ctx context.Context, jobids []string) (*DescribeMutilMediaProcessJobResult, *Response, error) { + jobidsStr := "" + if len(jobids) < 1 { + return nil, nil, errors.New("empty param jobids") + } else { + jobidsStr = strings.Join(jobids, ",") + } + + var res DescribeMutilMediaProcessJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs/" + jobidsStr, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeMediaJobsOptions TODO +type DescribeMediaJobsOptions struct { + QueueId string `url:"queueId,omitempty"` + Tag string `url:"tag,omitempty"` + OrderByTime string `url:"orderByTime,omitempty"` + NextToken string `url:"nextToken,omitempty"` + Size int `url:"size,omitempty"` + States string `url:"states,omitempty"` + StartCreationTime string `url:"startCreationTime,omitempty"` + EndCreationTime string `url:"endCreationTime,omitempty"` + WorkflowId string `url:"workflowId,omitempty"` + InventoryTriggerJobId string `url:"inventoryTriggerJobId,omitempty"` + InputObject string `url:"inputObject,omitempty"` +} + +// DescribeMediaJobsResult TODO +type DescribeMediaJobsResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail []MediaProcessJobDetail `xml:"JobsDetail,omitempty"` + NextToken string `xml:"NextToken,omitempty"` +} + +// DescribeMediaJobs TODO +// https://cloud.tencent.com/document/product/460/48235 +func (s *CIService) DescribeMediaJobs(ctx context.Context, opt *DescribeMediaJobsOptions) (*DescribeMediaJobsResult, *Response, error) { + var res DescribeMediaJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribePicProcessQueuesOptions TODO +type DescribePicProcessQueuesOptions DescribeMediaProcessQueuesOptions + +// DescribeMediaProcessQueuesOptions TODO +type DescribeMediaProcessQueuesOptions struct { + QueueIds string `url:"queueIds,omitempty"` + State string `url:"state,omitempty"` + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` + Category string `url:"category,omitempty"` +} + +// DescribePicProcessQueuesResult TODO +type DescribePicProcessQueuesResult DescribeMediaProcessQueuesResult + +// DescribeMediaProcessQueuesResult TODO +type DescribeMediaProcessQueuesResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + QueueList []MediaProcessQueue `xml:"QueueList,omitempty"` + NonExistPIDs []string `xml:"NonExistPIDs,omitempty"` +} + +// MediaProcessQueue TODO +type MediaProcessQueue struct { + QueueId string `xml:"QueueId,omitempty"` + Name string `xml:"Name,omitempty"` + State string `xml:"State,omitempty"` + MaxSize int `xml:"MaxSize,omitempty"` + MaxConcurrent int `xml:"MaxConcurrent,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + NotifyConfig *MediaProcessQueueNotifyConfig `xml:"NotifyConfig,omitempty"` +} + +// MediaProcessQueueNotifyConfig TODO +type MediaProcessQueueNotifyConfig struct { + Url string `xml:"Url,omitempty"` + State string `xml:"State,omitempty"` + Type string `xml:"Type,omitempty"` + Event string `xml:"Event,omitempty"` + ResultFormat string `xml:"ResultFormat,omitempty"` + MqMode string `xml:"MqMode,omitempty"` + MqRegion string `xml:"MqRegion,omitempty"` + MqName string `xml:"MqName,omitempty"` + KafkaConfig *KafkaConfig `xml:"KafkaConfig,omitempty"` +} + +type KafkaConfig struct { + Region string `xml:"Region,omitempty"` + InstanceId string `xml:"InstanceId,omitempty"` + Topic string `xml:"Topic,omitempty"` +} + +// DescribeMediaProcessQueues TODO +func (s *CIService) DescribeMediaProcessQueues(ctx context.Context, opt *DescribeMediaProcessQueuesOptions) (*DescribeMediaProcessQueuesResult, *Response, error) { + var res DescribeMediaProcessQueuesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/queue", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribePicProcessQueues TODO +func (s *CIService) DescribePicProcessQueues(ctx context.Context, opt *DescribePicProcessQueuesOptions) (*DescribePicProcessQueuesResult, *Response, error) { + var res DescribePicProcessQueuesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/picqueue", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeAIProcessQueues TODO +func (s *CIService) DescribeAIProcessQueues(ctx context.Context, opt *DescribeMediaProcessQueuesOptions) (*DescribeMediaProcessQueuesResult, *Response, error) { + var res DescribeMediaProcessQueuesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/ai_queue", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeASRQueues TODO +func (s *CIService) DescribeASRProcessQueues(ctx context.Context, opt *DescribeMediaProcessQueuesOptions) (*DescribeMediaProcessQueuesResult, *Response, error) { + var res DescribeMediaProcessQueuesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrqueue", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type DescribeFielProcessQueuesOptions DescribeMediaProcessQueuesOptions +type DescribeFileProcessQueuesResult DescribeMediaProcessQueuesResult + +// DescribeFileProcessQueues TODO +func (s *CIService) DescribeFileProcessQueues(ctx context.Context, opt *DescribeFielProcessQueuesOptions) (*DescribeFileProcessQueuesResult, *Response, error) { + var res DescribeFileProcessQueuesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/file_queue", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaProcessQueueOptions TODO +type UpdateMediaProcessQueueOptions struct { + XMLName xml.Name `xml:"Request"` + Name string `xml:"Name,omitempty"` + QueueID string `xml:"QueueID,omitempty"` + State string `xml:"State,omitempty"` + NotifyConfig *MediaProcessQueueNotifyConfig `xml:"NotifyConfig,omitempty"` +} + +// UpdateMediaProcessQueueResult TODO +type UpdateMediaProcessQueueResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId"` + Queue *MediaProcessQueue `xml:"Queue"` +} + +// UpdateMediaProcessQueue TODO +func (s *CIService) UpdateMediaProcessQueue(ctx context.Context, opt *UpdateMediaProcessQueueOptions) (*UpdateMediaProcessQueueResult, *Response, error) { + var res UpdateMediaProcessQueueResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/queue/" + opt.QueueID, + body: opt, + method: http.MethodPut, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribePicProcessBucketsOptions 描述图片处理桶的参数 +type DescribePicProcessBucketsOptions DescribeMediaProcessBucketsOptions + +// DescribeAIProcessBucketsOptions 描述AI处理桶的参数 +type DescribeAIProcessBucketsOptions DescribeMediaProcessBucketsOptions + +// DescribeASRProcessBucketsOptions 描述ASR处理桶的参数 +type DescribeASRProcessBucketsOptions DescribeMediaProcessBucketsOptions + +// DescribeFileProcessBucketsOptions 描述文件处理桶的参数 +type DescribeFileProcessBucketsOptions DescribeMediaProcessBucketsOptions + +// DescribeMediaProcessBucketsOptions 描述媒体处理桶的参数 +type DescribeMediaProcessBucketsOptions struct { + Regions string `url:"regions,omitempty"` + BucketNames string `url:"bucketNames,omitempty"` + BucketName string `url:"bucketName,omitempty"` + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` +} + +// DescribeMediaProcessBucketsResult 描述媒体处理桶的结果 +type DescribeMediaProcessBucketsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + MediaBucketList []MediaProcessBucket `xml:"MediaBucketList,omitempty"` +} + +// DescribeMediaProcessBucketsResult 描述图片处理桶的结果 +type DescribePicProcessBucketsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + MediaBucketList []MediaProcessBucket `xml:"PicBucketList,omitempty"` +} + +// DescribeMediaProcessBucketsResult 描述AI处理桶的结果 +type DescribeAIProcessBucketsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + MediaBucketList []MediaProcessBucket `xml:"AiBucketList,omitempty"` +} + +// DescribeMediaProcessBucketsResult 描述ASR处理桶的结果 +type DescribeASRProcessBucketsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + MediaBucketList []MediaProcessBucket `xml:"AsrBucketList,omitempty"` +} + +// DescribeFileProcessBucketsResult TODO +type DescribeFileProcessBucketsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + FileBucketList []MediaProcessBucket `xml:"FileBucketList,omitempty"` +} + +// MediaProcessBucket 媒体处理bucket +type MediaProcessBucket struct { + Name string `xml:"Name,omitempty"` + BucketId string `xml:"BucketId,omitempty"` + Region string `xml:"Region,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` +} + +// CreateMediaProcessBucketOptions 开通媒体处理服务参数 +type CreateMediaProcessBucketOptions struct { +} + +// CreateMediaProcessBucketResult 开通媒体处理服务返回 +type CreateMediaProcessBucketResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + MediaBucket MediaProcessBucket `xml:"MediaBucket,omitempty"` +} + +// CreateMediaProcessBucket 开通媒体处理服务 https://cloud.tencent.com/document/product/436/115298 +func (s *CIService) CreateMediaProcessBucket(ctx context.Context, opt *CreateMediaProcessBucketOptions) (*CreateMediaProcessBucketResult, *Response, error) { + var res CreateMediaProcessBucketResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/mediabucket", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeMediaProcessBuckets TODO +// 媒体bucket接口 https://cloud.tencent.com/document/product/436/48988 +func (s *CIService) DescribeMediaProcessBuckets(ctx context.Context, opt *DescribeMediaProcessBucketsOptions) (*DescribeMediaProcessBucketsResult, *Response, error) { + var res DescribeMediaProcessBucketsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/mediabucket", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreatePicProcessBucketOptions 开通图片处理异步能力参数 +type CreatePicProcessBucketOptions struct { +} + +// PicProcessBucket 图片处理桶信息别名 +type PicProcessBucket MediaProcessBucket + +// CreatePicProcessBucketResult 开通图片处理异步能力返回 +type CreatePicProcessBucketResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + PicBucket PicProcessBucket `xml:"PicBucket,omitempty"` +} + +// CreatePicProcessBucket 开通图片处理异步能力 https://cloud.tencent.com/document/product/460/95749 +func (s *CIService) CreatePicProcessBucket(ctx context.Context, opt *CreatePicProcessBucketOptions) (*CreatePicProcessBucketResult, *Response, error) { + var res CreatePicProcessBucketResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/picbucket", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribePicProcessBuckets TODO +func (s *CIService) DescribePicProcessBuckets(ctx context.Context, opt *DescribePicProcessBucketsOptions) (*DescribePicProcessBucketsResult, *Response, error) { + var res DescribePicProcessBucketsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/picbucket", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateAIProcessBucketOptions 开通AI处理能力参数 +type CreateAIProcessBucketOptions struct { +} + +// AIProcessBucket AI处理桶信息别名 +type AIProcessBucket MediaProcessBucket + +// CreateAIProcessBucketResult 开通AI处理能力返回 +type CreateAIProcessBucketResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + AiBucket AIProcessBucket `xml:"AiBucket,omitempty"` +} + +// CreateAIProcessBucket 开通AI处理能力 https://cloud.tencent.com/document/product/460/79593 +func (s *CIService) CreateAIProcessBucket(ctx context.Context, opt *CreateAIProcessBucketOptions) (*CreateAIProcessBucketResult, *Response, error) { + var res CreateAIProcessBucketResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/ai_bucket", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeAIProcessBuckets TODO +func (s *CIService) DescribeAIProcessBuckets(ctx context.Context, opt *DescribeAIProcessBucketsOptions) (*DescribeAIProcessBucketsResult, *Response, error) { + var res DescribeAIProcessBucketsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/ai_bucket", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateASRProcessBucketOptions 开通ASR处理服务参数 +type CreateASRProcessBucketOptions struct { +} + +// ASRBucketBucket ASR处理桶信息别名 +type AsrBucketBucket MediaProcessBucket + +// CreateASRProcessBucketResult 开通ASR处理服务返回 +type CreateASRProcessBucketResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + AsrBucketBucket AsrBucketBucket `xml:"AsrBucket,omitempty"` +} + +// CreateASRProcessBucket 开通ASR处理服务 https://cloud.tencent.com/document/product/460/86377 +func (s *CIService) CreateASRProcessBucket(ctx context.Context, opt *CreateASRProcessBucketOptions) (*CreateASRProcessBucketResult, *Response, error) { + var res CreateASRProcessBucketResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrbucket", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeASRProcessBuckets TODO +func (s *CIService) DescribeASRProcessBuckets(ctx context.Context, opt *DescribeASRProcessBucketsOptions) (*DescribeASRProcessBucketsResult, *Response, error) { + var res DescribeASRProcessBucketsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrbucket", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateFileProcessBucketOptions 开通文件处理服务参数 +type CreateFileProcessBucketOptions struct { +} + +// FileProcessBucket 文件处理桶信息别名 +type FileProcessBucket MediaProcessBucket + +// CreateFileProcessBucketResult 开通文件处理服务返回 +type CreateFileProcessBucketResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + FileProcessBucket FileProcessBucket `xml:"FileBucket,omitempty"` +} + +// CreateFileProcessBucket 开通文件处理服务 https://cloud.tencent.com/document/product/460/86377 +func (s *CIService) CreateFileProcessBucket(ctx context.Context, opt *CreateFileProcessBucketOptions) (*CreateFileProcessBucketResult, *Response, error) { + var res CreateFileProcessBucketResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/file_bucket", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeFileProcessBuckets TODO +func (s *CIService) DescribeFileProcessBuckets(ctx context.Context, opt *DescribeFileProcessBucketsOptions) (*DescribeFileProcessBucketsResult, *Response, error) { + var res DescribeFileProcessBucketsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/file_bucket", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetMediaInfoResult TODO +type GetMediaInfoResult struct { + XMLName xml.Name `xml:"Response"` + MediaInfo *MediaInfo `xml:"MediaInfo"` +} + +// GetMediaInfo TODO +// 媒体信息接口 https://cloud.tencent.com/document/product/436/55672 +func (s *CIService) GetMediaInfo(ctx context.Context, name string, opt *ObjectGetOptions, id ...string) (*GetMediaInfoResult, *Response, error) { + var u string + + // 兼容 name 以 / 开头的情况 + if strings.HasPrefix(name, "/") { + name = encodeURIComponent("/") + encodeURIComponent(name[1:], []byte{'/'}) + } else { + name = encodeURIComponent(name, []byte{'/'}) + } + + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&ci-process=videoinfo", name, id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?ci-process=videoinfo", name) + } else { + return nil, nil, fmt.Errorf("wrong params") + } + + var res GetMediaInfoResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type PlayKey struct { + MasterPlayKey string `xml:"MasterPlayKey"` + BackupPlayKey string `xml:"BackupPlayKey"` +} + +type PlayKeyResult struct { + XMLName xml.Name `xml:"Response"` + PlayKeyList *PlayKey `xml:"PlayKeyList"` +} + +func (s *CIService) CreatePlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *CIService) CreateMediaPlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + return s.CreatePlayKey(ctx) +} + +func (s *CIService) GetPlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *CIService) DescribeMediaPlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type UpdateMediaPlayKeyOptions struct { + MasterPlayKey string `url:"masterPlayKey,omitempty"` + BackupPlayKey string `url:"backupPlayKey,omitempty"` +} + +func (s *CIService) UpdateMediaPlayKey(ctx context.Context, opt *UpdateMediaPlayKeyOptions) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodPut, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GenerateMediaInfoOptions TODO +type GenerateMediaInfoOptions struct { + XMLName xml.Name `xml:"Request"` + Input *JobInput `xml:"Input,omitempty"` +} + +// GenerateMediaInfo TODO +// 生成媒体信息接口,支持大文件,耗时较大请求 +func (s *CIService) GenerateMediaInfo(ctx context.Context, opt *GenerateMediaInfoOptions) (*GetMediaInfoResult, *Response, error) { + var res GetMediaInfoResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/mediainfo", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GenerateAVInfoOptions 兼容avinfo接口 +type GenerateAVInfoOptions struct { + XMLName xml.Name `xml:"Request"` + Input *JobInput `xml:"Input,omitempty"` + OptHeaders *OptHeaders `header:"-,omitempty" url:"-" json:"-" xml:"-"` +} + +// GetAVInfoResult 兼容avinfo格式 +type GetAVInfoResult struct { + Format struct { + BitRate string `json:"bit_rate"` + Duration string `json:"duration"` + FormatLongName string `json:"format_long_name"` + FormatName string `json:"format_name"` + NbPrograms int `json:"nb_programs"` + NbStreams int `json:"nb_streams"` + Size string `json:"size"` + StartTime string `json:"start_time"` + } `json:"format"` + Streams []struct { + AvgFrameRate string `json:"avg_frame_rate,omitempty"` + BitRate string `json:"bit_rate"` + CodecLongName string `json:"codec_long_name"` + CodecName string `json:"codec_name"` + CodecTag string `json:"codec_tag"` + CodecTagString string `json:"codec_tag_string"` + CodecTimeBase string `json:"codec_time_base"` + CodecType string `json:"codec_type"` + ColorPrimaries string `json:"color_primaries,omitempty"` + ColorRange string `json:"color_range,omitempty"` + ColorTransfer string `json:"color_transfer,omitempty"` + CreationTime time.Time `json:"creation_time"` + DisplayAspectRatio string `json:"display_aspect_ratio,omitempty"` + Duration string `json:"duration"` + FiledOrder string `json:"filed_order,omitempty"` + HasBFrames string `json:"has_b_frames,omitempty"` + Height int `json:"height,omitempty"` + Index int `json:"index"` + Language string `json:"language"` + Level int `json:"level,omitempty"` + NbFrames string `json:"nb_frames,omitempty"` + PixFmt string `json:"pix_fmt,omitempty"` + Profile string `json:"profile,omitempty"` + RFrameRate string `json:"r_frame_rate,omitempty"` + Refs int `json:"refs,omitempty"` + Rotation string `json:"rotation,omitempty"` + SampleAspectRatio string `json:"sample_aspect_ratio,omitempty"` + StartTime string `json:"start_time"` + Timebase string `json:"timebase"` + Width int `json:"width,omitempty"` + ChannelLayout string `json:"channel_layout,omitempty"` + Channels int `json:"channels,omitempty"` + SampleFmt string `json:"sample_fmt,omitempty"` + SampleRate string `json:"sample_rate,omitempty"` + } `json:"streams"` +} + +// GenerateAVInfo TODO +// 生成媒体信息接口,支持大文件,耗时较大请求 +func (s *CIService) GenerateAVInfo(ctx context.Context, opt *GenerateAVInfoOptions) (*GetAVInfoResult, *Response, error) { + var buf bytes.Buffer + var res GetAVInfoResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/avinfo", + method: http.MethodPost, + body: opt, + result: &buf, + } + resp, err := s.client.send(ctx, &sendOpt) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +// GetSnapshotOptions TODO +type GetSnapshotOptions struct { + Time float32 `url:"time,omitempty"` + Height int `url:"height,omitempty"` + Width int `url:"width,omitempty"` + Format string `url:"format,omitempty"` + Rotate string `url:"rotate,omitempty"` + Mode string `url:"mode,omitempty"` +} + +// GetSnapshot TODO +// 媒体截图接口 https://cloud.tencent.com/document/product/436/55671 +func (s *CIService) GetSnapshot(ctx context.Context, name string, opt *GetSnapshotOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&ci-process=snapshot", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?ci-process=snapshot", encodeURIComponent(name)) + } else { + return nil, fmt.Errorf("wrong params") + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type PostSnapshotOptions struct { + XMLName xml.Name `xml:"Request"` + Input *JobInput `xml:"Input,omitempty"` + Time string `xml:"Time,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` + Mode string `xml:"Mode,omitempty"` + Rotate string `xml:"Rotate,omitempty"` + Format string `xml:"Format,omitempty"` + Output *JobOutput `xml:"Output,omitempty"` +} + +type PostSnapshotResult struct { + XMLName xml.Name `xml:"Response"` + Output *JobOutput `xml:"Output,omitempty"` +} + +// PostSnapshot +// https://cloud.tencent.com/document/product/460/73407 +// upload snapshot image to cos +func (s *CIService) PostSnapshot(ctx context.Context, opt *PostSnapshotOptions) (*PostSnapshotResult, *Response, error) { + var res PostSnapshotResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/snapshot", + body: opt, + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// PostCISnapshot 发送截图请求到万象ci服务 +func (s *CIService) PostCISnapshot(ctx context.Context, opt *PostSnapshotOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/cisnapshot", + body: opt, + method: http.MethodPost, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// GetPrivateM3U8Options TODO +type GetPrivateM3U8Options struct { + Expires int `url:"expires"` +} + +// GetPrivateM3U8 TODO +// 获取私有m3u8资源接口 https://cloud.tencent.com/document/product/460/63738 +func (s *CIService) GetPrivateM3U8(ctx context.Context, name string, opt *GetPrivateM3U8Options, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&ci-process=pm3u8", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?ci-process=pm3u8", encodeURIComponent(name)) + } else { + return nil, fmt.Errorf("wrong params") + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// TriggerWorkflowOptions TODO +type TriggerWorkflowOptions struct { + WorkflowId string `url:"workflowId"` + Object string `url:"object"` + Name string `url:"name"` +} + +// TriggerWorkflowResult TODO +type TriggerWorkflowResult struct { + XMLName xml.Name `xml:"Response"` + InstanceId string `xml:"InstanceId"` + RequestId string `xml:"RequestId"` +} + +// TriggerWorkflow TODO +// 单文件触发工作流 https://cloud.tencent.com/document/product/460/54640 +func (s *CIService) TriggerWorkflow(ctx context.Context, opt *TriggerWorkflowOptions) (*TriggerWorkflowResult, *Response, error) { + var res TriggerWorkflowResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/triggerworkflow", + optQuery: opt, + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeWorkflowExecutionsOptions TODO +type DescribeWorkflowExecutionsOptions struct { + WorkflowId string `url:"workflowId,omitempty"` + Name string `url:"name,omitempty"` + OrderByTime string `url:"orderByTime,omitempty"` + NextToken string `url:"nextToken,omitempty"` + Size int `url:"size,omitempty"` + States string `url:"states,omitempty"` + StartCreationTime string `url:"startCreationTime,omitempty"` + EndCreationTime string `url:"endCreationTime,omitempty"` + JobId string `url:"jobId,omitempty"` +} + +// WorkflowExecutionList TODO +type WorkflowExecutionList struct { + RunId string `xml:"RunId,omitempty"` + WorkflowId string `xml:"WorkflowId,omitempty"` + State string `xml:"State,omitempty"` + CreationTime string `xml:"CreationTime,omitempty"` + Object string `xml:"Object,omitempty"` +} + +// DescribeWorkflowExecutionsResult TODO +type DescribeWorkflowExecutionsResult struct { + XMLName xml.Name `xml:"Response"` + WorkflowExecutionList []WorkflowExecutionList `xml:"WorkflowExecutionList,omitempty"` + NextToken string `xml:"NextToken,omitempty"` +} + +// DescribeWorkflowExecutions TODO +// 获取工作流实例列表 https://cloud.tencent.com/document/product/460/80050 +func (s *CIService) DescribeWorkflowExecutions(ctx context.Context, opt *DescribeWorkflowExecutionsOptions) (*DescribeWorkflowExecutionsResult, *Response, error) { + var res DescribeWorkflowExecutionsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflowexecution", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// NotifyConfig TODO +type NotifyConfig struct { + URL string `xml:"Url,omitempty"` + Event string `xml:"Event,omitempty"` + Type string `xml:"Type,omitempty"` + ResultFormat string `xml:"ResultFormat,omitempty"` + State string `xml:"State,omitempty"` + KafkaConfig *KafkaConfig `xml:"KafkaConfig,omitempty" json:"KafkaConfig,omitempty"` +} + +// ExtFilter TODO +type ExtFilter struct { + State string `xml:"State,omitempty"` + Video string `xml:"Video,omitempty"` + Audio string `xml:"Audio,omitempty"` + Image string `xml:"Image,omitempty"` + ContentType string `xml:"ContentType,omitempty"` + Custom string `xml:"Custom,omitempty"` + CustomExts string `xml:"CustomExts,omitempty"` + AllFile string `xml:"AllFile,omitempty"` + AutoContentType []string `xml:"AutoContentType,omitempty"` +} + +// NodeInput TODO +type NodeInput struct { + QueueId string `xml:"QueueId,omitempty"` + ObjectPrefix string `xml:"ObjectPrefix,omitempty"` + NotifyConfig *NotifyConfig `xml:"NotifyConfig,omitempty" json:"NotifyConfig,omitempty"` + ExtFilter *ExtFilter `xml:"ExtFilter,omitempty" json:"ExtFilter,omitempty"` +} + +// NodeOutput TODO +type NodeOutput struct { + Region string `xml:"Region,omitempty"` + Bucket string `xml:"Bucket,omitempty"` + Object string `xml:"Object,omitempty"` + AuObject string `xml:"AuObject,omitempty"` + SpriteObject string `xml:"SpriteObject,omitempty"` + BassObject string `xml:"BassObject,omitempty"` + DrumObject string `xml:"DrumObject,omitempty"` + StreamExtract []StreamExtract `xml:"StreamExtract,omitempty"` +} + +// DelogoParam TODO +type DelogoParam struct { + Switch string `xml:"Switch,omitempty"` + Dx string `xml:"Dx,omitempty"` + Dy string `xml:"Dy,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` +} + +// NodeSDRtoHDR TODO +type NodeSDRtoHDR struct { + HdrMode string `xml:"HdrMode,omitempty"` +} + +// NodeSCF TODO +type NodeSCF struct { + Region string `xml:"Region,omitempty"` + FunctionName string `xml:"FunctionName,omitempty"` + Namespace string `xml:"Namespace,omitempty"` +} + +// VideoStreamConfig TODO +type VideoStreamConfig struct { + VideoStreamName string `xml:"VideoStreamName,omitempty"` + BandWidth string `xml:"BandWidth,omitempty"` +} + +// NodeHlsPackInfo TODO +type NodeHlsPackInfo struct { + VideoStreamConfig []VideoStreamConfig `xml:"VideoStreamConfig,omitempty"` +} + +// WorkflowNodeCondition TODO +type WorkflowNodeCondition struct { + Express string `xml:"Express,omitempty"` +} + +// SegmentVideoBody TODO +type SegmentVideoBody struct { + Mode string `xml:"Mode,omitempty"` + SegmentType string `xml:"SegmentType,omitempty"` + BackgroundBlue string `xml:"BackgroundBlue,omitempty"` + BackgroundRed string `xml:"BackgroundRed,omitempty"` + BackgroundGreen string `xml:"BackgroundGreen,omitempty"` + BackgroundLogoUrl string `xml:"BackgroundLogoUrl,omitempty"` + BinaryThreshold string `xml:"BinaryThreshold,omitempty"` + RemoveRed string `xml:"RemoveRed,omitempty"` + RemoveGreen string `xml:"RemoveGreen,omitempty"` + RemoveBlue string `xml:"RemoveBlue,omitempty"` +} + +// NodeSmartCover TODO +type NodeSmartCover struct { + Format string `xml:"Format,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Count string `xml:"Count,omitempty"` + DeleteDuplicates string `xml:"DeleteDuplicates,omitempty"` +} + +// NodeSegmentConfig TODO +type NodeSegmentConfig struct { + Format string `xml:"Format,omitempty"` + Duration string `xml:"Duration,omitempty"` +} + +// NodeStreamPackConfigInfo TODO +type NodeStreamPackConfigInfo struct { + PackType string `xml:"PackType,omitempty"` + IgnoreFailedStream bool `xml:"IgnoreFailedStream,omitempty"` + ReserveAllStreamNode string `xml:"ReserveAllStreamNode,omitempty"` +} + +// NodeOperation TODO +type NodeOperation struct { + TemplateId string `xml:"TemplateId,omitempty" json:"TemplateId,omitempty"` + Output *NodeOutput `xml:"Output,omitempty" json:"Output,omitempty"` + WatermarkTemplateId interface{} `xml:"WatermarkTemplateId,omitempty" json:"WatermarkTemplateId,omitempty"` // xml解析map有问题,必须interface结构 + DelogoParam *DelogoParam `xml:"DelogoParam,omitempty" json:"DelogoParam,omitempty"` + SDRtoHDR *NodeSDRtoHDR `xml:"SDRtoHDR,omitempty" json:"SDRtoHDR,omitempty"` + SCF *NodeSCF `xml:"SCF,omitempty" json:"SCF,omitempty"` + HlsPackInfo *NodeHlsPackInfo `xml:"HlsPackInfo,omitempty" json:"HlsPackInfo,omitempty"` + TranscodeTemplateId string `xml:"TranscodeTemplateId,omitempty" json:"TranscodeTemplateId,omitempty"` + SmartCover *NodeSmartCover `xml:"SmartCover,omitempty" json:"SmartCover,omitempty"` + SegmentConfig *NodeSegmentConfig `xml:"Segment,omitempty" json:"Segment,omitempty"` + DigitalWatermark *DigitalWatermark `xml:"DigitalWatermark,omitempty" json:"DigitalWatermark,omitempty"` + StreamPackConfigInfo *NodeStreamPackConfigInfo `xml:"StreamPackConfig,omitempty" json:"StreamPackConfig,omitempty"` + StreamPackInfo *NodeHlsPackInfo `xml:"StreamPackInfo,omitempty" json:"StreamPackInfo,omitempty"` + Condition *WorkflowNodeCondition `xml:"Condition,omitempty" json:"Condition,omitempty"` + SegmentVideoBody *SegmentVideoBody `xml:"SegmentVideoBody,omitempty" json:"SegmentVideoBody,omitempty"` + ImageInspect *ImageInspect `xml:"ImageInspect,omitempty" json:"ImageInspect,omitempty"` + TranscodeConfig *struct { + FreeTranscode string `xml:"FreeTranscode,omitempty" json:"FreeTranscode,omitempty"` + } `xml:"TranscodeConfig,omitempty" json:"TranscodeConfig,omitempty"` +} + +// Node TODO +type Node struct { + Type string `xml:"Type"` + Input *NodeInput `xml:"Input,omitempty" json:"Input,omitempty"` + Operation *NodeOperation `xml:"Operation,omitempty" json:"Operation,omitempty"` +} + +// Topology TODO +type Topology struct { + Dependencies map[string]string `xml:"Dependencies,omitempty" json:"Dependencies,omitempty"` + Nodes map[string]Node `xml:"Nodes,omitempty" json:"Nodes,omitempty"` +} + +// UnmarshalXML TODO +func (m *Topology) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var v struct { + XMLName xml.Name //`xml:"Topology"` + Dependencies struct { + Inner []byte `xml:",innerxml"` + } `xml:"Dependencies"` + Nodes struct { + Inner []byte `xml:",innerxml"` + } `xml:"Nodes"` + } + err := d.DecodeElement(&v, &start) + if err != nil { + return err + } + + myMap := make(map[string]interface{}) + + // ... do the mxj magic here ... - + + temp := v.Nodes.Inner + + prefix := "" + postfix := "" + str := prefix + string(temp) + postfix + // fmt.Println(str) + myMxjMap, _ := mxj.NewMapXml([]byte(str)) + myMap, _ = myMxjMap["Nodes"].(map[string]interface{}) + nodesMap := make(map[string]Node) + + for k, v := range myMap { + var node Node + // fmt.Printf("%+v\n", v) + mapstructure.Decode(v, &node) + // fmt.Printf("%+v\n", err) + nodesMap[k] = node + } + + // fill myMap + m.Nodes = nodesMap + + deps := make(map[string]interface{}) + + tep := "" + string(v.Dependencies.Inner) + "" + tepMxjMap, _ := mxj.NewMapXml([]byte(tep)) + deps, _ = tepMxjMap["Dependencies"].(map[string]interface{}) + depsString := make(map[string]string) + for k, v := range deps { + depsString[k] = v.(string) + } + m.Dependencies = depsString + return nil +} + +// WorkflowExecution TODO +type WorkflowExecution struct { + RunId string `xml:"RunId,omitempty" json:"RunId,omitempty"` + WorkflowId string `xml:"WorkflowId,omitempty" json:"WorkflowId,omitempty"` + WorkflowName string `xml:"WorkflowName,omitempty" json:"WorkflowName,omitempty"` + State string `xml:"State,omitempty" json:"State,omitempty"` + CreateTime string `xml:"CreateTime,omitempty" json:"CreateTime,omitempty"` + Object string `xml:"Object,omitempty" json:"Object,omitempty"` + Topology Topology `xml:"Topology,omitempty" json:"Topology,omitempty"` +} + +// DescribeWorkflowExecutionResult TODO +type DescribeWorkflowExecutionResult struct { + XMLName xml.Name `xml:"Response"` + WorkflowExecution []WorkflowExecution `xml:"WorkflowExecution,omitempty" json:"WorkflowExecution,omitempty"` + NextToken string `xml:"NextToken,omitempty" json:"NextToken,omitempty"` +} + +// DescribeWorkflowExecution TODO +// 获取工作流实例详情 https://cloud.tencent.com/document/product/460/45949 +func (s *CIService) DescribeWorkflowExecution(ctx context.Context, runId string) (*DescribeWorkflowExecutionResult, *Response, error) { + var res DescribeWorkflowExecutionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflowexecution/" + runId, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// SpeechRecognition TODO +type SpeechRecognition struct { + ChannelNum string `xml:"ChannelNum,omitempty"` + ConvertNumMode string `xml:"ConvertNumMode,omitempty"` + EngineModelType string `xml:"EngineModelType,omitempty"` + FilterDirty string `xml:"FilterDirty,omitempty"` + FilterModal string `xml:"FilterModal,omitempty"` + ResTextFormat string `xml:"ResTextFormat,omitempty"` + SpeakerDiarization string `xml:"SpeakerDiarization,omitempty"` + SpeakerNumber string `xml:"SpeakerNumber,omitempty"` + FilterPunc string `xml:"FilterPunc,omitempty"` + OutputFileType string `xml:"OutputFileType,omitempty"` + FlashAsr string `xml:"FlashAsr,omitempty"` + Format string `xml:"Format,omitempty"` + FirstChannelOnly string `xml:"FirstChannelOnly,omitempty"` + WordInfo string `xml:"WordInfo,omitempty"` + SentenceMaxLength string `xml:"SentenceMaxLength,omitempty"` +} + +// SpeechRecognitionResult TODO +type SpeechRecognitionResult struct { + AudioTime float64 `xml:"AudioTime,omitempty"` + Result []string `xml:"Result,omitempty"` + ObjectName string `xml:"ObjectName,omitempty"` + DetailObjectName string `xml:"DetailObjectName,omitempty"` + SpeechRecognitionFlashResult *SpeechRecognitionFlashResult `xml:"FlashResult,omitempty"` + SpeechRecognitionResultDetail *SpeechRecognitionResultDetail `xml:"ResultDetail,omitempty"` +} + +type SpeechRecognitionFlashResult struct { + ChannelId int32 `xml:"channel_id,omitempty"` + Text string `xml:"text,omitempty"` + SentenceList []SpeechRecognitionSentenceList `xml:"sentence_list,omitempty"` +} + +type SpeechRecognitionSentenceList struct { + Text string `xml:"text,omitempty"` + StartTime string `xml:"start_time,omitempty"` + EndTime string `xml:"end_time,omitempty"` + SpeakerId string `xml:"speaker_id,omitempty"` + WordList []SpeechRecognitionWordList `xml:"word_list,omitempty"` +} + +type SpeechRecognitionWordList struct { + Word string `xml:"word,omitempty"` + StartTime string `xml:"start_time,omitempty"` + EndTime string `xml:"end_time,omitempty"` +} + +type SpeechRecognitionResultDetail struct { + FinalSentence string `xml:"FinalSentence,omitempty"` + SliceSentence string `xml:"SliceSentence,omitempty"` + StartMs string `xml:"StartMs,omitempty"` + EndMs string `xml:"EndMs,omitempty"` + WordsNum string `xml:"WordsNum,omitempty"` + SpeechSpeed string `xml:"SpeechSpeed,omitempty"` + SpeakerId string `xml:"SpeakerId,omitempty"` + Words []SpeechRecognitionWords `xml:"Words,omitempty"` +} + +type SpeechRecognitionWords struct { + Word string `xml:"Word,omitempty"` + OffsetStartMs string `xml:"OffsetStartMs,omitempty"` + OffsetEndMs string `xml:"OffsetEndMs,omitempty"` +} + +// SoundHoundResult TODO +type SoundHoundResult struct { + SongList struct { + Inlier int `xml:"Inlier,omitempty"` + SingerName string `xml:"SingerName,omitempty"` + SongName string `xml:"SongName,omitempty"` + } `xml:"SongList,omitempty"` +} + +// ASRJobOperation TODO +type ASRJobOperation struct { + Tag string `xml:"Tag,omitempty"` + Output *JobOutput `xml:"Output,omitempty"` + SpeechRecognition *SpeechRecognition `xml:"SpeechRecognition,omitempty"` + SpeechRecognitionResult *SpeechRecognitionResult `xml:"SpeechRecognitionResult,omitempty"` + SoundHoundResult *SoundHoundResult `xml:"SoundHoundResult,omitempty"` + TemplateId string `xml:"TemplateId,omitempty"` + UserData string `xml:"UserData,omitempty"` + JobLevel int `xml:"JobLevel,omitempty"` +} + +// CreateASRJobsOptions TODO +type CreateASRJobsOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *ASRJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +// ASRJobDetail TODO +type ASRJobDetail struct { + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + JobId string `xml:"JobId,omitempty"` + Tag string `xml:"Tag,omitempty"` + State string `xml:"State,omitempty"` + CreationTime string `xml:"CreationTime,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *ASRJobOperation `xml:"Operation,omitempty"` +} + +// CreateASRJobsResult TODO +type CreateASRJobsResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail *ASRJobDetail `xml:"JobsDetail,omitempty"` +} + +// CreateASRJobs TODO +func (s *CIService) CreateASRJobs(ctx context.Context, opt *CreateASRJobsOptions) (*CreateASRJobsResult, *Response, error) { + var res CreateASRJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asr_jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeMutilASRJobResult TODO +type DescribeMutilASRJobResult struct { + XMLName xml.Name `xml:"Response"` + JobsDetail []ASRJobDetail `xml:"JobsDetail,omitempty"` + NonExistJobIds []string `xml:"NonExistJobIds,omitempty"` +} + +// DescribeMultiASRJob TODO +func (s *CIService) DescribeMultiASRJob(ctx context.Context, jobids []string) (*DescribeMutilASRJobResult, *Response, error) { + jobidsStr := "" + if len(jobids) < 1 { + return nil, nil, errors.New("empty param jobids") + } else { + jobidsStr = strings.Join(jobids, ",") + } + + var res DescribeMutilASRJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asr_jobs/" + jobidsStr, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeMediaTemplateOptions TODO +type DescribeMediaTemplateOptions struct { + Tag string `url:"tag,omitempty"` + Category string `url:"category,omitempty"` + Ids string `url:"ids,omitempty"` + Name string `url:"name,omitempty"` + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` +} + +// DescribeMediaTemplateResult TODO +type DescribeMediaTemplateResult struct { + XMLName xml.Name `xml:"Response"` + TemplateList []Template `xml:"TemplateList,omitempty"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` +} + +// DescribeMediaTemplate 搜索模板 +func (s *CIService) DescribeMediaTemplate(ctx context.Context, opt *DescribeMediaTemplateOptions) (*DescribeMediaTemplateResult, *Response, error) { + var res DescribeMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DeleteMediaTemplateResult TODO +type DeleteMediaTemplateResult struct { + RequestId string `xml:"RequestId,omitempty"` + TemplateId string `xml:"TemplateId,omitempty"` +} + +// DeleteMediaTemplate TODO +func (s *CIService) DeleteMediaTemplate(ctx context.Context, tempalteId string) (*DeleteMediaTemplateResult, *Response, error) { + var res DeleteMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + tempalteId, + method: http.MethodDelete, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaSnapshotTemplateOptions TODO +type CreateMediaSnapshotTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Snapshot *Snapshot `xml:"Snapshot,omitempty"` +} + +// CreateMediaTranscodeTemplateOptions TODO +type CreateMediaTranscodeTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Container *Container `xml:"Container,omitempty"` + Video *Video `xml:"Video,omitempty"` + Audio *Audio `xml:"Audio,omitempty"` + TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` + TransConfig *TransConfig `xml:"TransConfig,omitempty"` + AudioMix *AudioMix `xml:"AudioMix,omitempty"` + AudioMixArray []AudioMix `xml:"AudioMixArray,omitempty"` +} + +// CreateMediaAnimationTemplateOptions TODO +type CreateMediaAnimationTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Container *Container `xml:"Container,omitempty"` + Video *AnimationVideo `xml:"Video,omitempty"` + TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` +} + +// CreateMediaConcatTemplateOptions TODO +type CreateMediaConcatTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + ConcatTemplate *ConcatTemplate `xml:"ConcatTemplate,omitempty"` +} + +// CreateMediaVideoProcessTemplateOptions TODO +type CreateMediaVideoProcessTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + ColorEnhance *ColorEnhance `xml:"ColorEnhance,omitempty"` + MsSharpen *MsSharpen `xml:"MsSharpen,omitempty"` +} + +// CreateMediaVideoMontageTemplateOptions TODO +type CreateMediaVideoMontageTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Duration string `xml:"Duration,omitempty"` + Scene string `xml:"Scene,omitempty"` + Container *Container `xml:"Container,omitempty"` + Video *Video `xml:"Video,omitempty"` + Audio *Audio `xml:"Audio,omitempty"` + AudioMix *AudioMix `xml:"AudioMix,omitempty"` + AudioMixArray []AudioMix `xml:"AudioMixArray,omitempty"` +} + +// CreateMediaVoiceSeparateTemplateOptions TODO +type CreateMediaVoiceSeparateTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + AudioMode string `xml:"AudioMode,omitempty"` + AudioConfig *AudioConfig `xml:"AudioConfig,omitempty"` +} + +// CreateMediaSuperResolutionTemplateOptions TODO +type CreateMediaSuperResolutionTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Resolution string `xml:"Resolution,omitempty"` // sdtohd、hdto4k + EnableScaleUp string `xml:"EnableScaleUp,omitempty"` + Version string `xml:"Version,omitempty"` +} + +// CreateMediaPicProcessTemplateOptions TODO +type CreateMediaPicProcessTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + PicProcess *PicProcess `xml:"PicProcess,omitempty"` +} + +// CreateMediaWatermarkTemplateOptions TODO +type CreateMediaWatermarkTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Watermark *Watermark `xml:"Watermark,omitempty"` +} + +// CreateMediaTranscodeProTemplateOptions TODO +type CreateMediaTranscodeProTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Container *Container `xml:"Container,omitempty"` + Video *TranscodeProVideo `xml:"Video,omitempty"` + Audio *TranscodeProAudio `xml:"Audio,omitempty"` + TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` + TransConfig *TransConfig `xml:"TransConfig,omitempty"` +} + +// CreateMediaTtsTemplateOptions TODO +type CreateMediaTtsTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + Mode string `xml:"Mode,omitempty"` + Codec string `xml:"Codec,omitempty"` + VoiceType string `xml:"VoiceType,omitempty"` + Volume string `xml:"Volume,omitempty"` + Speed string `xml:"Speed,omitempty"` + Emotion string `xml:"Emotion,omitempty"` +} + +// CreateMediaSmartcoverTemplateOptions TODO +type CreateMediaSmartCoverTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + SmartCover *NodeSmartCover `xml:"SmartCover,omitempty" json:"SmartCover,omitempty"` +} + +// CreateMediaSpeechRecognitionTemplateOptions TODO +type CreateMediaSpeechRecognitionTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + SpeechRecognition *SpeechRecognition `xml:"SpeechRecognition,omitempty" json:"SpeechRecognition,omitempty"` +} + +// CreateNoiseReductionTemplateOptions TODO +type CreateNoiseReductionTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + NoiseReduction *NoiseReduction `xml:"NoiseReduction,omitempty" json:"NoiseReduction,omitempty"` +} + +// NoiseReduction TODO +type NoiseReduction struct { + Format string `xml:"Format,omitempty"` + Samplerate string `xml:"Samplerate,omitempty"` +} + +// CreateVideoEnhanceTemplateOptions TODO +type CreateVideoEnhanceTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + VideoEnhance *VideoEnhance `xml:"VideoEnhance,omitempty" json:"VideoEnhance,omitempty"` +} + +// VideoEnhance TODO +type VideoEnhance struct { + Transcode *Transcode `xml:"Transcode,omitempty"` + SuperResolution *SuperResolution `xml:"SuperResolution,omitempty"` + ColorEnhance *ColorEnhance `xml:"ColorEnhance,omitempty"` + MsSharpen *MsSharpen `xml:"MsSharpen,omitempty"` + SDRtoHDR *SDRtoHDR `xml:"SDRtoHDR,omitempty"` + FrameEnhance *FrameEnhance `xml:"FrameEnhance,omitempty"` +} + +// FrameEnhance TODO +type FrameEnhance struct { + FrameDoubling string `xml:"FrameDoubling,omitempty"` +} + +// CreateVideoTargetRecTemplateOptions TODO +type CreateVideoTargetRecTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + VideoTargetRec *VideoTargetRec `xml:"VideoTargetRec,omitempty" json:"VideoTargetRec,omitempty"` +} + +// VTRTranscode TODO +type VTRTranscode struct { + Container *Container `xml:"Container,omitempty"` + Video *VTRVideo `xml:"Video,omitempty"` +} + +// VTRVideo TODO +type VTRVideo struct { + Codec string `xml:"Codec"` + Bitrate string `xml:"Bitrate,omitempty"` + Crf string `xml:"Crf,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Fps string `xml:"Fps,omitempty"` +} + +// VideoTargetRec TODO +type VideoTargetRec struct { + Body string `xml:"Body,omitempty"` + Pet string `xml:"Pet,omitempty"` + Car string `xml:"Car,omitempty"` + Face string `xml:"Face,omitempty"` + Plate string `xml:"Plate,omitempty"` + ProcessType string `xml:"ProcessType,omitempty"` + TransTpl *VTRTranscode `xml:"TransTpl,omitempty"` +} + +// VideoTargetRecResult TODO +type VideoTargetRecResult struct { + BodyRecognition []*BodyRecognition `xml:"BodyRecognition,omitempty"` + PetRecognition []*PetRecognition `xml:"PetRecognition,omitempty"` + CarRecognition []*CarRecognition `xml:"CarRecognition,omitempty"` + FaceRecognition []*FaceRecognition `xml:"FaceRecognition,omitempty"` + LicenseRecognitionResult []*LicenseRecognitionResult `xml:"LicenseRecognitionResult,omitempty"` + Sensitive string `xml:"Sensitive,omitempty"` +} + +// BodyRecognition TODO +type BodyRecognition struct { + Time string `xml:"Time,omitempty"` + Url string `xml:"Url,omitempty"` + BodyInfo []*VideoTargetRecInfo `xml:"BodyInfo,omitempty"` +} + +// PetRecognition TODO +type PetRecognition struct { + Time string `xml:"Time,omitempty"` + Url string `xml:"Url,omitempty"` + PetInfo []*VideoTargetRecInfo `xml:"PetInfo,omitempty"` +} + +// CarRecognition TODO +type CarRecognition struct { + Time string `xml:"Time,omitempty"` + Url string `xml:"Url,omitempty"` + CarInfo []*VideoTargetRecInfo `xml:"CarInfo,omitempty"` +} + +// FaceRecognition TODO +type FaceRecognition struct { + Time string `xml:"Time,omitempty"` + Url string `xml:"Url,omitempty"` + FaceInfo []*VideoTargetRecInfo `xml:"FaceInfo,omitempty"` +} + +// LicenseRecognitionResult TODO +type LicenseRecognitionResult struct { + Time string `xml:"Time,omitempty"` + Url string `xml:"Url,omitempty"` + PlateInfo []*VideoTargetRecInfo `xml:"PlateInfo,omitempty"` +} + +// BodyInfo TODO +type VideoTargetRecInfo struct { + Name string `xml:"Name,omitempty"` + Score string `xml:"Score,omitempty"` + Location *VideoTargetRecLocation `xml:"Location,omitempty"` +} + +// VideoTargetRecLocation TODO +type VideoTargetRecLocation struct { + X string `xml:"X,omitempty"` + Y string `xml:"Y,omitempty"` + Height string `xml:"Height,omitempty"` + Width string `xml:"Width,omitempty"` +} + +// SplitVideoParts TODO +type SplitVideoParts struct { + Mode string `xml:"Mode,omitempty"` +} + +// SplitVideoInfoResult TODO +type SplitVideoInfoResult struct { + TimeInfo []struct { + Index string `xml:"Index,omitempty"` + PartBegin string `xml:"PartBegin,omitempty"` + PartEnd string `xml:"PartEnd,omitempty"` + } `xml:"TimeInfo,omitempty"` +} + +// CreateMediaTemplateResult TODO +type CreateMediaTemplateResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + Template *Template `xml:"Template,omitempty"` +} + +// Template TODO +type Template struct { + TemplateId string `xml:"TemplateId,omitempty"` + Tag string `xml:"Code,omitempty"` + Name string `xml:"Name,omitempty"` + TransTpl *Transcode `xml:"TransTpl,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + BucketId string `xml:"BucketId,omitempty"` + Category string `xml:"Category,omitempty"` + Snapshot *Snapshot `xml:"Snapshot,omitempty"` + Animation *Animation `xml:"Animation,omitempty"` + ConcatTemplate *ConcatTemplate `xml:"ConcatTemplate,omitempty"` + VideoProcess *VideoProcess `xml:"VideoProcess,omitempty"` + VideoMontage *VideoMontage `xml:"VideoMontage,omitempty"` + VoiceSeparate *VoiceSeparate `xml:"VoiceSeparate,omitempty"` + SuperResolution *SuperResolution `xml:"SuperResolution,omitempty"` + PicProcess *PicProcess `xml:"PicProcess,omitempty"` + Watermark *Watermark `xml:"Watermark,omitempty"` + TransProTpl *TranscodePro `xml:"TransProTpl,omitempty"` + TtsTpl *TtsTpl `xml:"TtsTpl,omitempty"` + SmartCover *NodeSmartCover `xml:"SmartCover,omitempty" json:"SmartCover,omitempty"` + SpeechRecognition *SpeechRecognition `xml:"SpeechRecognition,omitempty" json:"SpeechRecognition,omitempty"` + NoiseReduction *NoiseReduction `xml:"NoiseReduction,omitempty" json:"NoiseReduction,omitempty"` + VideoEnhance *VideoEnhance `xml:"VideoEnhance,omitempty" json:"VideoEnhance,omitempty"` + VideoTargetRec *VideoTargetRec `xml:"VideoTargetRec,omitempty" json:"VideoTargetRec,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty" json:"ImageOCR,omitempty"` +} + +// CreateMediaSnapshotTemplate 创建截图模板 +func (s *CIService) CreateMediaSnapshotTemplate(ctx context.Context, opt *CreateMediaSnapshotTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaSnapshotTemplate 更新截图模板 +func (s *CIService) UpdateMediaSnapshotTemplate(ctx context.Context, opt *CreateMediaSnapshotTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaTranscodeTemplate Options 创建转码模板 +func (s *CIService) CreateMediaTranscodeTemplate(ctx context.Context, opt *CreateMediaTranscodeTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaTranscodeTemplate 更新转码模板 +func (s *CIService) UpdateMediaTranscodeTemplate(ctx context.Context, opt *CreateMediaTranscodeTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaAnimationTemplate 创建动图模板 +func (s *CIService) CreateMediaAnimationTemplate(ctx context.Context, opt *CreateMediaAnimationTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaAnimationTemplate 更新动图模板 +func (s *CIService) UpdateMediaAnimationTemplate(ctx context.Context, opt *CreateMediaAnimationTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaConcatTemplate 创建拼接模板 +func (s *CIService) CreateMediaConcatTemplate(ctx context.Context, opt *CreateMediaConcatTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaConcatTemplate 更新拼接模板 +func (s *CIService) UpdateMediaConcatTemplate(ctx context.Context, opt *CreateMediaConcatTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaVideoProcessTemplate 创建视频增强模板 +func (s *CIService) CreateMediaVideoProcessTemplate(ctx context.Context, opt *CreateMediaVideoProcessTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaVideoProcessTemplate 更新视频增强模板 +func (s *CIService) UpdateMediaVideoProcessTemplate(ctx context.Context, opt *CreateMediaVideoProcessTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaVideoMontageTemplate 创建精彩集锦模板 +func (s *CIService) CreateMediaVideoMontageTemplate(ctx context.Context, opt *CreateMediaVideoMontageTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaVideoMontageTemplate 更新精彩集锦模板 +func (s *CIService) UpdateMediaVideoMontageTemplate(ctx context.Context, opt *CreateMediaVideoMontageTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaVoiceSeparateTemplate 创建人声分离模板 +func (s *CIService) CreateMediaVoiceSeparateTemplate(ctx context.Context, opt *CreateMediaVoiceSeparateTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaVoiceSeparateTemplate 更新人声分离模板 +func (s *CIService) UpdateMediaVoiceSeparateTemplate(ctx context.Context, opt *CreateMediaVoiceSeparateTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaSuperResolutionTemplate 创建超级分辨率模板 +func (s *CIService) CreateMediaSuperResolutionTemplate(ctx context.Context, opt *CreateMediaSuperResolutionTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaSuperResolutionTemplate 更新超级分辨率模板 +func (s *CIService) UpdateMediaSuperResolutionTemplate(ctx context.Context, opt *CreateMediaSuperResolutionTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaPicProcessTemplate 创建图片处理模板 +func (s *CIService) CreateMediaPicProcessTemplate(ctx context.Context, opt *CreateMediaPicProcessTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaPicProcessTemplate 更新图片处理模板 +func (s *CIService) UpdateMediaPicProcessTemplate(ctx context.Context, opt *CreateMediaPicProcessTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaWatermarkTemplate 创建水印模板 +func (s *CIService) CreateMediaWatermarkTemplate(ctx context.Context, opt *CreateMediaWatermarkTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaWatermarkTemplate 更新水印模板 +func (s *CIService) UpdateMediaWatermarkTemplate(ctx context.Context, opt *CreateMediaWatermarkTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaTranscodeProTemplate 创建广电转码模板 +func (s *CIService) CreateMediaTranscodeProTemplate(ctx context.Context, opt *CreateMediaTranscodeProTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaTranscodeProTemplate 更新广电转码模板 +func (s *CIService) UpdateMediaTranscodeProTemplate(ctx context.Context, opt *CreateMediaTranscodeProTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaTtsTemplate 创建语音合成模板 +func (s *CIService) CreateMediaTtsTemplate(ctx context.Context, opt *CreateMediaTtsTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaTtsTemplate 更新语音合成模板 +func (s *CIService) UpdateMediaTtsTemplate(ctx context.Context, opt *CreateMediaTtsTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaTtsTemplate 创建智能封面模板 +func (s *CIService) CreateMediaSmartCoverTemplate(ctx context.Context, opt *CreateMediaSmartCoverTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaTtsTemplate 更新智能封面模板 +func (s *CIService) UpdateMediaSmartCoverTemplate(ctx context.Context, opt *CreateMediaSmartCoverTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMediaTtsTemplate 创建语音识别模板 +func (s *CIService) CreateMediaSpeechRecognitionTemplate(ctx context.Context, opt *CreateMediaSpeechRecognitionTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaTtsTemplate 更新语音识别模板 +func (s *CIService) UpdateMediaSpeechRecognitionTemplate(ctx context.Context, opt *CreateMediaSpeechRecognitionTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateNoiseReductionTemplate 创建音频降噪模板 +func (s *CIService) CreateNoiseReductionTemplate(ctx context.Context, opt *CreateNoiseReductionTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateNoiseReductionTemplate 更新音频降噪模板 +func (s *CIService) UpdateNoiseReductionTemplate(ctx context.Context, opt *CreateNoiseReductionTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateVideoEnhanceTemplate 创建画质增强模板 +func (s *CIService) CreateVideoEnhanceTemplate(ctx context.Context, opt *CreateVideoEnhanceTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateVideoEnhanceTemplate 更新画质增强模板 +func (s *CIService) UpdateVideoEnhanceTemplate(ctx context.Context, opt *CreateVideoEnhanceTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateVideoTargetRecTemplate 创建移动物体检测模板 +func (s *CIService) CreateVideoTargetRecTemplate(ctx context.Context, opt *CreateVideoTargetRecTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateVideoTargetRecTemplate 更新移动物体检测模板 +func (s *CIService) UpdateVideoTargetRecTemplate(ctx context.Context, opt *CreateVideoTargetRecTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// MediaWorkflow TODO +type MediaWorkflow struct { + Name string `xml:"Name,omitempty"` + WorkflowId string `xml:"WorkflowId,omitempty"` + State string `xml:"State,omitempty"` + Topology *Topology `xml:"Topology,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + BucketId string `xml:"BucketId,omitempty"` +} + +// MarshalXML TODO +func (m *CreateMediaWorkflowOptions) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if m == nil { + return nil + } + type xmlMapEntry struct { + XMLName xml.Name + Type string `xml:"Type"` + Input interface{} `xml:",innerxml"` + Operation interface{} `xml:",innerxml"` + } + tokens := []xml.Token{} + tokens = append(tokens, xml.StartElement{Name: xml.Name{Local: "Request"}}) + tokens = append(tokens, xml.StartElement{Name: xml.Name{Local: "MediaWorkflow"}}) + t := xml.StartElement{Name: xml.Name{Local: "Name"}} + tokens = append(tokens, t, xml.CharData(m.MediaWorkflow.Name), xml.EndElement{Name: t.Name}) + t = xml.StartElement{Name: xml.Name{Local: "State"}} + tokens = append(tokens, t, xml.CharData(m.MediaWorkflow.State), xml.EndElement{Name: t.Name}) + tokens = append(tokens, xml.StartElement{Name: xml.Name{Local: "Topology"}}) + tokens = append(tokens, xml.StartElement{Name: xml.Name{Local: "Dependencies"}}) + + var dependenciesKeys []string + for k := range m.MediaWorkflow.Topology.Dependencies { + dependenciesKeys = append(dependenciesKeys, k) + } + sort.Strings(dependenciesKeys) + for _, k := range dependenciesKeys { + t := xml.StartElement{Name: xml.Name{Local: k}} + tokens = append(tokens, t, xml.CharData(m.MediaWorkflow.Topology.Dependencies[k]), xml.EndElement{Name: t.Name}) + } + tokens = append(tokens, xml.EndElement{Name: xml.Name{Local: "Dependencies"}}) + // Nodes + tokens = append(tokens, xml.StartElement{Name: xml.Name{Local: "Nodes"}}) + for _, t := range tokens { + err := e.EncodeToken(t) + if err != nil { + return err + } + } + tokens = tokens[:0] + var nodesKeys []string + for k := range m.MediaWorkflow.Topology.Nodes { + nodesKeys = append(nodesKeys, k) + } + sort.Strings(nodesKeys) + for _, k := range nodesKeys { + e.Encode(xmlMapEntry{XMLName: xml.Name{Local: k}, Type: m.MediaWorkflow.Topology.Nodes[k].Type, + Input: m.MediaWorkflow.Topology.Nodes[k].Input, Operation: m.MediaWorkflow.Topology.Nodes[k].Operation}) + } + tokens = append(tokens, xml.EndElement{Name: xml.Name{Local: "Nodes"}}) + tokens = append(tokens, xml.EndElement{Name: xml.Name{Local: "Topology"}}) + tokens = append(tokens, xml.EndElement{Name: xml.Name{Local: "MediaWorkflow"}}) + tokens = append(tokens, xml.EndElement{Name: xml.Name{Local: "Request"}}) + for _, t := range tokens { + err := e.EncodeToken(t) + if err != nil { + return err + } + } + return e.Flush() +} + +// UnmarshalXML TODO +func (m *CreateMediaWorkflowOptions) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var v struct { + XMLName xml.Name //`xml:"Topology"` + Dependencies struct { + Inner []byte `xml:",innerxml"` + } `xml:"Dependencies"` + Nodes struct { + Inner []byte `xml:",innerxml"` + } `xml:"Nodes"` + } + err := d.DecodeElement(&v, &start) + if err != nil { + return err + } + + myMap := make(map[string]interface{}) + + // ... do the mxj magic here ... - + + temp := v.Nodes.Inner + + prefix := "" + postfix := "" + str := prefix + string(temp) + postfix + myMxjMap, _ := mxj.NewMapXml([]byte(str)) + myMap, _ = myMxjMap["Nodes"].(map[string]interface{}) + nodesMap := make(map[string]Node) + + for k, v := range myMap { + var node Node + mapstructure.Decode(v, &node) + nodesMap[k] = node + } + + // fill myMap + m.MediaWorkflow.Topology.Nodes = nodesMap + + deps := make(map[string]interface{}) + + tep := "" + string(v.Dependencies.Inner) + "" + tepMxjMap, _ := mxj.NewMapXml([]byte(tep)) + deps, _ = tepMxjMap["Dependencies"].(map[string]interface{}) + depsString := make(map[string]string) + for k, v := range deps { + depsString[k] = v.(string) + } + m.MediaWorkflow.Topology.Dependencies = depsString + return nil +} + +// CreateMediaWorkflowOptions TODO +type CreateMediaWorkflowOptions struct { + XMLName xml.Name `xml:"Request"` + MediaWorkflow *MediaWorkflow `xml:"MediaWorkflow,omitempty"` +} + +// CreateMediaWorkflowResult TODO +type CreateMediaWorkflowResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + MediaWorkflow *MediaWorkflow `xml:"MediaWorkflow,omitempty"` +} + +// CreateMediaWorkflow 创建工作流 +func (s *CIService) CreateMediaWorkflow(ctx context.Context, opt *CreateMediaWorkflowOptions) (*CreateMediaWorkflowResult, *Response, error) { + var res CreateMediaWorkflowResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflow", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaWorkflow TODO +func (s *CIService) UpdateMediaWorkflow(ctx context.Context, opt *CreateMediaWorkflowOptions, workflowId string) (*CreateMediaWorkflowResult, *Response, error) { + var res CreateMediaWorkflowResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflow/" + workflowId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateMediaWorkflow TODO +func (s *CIService) ActiveMediaWorkflow(ctx context.Context, workflowId string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflow/" + workflowId + "?active", + method: http.MethodPut, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// UpdateMediaWorkflow TODO +func (s *CIService) PausedMediaWorkflow(ctx context.Context, workflowId string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflow/" + workflowId + "?paused", + method: http.MethodPut, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// DescribeMediaWorkflowOptions TODO +type DescribeMediaWorkflowOptions struct { + Ids string `url:"ids,omitempty"` + Name string `url:"name,omitempty"` + PageNumber int `url:"pageNumber,omitempty"` + PageSize int `url:"pageSize,omitempty"` +} + +// DescribeMediaWorkflowResult TODO +type DescribeMediaWorkflowResult struct { + XMLName xml.Name `xml:"Response"` + MediaWorkflowList []MediaWorkflow `xml:"MediaWorkflowList,omitempty"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + NonExistIDs []string `xml:"NonExistIDs,omitempty"` +} + +// DescribeMediaWorkflow 搜索工作流 +func (s *CIService) DescribeMediaWorkflow(ctx context.Context, opt *DescribeMediaWorkflowOptions) (*DescribeMediaWorkflowResult, *Response, error) { + var res DescribeMediaWorkflowResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflow", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DeleteMediaWorkflowResult TODO +type DeleteMediaWorkflowResult struct { + RequestId string `xml:"RequestId,omitempty"` + WorkflowId string `xml:"WorkflowId,omitempty"` +} + +// DeleteMediaWorkflow 删除工作流 +func (s *CIService) DeleteMediaWorkflow(ctx context.Context, workflowId string) (*DeleteMediaWorkflowResult, *Response, error) { + var res DeleteMediaWorkflowResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/workflow/" + workflowId, + method: http.MethodDelete, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// InventoryTriggerJobInput TODO +type InventoryTriggerJobInput struct { + Manifest string `xml:"Manifest,omitempty"` + UrlFile string `xml:"UrlFile,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + Object string `xml:"Object,omitempty"` +} + +// InventoryTriggerJobOperationTimeInterval TODO +type InventoryTriggerJobOperationTimeInterval struct { + Start string `xml:"Start,omitempty"` + End string `xml:"End,omitempty"` +} + +// InventoryTriggerJobOperation TODO +type InventoryTriggerJobOperation struct { + WorkflowIds string `xml:"WorkflowIds,omitempty"` + TimeInterval InventoryTriggerJobOperationTimeInterval `xml:"TimeInterval,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + UserData string `xml:"UserData,omitempty"` + JobLevel int `xml:"JobLevel,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + Tag string `xml:"Tag,omitempty"` + JobParam *InventoryTriggerJobOperationJobParam `xml:"JobParam,omitempty"` + Output *JobOutput `xml:"Output,omitempty"` + FreeTranscode string `xml:"FreeTranscode,omitempty"` +} + +// InventoryTriggerJobOperationJobParam TODO +type InventoryTriggerJobOperationJobParam struct { + MediaResult *MediaResult `xml:"MediaResult,omitempty"` + MediaInfo *MediaInfo `xml:"MediaInfo,omitempty"` + Transcode *Transcode `xml:"Transcode,omitempty"` + Watermark []Watermark `xml:"Watermark,omitempty"` + TemplateId string `xml:"TemplateId,omitempty"` + WatermarkTemplateId []string `xml:"WatermarkTemplateId,omitempty"` + ConcatTemplate *ConcatTemplate `xml:"ConcatTemplate,omitempty"` + Snapshot *Snapshot `xml:"Snapshot,omitempty"` + Animation *Animation `xml:"Animation,omitempty"` + Segment *Segment `xml:"Segment,omitempty"` + VideoMontage *VideoMontage `xml:"VideoMontage,omitempty"` + VoiceSeparate *VoiceSeparate `xml:"VoiceSeparate,omitempty"` + VideoProcess *VideoProcess `xml:"VideoProcess,omitempty"` + TranscodeTemplateId string `xml:"TranscodeTemplateId,omitempty"` // 视频增强、超分、SDRtoHDR任务类型,可以选择转码模板相关参数 + SDRtoHDR *SDRtoHDR `xml:"SDRtoHDR,omitempty"` + SuperResolution *SuperResolution `xml:"SuperResolution,omitempty"` + DigitalWatermark *DigitalWatermark `xml:"DigitalWatermark,omitempty"` + ExtractDigitalWatermark *ExtractDigitalWatermark `xml:"ExtractDigitalWatermark,omitempty"` + VideoTag *VideoTag `xml:"VideoTag,omitempty"` + VideoTagResult *VideoTagResult `xml:"VideoTagResult,omitempty"` + SmartCover *NodeSmartCover `xml:"SmartCover,omitempty"` + QualityEstimate *QualityEstimate `xml:"QualityEstimate,omitempty"` + TtsTpl *TtsTpl `xml:"TtsTpl,omitempty"` + TtsConfig *TtsConfig `xml:"TtsConfig,omitempty"` + Translation *Translation `xml:"Translation,omitempty"` + WordsGeneralize *WordsGeneralize `xml:"WordsGeneralize,omitempty"` + WordsGeneralizeResult *WordsGeneralizeResult `xml:"WordsGeneralizeResult,omitempty"` + NoiseReduction *NoiseReduction `xml:"NoiseReduction,omitempty"` + DnaConfig *DnaConfig `xml:"DnaConfig,omitempty"` + DnaResult *DnaResult `xml:"DnaResult,omitempty"` + VocalScore *VocalScore `xml:"VocalScore,omitempty"` + VocalScoreResult *VocalScoreResult `xml:"VocalScoreResult,omitempty"` + ImageInspect *ImageInspect `xml:"ImageInspect,omitempty"` + ImageInspectResult *ImageInspectResult `xml:"ImageInspectResult,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty"` + Detection *ImageOCRDetection `xml:"Detection,omitempty"` +} + +// InventoryTriggerJob TODO +type InventoryTriggerJob struct { + Name string `xml:"Name,omitempty"` + Input *InventoryTriggerJobInput `xml:"Input,omitempty"` + Operation *InventoryTriggerJobOperation `xml:"Operation,omitempty"` +} + +// CreateInventoryTriggerJobOptions TODO +type CreateInventoryTriggerJobOptions struct { + XMLName xml.Name `xml:"Request"` + Name string `xml:"Name,omitempty"` + Type string `xml:"Type,omitempty"` + Input *InventoryTriggerJobInput `xml:"Input,omitempty"` + Operation *InventoryTriggerJobOperation `xml:"Operation,omitempty"` +} + +// InventoryTriggerJobDetail TODO +type InventoryTriggerJobDetail struct { + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + JobId string `xml:"JobId,omitempty"` + Tag string `xml:"Tag,omitempty"` + Progress string `xml:"Progress,omitempty"` + State string `xml:"State,omitempty"` + CreationTime string `xml:"CreationTime,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + Input *InventoryTriggerJobInput `xml:"Input,omitempty"` + Operation *InventoryTriggerJobOperation `xml:"Operation,omitempty"` +} + +// CreateInventoryTriggerJobResult TODO +type CreateInventoryTriggerJobResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + JobsDetail *InventoryTriggerJobDetail `xml:"JobsDetail,omitempty"` +} + +// CreateInventoryTriggerJob TODO +func (s *CIService) CreateInventoryTriggerJob(ctx context.Context, opt *CreateInventoryTriggerJobOptions) (*CreateInventoryTriggerJobResult, *Response, error) { + var res CreateInventoryTriggerJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/inventorytriggerjob", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeInventoryTriggerJobResult TODO +type DescribeInventoryTriggerJobResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + JobsDetail *InventoryTriggerJobDetail `xml:"JobsDetail,omitempty"` + NonExistJobId string `xml:"NonExistJobId,omitempty"` +} + +// DescribeInventoryTriggerJob 查询指定存量触发工作流的任务 +func (s *CIService) DescribeInventoryTriggerJob(ctx context.Context, jobId string) (*DescribeInventoryTriggerJobResult, *Response, error) { + var res DescribeInventoryTriggerJobResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/inventorytriggerjob/" + jobId, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeInventoryTriggerJobsOptions TODO +type DescribeInventoryTriggerJobsOptions struct { + NextToken string `url:"nextToken,omitempty"` + Size string `url:"size,omitempty"` + Type string `url:"type,omitempty"` + OrderByTime string `url:"orderByTime,omitempty"` + States string `url:"states,omitempty"` + StartCreationTime string `url:"startCreationTime,omitempty"` + EndCreationTime string `url:"endCreationTime,omitempty"` + WorkflowId string `url:"workflowId,omitempty"` + JobId string `url:"jobId,omitempty"` + Name string `url:"name,omitempty"` +} + +// DescribeInventoryTriggerJobsResult TODO +type DescribeInventoryTriggerJobsResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + JobsDetail *InventoryTriggerJobDetail `xml:"JobsDetail,omitempty"` + NextToken string `xml:"NextToken,omitempty"` +} + +// DescribeInventoryTriggerJobs 查询存量触发工作流的任务 +func (s *CIService) DescribeInventoryTriggerJobs(ctx context.Context, opt *DescribeInventoryTriggerJobsOptions) (*DescribeInventoryTriggerJobsResult, *Response, error) { + var res DescribeInventoryTriggerJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/inventorytriggerjob", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CancelInventoryTriggerJob TODO +func (s *CIService) CancelInventoryTriggerJob(ctx context.Context, jobId string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/inventorytriggerjob/" + jobId, + method: http.MethodPut, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// CreateImageSearchBucketOptions 开通以图搜图选项 +type CreateImageSearchBucketOptions struct { + XMLName xml.Name `xml:"Request"` + MaxCapacity string `xml:"MaxCapacity,omitempty"` + MaxQps string `xml:"MaxQps,omitempty"` +} + +// CreateImageSearchBucket 开通以图搜图 +func (s *CIService) CreateImageSearchBucket(ctx context.Context, opt *CreateImageSearchBucketOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/ImageSearchBucket", + body: opt, + method: http.MethodPost, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// AddImageOptions 添加图库图片选项 +type AddImageOptions struct { + XMLName xml.Name `xml:"Request"` + EntityId string `xml:"EntityId,omitempty"` + CustomContent string `xml:"CustomContent,omitempty"` + Tags string `xml:"Tags,omitempty"` +} + +// AddImage 添加图库图片 +func (s *CIService) AddImage(ctx context.Context, name string, opt *AddImageOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=ImageSearch&action=AddImage", + body: opt, + method: http.MethodPost, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// ImageSearchOptions 图片搜索接口选项 +type ImageSearchOptions struct { + MatchThreshold int `url:"MatchThreshold,omitempty"` + Offset int `url:"Offset,omitempty"` + Limit int `url:"Limit,omitempty"` + Filter string `url:"Filter,omitempty"` +} + +// ImageSearchResult 图片搜索接口结果 +type ImageSearchResult struct { + XMLName xml.Name `xml:"Response"` + Count int `xml:"Count"` + RequestId string `xml:"RequestId"` + ImageInfos []*struct { + EntityId string `xml:"EntityId"` + CustomContent string `xml:"CustomContent"` + Tags string `xml:"Tags"` + PicName string `xml:"PicName"` + Score int `xml:"Score"` + } `xml:"ImageInfos,omitempty"` +} + +// ImageSearch 图片搜索接口 +func (s *CIService) ImageSearch(ctx context.Context, name string, opt *ImageSearchOptions) (*ImageSearchResult, *Response, error) { + var res ImageSearchResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=ImageSearch&action=SearchImage", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DelImageOptions 删除图库图片选项 +type DelImageOptions struct { + XMLName xml.Name `xml:"Request"` + EntityId string `xml:"EntityId,omitempty"` +} + +// DelImage 删除图库图片 +func (s *CIService) DelImage(ctx context.Context, name string, opt *DelImageOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=ImageSearch&action=DeleteImage", + body: opt, + method: http.MethodPost, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// CreateJobsOptions 提交任务的公用结构体 +type CreateJobsOptions CreateMediaJobsOptions + +// CreateJobsOptions 任务结果的公用结构体 +type CreateJobsResult CreateMediaJobsResult + +// CreateJobsOptions 提交任务的公用方法 +func (s *CIService) CreateJob(ctx context.Context, opt *CreateJobsOptions) (*CreateJobsResult, *Response, error) { + var res CreateJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateJobsOptions 提交任务的公用方法 +func (s *CIService) CancelJob(ctx context.Context, jobId string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs/" + jobId + "?cancel", + method: http.MethodPut, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// DescribeJobsOptions 查询任务的公用选项 +type DescribeJobsOptions DescribeMediaJobsOptions + +// DescribeJobsResult 查询任务结果的公用结构体 +type DescribeJobsResult DescribeMediaJobsResult + +// DescribeJobs 查询任务列表的公用方法 +func (s *CIService) DescribeJobs(ctx context.Context, opt *DescribeJobsOptions) (*DescribeJobsResult, *Response, error) { + var res DescribeJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeJobs 查询指定任务的公用方法 +func (s *CIService) DescribeJob(ctx context.Context, jobid string) (*DescribeJobsResult, *Response, error) { + var res DescribeJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs/" + jobid, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// JobsNotifyBody TODO +type JobsNotifyBody struct { + XMLName xml.Name `xml:"Response"` + EventName string `xml:"EventName"` + JobsDetail []MediaProcessJobDetail `xml:"JobsDetail,omitempty"` +} + +// ModifyM3U8TokenOptions TODO +type ModifyM3U8TokenOptions struct { + Token string `url:"token"` +} + +// ModifyM3U8Token TODO +func (s *CIService) ModifyM3U8Token(ctx context.Context, name string, opt *ModifyM3U8TokenOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&ci-process=modifym3u8token", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?ci-process=modifym3u8token", encodeURIComponent(name)) + } else { + return nil, fmt.Errorf("wrong params") + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// DescribeJobsOptions 查询模板的公用选项 +type DescribeTemplateOptions DescribeMediaTemplateOptions + +// DescribeJobsResult 查询模板结果的公用结构体 +type DescribeTemplateResult DescribeMediaTemplateResult + +// DescribeTemplate 搜索模板的公用方法 +func (s *CIService) DescribeTemplate(ctx context.Context, opt *DescribeTemplateOptions) (*DescribeTemplateResult, *Response, error) { + var res DescribeTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeJobsResult 删除模板结果的公用结构体 +type DeleteTemplateResult DeleteMediaTemplateResult + +// DeleteTemplate 删除模板的公用方法 +func (s *CIService) DeleteTemplate(ctx context.Context, tempalteId string) (*DeleteTemplateResult, *Response, error) { + var res DeleteTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + tempalteId, + method: http.MethodDelete, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// FillConcat 填充拼接 +type FillConcat struct { + Format string `xml:"Format,omitempty"` + FillInput []FillConcatInput `xml:"FillInput,omitempty"` + RefMode string `xml:"RefMode,omitempty"` + RefIndex string `xml:"RefIndex,omitempty"` +} + +// FillConcatInput 填充拼接输入 +type FillConcatInput struct { + Url string `xml:"Url,omitempty"` + FillTime string `xml:"FillTime,omitempty"` +} + +// VideoSynthesis 视频合成 +type VideoSynthesis struct { + KeepAudioTrack string `xml:"KeepAudioTrack,omitempty"` + SpliceInfo []VideoSynthesisSpliceInfo `xml:"SpliceInfo,omitempty"` +} + +// VideoSynthesisSpliceInfo 视频合成输入 +type VideoSynthesisSpliceInfo struct { + Url string `xml:"Url,omitempty"` + X string `xml:"X,omitempty"` + Y string `xml:"Y,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` +} + +// DnaConfig DNA任务配置 +type DnaConfig struct { + RuleType string `xml:"RuleType,omitempty"` + DnaDbId string `xml:"DnaDbId,omitempty"` + VideoId string `xml:"VideoId,omitempty"` +} + +// DnaResult DNA任务结果 +type DnaResult struct { + VideoId string `xml:"VideoId,omitempty"` + Duration int `xml:"Duration,omitempty"` + Detection *DnaResultDetection `xml:"Detection,omitempty"` +} + +// DnaResultDetection DNA任务结果 +type DnaResultDetection struct { + VideoId string `xml:"VideoId,omitempty"` + Similar int `xml:"Similar,omitempty"` + SimilarDuration int `xml:"SimilarDuration,omitempty"` + Duration int `xml:"Duration,omitempty"` + MatchDetail []DnaResultMatchDetail `xml:"MatchDetail,omitempty"` + Audio DnaResultAudio `xml:"Audio,omitempty"` +} + +// DnaResultMatchDetail DNA任务结果 +type DnaResultMatchDetail struct { + MatchStartTime int `xml:"MatchStartTime,omitempty"` + MatchEndTime int `xml:"MatchEndTime,omitempty"` + SrcStartTime int `xml:"SrcStartTime,omitempty"` + SrcEndTime int `xml:"SrcEndTime,omitempty"` +} + +// DnaResultAudio DNA任务结果 +type DnaResultAudio struct { + Similar int `xml:"Similar,omitempty"` +} + +// GetDnaDbOptions 查询 DNA 库列表参数 +type GetDnaDbOptions struct { + Ids string `url:"ids,omitempty"` + PageNumber string `url:"pageNumber,omitempty"` + PageSize string `url:"pageSize,omitempty"` +} + +// GetDnaDbResult 查询 DNA 库列表结果 +type GetDnaDbResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + DNADbConfig []DNADbConfig `xml:"DNADbConfig,omitempty"` + NonExistIDs []string `xml:"NonExistIDs,omitempty"` +} + +// DNADbConfig DNA 库详情 +type DNADbConfig struct { + BucketId string `xml:"BucketId,omitempty"` + Region string `xml:"Region,omitempty"` + DNADbId string `xml:"DNADbId,omitempty"` + DNADbName string `xml:"DNADbName,omitempty"` + Capacity int `xml:"Capacity,omitempty"` + Description string `xml:"Description,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` +} + +// GetDnaDb 查询 DNA 库列表 +func (s *CIService) GetDnaDb(ctx context.Context, opt *GetDnaDbOptions) (*GetDnaDbResult, *Response, error) { + var res GetDnaDbResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/dnadb", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetDnaDbFilesOptions 获取 DNA 库中文件列表参数 +type GetDnaDbFilesOptions struct { + object string `url:"object,omitempty"` + DnaDbId string `url:"dnaDbId,omitempty"` + PageNumber string `url:"pageNumber,omitempty"` + PageSize string `url:"pageSize,omitempty"` +} + +// GetDnaDbFilesResult 查询 DNA 库列表结果 +type GetDnaDbFilesResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + DNADbFiles []DNADbFiles `xml:"DNADbFiles,omitempty"` +} + +// DNADbFiles DNA 文件详情 +type DNADbFiles struct { + BucketId string `xml:"BucketId,omitempty"` + Region string `xml:"Region,omitempty"` + DNADbId string `xml:"DNADbId,omitempty"` + VideoId string `xml:"VideoId,omitempty"` + Object int `xml:"Object,omitempty"` + ETag string `xml:"ETag,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` +} + +// GetDnaDbFiles 查询 DNA 库列表 +func (s *CIService) GetDnaDbFiles(ctx context.Context, opt *GetDnaDbFilesOptions) (*GetDnaDbFilesResult, *Response, error) { + var res GetDnaDbFilesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/dnadb_files", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// VocalScore 音乐评分 +type VocalScore struct { + StandardObject string `xml:"StandardObject,omitempty"` +} + +// VocalScoreResult 音乐评分结果 +type VocalScoreResult struct { + PitchScore *VocalScoreResultPitchScore `xml:"PitchScore,omitempty"` + RhythemScore *VocalScoreResultRhythemScore `xml:"RhythemScore,omitempty"` +} + +// VocalScoreResultPitchScore 音高评分 +type VocalScoreResultPitchScore struct { + TotalScore float64 `xml:"TotalScore,omitempty"` + SentenceScores []VocalScoreResultSentenceScores `xml:"SentenceScores,omitempty"` +} + +// VocalScoreResultRhythemScore 节奏评分 +type VocalScoreResultSentenceScores struct { + StartTime float64 `xml:"StartTime,omitempty"` + EndTime float64 `xml:"EndTime,omitempty"` + Score float64 `xml:"Score,omitempty"` +} + +type VocalScoreResultRhythemScore struct { + TotalScore float64 `xml:"TotalScore,omitempty"` + SentenceScores []VocalScoreResultSentenceScores `xml:"SentenceScores,omitempty"` +} + +// ImageInspect 黑产检测 +type ImageInspect struct { + AutoProcess string `xml:"AutoProcess,omitempty"` + ProcessType string `xml:"ProcessType,omitempty"` +} + +// ImageInspectResult 黑产检测结果 +type ImageInspectResult struct { + State string `xml:"State,omitempty"` + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + InputObjectName string `xml:"InputObjectName,omitempty"` + InputObjectUrl string `xml:"InputObjectUrl,omitempty"` + ProcessResult *ImageInspectProcessResult `xml:"ProcessResult,omitempty"` +} + +// ImageInspectProcessResult 黑产检测结果 +type ImageInspectProcessResult struct { + PicSize int `xml:"PicSize,omitempty"` + PicType string `xml:"PicType,omitempty"` + Suspicious string `xml:"Suspicious,omitempty"` + SuspiciousBeginByte int `xml:"SuspiciousBeginByte,omitempty"` + SuspiciousEndByte int `xml:"SuspiciousEndByte,omitempty"` + SuspiciousSize int `xml:"SuspiciousSize,omitempty"` + SuspiciousType string `xml:"SuspiciousType,omitempty"` + AutoProcessResult *ImageInspectAutoProcessResult `xml:"AutoProcessResult,omitempty"` +} + +// ImageInspectAutoProcessResult 黑产检测结果 +type ImageInspectAutoProcessResult struct { + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` +} + +type CosImageInspectOptions struct { +} + +// CosImageInspectProcessResult 黑产检测同步接口结果 +type CosImageInspectProcessResult struct { + PicSize int `json:"picSize,omitempty"` + PicType string `json:"picType,omitempty"` + Suspicious bool `json:"suspicious,omitempty"` + SuspiciousBeginByte int `json:"suspiciousBeginByte,omitempty"` + SuspiciousEndByte int `json:"suspiciousEndByte,omitempty"` + SuspiciousSize int `json:"suspiciousSize,omitempty"` + SuspiciousType string `json:"suspiciousType,omitempty"` +} + +// Write 回包是json格式序列化 +func (w *CosImageInspectProcessResult) Write(p []byte) (n int, err error) { + err = json.Unmarshal(p, w) + if err != nil { + return 0, err + } + return len(p), nil +} + +// CosImageInspect 黑产检查同步接口 +// 参数: +// +// ctx: 上下文对象 +// name: 图片名称 +// opt: 选项对象 +// +// 返回值: +// +// *CosImageInspectProcessResult: 图片检查结果 +// *Response: HTTP响应对象 +// error: 错误信息 +func (s *CIService) CosImageInspect(ctx context.Context, name string, opt *CosImageInspectOptions) (*CosImageInspectProcessResult, *Response, error) { + var res CosImageInspectProcessResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=ImageInspect", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateOCRTemplateOptions TODO +type CreateOCRTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty" json:"ImageOCR,omitempty"` +} + +// ImageOCRTemplate TODO +type ImageOCRTemplate struct { + Type string `xml:"Type,omitempty"` + LanguageType string `xml:"LanguageType,omitempty"` + IsPdf string `xml:"IsPdf,omitempty"` + PdfPageNumber string `xml:"PdfPageNumber,omitempty"` + IsWord string `xml:"IsWord,omitempty"` + EnableWordPolygon string `xml:"EnableWordPolygon,omitempty"` +} + +// CreateOCRTemplate 创建OCR模板 +func (s *CIService) CreateOCRTemplate(ctx context.Context, opt *CreateOCRTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateOCRTemplate 更新OCR模板 +func (s *CIService) UpdateOCRTemplate(ctx context.Context, opt *CreateOCRTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// ImageOCRDetection TODO +type ImageOCRDetection struct { + InputObjectName string `xml:"InputObjectName,omitempty"` + InputObjectUrl string `xml:"InputObjectUrl,omitempty"` + ObjectName string `xml:"ObjectName,omitempty"` + ObjectUrl string `xml:"ObjectUrl,omitempty"` + Code string `xml:"Code,omitempty"` + State string `xml:"State,omitempty"` + Message string `xml:"Message,omitempty"` + TextDetections []ImageOCRTextDetections `xml:"TextDetections,omitempty"` + Language string `xml:"Language,omitempty"` + Angel string `xml:"Angel,omitempty"` + PdfPageSize int `xml:"PdfPageSize,omitempty"` +} + +// ImageOCRTextDetections TODO +type ImageOCRTextDetections struct { + DetectedText string `xml:"DetectedText,omitempty"` + Confidence int `xml:"Confidence,omitempty"` + Polygon []ImageOCRTextPolygon `xml:"Polygon,omitempty"` + ItemPolygon []ImageOCRTextItemPolygon `xml:"ItemPolygon,omitempty"` + Words []ImageOCRTextWords `xml:"Words,omitempty"` + WordPolygon []ImageOCRTextWordPolygon `xml:"WordPolygon,omitempty"` +} + +// ImageOCRTextPolygon TODO +type ImageOCRTextPolygon struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` +} + +// ImageOCRTextItemPolygon TODO +type ImageOCRTextItemPolygon struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` +} + +// ImageOCRTextWords TODO +type ImageOCRTextWords struct { + Confidence int `xml:"Confidence,omitempty"` + Character string `xml:"Character,omitempty"` + WordCoordPoint []struct { + WordCoordinate []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"WordCoordinate,omitempty"` + } `xml:"WordCoordPoint,omitempty"` +} + +// ImageOCRTextWordPolygon TODO +type ImageOCRTextWordPolygon struct { + LeftTop []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"LeftTop,omitempty"` + RightTop []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"RightTop,omitempty"` + LeftBottom []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"LeftBottom,omitempty"` + RightBottom []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"RightBottom,omitempty"` +} + +type LiveTanscodeVideo struct { + Codec string `xml:"Codec"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Fps string `xml:"Fps,omitempty"` + Profile string `xml:"Profile,omitempty"` + Bitrate string `xml:"Bitrate,omitempty"` + Gop string `xml:"Gop,omitempty"` + Maxrate string `xml:"Maxrate,omitempty"` + Crf string `xml:"Crf,omitempty"` + Pixfmt string `xml:"Pixfmt,omitempty"` + LongShortMode string `xml:"LongShortMode,omitempty"` + Interlaced string `xml:"Interlaced,omitempty"` + ColorParam *VideoColorParam `xml:"ColorParam,omitempty"` +} + +type LiveTanscodeTransConfig struct { + InitialClipNum string `xml:"InitialClipNum,omitempty"` + CosTag string `xml:"CosTag,omitempty"` + HlsEncrypt *HlsEncrypt `xml:"HlsEncrypt,omitempty"` +} + +type LiveTanscode struct { + Container *Container `xml:"Container,omitempty"` + Video *LiveTanscodeVideo `xml:"Video,omitempty"` + // TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` + // Audio *Audio `xml:"Audio,omitempty"` + TransConfig *LiveTanscodeTransConfig `xml:"TransConfig,omitempty"` +} + +type GeneratePlayListJobOperation struct { + Tag string `xml:"Tag,omitempty"` + Output *JobOutput `xml:"Output,omitempty"` + MediaResult *MediaResult `xml:"MediaResult,omitempty"` + MediaInfo *MediaInfo `xml:"MediaInfo,omitempty"` + Transcode *LiveTanscode `xml:"Transcode,omitempty"` + UserData string `xml:"UserData,omitempty"` + JobLevel int `xml:"JobLevel,omitempty"` + Watermark []Watermark `xml:"Watermark,omitempty"` + WatermarkTemplateId []string `xml:"WatermarkTemplateId,omitempty"` +} + +type CreateGeneratePlayListJobOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *GeneratePlayListJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +func (s *CIService) CreateGeneratePlayListJob(ctx context.Context, opt *CreateGeneratePlayListJobOptions) (*CreateJobsResult, *Response, error) { + var res CreateJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMultiGeneratePlayListJobsOptions TODO +type CreateMultiGeneratePlayListJobsOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation []GeneratePlayListJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +// CreateMultiGeneratePlayListJobs TODO +func (s *CIService) CreateMultiGeneratePlayListJobs(ctx context.Context, opt *CreateMultiGeneratePlayListJobsOptions) (*CreateMultiMediaJobsResult, *Response, error) { + var res CreateMultiMediaJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type VocabularyWeight struct { + Vocabulary string `xml:"Vocabulary,omitempty"` + Weight int `xml:"Weight,omitempty"` +} + +// CreateAsrVocabularyTableOptions TODO +type CreateAsrVocabularyTableOptions struct { + XMLName xml.Name `xml:"Request"` + TableName string `xml:"TableName,omitempty"` + TableDescription string `xml:"TableDescription,omitempty"` + VocabularyWeights []VocabularyWeight `xml:"VocabularyWeights,omitempty"` + VocabularyWeightStr string `xml:"VocabularyWeightStr,omitempty"` +} + +// CreateAsrVocabularyTableResult TODO +type CreateAsrVocabularyTableResult struct { + XMLName xml.Name `xml:"Response"` + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + TableId string `xml:"TableId,omitempty"` + RequestId string `xml:"RequestId,omitempty"` +} + +func (s *CIService) CreateAsrVocabularyTable(ctx context.Context, opt *CreateAsrVocabularyTableOptions) (*CreateAsrVocabularyTableResult, *Response, error) { + var res CreateAsrVocabularyTableResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrhotvocabtable", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DeleteAsrVocabularyTable TODO +func (s *CIService) DeleteAsrVocabularyTable(ctx context.Context, tableId string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrhotvocabtable/" + tableId, + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// UpdateAsrVocabularyTableOptions TODO +type UpdateAsrVocabularyTableOptions struct { + XMLName xml.Name `xml:"Request"` + TableId string `xml:"TableId,omitempty"` + TableName string `xml:"TableName,omitempty"` + TableDescription string `xml:"TableDescription,omitempty"` + VocabularyWeights []VocabularyWeight `xml:"VocabularyWeights,omitempty"` + VocabularyWeightStr string `xml:"VocabularyWeightStr,omitempty"` +} + +type UpdateAsrVocabularyTableResult CreateAsrVocabularyTableResult + +// UpdateAsrVocabularyTable TODO +func (s *CIService) UpdateAsrVocabularyTable(ctx context.Context, opt *UpdateAsrVocabularyTableOptions) (*UpdateAsrVocabularyTableResult, *Response, error) { + var res UpdateAsrVocabularyTableResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrhotvocabtable", + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type VocabularyTable struct { + TableId string `xml:"TableId,omitempty"` + TableName string `xml:"TableName,omitempty"` + TableDescription string `xml:"TableDescription,omitempty"` + VocabularyWeights []VocabularyWeight `xml:"VocabularyWeights,omitempty"` + VocabularyWeightStr string `xml:"VocabularyWeightStr,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` +} + +// DescribeAsrVocabularyTableResult TODO +type DescribeAsrVocabularyTableResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TableId string `xml:"TableId,omitempty"` + TableName string `xml:"TableName,omitempty"` + TableDescription string `xml:"TableDescription,omitempty"` + VocabularyWeights []VocabularyWeight `xml:"VocabularyWeights,omitempty"` + VocabularyWeightStr string `xml:"VocabularyWeightStr,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` +} + +// DescribeAsrVocabularyTable 查询指定的语音识别热词表 +func (s *CIService) DescribeAsrVocabularyTable(ctx context.Context, tableId string) (*DescribeAsrVocabularyTableResult, *Response, error) { + var res DescribeAsrVocabularyTableResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrhotvocabtable/" + tableId, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// DescribeAsrVocabularyTablesOptions TODO +type DescribeAsrVocabularyTablesOptions struct { + Offset int `url:"offset,omitempty"` + Limit int `url:"limit,omitempty"` +} + +type DescribeAsrVocabularyTablesResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount string `xml:"TotalCount,omitempty"` + VocabularyTable []VocabularyTable `xml:"VocabularyTable,omitempty"` +} + +// DescribeAsrVocabularyTables 查询语音识别热词表列表 +func (s *CIService) DescribeAsrVocabularyTables(ctx context.Context, opt *DescribeAsrVocabularyTablesOptions) (*DescribeAsrVocabularyTablesResult, *Response, error) { + var res DescribeAsrVocabularyTablesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/asrhotvocabtable", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go new file mode 100644 index 00000000000..15d6b22504f --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go @@ -0,0 +1,616 @@ +package cos + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "strings" +) + +type MetaInsightService service + +// OptHeaders 请求头 +type OptHeaders struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" json:"-" xml:"-"` +} + +func (s *MetaInsightService) baseSend(ctx context.Context, opt interface{}, optionHeader *OptHeaders, uri string, method string) (*bytes.Buffer, *Response, error) { + var buf bytes.Buffer + var f *strings.Reader + var sendOpt *sendOptions + if optionHeader == nil { + optionHeader = &OptHeaders{ + XOptionHeader: &http.Header{}, + } + } + optionHeader.XOptionHeader.Add("Content-Type", "application/json") + optionHeader.XOptionHeader.Add("Accept", "application/json") + if method == http.MethodGet { + sendOpt = &sendOptions{ + baseURL: s.client.BaseURL.MetaInsightURL, + uri: uri, + method: method, + optHeader: optionHeader, + optQuery: opt, + result: &buf, + } + } else { + if opt != nil { + bs, err := json.Marshal(opt) + if err != nil { + return nil, nil, err + } + f = strings.NewReader(string(bs)) + } + sendOpt = &sendOptions{ + baseURL: s.client.BaseURL.MetaInsightURL, + uri: uri, + method: method, + body: f, + optHeader: optionHeader, + result: &buf, + } + } + resp, err := s.client.send(ctx, sendOpt) + return &buf, resp, err +} + +type CreateDatasetOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。命名规则如下: 长度为1~32字符。 只能包含小写英文字母,数字,短划线(-)。 必须以英文字母和数字开头。 + Description string `json:"Description, omitempty" url:"-" ` // 数据集描述信息。长度为1~256个英文或中文字符,默认值为空。 + TemplateId string `json:"TemplateId, omitempty" url:"-" ` // 指模板,在建立元数据索引时,后端将根据模板来决定收集哪些元数据。每个模板都包含一个或多个算子,不同的算子表示不同的元数据。目前支持的模板: Official:DefaultEmptyId:默认为空的模板,表示不进行元数据的采集。 Official:COSBasicMeta:基础信息模板,包含 COS 文件基础元信息算子,表示采集 COS 文件的名称、类型、ACL等基础元信息数据。 Official:FaceSearch:人脸检索模板,包含人脸检索、COS 文件基础元信息算子。Official:ImageSearch:图像检索模板,包含图像检索、COS 文件基础元信息算子。 + Version string `json:"Version, omitempty" url:"-" ` // 数据集版本。basic、standard,默认为basic。 + Volume int `json:"Volume, omitempty" url:"-" ` // Version为basic时为50w。Version为standard时,默认为500w,可设置1-10000,单位w。传0采用默认值。 + TrainingMode int `json:"TrainingMode, omitempty" url:"-" ` // 训练数据的来源模式。默认为0,表示训练数据来源于指定数据集,值为1时表示训练数据来源于cos某个bucket目录下文件。仅在Version为standard时生效。 + TrainingDataset string `json:"TrainingDataset, omitempty" url:"-" ` // 训练数据的数据集名称。仅在TrainingMode为0时生效。 + TrainingURI string `json:"TrainingURI, omitempty" url:"-" ` // 训练数据的资源路径。仅在TrainingMode为1时生效。 + SceneType string `json:"SceneType, omitempty" url:"-" ` // 场景类型。支持general、E-commercial、iDrive,默认为general。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type CreateDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +type Dataset struct { + TemplateId string `json:"TemplateId"` // 模板ID。 + Description string `json:"Description"` // 数据集描述信息 + CreateTime string `json:"CreateTime"` // 数据集创建时间的时间戳,格式为RFC3339Nano + UpdateTime string `json:"UpdateTime"` // 数据集修改时间的时间戳,格式为RFC3339Nano创建数据集后,如果未更新过数据集,则数据集修改时间的时间戳和数据集创建时间的时间戳相同 + BindCount int `json:"BindCount"` // 数据集当前绑定的COS Bucket数量 + FileCount int `json:"FileCount"` // 数据集当前文件数量 + TotalFileSize int `json:"TotalFileSize"` // 数据集中当前文件总大小,单位为字节 + DatasetName string `json:"DatasetName"` // 数据集名称 +} + +// CreateDataset 创建数据集 +// https://cloud.tencent.com/document/product/460/106020 +func (s *MetaInsightService) CreateDataset(ctx context.Context, opt *CreateDatasetOptions) (*CreateDatasetResult, *Response, error) { + var res CreateDatasetResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetsOptions struct { + Maxresults int `url:"maxresults, omitempty" json:"-"` // 本次返回数据集的最大个数,取值范围为0~200。不设置此参数或者设置为0时,则默认值为100。 + Nexttoken string `url:"nexttoken, omitempty" json:"-"` // 翻页标记。当文件总数大于设置的MaxResults时,用于翻页的Token。从NextToken开始按字典序返回文件信息列表。填写上次查询返回的值,首次使用时填写为空。 + Prefix string `url:"prefix, omitempty" json:"-"` // 数据集名称前缀。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetsResult struct { + RequestId string `json:"RequestId"` // 请求ID + Datasets []*Dataset `json:"Datasets"` // 数据集信息 + NextToken string `json:"NextToken"` // 翻页标记。当任务列表总数大于设置的MaxResults时,用于翻页的Token。符合条件的任务列表未全部返回时,此参数才有值。下一次列出任务列表时将此值作为NextToken传入,将后续的任务列表返回。 +} + +// DescribeDatasets 列出数据集 +// https://cloud.tencent.com/document/product/460/106158 +func (s *MetaInsightService) DescribeDatasets(ctx context.Context, opt *DescribeDatasetsOptions) (*DescribeDatasetsResult, *Response, error) { + var res DescribeDatasetsResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasets", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type UpdateDatasetOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Description string `json:"Description, omitempty" url:"-" ` // 数据集描述信息。长度为1~256个英文或中文字符,默认值为空。 + TemplateId string `json:"TemplateId, omitempty" url:"-" ` // 该参数表示模板,在建立元数据索引时,后端将根据模板来决定收集哪些元数据。每个模板都包含一个或多个算子,不同的算子表示不同的元数据。目前支持的模板: Official:Empty:默认为空的模板,表示不进行元数据的采集。 Official:COSBasicMeta:基础信息模板,包含COS文件基础元信息算子,表示采集cos文件的名称、类型、acl等基础元信息数据。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type UpdateDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +// UpdateDataset 更新数据集 +// https://cloud.tencent.com/document/product/460/106156 +func (s *MetaInsightService) UpdateDataset(ctx context.Context, opt *UpdateDatasetOptions) (*UpdateDatasetResult, *Response, error) { + var res UpdateDatasetResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodPut) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DeleteDatasetOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DeleteDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +// DeleteDataset 删除数据集 +// https://cloud.tencent.com/document/product/460/106157 +func (s *MetaInsightService) DeleteDataset(ctx context.Context, opt *DeleteDatasetOptions) (*DeleteDatasetResult, *Response, error) { + var res DeleteDatasetResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodDelete) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Statistics bool `url:"statistics, omitempty" json:"-"` // 是否需要实时统计数据集中文件相关信息。有效值: false:不统计,返回的文件的总大小、数量信息可能不正确也可能都为0。 true:需要统计,返回数据集中当前的文件的总大小、数量信息。 默认值为false。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +// DescribeDataset 查询数据集 +// https://cloud.tencent.com/document/product/460/106155 +func (s *MetaInsightService) DescribeDataset(ctx context.Context, opt *DescribeDatasetOptions) (*DescribeDatasetResult, *Response, error) { + var res DescribeDatasetResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type CreateFileMetaIndexOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + File *File `json:"File, omitempty" url:"-" ` // 用于建立索引的文件信息。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type File struct { + CustomId string `json:"CustomId, omitempty" url:"-" ` // 自定义ID。该文件索引到数据集后,作为该行元数据的属性存储,用于和您的业务系统进行关联、对应。您可以根据业务需求传入该值,例如将某个URI关联到您系统内的某个ID。推荐传入全局唯一的值。在查询时,该字段支持前缀查询和排序,详情请见字段和操作符的支持列表。 + CustomLabels *map[string]string `json:"CustomLabels, omitempty" url:"-" ` // 自定义标签。您可以根据业务需要自定义添加标签键值对信息,用于在查询时可以据此为筛选项进行检索,详情请见字段和操作符的支持列表。 + Key string `json:"Key, omitempty" url:"-" ` // 自定义标签键 + Value string `json:"Value, omitempty" url:"-" ` // 自定义标签值 + MediaType string `json:"MediaType, omitempty" url:"-" ` // 可选项,文件媒体类型,枚举值: image:图片。 other:其他。 document:文档。 archive:压缩包。 video:视频。 audio:音频。 + ContentType string `json:"ContentType, omitempty" url:"-" ` // 可选项,文件内容类型(MIME Type),如image/jpeg。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址,当前仅支持COS上的文件,字段规则:cos:///,其中BucketName表示COS存储桶名称,ObjectKey表示文件完整路径,例如:cos://examplebucket-1250000000/test1/img.jpg。 注意: 1、仅支持本账号内的COS文件 2、不支持HTTP开头的地址 + MaxFaceNum int `json:"MaxFaceNum, omitempty" url:"-" ` // 输入图片中检索的人脸数量,默认值为20,最大值为20。(仅当数据集模板 ID 为 Official:FaceSearch 有效)。 + Persons []*Persons `json:"Persons, omitempty" url:"-" ` // 自定义人物属性(仅当数据集模板 ID 为 Official:FaceSearch 有效)。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type Persons struct { + PersonId string `json:"PersonId, omitempty" url:"-" ` // 自定义人物 ID。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type CreateFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID + EventId string `json:"EventId"` // 创建元数据索引的任务ID +} + +// CreateFileMetaIndex 创建元数据索引 +// https://cloud.tencent.com/document/product/460/106022 +func (s *MetaInsightService) CreateFileMetaIndex(ctx context.Context, opt *CreateFileMetaIndexOptions) (*CreateFileMetaIndexResult, *Response, error) { + var res CreateFileMetaIndexResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type UpdateFileMetaIndexOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Callback string `json:"Callback, omitempty" url:"-" ` // 元数据索引结果(以回调形式发送至您的回调地址,支持以 http:// 或者 https:// 开头的地址,例如: http://www.callback.com + File *File `json:"File, omitempty" url:"-" ` // 用于建立索引的文件信息。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type UpdateFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID + EventId string `json:"EventId"` // 创建元数据索引的任务ID +} + +// UpdateFileMetaIndex 更新元数据索引 +// https://cloud.tencent.com/document/product/460/106162 +func (s *MetaInsightService) UpdateFileMetaIndex(ctx context.Context, opt *UpdateFileMetaIndexOptions) (*UpdateFileMetaIndexResult, *Response, error) { + var res UpdateFileMetaIndexResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodPut) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeFileMetaIndexOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Uri string `url:"uri, omitempty" json:"-"` // 资源标识字段,表示需要建立索引的文件地址,当前仅支持COS上的文件,字段规则:cos:///,其中BucketName表示COS存储桶名称,ObjectKey表示文件完整路径,例如:cos://examplebucket-1250000000/test1/img.jpg。 注意: 1、仅支持本账号内的COS文件 2、不支持HTTP开头的地址 3、需UrlEncode + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID。 + Files []*FilesDetail `json:"Files"` // 文件元数据的结构体。实际返回的数据可能并不包含该结构体的所有属性,这和您索引该文件时选用的工作流模板配置以及文件本身的内容有关。 +} + +type FilesDetail struct { + CreateTime string `json:"CreateTime"` // 元数据创建时间的时间戳,格式为RFC3339Nano + UpdateTime string `json:"UpdateTime"` // 元数据修改时间的时间戳,格式为RFC3339Nano创建元数据后,如果未更新过元数据,则元数据修改时间的时间戳和元数据创建时间的时间戳相同 + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址 + Filename string `json:"Filename"` // 文件路径 + MediaType string `json:"MediaType"` // 文件媒体类型。 枚举值:image:图片。other:其他。document:文档。archive:压缩包。audio:音频。video:视频。 + ContentType string `json:"ContentType"` // 文件内容类型(MIME Type)。 + COSStorageClass string `json:"COSStorageClass"` // 文件存储空间类型。 + COSCRC64 string `json:"COSCRC64"` // 文件CRC64值。 + ObjectACL string `json:"ObjectACL"` // 对象ACL。 + Size int `json:"Size"` // 文件大小,单位为字节。 + CacheControl string `json:"CacheControl"` // 指定Object被下载时网页的缓存行为。 + ETag string `json:"ETag"` // Object生成时会创建相应的ETag ,ETag用于标识一个Object的内容。 + FileModifiedTime string `json:"FileModifiedTime"` // 文件最近一次修改时间的时间戳, 格式为RFC3339Nano。 + CustomId string `json:" CustomId"` // 该文件的自定义ID。该文件索引到数据集后,作为该行元数据的属性存储,用于和您的业务系统进行关联、对应。您可以根据业务需求传入该值,例如将某个URI关联到您系统内的某个ID。推荐传入全局唯一的值。 + CustomLabels *map[string]string `json:"CustomLabels"` // 文件自定义标签列表。储存您业务自定义的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 +} + +// DescribeFileMetaIndex 查询元数据索引 +// https://cloud.tencent.com/document/product/460/106164 +func (s *MetaInsightService) DescribeFileMetaIndex(ctx context.Context, opt *DescribeFileMetaIndexOptions) (*DescribeFileMetaIndexResult, *Response, error) { + var res DescribeFileMetaIndexResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DeleteFileMetaIndexOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DeleteFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID +} + +// DeleteFileMetaIndex 删除元数据索引 +// https://cloud.tencent.com/document/product/460/106163 +func (s *MetaInsightService) DeleteFileMetaIndex(ctx context.Context, opt *DeleteFileMetaIndexOptions) (*DeleteFileMetaIndexResult, *Response, error) { + var res DeleteFileMetaIndexResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodDelete) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type CreateDatasetBindingOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶的资源,字段规则:cos:///,其中BucketName表示COS存储桶名称,Path表示资源路径,例如:cos://examplebucket-1250000000/test/。 + Mode int `json:"Mode", omitempty" url:"-" ` // 建立绑定后,以何种方式进行文件索引特征的提取,有效值:0,表示仅对增量文件建立索引;1,表示在对增量文件建立索引的同时,也会对存储桶中存量文件建立索引,存量文件索引建立的时长与存量文件数有关;默认值为0。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type CreateDatasetBindingResult struct { + RequestId string `json:"RequestId"` // 请求ID + Binding *Binding `json:"Binding"` // 绑定信息 +} + +type Binding struct { + URI string `json:"URI"` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶,字段规则:cos://,其中BucketName表示COS存储桶名称,例如:cos://examplebucket-1250000000 + State string `json:"State"` // 数据集和 COS Bucket绑定关系的状态。取值范围如下:Running:绑定关系运行中。 + StockState string `json:"StockState"` // 当前绑定的存储桶对应的存量索引的状态:有效值:NoIndexing(未进行存量建立索引)、Indexing(存量索引建立中)、Success(存量索引已建立完成)。 + CreateTime string `json:"CreateTime"` // 数据集和 COS Bucket绑定关系创建时间的时间戳,格式为RFC3339Nano。 + UpdateTime string `json:"UpdateTime"` // 数据集和 COS Bucket的绑定关系修改时间的时间戳,格式为RFC3339Nano。创建绑定关系后,如果未暂停或者未重启过绑定关系,则绑定关系修改时间的时间戳和绑定关系创建时间的时间戳相同。 + DatasetName string `json:"DatasetName"` // 数据集名称。 + Detail string `json:"Detail"` // 详情 +} + +// CreateDatasetBinding 绑定存储桶与数据集 +// https://cloud.tencent.com/document/product/460/106159 +func (s *MetaInsightService) CreateDatasetBinding(ctx context.Context, opt *CreateDatasetBindingOptions) (*CreateDatasetBindingResult, *Response, error) { + var res CreateDatasetBindingResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbinding", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetBindingOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Uri string `url:"uri, omitempty" json:"-"` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶,字段规则:cos://,其中BucketName表示COS存储桶名称,例如(需要进行urlencode):cos%3A%2F%2Fexample-125000 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetBindingResult struct { + RequestId string `json:"RequestId"` // 请求ID + Binding *Binding `json:"Binding"` // 数据集和 COS Bucket 绑定关系信息的列表。 +} + +// DescribeDatasetBinding 查询数据集与存储桶的绑定关系 +// https://cloud.tencent.com/document/product/460/106485 +func (s *MetaInsightService) DescribeDatasetBinding(ctx context.Context, opt *DescribeDatasetBindingOptions) (*DescribeDatasetBindingResult, *Response, error) { + var res DescribeDatasetBindingResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbinding", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetBindingsOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Maxresults int `url:"maxresults, omitempty" json:"-"` // 返回绑定关系的最大个数,取值范围为0~200。不设置此参数或者设置为0时,则默认值为100。 + Nexttoken string `url:"nexttoken, omitempty" json:"-"` // 当绑定关系总数大于设置的MaxResults时,用于翻页的token。从NextToken开始按字典序返回绑定关系信息列表。第一次调用此接口时,设置为空。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetBindingsResult struct { + RequestId string `json:"RequestId"` // 请求ID + NextToken string `json:"NextToken"` // 当绑定关系总数大于设置的MaxResults时,用于翻页的token。下一次列出绑定关系信息时以此值为NextToken,将未返回的结果返回。当绑定关系未全部返回时,此参数才有值。 + Bindings []*Binding `json:"Bindings"` // 数据集和 COS Bucket 绑定关系信息的列表。 +} + +// DescribeDatasetBindings 查询绑定关系列表 +// https://cloud.tencent.com/document/product/460/106161 +func (s *MetaInsightService) DescribeDatasetBindings(ctx context.Context, opt *DescribeDatasetBindingsOptions) (*DescribeDatasetBindingsResult, *Response, error) { + var res DescribeDatasetBindingsResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbindings", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DeleteDatasetBindingOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶,字段规则:cos://,其中BucketName表示COS存储桶名称,例如:cos://examplebucket-1250000000 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DeleteDatasetBindingResult struct { + RequestId string `json:"RequestId"` // 请求ID +} + +// DeleteDatasetBinding 解绑存储桶与数据集 +// https://cloud.tencent.com/document/product/460/106160 +func (s *MetaInsightService) DeleteDatasetBinding(ctx context.Context, opt *DeleteDatasetBindingOptions) (*DeleteDatasetBindingResult, *Response, error) { + var res DeleteDatasetBindingResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbinding", http.MethodDelete) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DatasetSimpleQueryOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Query *Query `json:"Query, omitempty" url:"-" ` // 简单查询参数条件,可自嵌套。 + MaxResults int `json:"MaxResults, omitempty" url:"-" ` // 返回文件元数据的最大个数,取值范围为0200。 使用聚合参数时,该值表示返回分组的最大个数,取值范围为02000。 不设置此参数或者设置为0时,则取默认值100。 + NextToken string `json:"NextToken, omitempty" url:"-" ` // 当绑定关系总数大于设置的MaxResults时,用于翻页的token。从NextToken开始按字典序返回绑定关系信息列表。第一次调用此接口时,设置为空。 + Sort string `json:"Sort, omitempty" url:"-" ` // 排序字段列表。请参考字段和操作符的支持列表。 多个排序字段可使用半角逗号(,)分隔,例如:Size,Filename。 最多可设置5个排序字段。 排序字段顺序即为排序优先级顺序。 + Order string `json:"Order, omitempty" url:"-" ` // 排序字段的排序方式。取值如下: asc:升序; desc(默认):降序。 多个排序方式可使用半角逗号(,)分隔,例如:asc,desc。 排序方式不可多于排序字段,即参数Order的元素数量需小于等于参数Sort的元素数量。例如Sort取值为Size,Filename时,Order可取值为asc,desc或asc。 排序方式少于排序字段时,未排序的字段默认取值asc。例如Sort取值为Size,Filename,Order取值为asc时,Filename默认排序方式为asc,即升序排列 + Aggregations []*Aggregations `json:"Aggregations, omitempty" url:"-" ` // 聚合字段信息列表。 当您使用聚合查询时,仅返回聚合结果,不再返回匹配到的元信息列表。 + WithFields []string `json:"WithFields, omitempty" url:"-" ` // 仅返回特定字段的值,而不是全部已有的元信息字段。可用于降低返回的结构体大小。不填或留空则返回所有字段。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type Aggregations struct { + Operation string `json:"Operation, omitempty" url:"-" ` // 聚合字段的操作符。枚举值:min:最小值。max:最大值。average:平均数sum:求和。count:计数。distinct:去重计数。group:分组计数,按照分组计数结果从高到低排序。 + Field string `json:"Field, omitempty" url:"-" ` // 字段名称。关于支持的字段,请参考字段和操作符的支持列表。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type Query struct { + Operation string `json:"Operation, omitempty" url:"-" ` // 操作运算符。枚举值: not:逻辑非。 or:逻辑或。 and:逻辑与。 lt:小于。 lte:小于等于。 gt:大于。 gte:大于等于。 eq:等于。 exist:存在性查询。 prefix:前缀查询。 match-phrase:字符串匹配查询。 nested:字段为数组时,其中同一对象内逻辑条件查询。 + SubQueries []*SubQueries `json:"SubQueries, omitempty" url:"-" ` // 子查询的结构体。 只有当Operations为逻辑运算符(and、or、not或nested)时,才能设置子查询条件。 在逻辑运算符为and/or/not时,其SubQueries内描述的所有条件需符合父级设置的and/or/not逻辑关系。 在逻辑运算符为nested时,其父级的Field必须为一个数组类的字段(如:Labels)。 子查询条件SubQueries组的Operation必须为and/or/not中的一个或多个,其Field必须为父级Field的子属性。 + Field string `json:"Field, omitempty" url:"-" ` // 字段名称。关于支持的字段,请参考字段和操作符的支持列表。 + Value string `json:"Value, omitempty" url:"-" ` // 查询的字段值。当Operations为逻辑运算符(and、or、not或nested)时,该字段无效。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type SubQueries struct { + Value string `json:"Value, omitempty" url:"-" ` // 查询的字段值。当Operations为逻辑运算符(and、or、not或nested)时,该字段无效。 + Operation string `json:"Operation, omitempty" url:"-" ` // 操作运算符。枚举值:not:逻辑非。or:逻辑或。and:逻辑与。lt:小于。lte:小于等于。gt:大于。gte:大于等于。eq:等于。exist:存在性查询。prefix:前缀查询。match-phrase:字符串匹配查询。nested:字段为数组时,其中同一对象内逻辑条件查询。 + Field string `json:"Field, omitempty" url:"-" ` // 字段名称。关于支持的字段,请参考字段和操作符的支持列表。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DatasetSimpleQueryResult struct { + RequestId string `json:"RequestId"` // 请求ID + Files []*FileResult `json:"Files"` // 文件信息列表。仅在请求的Aggregations为空时返回。 + Aggregations []*AggregationsResult `json:"Aggregations"` // 聚合字段信息列表。仅在请求的Aggregations不为空时返回。 + NextToken string `json:"NextToken"` // 翻页标记。当文件总数大于设置的MaxResults时,用于翻页的Token。符合条件的文件信息未全部返回时,此参数才有值。下一次列出文件信息时将此值作为NextToken传入,将后续的文件信息返回。 +} + +type AggregationsResult struct { + Operation string `json:"Operation"` // 聚合字段的聚合操作符。 + Value float64 `json:"Value"` // 聚合的统计结果。 + Groups []*Groups `json:"Groups"` // 分组聚合的结果列表。仅在请求的Aggregations中存在group类型的Operation时才会返回。 + Field string `json:"Field"` // 聚合字段名称。 +} + +type Groups struct { + Count int `json:"Count"` // 分组聚合的总个数。 + Value string `json:"Value"` // 分组聚合的值。 +} + +type FileResult struct { + ObjectId string `json:"ObjectId"` // 对象唯一ID。 + CreateTime string `json:"CreateTime"` // 元数据创建时间的时间戳,格式为RFC3339Nano + UpdateTime string `json:"UpdateTime"` // 元数据修改时间的时间戳,格式为RFC3339Nano创建元数据后,如果未更新过元数据,则元数据修改时间的时间戳和元数据创建时间的时间戳相同 + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址 + Filename string `json:"Filename"` // 文件路径 + MediaType string `json:"MediaType"` // 文件媒体类型。 枚举值:image:图片。other:其他。document:文档。archive:压缩包。audio:音频。video:视频。 + ContentType string `json:"ContentType"` // 文件内容类型(MIME Type)。 + COSStorageClass string `json:"COSStorageClass"` // 文件存储空间类型。 + COSCRC64 string `json:"COSCRC64"` // 文件CRC64值。 + Size int `json:"Size"` // 文件大小,单位为字节。 + CacheControl string `json:"CacheControl"` // 指定Object被下载时网页的缓存行为。该字段需要设置COS Object HTTP属性Cache-Control。 + ContentDisposition string `json:"ContentDisposition"` // 指定Object被下载时的名称。需要设置COS Object HTTP属性Content-Disposition。 + ContentEncoding string `json:"ContentEncoding"` // 指定该Object被下载时的内容编码格式。需要设置COS Object HTTP属性Content-Encoding。 + ContentLanguage string `json:"ContentLanguage"` // Object内容使用的语言。需要设置COS Object HTTP属性Content-Language。 + ServerSideEncryption string `json:"ServerSideEncryption"` // 加密算法,需要设置x-cos-server-side-encryption。 + ETag string `json:"ETag"` // Object生成时会创建相应的ETag ,ETag用于标识一个Object的内容。 + FileModifiedTime string `json:"FileModifiedTime"` // 文件最近一次修改时间的时间戳, 格式为RFC3339Nano。 + CustomId string `json:"CustomId"` // 该文件的自定义ID。该文件索引到数据集后,作为该行元数据的属性存储,用于和您的业务系统进行关联、对应。您可以根据业务需求传入该值,例如将某个URI关联到您系统内的某个ID。推荐传入全局唯一的值。 + CustomLabels *map[string]string `json:"CustomLabels"` // 文件自定义标签列表。储存您业务自定义的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 + COSUserMeta *map[string]string `json:"COSUserMeta"` // cos自定义头部。储存您业务在cos object上的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 + ObjectACL string `json:"ObjectACL"` // 文件访问权限属性。 + COSTagging *map[string]string `json:"COSTagging"` // cos自定义标签。储存您业务在cos object上的自定义标签的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 + COSTaggingCount int `json:"COSTaggingCount"` // cos自定义标签的数量。 + DatasetName string `json:"DatasetName"` // 数据集名称。 +} + +// DatasetSimpleQuery 简单查询 +// https://cloud.tencent.com/document/product/460/106375 +func (s *MetaInsightService) DatasetSimpleQuery(ctx context.Context, opt *DatasetSimpleQueryOptions) (*DatasetSimpleQueryResult, *Response, error) { + var res DatasetSimpleQueryResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetquery"+"/"+"simple", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DatasetFaceSearchOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址。 + MaxFaceNum int `json:"MaxFaceNum, omitempty" url:"-" ` // 输入图片中检索的人脸数量,默认值为1(传0或不传采用默认值),最大值为10。 + Limit int `json:"Limit, omitempty" url:"-" ` // 检索的每张人脸返回相关人脸数量,默认值为10,最大值为100。 + MatchThreshold int `json:"MatchThreshold, omitempty" url:"-" ` // 出参 Score 中,只有超过 MatchThreshold 值的结果才会返回。范围:1-100,默认值为0,推荐值为80。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DatasetFaceSearchResult struct { + FaceResult []*FaceResult `json:"FaceResult"` // 人脸检索识别结果信息列表。 + RequestId string `json:"RequestId"` // 请求 ID。 +} + +type FaceResult struct { + FaceInfos []*FaceInfosInMeta `json:"FaceInfos"` // 相关人脸信息列表。 + InputFaceBoundary *FaceBoundary `json:"InputFaceBoundary"` // 输入图片的人脸框位置。 +} + +type FaceBoundary struct { + Height int `json:"Height"` // 人脸高度。 + Width int `json:"Width"` // 人脸宽度。 + Left int `json:"Left"` // 人脸框左上角横坐标。 + Top int `json:"Top"` // 人脸框左上角纵坐标。 +} + +type FaceInfosInMeta struct { + PersonId string `json:"PersonId"` // 自定义人物ID。 + FaceBoundary *FaceBoundary `json:"FaceBoundary"` // 相关人脸框位置。 + FaceId string `json:"FaceId"` // 人脸ID。 + Score int `json:"Score"` // 相关人脸匹配得分。 + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址。 +} + +// DatasetFaceSearch 人脸搜索 +// https://cloud.tencent.com/document/product/460/106166 +func (s *MetaInsightService) DatasetFaceSearch(ctx context.Context, opt *DatasetFaceSearchOptions) (*DatasetFaceSearchResult, *Response, error) { + var res DatasetFaceSearchResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetquery"+"/"+"facesearch", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type SearchImageOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Mode string `json:"Mode, omitempty" url:"-" ` // 指定检索方式为图片或文本,pic 为图片检索,text 为文本检索,默认为 pic。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址(Mode 为 pic 时必选)。 + Limit int `json:"Limit, omitempty" url:"-" ` // 返回相关图片的数量,默认值为10,最大值为100。 + Text string `json:"Text, omitempty" url:"-" ` // 检索语句,检索方式为 text 时必填,最多支持60个字符 (Mode 为 text 时必选)。 + MatchThreshold int `json:"MatchThreshold, omitempty" url:"-" ` // 出参 Score(相关图片匹配得分) 中,只有超过 MatchThreshold 值的结果才会返回。默认值为0,推荐值为80。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type SearchImageResult struct { + ImageResult []*ImageResult `json:"ImageResult"` // 图像检索识别结果信息列表。 + RequestId string `json:"RequestId"` // 请求ID。 +} + +type ImageResult struct { + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址。 + Score int `json:"Score"` // 相关图片匹配得分。 +} + +// SearchImage 图像检索 +// https://cloud.tencent.com/document/product/460/106376 +func (s *MetaInsightService) SearchImage(ctx context.Context, opt *SearchImageOptions) (*SearchImageResult, *Response, error) { + var res SearchImageResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetquery"+"/"+"imagesearch", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go new file mode 100644 index 00000000000..d16fa2301b0 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go @@ -0,0 +1,770 @@ +package cos + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/xml" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "path/filepath" + "reflect" + "strings" + "text/template" + "time" + + "regexp" + "strconv" + + "github.com/google/go-querystring/query" + "github.com/mozillazg/go-httpheader" +) + +const ( + // Version current go sdk version + Version = "0.7.66" + UserAgent = "cos-go-sdk-v5/" + Version + contentTypeXML = "application/xml" + defaultServiceBaseURL = "http://service.cos.myqcloud.com" + XOptionalKey = "cos-go-sdk-v5-XOptionalKey" +) + +var ( + bucketURLTemplate = template.Must( + template.New("bucketURLFormat").Parse( + "{{.Schema}}://{{.BucketName}}.cos.{{.Region}}.myqcloud.com", + ), + ) + + // {|}{bucketname-appid}.{cos|cos-internal|cos-website|ci}.{region}.{myqcloud.com/tencentcos.cn}{/} + hostSuffix = regexp.MustCompile(`^.*((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) + hostPrefix = regexp.MustCompile(`^(http://|https://){0,1}([a-z0-9-]+-[0-9]+\.){0,1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) + metaInsightHostPrefix = regexp.MustCompile(`^(http://|https://){0,1}([0-9]+\.){1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) + bucketChecker = regexp.MustCompile(`^[a-z0-9-]+-[0-9]+$`) + regionChecker = regexp.MustCompile(`^[a-z-1]+$`) + + // 校验传入的url + domainSuffix = regexp.MustCompile(`^.*\.(myqcloud\.com(:[0-9]+){0,1}|tencentcos\.cn(:[0-9]+){0,1})$`) + bucketDomainChecker = regexp.MustCompile(`^(http://|https://){0,1}([a-z0-9-]+\.)+(myqcloud\.com|tencentcos\.cn)(:[0-9]+){0,1}$`) + invalidBucketErr = fmt.Errorf("invalid bucket format, please check your cos.BaseURL") + + switchHost = regexp.MustCompile(`([a-z0-9-]+-[0-9]+\.)(cos\.[a-z-1]+)\.(myqcloud\.com)(:[0-9]+){0,1}$`) + accelerateDomainSuffix = "accelerate.myqcloud.com" + oldDomainSuffix = ".myqcloud.com" + newDomainSuffix = ".tencentcos.cn" + + ObjectKeySimplifyCheckErr = fmt.Errorf("The Getobject Key is illegal") +) + +// BaseURL 访问各 API 所需的基础 URL +type BaseURL struct { + // 访问 bucket, object 相关 API 的基础 URL(不包含 path 部分): http://example.com + BucketURL *url.URL + // 访问 service API 的基础 URL(不包含 path 部分): http://example.com + ServiceURL *url.URL + // 访问 job API 的基础 URL (不包含 path 部分): http://example.com + BatchURL *url.URL + // 访问 CI 的基础 URL + CIURL *url.URL + // 访问 Fetch Task 的基础 URL + FetchURL *url.URL + // 访问 MetaInsight 的基础 URL + MetaInsightURL *url.URL +} + +func (*BaseURL) innerCheck(u *url.URL, reg *regexp.Regexp) bool { + if u == nil { + return true + } + urlStr := strings.TrimRight(u.String(), "/") + if !strings.HasPrefix(urlStr, "https://") && !strings.HasPrefix(urlStr, "http://") { + return false + } + if domainSuffix.MatchString(urlStr) && !reg.MatchString(urlStr) { + return false + } + host := u.Hostname() + if domainSuffix.MatchString(host) && !reg.MatchString(u.Scheme+"://"+host) { + return false + } + return true +} + +func (u *BaseURL) Check() bool { + return u.innerCheck(u.BucketURL, bucketDomainChecker) && u.innerCheck(u.ServiceURL, bucketDomainChecker) && u.innerCheck(u.BatchURL, bucketDomainChecker) +} + +// NewBucketURL 生成 BaseURL 所需的 BucketURL +// +// bucketName: bucket名称, bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式 +// Region: 区域代码: ap-beijing-1,ap-beijing,ap-shanghai,ap-guangzhou... +// secure: 是否使用 https +func NewBucketURL(bucketName, region string, secure bool) (*url.URL, error) { + schema := "https" + if !secure { + schema = "http" + } + + if region == "" || !regionChecker.MatchString(region) { + return nil, fmt.Errorf("region[%v] is invalid", region) + } + if bucketName == "" || !strings.ContainsAny(bucketName, "-") { + return nil, fmt.Errorf("bucketName[%v] is invalid", bucketName) + } + w := bytes.NewBuffer(nil) + bucketURLTemplate.Execute(w, struct { + Schema string + BucketName string + Region string + }{ + schema, bucketName, region, + }) + + u, _ := url.Parse(w.String()) + return u, nil +} + +type RetryOptions struct { + Count int + Interval time.Duration + AutoSwitchHost bool +} +type Config struct { + EnableCRC bool + RequestBodyClose bool + RetryOpt RetryOptions + ObjectKeySimplifyCheck bool +} + +// Client is a client manages communication with the COS API. +type Client struct { + client *http.Client + + Host string + UserAgent string + BaseURL *BaseURL + + common service + + Service *ServiceService + Bucket *BucketService + Object *ObjectService + Batch *BatchService + CI *CIService + MetaInsight *MetaInsightService + + Conf *Config + + invalidURL bool +} + +type service struct { + client *Client +} + +// go http default CheckRedirect +func HttpDefaultCheckRedirect(req *http.Request, via []*http.Request) error { + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } + return nil +} + +// NewClient returns a new COS API client. +func NewClient(uri *BaseURL, httpClient *http.Client) *Client { + if httpClient == nil { + httpClient = &http.Client{} + } + // avoid SSRF, default don't follow 3xx + if httpClient.CheckRedirect == nil { + httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + } + + baseURL := &BaseURL{} + if uri != nil { + baseURL.BucketURL = uri.BucketURL + baseURL.ServiceURL = uri.ServiceURL + baseURL.BatchURL = uri.BatchURL + baseURL.CIURL = uri.CIURL + baseURL.FetchURL = uri.FetchURL + baseURL.MetaInsightURL = uri.MetaInsightURL + } + if baseURL.ServiceURL == nil { + baseURL.ServiceURL, _ = url.Parse(defaultServiceBaseURL) + } + var invalidURL bool + if !baseURL.Check() { + invalidURL = true + } + + c := &Client{ + client: httpClient, + UserAgent: UserAgent, + BaseURL: baseURL, + Conf: &Config{ + EnableCRC: true, + RequestBodyClose: false, + RetryOpt: RetryOptions{ + Count: 3, + Interval: time.Duration(0), + AutoSwitchHost: false, + }, + ObjectKeySimplifyCheck: true, + }, + invalidURL: invalidURL, + } + c.common.client = c + c.Service = (*ServiceService)(&c.common) + c.Bucket = (*BucketService)(&c.common) + c.Object = (*ObjectService)(&c.common) + c.Batch = (*BatchService)(&c.common) + c.CI = (*CIService)(&c.common) + c.MetaInsight = (*MetaInsightService)(&c.common) + return c +} + +func (c *Client) DisableURLCheck() { + c.invalidURL = false +} + +type Credential struct { + SecretID string + SecretKey string + SessionToken string +} + +func (c *Client) GetCredential() *Credential { + if auth, ok := c.client.Transport.(TransportIface); ok { + ak, sk, token, err := auth.GetCredential() + if err != nil { + return nil + } + return &Credential{ + SecretID: ak, + SecretKey: sk, + SessionToken: token, + } + } + return nil +} + +type commonHeader struct { + ContentLength int64 `header:"Content-Length,omitempty"` +} + +func (c *Client) newPresignedRequest(ctx context.Context, sendOpt *sendOptions, enablePathMerge bool) (req *http.Request, err error) { + sendOpt.uri, err = addURLOptions(sendOpt.uri, sendOpt.optQuery) + if err != nil { + return + } + urlStr := fmt.Sprintf("%s://%s%s", sendOpt.baseURL.Scheme, sendOpt.baseURL.Host, sendOpt.uri) + if enablePathMerge { + u, _ := url.Parse(sendOpt.uri) + urlStr = sendOpt.baseURL.ResolveReference(u).String() + } + req, err = http.NewRequest(sendOpt.method, urlStr, nil) + if err != nil { + return + } + + req.Header, err = addHeaderOptions(ctx, req.Header, sendOpt.optHeader) + if err != nil { + return + } + return req, err +} + +func (c *Client) newRequest(ctx context.Context, baseURL *url.URL, uri, method string, body interface{}, optQuery interface{}, optHeader interface{}, isRetry bool) (req *http.Request, err error) { + if c.invalidURL { + return nil, invalidBucketErr + } + if baseURL == nil { + return nil, invalidBucketErr + } + if !checkURL(baseURL) { + host := baseURL.String() + if c.BaseURL.MetaInsightURL != baseURL || !metaInsightHostPrefix.MatchString(host) { + return nil, invalidBucketErr + } + } + uri, err = addURLOptions(uri, optQuery) + if err != nil { + return + } + u, _ := url.Parse(uri) + urlStr := baseURL.ResolveReference(u).String() + + var reader io.Reader + contentType := "" + contentMD5 := "" + contentLength := int64(-1) + if body != nil { + // 上传文件 + if r, ok := body.(io.Reader); ok { + reader = r + } else { + b, err := xml.Marshal(body) + if err != nil { + return nil, err + } + contentType = contentTypeXML + reader = bytes.NewReader(b) + contentMD5 = base64.StdEncoding.EncodeToString(calMD5Digest(b)) + contentLength = int64(len(b)) + } + } else if method == http.MethodPut || method == http.MethodPost { + contentLength = 0 + } + + req, err = http.NewRequest(method, urlStr, reader) + if err != nil { + return + } + + req.Header, err = addHeaderOptions(ctx, req.Header, optHeader) + if err != nil { + return + } + if v := req.Header.Get("Content-Length"); v == "" && contentLength >= 0 { + req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) + } + if v := req.Header.Get("Content-Length"); req.ContentLength == 0 && v != "" && v != "0" { + req.ContentLength, _ = strconv.ParseInt(v, 10, 64) + } + + if contentMD5 != "" { + req.Header["Content-MD5"] = []string{contentMD5} + } + if v := req.Header.Get("User-Agent"); v == "" || !strings.HasPrefix(v, UserAgent) { + if c.UserAgent != "" { + req.Header.Set("User-Agent", c.UserAgent) + } + } + if req.Header.Get("Content-Type") == "" && contentType != "" { + req.Header.Set("Content-Type", contentType) + } + if isRetry { + req.Header.Set("X-Cos-Sdk-Retry", "true") + } + if c.Host != "" { + req.Host = c.Host + } + if c.Conf.RequestBodyClose { + req.Close = true + } + return +} + +func (c *Client) doAPI(ctx context.Context, req *http.Request, result interface{}, closeBody bool) (*Response, error) { + var cancel context.CancelFunc + if closeBody { + ctx, cancel = context.WithCancel(ctx) + defer cancel() + } + req = req.WithContext(ctx) + + resp, err := c.client.Do(req) + if err != nil { + // If we got an error, and the context has been canceled, + // the context's error is probably more useful. + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + return nil, err + } + + defer func() { + if closeBody { + // Close the body to let the Transport reuse the connection + io.Copy(ioutil.Discard, resp.Body) + resp.Body.Close() + } + }() + + response := newResponse(resp) + + err = checkResponse(resp) + if err != nil { + // StatusCode != 2xx when Get Object + if !closeBody { + resp.Body.Close() + } + // even though there was an error, we still return the response + // in case the caller wants to inspect it further + return response, err + } + + // need CRC64 verification + if reader, ok := req.Body.(*teeReader); ok { + if c.Conf.EnableCRC && reader.writer != nil && !reader.disableCheckSum { + localcrc := reader.Crc64() + scoscrc := response.Header.Get("x-cos-hash-crc64ecma") + icoscrc, err := strconv.ParseUint(scoscrc, 10, 64) + if icoscrc != localcrc { + return response, fmt.Errorf("verification failed, want:%v, return:%v, x-cos-hash-crc64ecma:%v, err:%v, header:%+v", localcrc, icoscrc, scoscrc, err, response.Header) + } + } + } + + if result != nil { + if w, ok := result.(io.Writer); ok { + _, err = io.Copy(w, resp.Body) + if err != nil { // read body failed + return response, err + } + } else { + err = xml.NewDecoder(resp.Body).Decode(result) + if err == io.EOF { + err = nil // ignore EOF errors caused by empty response body + } + } + } + + return response, err +} + +type sendOptions struct { + // 基础 URL + baseURL *url.URL + // URL 中除基础 URL 外的剩余部分 + uri string + // 请求方法 + method string + + body interface{} + // url 查询参数 + optQuery interface{} + // http header 参数 + optHeader interface{} + // 用 result 反序列化 resp.Body + result interface{} + // 是否禁用自动调用 resp.Body.Close() + // 自动调用 Close() 是为了能够重用连接 + disableCloseBody bool + // 是否重试 + isRetry bool +} + +func toSwitchHost(oldURL *url.URL) *url.URL { + // 判断域名是否能够切换 + if !switchHost.MatchString(oldURL.Host) { + return oldURL + } + newURL, _ := url.Parse(oldURL.String()) + hostAndPort := strings.SplitN(newURL.Host, ":", 2) + newHost := hostAndPort[0] + // 加速域名不切换 + if strings.HasSuffix(newHost, accelerateDomainSuffix) { + return oldURL + } + newHost = newHost[:len(newHost)-len(oldDomainSuffix)] + newDomainSuffix + if len(hostAndPort) > 1 { + newHost += ":" + hostAndPort[1] + } + newURL.Host = newHost + return newURL +} + +func (c *Client) CheckRetrieable(u *url.URL, resp *Response, err error, secondLast bool) (*url.URL, bool) { + res := u + if err != nil && err != invalidBucketErr { + // 不重试 + if resp != nil && resp.StatusCode < 500 { + if c.Conf.RetryOpt.AutoSwitchHost { + if resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307 { + if resp.Header.Get("X-Cos-Request-Id") == "" { + res = toSwitchHost(u) + if res != u { + return res, true + } + } + } + } + return res, false + } + if c.Conf.RetryOpt.AutoSwitchHost && secondLast { + // 收不到报文 或者 不存在RequestId + if resp == nil || resp.Header.Get("X-Cos-Request-Id") == "" { + res = toSwitchHost(u) + } + } + return res, true + } + return res, false +} + +func (c *Client) doRetry(ctx context.Context, opt *sendOptions) (resp *Response, err error) { + if opt.body != nil { + if _, ok := opt.body.(io.Reader); ok { + resp, err = c.send(ctx, opt) + return + } + } + count := 1 + if c.Conf.RetryOpt.Count > 0 { + count = c.Conf.RetryOpt.Count + } + retryErr := &RetryError{} + var retrieable bool + for nr := 0; nr < count; nr++ { + // 把上一次错误记录下来 + if err != nil { + retryErr.Add(err) + } + opt.isRetry = nr > 0 + resp, err = c.send(ctx, opt) + opt.baseURL, retrieable = c.CheckRetrieable(opt.baseURL, resp, err, nr >= count-2) + if retrieable { + if c.Conf.RetryOpt.Interval > 0 && nr+1 < count { + time.Sleep(c.Conf.RetryOpt.Interval) + } + continue + } + break + } + // 最后一次非COS错误,输出三次结果 + if err != nil { + if _, ok := err.(*ErrorResponse); !ok { + retryErr.Add(err) + err = retryErr + } + } + return +} + +func (c *Client) send(ctx context.Context, opt *sendOptions) (resp *Response, err error) { + req, err := c.newRequest(ctx, opt.baseURL, opt.uri, opt.method, opt.body, opt.optQuery, opt.optHeader, opt.isRetry) + if err != nil { + return + } + + resp, err = c.doAPI(ctx, req, opt.result, !opt.disableCloseBody) + return +} + +// addURLOptions adds the parameters in opt as URL query parameters to s. opt +// must be a struct whose fields may contain "url" tags. +func addURLOptions(s string, opt interface{}) (string, error) { + v := reflect.ValueOf(opt) + if v.Kind() == reflect.Ptr && v.IsNil() { + return s, nil + } + + u, err := url.Parse(s) + if err != nil { + return s, err + } + + qs, err := query.Values(opt) + if err != nil { + return s, err + } + + // 保留原有的参数,并且放在前面。因为 cos 的 url 路由是以第一个参数作为路由的 + // e.g. /?uploads + q := u.RawQuery + rq := qs.Encode() + if q != "" { + if rq != "" { + u.RawQuery = fmt.Sprintf("%s&%s", q, qs.Encode()) + } + } else { + u.RawQuery = rq + } + return u.String(), nil +} + +type XOptionalValue struct { + Header *http.Header +} + +// addHeaderOptions adds the parameters in opt as Header fields to req. opt +// must be a struct whose fields may contain "header" tags. +func addHeaderOptions(ctx context.Context, header http.Header, opt interface{}) (http.Header, error) { + defer func() { + // 通过context传递 + if val := ctx.Value(XOptionalKey); val != nil { + if optVal, ok := val.(*XOptionalValue); ok { + if optVal.Header != nil { + for key, values := range *optVal.Header { + for _, value := range values { + header.Add(key, value) + } + } + } + } + } + }() + v := reflect.ValueOf(opt) + if v.Kind() == reflect.Ptr && v.IsNil() { + return header, nil + } + + h, err := httpheader.Header(opt) + if err != nil { + return nil, err + } + + for key, values := range h { + for _, value := range values { + header.Add(key, value) + } + } + + return header, nil +} + +func checkURL(baseURL *url.URL) bool { + if baseURL == nil { + return false + } + if baseURL.Scheme == "" || baseURL.Hostname() == "" { + return false + } + host := baseURL.String() + if hostSuffix.MatchString(host) && !hostPrefix.MatchString(host) { + return false + } + return true +} + +func CheckObjectKeySimplify(key string) bool { + res, err := filepath.Abs(key) + if res == "/" || err != nil { + return false + } + return true +} + +// Owner defines Bucket/Object's owner +type Owner struct { + UIN string `xml:"uin,omitempty"` + ID string `xml:",omitempty"` + DisplayName string `xml:",omitempty"` +} + +// Initiator same to the Owner struct +type Initiator Owner + +// Response API 响应 +type Response struct { + *http.Response +} + +func newResponse(resp *http.Response) *Response { + return &Response{ + Response: resp, + } +} + +// ACLHeaderOptions is the option of ACLHeader +type ACLHeaderOptions struct { + XCosACL string `header:"x-cos-acl,omitempty" url:"-" xml:"-"` + XCosGrantRead string `header:"x-cos-grant-read,omitempty" url:"-" xml:"-"` + XCosGrantWrite string `header:"x-cos-grant-write,omitempty" url:"-" xml:"-"` + XCosGrantFullControl string `header:"x-cos-grant-full-control,omitempty" url:"-" xml:"-"` + XCosGrantReadACP string `header:"x-cos-grant-read-acp,omitempty" url:"-" xml:"-"` + XCosGrantWriteACP string `header:"x-cos-grant-write-acp,omitempty" url:"-" xml:"-"` +} + +// ACLGrantee is the param of ACLGrant +type ACLGrantee struct { + TypeAttr xml.Attr `xml:",attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + UIN string `xml:"uin,omitempty"` + URI string `xml:"URI,omitempty"` + ID string `xml:",omitempty"` + DisplayName string `xml:",omitempty"` + SubAccount string `xml:"Subaccount,omitempty"` +} + +// ACLGrant is the param of ACLXml +type ACLGrant struct { + Grantee *ACLGrantee + Permission string +} + +// ACLXml is the ACL body struct +type ACLXml struct { + XMLName xml.Name `xml:"AccessControlPolicy"` + Owner *Owner + AccessControlList []ACLGrant `xml:"AccessControlList>Grant,omitempty"` +} + +type aclEnum struct { + Private string + PublicRead string + PublicReadWrite string + AuthenticatedRead string + Default string + BucketOwnerRead string + BucketOwnerFullControl string +} + +var ACL = &aclEnum{ + Private: "private", + PublicRead: "public-read", + PublicReadWrite: "public-read-write", + AuthenticatedRead: "authenticated-read", + Default: "default", + BucketOwnerRead: "bucket-owner-read", + BucketOwnerFullControl: "bucket-owner-full-control", +} + +func decodeACL(resp *Response, res *ACLXml) { + ItemMap := map[string]string{ + "ACL": "x-cos-acl", + "READ": "x-cos-grant-read", + "WRITE": "x-cos-grant-write", + "READ_ACP": "x-cos-grant-read-acp", + "WRITE_ACP": "x-cos-grant-write-acp", + "FULL_CONTROL": "x-cos-grant-full-control", + } + publicACL := make(map[string]int) + resACL := make(map[string][]string) + for _, item := range res.AccessControlList { + if item.Grantee == nil { + continue + } + if item.Grantee.ID == "qcs::cam::anyone:anyone" || item.Grantee.URI == "http://cam.qcloud.com/groups/global/AllUsers" { + publicACL[item.Permission] = 1 + } else if item.Grantee.ID != res.Owner.ID { + resACL[item.Permission] = append(resACL[item.Permission], "id=\""+item.Grantee.ID+"\"") + } + } + if publicACL["FULL_CONTROL"] == 1 || (publicACL["READ"] == 1 && publicACL["WRITE"] == 1) { + resACL["ACL"] = []string{"public-read-write"} + } else if publicACL["READ"] == 1 { + resACL["ACL"] = []string{"public-read"} + } else { + resACL["ACL"] = []string{"private"} + } + + for item, header := range ItemMap { + if len(resp.Header.Get(header)) > 0 || len(resACL[item]) == 0 { + continue + } + resp.Header.Set(header, uniqueGrantID(resACL[item])) + } +} + +func uniqueGrantID(grantIDs []string) string { + res := []string{} + filter := make(map[string]int) + for _, id := range grantIDs { + if filter[id] != 0 { + continue + } + filter[id] = 1 + res = append(res, id) + } + return strings.Join(res, ",") +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/doc.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/doc.go new file mode 100644 index 00000000000..99005ab3a1c --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/doc.go @@ -0,0 +1,3 @@ +// Package cos is COS(Cloud Object Storage) Go SDK. The V5 version(XML API). +// There are examples of using each API in the project's 'example' directory. +package cos diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/error.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/error.go new file mode 100644 index 00000000000..d3a20e44ecc --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/error.go @@ -0,0 +1,112 @@ +package cos + +import ( + "encoding/json" + "encoding/xml" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "strings" +) + +type RetryError struct { + Errs []error +} + +func (r *RetryError) Error() string { + var errStr []string + for _, err := range r.Errs { + errStr = append(errStr, err.Error()) + } + return strings.Join(errStr, "; ") +} + +func (r *RetryError) Add(err error) { + r.Errs = append(r.Errs, err) +} + +// ErrorResponse 包含 API 返回的错误信息 +// +// https://www.qcloud.com/document/product/436/7730 +type ErrorResponse struct { + XMLName xml.Name `xml:"Error"` + Response *http.Response `xml:"-"` + Code string + Message string + Resource string + RequestID string `header:"x-cos-request-id,omitempty" url:"-" xml:"RequestId,omitempty"` + TraceID string `xml:"TraceId,omitempty"` +} + +// Error returns the error msg +func (r *ErrorResponse) Error() string { + RequestID := r.RequestID + if RequestID == "" { + RequestID = r.Response.Header.Get("X-Cos-Request-Id") + } + TraceID := r.TraceID + if TraceID == "" { + TraceID = r.Response.Header.Get("X-Cos-Trace-Id") + } + decodeURL, err := decodeURIComponent(r.Response.Request.URL.String()) + if err != nil { + decodeURL = r.Response.Request.URL.String() + } + return fmt.Sprintf("%v %v: %d %v(Message: %v, RequestId: %v, TraceId: %v)", + r.Response.Request.Method, decodeURL, + r.Response.StatusCode, r.Code, r.Message, RequestID, TraceID) +} + +type jsonError struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` + RequestID string `json:"request_id,omitempty"` +} + +// 检查 response 是否是出错时的返回的 response +func checkResponse(r *http.Response) error { + if c := r.StatusCode; 200 <= c && c <= 299 { + return nil + } + errorResponse := &ErrorResponse{Response: r} + data, err := ioutil.ReadAll(r.Body) + if err == nil && data != nil { + xml.Unmarshal(data, errorResponse) + } + // 是否为 json 格式 + if errorResponse.Code == "" { + ctype := strings.TrimLeft(r.Header.Get("Content-Type"), " ") + if strings.HasPrefix(ctype, "application/json") { + var jerror jsonError + json.Unmarshal(data, &jerror) + errorResponse.Code = strconv.Itoa(jerror.Code) + errorResponse.Message = jerror.Message + errorResponse.RequestID = jerror.RequestID + } + + } + return errorResponse +} + +func IsNotFoundError(e error) bool { + if e == nil { + return false + } + err, ok := e.(*ErrorResponse) + if !ok { + return false + } + if err.Response != nil && err.Response.StatusCode == 404 { + return true + } + return false +} + +func IsCOSError(e error) (*ErrorResponse, bool) { + if e == nil { + return nil, false + } + err, ok := e.(*ErrorResponse) + return err, ok +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go new file mode 100644 index 00000000000..e4f08b64434 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go @@ -0,0 +1,480 @@ +package cos + +import ( + "bytes" + "crypto/md5" + "crypto/sha1" + "errors" + "fmt" + "github.com/mozillazg/go-httpheader" + "hash/crc64" + "io" + "net/http" + "net/url" + "os" + "regexp" + "strconv" + "strings" +) + +// 单次上传文件最大为5GB +const singleUploadMaxLength = 5 * 1024 * 1024 * 1024 +const singleUploadThreshold = 32 * 1024 * 1024 + +// 计算 md5 或 sha1 时的分块大小 +const calDigestBlockSize = 1024 * 1024 * 10 + +func calMD5Digest(msg []byte) []byte { + // TODO: 分块计算,减少内存消耗 + m := md5.New() + m.Write(msg) + return m.Sum(nil) +} + +func calSHA1Digest(msg []byte) []byte { + // TODO: 分块计算,减少内存消耗 + m := sha1.New() + m.Write(msg) + return m.Sum(nil) +} + +func calCRC64(fd io.Reader) (uint64, error) { + tb := crc64.MakeTable(crc64.ECMA) + hash := crc64.New(tb) + _, err := io.Copy(hash, fd) + if err != nil { + return 0, err + } + sum := hash.Sum64() + return sum, nil +} + +// cloneRequest returns a clone of the provided *http.Request. The clone is a +// shallow copy of the struct and its Header map. +func cloneRequest(r *http.Request) *http.Request { + // shallow copy of the struct + r2 := new(http.Request) + *r2 = *r + // deep copy of the Header + r2.Header = make(http.Header, len(r.Header)) + for k, s := range r.Header { + r2.Header[k] = append([]string(nil), s...) + } + return r2 +} + +// encodeURIComponent like same function in javascript +// +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent +// +// http://www.ecma-international.org/ecma-262/6.0/#sec-uri-syntax-and-semantics +func encodeURIComponent(s string, excluded ...[]byte) string { + var b bytes.Buffer + written := 0 + + for i, n := 0, len(s); i < n; i++ { + c := s[i] + + switch c { + case '-', '_', '.', '!', '~', '*', '\'', '(', ')': + continue + default: + // Unreserved according to RFC 3986 sec 2.3 + if 'a' <= c && c <= 'z' { + + continue + + } + if 'A' <= c && c <= 'Z' { + + continue + + } + if '0' <= c && c <= '9' { + + continue + } + if len(excluded) > 0 { + conti := false + for _, ch := range excluded[0] { + if ch == c { + conti = true + break + } + } + if conti { + continue + } + } + } + + b.WriteString(s[written:i]) + fmt.Fprintf(&b, "%%%02X", c) + written = i + 1 + } + + if written == 0 { + return s + } + b.WriteString(s[written:]) + return b.String() +} + +func decodeURIComponent(s string) (string, error) { + decodeStr, err := url.QueryUnescape(s) + if err != nil { + return s, err + } + return decodeStr, err +} + +func DecodeURIComponent(s string) (string, error) { + return decodeURIComponent(s) +} + +func EncodeURIComponent(s string) string { + return encodeURIComponent(s) +} + +func GetReaderLen(reader io.Reader) (length int64, err error) { + switch v := reader.(type) { + case *bytes.Buffer: + length = int64(v.Len()) + case *bytes.Reader: + length = int64(v.Len()) + case *strings.Reader: + length = int64(v.Len()) + case *os.File: + stat, ferr := v.Stat() + if ferr != nil { + err = fmt.Errorf("can't get reader length: %s", ferr.Error()) + } else { + length = stat.Size() + } + case *io.LimitedReader: + length = int64(v.N) + case *LimitedReadCloser: + length = int64(v.N) + case FixedLengthReader: + length = v.Size() + default: + err = fmt.Errorf("can't get reader content length, unkown reader type") + } + return +} + +func IsLenReader(reader io.Reader) bool { + switch reader.(type) { + case *bytes.Buffer: + return true + case *bytes.Reader: + return true + case *strings.Reader: + return true + case *os.File: + return true + default: + return false + } + return false +} + +func CheckReaderLen(reader io.Reader) error { + nlen, err := GetReaderLen(reader) + if err != nil || nlen <= singleUploadMaxLength { + return nil + } + return errors.New("The single object size you upload can not be larger than 5GB") +} + +func cloneHeader(opt *http.Header) *http.Header { + if opt == nil { + return nil + } + h := make(http.Header, len(*opt)) + for k, vv := range *opt { + vv2 := make([]string, len(vv)) + copy(vv2, vv) + h[k] = vv2 + } + return &h +} + +func CopyOptionsToMulti(opt *ObjectCopyOptions) *InitiateMultipartUploadOptions { + if opt == nil { + return nil + } + optini := &InitiateMultipartUploadOptions{ + opt.ACLHeaderOptions, + &ObjectPutHeaderOptions{}, + } + if opt.ObjectCopyHeaderOptions == nil { + return optini + } + optini.ObjectPutHeaderOptions = &ObjectPutHeaderOptions{ + CacheControl: opt.ObjectCopyHeaderOptions.CacheControl, + ContentDisposition: opt.ObjectCopyHeaderOptions.ContentDisposition, + ContentEncoding: opt.ObjectCopyHeaderOptions.ContentEncoding, + ContentType: opt.ObjectCopyHeaderOptions.ContentType, + ContentLanguage: opt.ObjectCopyHeaderOptions.ContentLanguage, + Expect: opt.ObjectCopyHeaderOptions.Expect, + Expires: opt.ObjectCopyHeaderOptions.Expires, + XCosMetaXXX: opt.ObjectCopyHeaderOptions.XCosMetaXXX, + XCosStorageClass: opt.ObjectCopyHeaderOptions.XCosStorageClass, + XCosServerSideEncryption: opt.ObjectCopyHeaderOptions.XCosServerSideEncryption, + XCosSSECustomerAglo: opt.ObjectCopyHeaderOptions.XCosSSECustomerAglo, + XCosSSECustomerKey: opt.ObjectCopyHeaderOptions.XCosSSECustomerKey, + XCosSSECustomerKeyMD5: opt.ObjectCopyHeaderOptions.XCosSSECustomerKeyMD5, + XOptionHeader: opt.ObjectCopyHeaderOptions.XOptionHeader, + } + return optini +} + +func CloneObjectPutOptions(opt *ObjectPutOptions) *ObjectPutOptions { + res := &ObjectPutOptions{ + &ACLHeaderOptions{}, + &ObjectPutHeaderOptions{}, + nil, + } + if opt != nil { + if opt.ACLHeaderOptions != nil { + *res.ACLHeaderOptions = *opt.ACLHeaderOptions + } + if opt.ObjectPutHeaderOptions != nil { + *res.ObjectPutHeaderOptions = *opt.ObjectPutHeaderOptions + res.XCosMetaXXX = cloneHeader(opt.XCosMetaXXX) + res.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + if opt.innerSwitchURL != nil { + res.innerSwitchURL = opt.innerSwitchURL + } + } + return res +} + +func CloneInitiateMultipartUploadOptions(opt *InitiateMultipartUploadOptions) *InitiateMultipartUploadOptions { + res := &InitiateMultipartUploadOptions{ + &ACLHeaderOptions{}, + &ObjectPutHeaderOptions{}, + } + if opt != nil { + if opt.ACLHeaderOptions != nil { + *res.ACLHeaderOptions = *opt.ACLHeaderOptions + } + if opt.ObjectPutHeaderOptions != nil { + *res.ObjectPutHeaderOptions = *opt.ObjectPutHeaderOptions + res.XCosMetaXXX = cloneHeader(opt.XCosMetaXXX) + res.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + } + return res +} + +func CloneObjectUploadPartOptions(opt *ObjectUploadPartOptions) *ObjectUploadPartOptions { + var res ObjectUploadPartOptions + if opt != nil { + res = *opt + res.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + return &res +} + +func CloneObjectGetOptions(opt *ObjectGetOptions) *ObjectGetOptions { + var res ObjectGetOptions + if opt != nil { + res = *opt + res.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + return &res +} + +func CloneCompleteMultipartUploadOptions(opt *CompleteMultipartUploadOptions) *CompleteMultipartUploadOptions { + var res CompleteMultipartUploadOptions + if opt != nil { + res.XMLName = opt.XMLName + if len(opt.Parts) > 0 { + res.Parts = make([]Object, len(opt.Parts)) + copy(res.Parts, opt.Parts) + } + res.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + return &res +} + +func cloneObjectCopyPartOptions(opt *ObjectCopyPartOptions) *ObjectCopyPartOptions { + var res ObjectCopyPartOptions + if opt != nil { + res = *opt + res.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + return &res +} + +type RangeOptions struct { + HasStart bool + HasEnd bool + Start int64 + End int64 +} + +func FormatRangeOptions(opt *RangeOptions) string { + if opt == nil { + return "" + } + if opt.HasStart && opt.HasEnd { + return fmt.Sprintf("bytes=%v-%v", opt.Start, opt.End) + } + if opt.HasStart { + return fmt.Sprintf("bytes=%v-", opt.Start) + } + if opt.HasEnd { + return fmt.Sprintf("bytes=-%v", opt.End) + } + return "" +} +func GetRangeOptions(opt *ObjectGetOptions) (*RangeOptions, error) { + if opt == nil || opt.Range == "" { + return nil, nil + } + return GetRange(opt.Range) +} + +func GetRange(rangeStr string) (*RangeOptions, error) { + // bytes=M-N + slices := strings.Split(rangeStr, "=") + if len(slices) != 2 || slices[0] != "bytes" { + return nil, fmt.Errorf("Invalid Parameter Range: %v", rangeStr) + } + // byte=M-N, X-Y + fSlice := strings.Split(slices[1], ",") + rstr := fSlice[0] + + var err error + var ropt RangeOptions + sted := strings.Split(rstr, "-") + if len(sted) != 2 { + return nil, fmt.Errorf("Invalid Parameter Range: %v", rangeStr) + } + // M + if len(sted[0]) > 0 { + ropt.Start, err = strconv.ParseInt(sted[0], 10, 64) + if err != nil { + return nil, fmt.Errorf("Invalid Parameter Range: %v,err: %v", rangeStr, err) + } + ropt.HasStart = true + } + // N + if len(sted[1]) > 0 { + ropt.End, err = strconv.ParseInt(sted[1], 10, 64) + if err != nil || ropt.End == 0 { + return nil, fmt.Errorf("Invalid Parameter Range: %v,err: %v", rangeStr, err) + } + ropt.HasEnd = true + } + return &ropt, nil +} + +var deliverHeader = map[string]bool{} + +func isDeliverHeader(key string) bool { + for k, v := range deliverHeader { + if key == k && v { + return true + } + } + return strings.HasPrefix(key, privateHeaderPrefix) || strings.HasPrefix(key, "x-") +} + +func deliverInitOptions(opt *InitiateMultipartUploadOptions) (*http.Header, error) { + if opt == nil { + return nil, nil + } + h, err := httpheader.Header(opt) + if err != nil { + return nil, err + } + header := &http.Header{} + for key, values := range h { + key = strings.ToLower(key) + if isDeliverHeader(key) { + for _, value := range values { + header.Add(key, value) + } + } + } + return header, nil +} + +var ( + bucketReg = regexp.MustCompile(`([a-z0-9-]+-[0-9]+)`) + keyReg = regexp.MustCompile(`(.*?)`) + uploadIdReg = regexp.MustCompile(`([a-z0-9]+)`) + locationReg = regexp.MustCompile(`(.*?)`) + etagReg = regexp.MustCompile(`"(.*?)"`) +) + +func UnmarshalInitMultiUploadResult(data []byte, res *InitiateMultipartUploadResult) error { + match := bucketReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Bucket = match[1] + } else { + return fmt.Errorf("Unmarshal failed, %v", string(data)) + } + match = keyReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Key = match[1] + } else { + return fmt.Errorf("Unmarshal failed, %v", string(data)) + } + match = uploadIdReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.UploadID = match[1] + } else { + return fmt.Errorf("Unmarshal failed, %v", string(data)) + } + return nil +} + +func UnmarshalCompleteMultiUploadResult(data []byte, res *CompleteMultipartUploadResult) error { + match := locationReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Location = match[1] + } else { + return fmt.Errorf("Unmarshal Location failed, %v", string(data)) + } + match = bucketReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Bucket = match[1] + } else { + return fmt.Errorf("Unmarshal Bucket failed, %v", string(data)) + } + match = keyReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Key = match[1] + } else { + return fmt.Errorf("Unmarshal Key failed, %v", string(data)) + } + match = etagReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.ETag = "\"" + match[1] + "\"" + } else { + return fmt.Errorf("Unmarshal Etag failed, %v", string(data)) + } + + return nil +} + +func GetBucketRegionFromUrl(u *url.URL) (string, string) { + if u == nil { + return "", "" + } + vec := strings.Split(u.Host, ".") + if len(vec) < 3 { + return "", "" + } + return vec[0], vec[2] +} + +func Bool(v bool) *bool { + return &v +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/object.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/object.go new file mode 100644 index 00000000000..7d0dc8fe8d3 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/object.go @@ -0,0 +1,2189 @@ +package cos + +import ( + "bytes" + "context" + "crypto/md5" + "encoding/hex" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "hash/crc64" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "sort" + "strconv" + "strings" + "time" +) + +// ObjectService 相关 API +type ObjectService service + +// ObjectGetOptions is the option of GetObject +type ObjectGetOptions struct { + ResponseContentType string `url:"response-content-type,omitempty" header:"-"` + ResponseContentLanguage string `url:"response-content-language,omitempty" header:"-"` + ResponseExpires string `url:"response-expires,omitempty" header:"-"` + ResponseCacheControl string `url:"response-cache-control,omitempty" header:"-"` + ResponseContentDisposition string `url:"response-content-disposition,omitempty" header:"-"` + ResponseContentEncoding string `url:"response-content-encoding,omitempty" header:"-"` + CiProcess string `url:"ci-process,omitempty" header:"-"` + Range string `url:"-" header:"Range,omitempty"` + IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"` + // SSE-C + XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + + //兼容其他自定义头部 + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` + XCosTrafficLimit int `header:"x-cos-traffic-limit,omitempty" url:"-" xml:"-"` + + // 下载进度, ProgressCompleteEvent不能表示对应API调用成功,API是否调用成功的判断标准为返回err==nil + Listener ProgressListener `header:"-" url:"-" xml:"-"` +} + +// presignedURLTestingOptions is the opt of presigned url +type presignedURLTestingOptions struct { + authTime *AuthTime +} + +// Get Object 请求可以将一个文件(Object)下载至本地。 +// 该操作需要对目标 Object 具有读权限或目标 Object 对所有人都开放了读权限(公有读)。 +// +// https://www.qcloud.com/document/product/436/7753 +func (s *ObjectService) Get(ctx context.Context, name string, opt *ObjectGetOptions, id ...string) (*Response, error) { + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = "/" + encodeURIComponent(name) + } else { + return nil, errors.New("wrong params") + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + disableCloseBody: true, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + + if opt != nil && opt.Listener != nil { + if err == nil && resp != nil { + if totalBytes, e := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64); e == nil { + resp.Body = TeeReader(resp.Body, nil, totalBytes, opt.Listener) + } + } + } + return resp, err +} + +// GetToFile download the object to local file +func (s *ObjectService) GetToFile(ctx context.Context, name, localpath string, opt *ObjectGetOptions, id ...string) (*Response, error) { + resp, err := s.Get(ctx, name, opt, id...) + if err != nil { + return resp, err + } + defer resp.Body.Close() + + // If file exist, overwrite it + fd, err := os.OpenFile(localpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660) + if err != nil { + return resp, err + } + + _, err = io.Copy(fd, resp.Body) + fd.Close() + if err != nil { + return resp, err + } + + return resp, nil +} + +func (s *ObjectService) GetObjectURL(name string) *url.URL { + uri, _ := url.Parse("/" + encodeURIComponent(name, []byte{'/'})) + return s.client.BaseURL.BucketURL.ResolveReference(uri) +} + +type PresignedURLOptions struct { + Query *url.Values `xml:"-" url:"-" header:"-"` + Header *http.Header `header:"-,omitempty" url:"-" xml:"-"` + SignMerged bool `xml:"-" url:"-" header:"-"` + AuthTime *AuthTime `xml:"-" url:"-" header:"-"` + EncodeDelimiter bool `xml:"-" url:"-" header:"-"` + EnablePathMerge bool `xml:"-" url:"-" header:"-"` +} + +// GetPresignedURL get the object presigned to down or upload file by url +// 预签名函数,signHost: 默认签入Header Host, 您也可以选择不签入Header Host,但可能导致请求失败或安全漏洞 +func (s *ObjectService) GetPresignedURL(ctx context.Context, httpMethod, name, ak, sk string, expired time.Duration, opt interface{}, signHost ...bool) (*url.URL, error) { + if name == "" { + return nil, fmt.Errorf("object key is empty.") + } + // 兼容 name 以 / 开头的情况 + if strings.HasPrefix(name, "/") { + name = encodeURIComponent("/") + encodeURIComponent(name[1:], []byte{'/'}) + } else { + name = encodeURIComponent(name, []byte{'/'}) + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + name, + method: httpMethod, + optQuery: opt, + optHeader: opt, + } + var authTime *AuthTime + var enablePathMerge bool + if opt != nil { + if popt, ok := opt.(*presignedURLTestingOptions); ok { + authTime = popt.authTime + } + if popt, ok := opt.(*PresignedURLOptions); ok { + if popt.Query != nil { + qs := popt.Query.Encode() + if qs != "" { + sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + } + } + if popt.AuthTime != nil { + authTime = popt.AuthTime + } + if popt.EnablePathMerge { + enablePathMerge = true + } + } + } + req, err := s.client.newPresignedRequest(ctx, &sendOpt, enablePathMerge) + if err != nil { + return nil, err + } + + if authTime == nil { + authTime = NewAuthTime(expired) + } + signedHost := true + if len(signHost) > 0 { + signedHost = signHost[0] + } + authorization := newAuthorization(ak, sk, req, authTime, signedHost) + if opt != nil { + if opt, ok := opt.(*PresignedURLOptions); ok { + if opt.SignMerged { + sign := encodeURIComponent(authorization) + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("sign=%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&sign=%s", req.URL.RawQuery, sign) + } + return req.URL, nil + } + } + } + sign := encodeURIComponent(authorization, []byte{'&', '='}) + + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&%s", req.URL.RawQuery, sign) + } + return req.URL, nil +} + +func (s *ObjectService) GetPresignedURL2(ctx context.Context, httpMethod, name string, expired time.Duration, opt interface{}, signHost ...bool) (*url.URL, error) { + if name == "" { + return nil, fmt.Errorf("object key is empty.") + } + // 兼容 name 以 / 开头的情况 + if strings.HasPrefix(name, "/") { + name = encodeURIComponent("/") + encodeURIComponent(name[1:], []byte{'/'}) + } else { + name = encodeURIComponent(name, []byte{'/'}) + } + + cred := s.client.GetCredential() + if cred == nil { + return nil, fmt.Errorf("GetCredential failed") + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + name, + method: httpMethod, + optQuery: opt, + optHeader: opt, + } + var enablePathMerge bool + var authTime *AuthTime + mark := "?" + if opt != nil { + if popt, ok := opt.(*presignedURLTestingOptions); ok { + authTime = popt.authTime + } + if popt, ok := opt.(*PresignedURLOptions); ok { + if popt.Query != nil { + qs := popt.Query.Encode() + if qs != "" { + sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + mark = "&" + } + } + if popt.AuthTime != nil { + authTime = popt.AuthTime + } + if popt.EnablePathMerge { + enablePathMerge = true + } + } + } + if cred.SessionToken != "" { + sendOpt.uri = fmt.Sprintf("%s%s%s", sendOpt.uri, mark, url.Values{"x-cos-security-token": []string{cred.SessionToken}}.Encode()) + } + + req, err := s.client.newPresignedRequest(ctx, &sendOpt, enablePathMerge) + if err != nil { + return nil, err + } + + if authTime == nil { + authTime = NewAuthTime(expired) + } + signedHost := true + if len(signHost) > 0 { + signedHost = signHost[0] + } + authorization := newAuthorization(cred.SecretID, cred.SecretKey, req, authTime, signedHost) + if opt != nil { + if opt, ok := opt.(*PresignedURLOptions); ok { + if opt.SignMerged { + sign := encodeURIComponent(authorization) + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("sign=%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&sign=%s", req.URL.RawQuery, sign) + } + return req.URL, nil + } + } + } + sign := encodeURIComponent(authorization, []byte{'&', '='}) + + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&%s", req.URL.RawQuery, sign) + } + return req.URL, nil +} + +func (s *ObjectService) GetPresignedURL3(ctx context.Context, httpMethod, name string, expired time.Duration, opt interface{}, signHost ...bool) (*url.URL, error) { + if name == "" { + return nil, fmt.Errorf("object key is empty.") + } + var encodeDelimiter bool + if opt != nil { + if popt, ok := opt.(*PresignedURLOptions); ok { + encodeDelimiter = popt.EncodeDelimiter + } + } + if encodeDelimiter { + name = encodeURIComponent(name) + } else { + name = encodeURIComponent(name, []byte("/")) + } + + cred := s.client.GetCredential() + if cred == nil { + return nil, fmt.Errorf("GetCredential failed") + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + name, + method: httpMethod, + optQuery: opt, + optHeader: opt, + } + var enablePathMerge bool + var authTime *AuthTime + mark := "?" + if opt != nil { + if popt, ok := opt.(*presignedURLTestingOptions); ok { + authTime = popt.authTime + } + if popt, ok := opt.(*PresignedURLOptions); ok { + if popt.Query != nil { + qs := popt.Query.Encode() + if qs != "" { + sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + mark = "&" + } + } + if popt.AuthTime != nil { + authTime = popt.AuthTime + } + if popt.EnablePathMerge { + enablePathMerge = true + } + } + } + if cred.SessionToken != "" { + sendOpt.uri = fmt.Sprintf("%s%s%s", sendOpt.uri, mark, url.Values{"x-cos-security-token": []string{cred.SessionToken}}.Encode()) + } + + req, err := s.client.newPresignedRequest(ctx, &sendOpt, enablePathMerge) + if err != nil { + return nil, err + } + + if authTime == nil { + authTime = NewAuthTime(expired) + } + signedHost := true + if len(signHost) > 0 { + signedHost = signHost[0] + } + authorization := newAuthorization(cred.SecretID, cred.SecretKey, req, authTime, signedHost) + if opt != nil { + if opt, ok := opt.(*PresignedURLOptions); ok { + if opt.SignMerged { + sign := encodeURIComponent(authorization) + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("sign=%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&sign=%s", req.URL.RawQuery, sign) + } + return req.URL, nil + } + } + } + sign := encodeURIComponent(authorization, []byte{'&', '='}) + + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&%s", req.URL.RawQuery, sign) + } + return req.URL, nil +} + +func (s *ObjectService) GetSignature(ctx context.Context, httpMethod, name, ak, sk string, expired time.Duration, opt *PresignedURLOptions, signHost ...bool) string { + // 兼容 name 以 / 开头的情况 + name = encodeURIComponent(name) + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + name, + method: httpMethod, + optQuery: opt, + optHeader: opt, + } + if opt != nil && opt.Query != nil { + qs := opt.Query.Encode() + if qs != "" { + sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + } + } + req, err := s.client.newPresignedRequest(ctx, &sendOpt, false) + if err != nil { + return "" + } + + authTime := NewAuthTime(expired) + signedHost := true + if len(signHost) > 0 { + signedHost = signHost[0] + } + authorization := newAuthorization(ak, sk, req, authTime, signedHost) + return authorization +} + +// ObjectPutHeaderOptions the options of header of the put object +type ObjectPutHeaderOptions struct { + CacheControl string `header:"Cache-Control,omitempty" url:"-"` + ContentDisposition string `header:"Content-Disposition,omitempty" url:"-"` + ContentEncoding string `header:"Content-Encoding,omitempty" url:"-"` + ContentType string `header:"Content-Type,omitempty" url:"-"` + ContentMD5 string `header:"Content-MD5,omitempty" url:"-"` + ContentLength int64 `header:"Content-Length,omitempty" url:"-"` + ContentLanguage string `header:"Content-Language,omitempty" url:"-"` + Expect string `header:"Expect,omitempty" url:"-"` + Expires string `header:"Expires,omitempty" url:"-"` + XCosContentSHA1 string `header:"x-cos-content-sha1,omitempty" url:"-"` + // 自定义的 x-cos-meta-* header + XCosMetaXXX *http.Header `header:"x-cos-meta-*,omitempty" url:"-"` + XCosStorageClass string `header:"x-cos-storage-class,omitempty" url:"-"` + // 可选值: Normal, Appendable + //XCosObjectType string `header:"x-cos-object-type,omitempty" url:"-"` + // Enable Server Side Encryption, Only supported: AES256 + XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-" xml:"-"` + // SSE-C + XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + //兼容其他自定义头部 + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` + XCosTrafficLimit int `header:"x-cos-traffic-limit,omitempty" url:"-" xml:"-"` + + // 上传进度, ProgressCompleteEvent不能表示对应API调用成功,API是否调用成功的判断标准为返回err==nil + Listener ProgressListener `header:"-" url:"-" xml:"-"` +} + +// ObjectPutOptions the options of put object +type ObjectPutOptions struct { + *ACLHeaderOptions `header:",omitempty" url:"-" xml:"-"` + *ObjectPutHeaderOptions `header:",omitempty" url:"-" xml:"-"` + + // PutFromFile 使用 + innerSwitchURL *url.URL `header:"-" url:"-" xml:"-"` +} + +// Put Object请求可以将一个文件(Oject)上传至指定Bucket。 +// +// https://www.qcloud.com/document/product/436/7749 +func (s *ObjectService) Put(ctx context.Context, name string, r io.Reader, uopt *ObjectPutOptions) (*Response, error) { + if r == nil { + return nil, fmt.Errorf("reader is nil") + } + if err := CheckReaderLen(r); err != nil { + return nil, err + } + opt := CloneObjectPutOptions(uopt) + totalBytes, err := GetReaderLen(r) + if err != nil && opt != nil && opt.Listener != nil { + if opt.ContentLength == 0 { + return nil, err + } + totalBytes = opt.ContentLength + } + if err == nil { + // 非bytes.Buffer/bytes.Reader/strings.Reader/os.File 由用户指定ContentLength, 或使用 Chunk 上传 + if opt != nil && opt.ContentLength == 0 && IsLenReader(r) { + opt.ContentLength = totalBytes + } + } + // 如果是io.Seeker,则重试 + count := 1 + var position int64 + if seeker, ok := r.(io.Seeker); ok { + // 记录原始位置 + position, err = seeker.Seek(0, io.SeekCurrent) + if err == nil && s.client.Conf.RetryOpt.Count > 0 { + count = s.client.Conf.RetryOpt.Count + } + } + var resp *Response + var retrieable bool + sUrl := s.client.BaseURL.BucketURL + if opt.innerSwitchURL != nil { + sUrl = opt.innerSwitchURL + } + retryErr := &RetryError{} + for nr := 0; nr < count; nr++ { + reader := TeeReader(r, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + } + if opt != nil && opt.Listener != nil { + reader.listener = opt.Listener + } + sendOpt := sendOptions{ + baseURL: sUrl, + uri: "/" + encodeURIComponent(name), + method: http.MethodPut, + body: reader, + optHeader: opt, + isRetry: nr > 0, + } + + // 把上一次错误记录下来 + if err != nil { + retryErr.Add(err) + } + resp, err = s.client.send(ctx, &sendOpt) + sUrl, retrieable = s.client.CheckRetrieable(sUrl, resp, err, nr >= count-2) + if retrieable && nr+1 < count { + if seeker, ok := r.(io.Seeker); ok { + _, e := seeker.Seek(position, io.SeekStart) + if e != nil { + break + } + continue + } + } + break + } + if err != nil { + if _, ok := err.(*ErrorResponse); !ok { + retryErr.Add(err) + err = retryErr + } + } + + return resp, err +} + +// PutFromFile put object from local file +func (s *ObjectService) PutFromFile(ctx context.Context, name string, filePath string, uopt *ObjectPutOptions) (resp *Response, err error) { + opt := CloneObjectPutOptions(uopt) + nr := 0 + for nr < 3 { + fd, e := os.Open(filePath) + if e != nil { + err = e + return + } + resp, err = s.Put(ctx, name, fd, opt) + if err != nil { + nr++ + fd.Close() + if s.client.Conf.RetryOpt.AutoSwitchHost { + // 收不到报文 或者 不存在RequestId + if resp == nil || resp.Header.Get("X-Cos-Request-Id") == "" { + opt.innerSwitchURL = toSwitchHost(s.client.BaseURL.BucketURL) + } + } + continue + } + fd.Close() + break + } + return +} + +// ObjectCopyHeaderOptions is the head option of the Copy +type ObjectCopyHeaderOptions struct { + // When use replace directive to update meta infos + CacheControl string `header:"Cache-Control,omitempty" url:"-"` + ContentDisposition string `header:"Content-Disposition,omitempty" url:"-"` + ContentEncoding string `header:"Content-Encoding,omitempty" url:"-"` + ContentLanguage string `header:"Content-Language,omitempty" url:"-"` + ContentType string `header:"Content-Type,omitempty" url:"-"` + Expires string `header:"Expires,omitempty" url:"-"` + Expect string `header:"Expect,omitempty" url:"-"` + XCosMetadataDirective string `header:"x-cos-metadata-directive,omitempty" url:"-" xml:"-"` + XCosCopySourceIfModifiedSince string `header:"x-cos-copy-source-If-Modified-Since,omitempty" url:"-" xml:"-"` + XCosCopySourceIfUnmodifiedSince string `header:"x-cos-copy-source-If-Unmodified-Since,omitempty" url:"-" xml:"-"` + XCosCopySourceIfMatch string `header:"x-cos-copy-source-If-Match,omitempty" url:"-" xml:"-"` + XCosCopySourceIfNoneMatch string `header:"x-cos-copy-source-If-None-Match,omitempty" url:"-" xml:"-"` + XCosStorageClass string `header:"x-cos-storage-class,omitempty" url:"-" xml:"-"` + // 自定义的 x-cos-meta-* header + XCosMetaXXX *http.Header `header:"x-cos-meta-*,omitempty" url:"-"` + XCosCopySource string `header:"x-cos-copy-source" url:"-" xml:"-"` + XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-" xml:"-"` + // SSE-C + XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + XCosCopySourceSSECustomerAglo string `header:"x-cos-copy-source-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosCopySourceSSECustomerKey string `header:"x-cos-copy-source-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosCopySourceSSECustomerKeyMD5 string `header:"x-cos-copy-source-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + //兼容其他自定义头部 + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// ObjectCopyOptions is the option of Copy, choose header or body +type ObjectCopyOptions struct { + *ObjectCopyHeaderOptions `header:",omitempty" url:"-" xml:"-"` + *ACLHeaderOptions `header:",omitempty" url:"-" xml:"-"` +} + +// ObjectCopyResult is the result of Copy +type ObjectCopyResult struct { + XMLName xml.Name `xml:"CopyObjectResult"` + ETag string `xml:"ETag,omitempty"` + LastModified string `xml:"LastModified,omitempty"` + CRC64 string `xml:"CRC64,omitempty"` + VersionId string `xml:"VersionId,omitempty"` +} + +// Copy 调用 PutObjectCopy 请求实现将一个文件从源路径复制到目标路径。建议文件大小 1M 到 5G, +// 超过 5G 的文件请使用分块上传 Upload - Copy。在拷贝的过程中,文件元属性和 ACL 可以被修改。 +// +// 用户可以通过该接口实现文件移动,文件重命名,修改文件属性和创建副本。 +// +// 注意:在跨帐号复制的时候,需要先设置被复制文件的权限为公有读,或者对目标帐号赋权,同帐号则不需要。 +// +// https://cloud.tencent.com/document/product/436/10881 +func (s *ObjectService) Copy(ctx context.Context, name, sourceURL string, opt *ObjectCopyOptions, id ...string) (*ObjectCopyResult, *Response, error) { + if strings.HasPrefix(sourceURL, "http://") || strings.HasPrefix(sourceURL, "https://") { + return nil, nil, errors.New("sourceURL format is invalid.") + } + surl := strings.SplitN(sourceURL, "/", 2) + if len(surl) < 2 { + return nil, nil, errors.New(fmt.Sprintf("x-cos-copy-source format error: %s", sourceURL)) + } + var u string + if len(id) == 1 { + u = fmt.Sprintf("%s/%s?versionId=%s", surl[0], encodeURIComponent(surl[1]), id[0]) + } else if len(id) == 0 { + keyAndVer := strings.SplitN(surl[1], "?", 2) + if len(keyAndVer) < 2 { + u = fmt.Sprintf("%s/%s", surl[0], encodeURIComponent(surl[1], []byte{'/'})) + } else { + u = fmt.Sprintf("%v/%v?%v", surl[0], encodeURIComponent(keyAndVer[0], []byte{'/'}), encodeURIComponent(keyAndVer[1], []byte{'='})) + } + } else { + return nil, nil, errors.New("wrong params") + } + + var res ObjectCopyResult + copyOpt := &ObjectCopyOptions{ + &ObjectCopyHeaderOptions{}, + &ACLHeaderOptions{}, + } + if opt != nil { + if opt.ObjectCopyHeaderOptions != nil { + *copyOpt.ObjectCopyHeaderOptions = *opt.ObjectCopyHeaderOptions + } + if opt.ACLHeaderOptions != nil { + *copyOpt.ACLHeaderOptions = *opt.ACLHeaderOptions + } + } + copyOpt.XCosCopySource = u + + var bs bytes.Buffer + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name), + method: http.MethodPut, + body: nil, + optHeader: copyOpt, + result: &bs, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + + if err == nil { // 请求正常 + err = xml.Unmarshal(bs.Bytes(), &res) // body 正常返回 + // If the error occurs during the copy operation, the error response is embedded in the 200 OK response. This means that a 200 OK response can contain either a success or an error. + if resp != nil && resp.StatusCode == 200 { + if err != nil { + resErr := &ErrorResponse{Response: resp.Response} + xml.Unmarshal(bs.Bytes(), resErr) + return &res, resp, resErr + } + } + } + + return &res, resp, err +} + +type ObjectDeleteOptions struct { + // SSE-C + XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + //兼容其他自定义头部 + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` + XOptionQuery *url.Values `header:"-" url:"-" xml:"-"` + VersionId string `header:"-" url:"VersionId,omitempty" xml:"-"` +} + +// Delete Object请求可以将一个文件(Object)删除。 +// +// https://www.qcloud.com/document/product/436/7743 +func (s *ObjectService) Delete(ctx context.Context, name string, opt ...*ObjectDeleteOptions) (*Response, error) { + var optHeader *ObjectDeleteOptions + if len(name) == 0 || name == "/" { + return nil, errors.New("empty object name") + } + // When use "" string might call the delete bucket interface + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } + + if len(opt) > 0 { + optHeader = opt[0] + } + uri := "/" + encodeURIComponent(name) + if optHeader != nil && optHeader.XOptionQuery != nil { + uri = uri + "?" + optHeader.XOptionQuery.Encode() + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: uri, + method: http.MethodDelete, + optHeader: optHeader, + optQuery: optHeader, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +// ObjectHeadOptions is the option of HeadObject +type ObjectHeadOptions struct { + IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"` + // SSE-C + XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// Head Object请求可以取回对应Object的元数据,Head的权限与Get的权限一致 +// +// https://www.qcloud.com/document/product/436/7745 +func (s *ObjectService) Head(ctx context.Context, name string, opt *ObjectHeadOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = "/" + encodeURIComponent(name) + } else { + return nil, errors.New("wrong params") + } + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodHead, + optHeader: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + if resp != nil && resp.Header["X-Cos-Object-Type"] != nil && resp.Header["X-Cos-Object-Type"][0] == "appendable" { + resp.Header.Add("x-cos-next-append-position", resp.Header.Get("Content-Length")) + } + + return resp, err +} + +func (s *ObjectService) IsExist(ctx context.Context, name string, id ...string) (bool, error) { + _, err := s.Head(ctx, name, nil, id...) + if err == nil { + return true, nil + } + if IsNotFoundError(err) { + return false, nil + } + return false, err +} + +// ObjectOptionsOptions is the option of object options +type ObjectOptionsOptions struct { + Origin string `url:"-" header:"Origin"` + AccessControlRequestMethod string `url:"-" header:"Access-Control-Request-Method"` + AccessControlRequestHeaders string `url:"-" header:"Access-Control-Request-Headers,omitempty"` +} + +// Options Object请求实现跨域访问的预请求。即发出一个 OPTIONS 请求给服务器以确认是否可以进行跨域操作。 +// +// 当CORS配置不存在时,请求返回403 Forbidden。 +// +// https://www.qcloud.com/document/product/436/8288 +func (s *ObjectService) Options(ctx context.Context, name string, opt *ObjectOptionsOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name), + method: http.MethodOptions, + optHeader: opt, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +// CASJobParameters support three way: Standard(in 35 hours), Expedited(quick way, in 15 mins), Bulk(in 5-12 hours_ +type CASJobParameters struct { + Tier string `xml:"Tier" header:"-" url:"-"` +} + +// ObjectRestoreOptions is the option of object restore +type ObjectRestoreOptions struct { + XMLName xml.Name `xml:"RestoreRequest" header:"-" url:"-"` + Days int `xml:"Days,omitempty" header:"-" url:"-"` + Tier *CASJobParameters `xml:"CASJobParameters" header:"-" url:"-"` + XOptionHeader *http.Header `xml:"-" header:",omitempty" url:"-"` +} + +// PutRestore API can recover an object of type archived by COS archive. +// +// https://cloud.tencent.com/document/product/436/12633 +func (s *ObjectService) PostRestore(ctx context.Context, name string, opt *ObjectRestoreOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?restore&versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?restore", encodeURIComponent(name)) + } else { + return nil, errors.New("wrong params") + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPost, + body: opt, + optHeader: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + + return resp, err +} + +// Append请求可以将一个文件(Object)以分块追加的方式上传至 Bucket 中。使用Append Upload的文件必须事前被设定为Appendable。 +// 当Appendable的文件被执行Put Object的操作以后,文件被覆盖,属性改变为Normal。 +// +// 文件属性可以在Head Object操作中被查询到,当您发起Head Object请求时,会返回自定义Header『x-cos-object-type』,该Header只有两个枚举值:Normal或者Appendable。 +// +// 追加上传建议文件大小1M - 5G。如果position的值和当前Object的长度不致,COS会返回409错误。 +// 如果Append一个Normal的Object,COS会返回409 ObjectNotAppendable。 +// +// Appendable的文件不可以被复制,不参与版本管理,不参与生命周期管理,不可跨区域复制。 +// +// 当 r 不是 bytes.Buffer/bytes.Reader/strings.Reader 时,必须指定 opt.ObjectPutHeaderOptions.ContentLength +// +// https://www.qcloud.com/document/product/436/7741 +func (s *ObjectService) Append(ctx context.Context, name string, position int, r io.Reader, opt *ObjectPutOptions) (int, *Response, error) { + res := position + if r == nil { + return res, nil, fmt.Errorf("reader is nil") + } + if err := CheckReaderLen(r); err != nil { + return res, nil, err + } + opt = CloneObjectPutOptions(opt) + totalBytes, err := GetReaderLen(r) + if err != nil && opt != nil && opt.Listener != nil { + if opt.ContentLength == 0 { + return res, nil, err + } + totalBytes = opt.ContentLength + } + if err == nil { + // 非bytes.Buffer/bytes.Reader/strings.Reader/os.File 由用户指定ContentLength, 或使用 Chunk 上传 + if opt != nil && opt.ContentLength == 0 && IsLenReader(r) { + opt.ContentLength = totalBytes + } + } + reader := TeeReader(r, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + reader.writer = md5.New() // MD5校验 + reader.disableCheckSum = true + } + if opt != nil && opt.Listener != nil { + reader.listener = opt.Listener + } + u := fmt.Sprintf("/%s?append&position=%d", encodeURIComponent(name), position) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPost, + optHeader: opt, + body: reader, + } + resp, err := s.client.send(ctx, &sendOpt) + + if err == nil { + // 数据校验 + if s.client.Conf.EnableCRC && reader.writer != nil { + wanted := hex.EncodeToString(reader.Sum()) + if wanted != resp.Header.Get("x-cos-content-sha1") { + return res, resp, fmt.Errorf("append verification failed, want:%v, return:%v, header:%+v", wanted, resp.Header.Get("x-cos-content-sha1"), resp.Header) + } + } + np, err := strconv.ParseInt(resp.Header.Get("x-cos-next-append-position"), 10, 64) + return int(np), resp, err + } + return res, resp, err +} + +// ObjectDeleteMultiOptions is the option of DeleteMulti +type ObjectDeleteMultiOptions struct { + XMLName xml.Name `xml:"Delete" header:"-"` + Quiet bool `xml:"Quiet" header:"-"` + Objects []Object `xml:"Object" header:"-"` + //XCosSha1 string `xml:"-" header:"x-cos-sha1"` +} + +// ObjectDeleteMultiResult is the result of DeleteMulti +type ObjectDeleteMultiResult struct { + XMLName xml.Name `xml:"DeleteResult"` + DeletedObjects []Object `xml:"Deleted,omitempty"` + Errors []struct { + Key string `xml:",omitempty"` + Code string `xml:",omitempty"` + Message string `xml:",omitempty"` + VersionId string `xml:",omitempty"` + } `xml:"Error,omitempty"` +} + +// DeleteMulti 请求实现批量删除文件,最大支持单次删除1000个文件。 +// 对于返回结果,COS提供Verbose和Quiet两种结果模式。Verbose模式将返回每个Object的删除结果; +// Quiet模式只返回报错的Object信息。 +// https://www.qcloud.com/document/product/436/8289 +func (s *ObjectService) DeleteMulti(ctx context.Context, opt *ObjectDeleteMultiOptions) (*ObjectDeleteMultiResult, *Response, error) { + var res ObjectDeleteMultiResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?delete", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +// Object is the meta info of the object +type Object struct { + Key string `xml:",omitempty"` + ETag string `xml:",omitempty"` + Size int64 `xml:",omitempty"` + PartNumber int `xml:",omitempty"` + LastModified string `xml:",omitempty"` + StorageClass string `xml:",omitempty"` + Owner *Owner `xml:",omitempty"` + VersionId string `xml:",omitempty"` + StorageTier string `xml:",omitempty"` + RestoreStatus string `xml:",omitempty"` +} + +// MultiUploadOptions is the option of the multiupload, +// ThreadPoolSize default is one +type MultiUploadOptions struct { + OptIni *InitiateMultipartUploadOptions + PartSize int64 + ThreadPoolSize int + CheckPoint bool + DisableChecksum bool +} + +type MultiDownloadOptions struct { + Opt *ObjectGetOptions + PartSize int64 + ThreadPoolSize int + CheckPoint bool + CheckPointFile string + DisableChecksum bool +} + +type MultiDownloadCPInfo struct { + Size int64 `json:"contentLength,omitempty"` + ETag string `json:"eTag,omitempty"` + CRC64 string `json:"crc64ecma,omitempty"` + LastModified string `json:"lastModified,omitempty"` + DownloadedBlocks []DownloadedBlock `json:"downloadedBlocks,omitempty"` +} +type DownloadedBlock struct { + From int64 `json:"from,omitempty"` + To int64 `json:"to,omitempty"` +} + +type Chunk struct { + Number int + OffSet int64 + Size int64 + Done bool + ETag string +} + +// jobs +type Jobs struct { + Name string + UploadId string + FilePath string + RetryTimes int + VersionId []string + Chunk Chunk + Data io.Reader + Opt *ObjectUploadPartOptions + DownOpt *ObjectGetOptions +} + +type Results struct { + PartNumber int + Resp *Response + err error +} + +func LimitReadCloser(r io.Reader, n int64) io.Reader { + var lc LimitedReadCloser + lc.R = r + lc.N = n + return &lc +} + +type LimitedReadCloser struct { + io.LimitedReader +} + +func (lc *LimitedReadCloser) Close() error { + if r, ok := lc.R.(io.ReadCloser); ok { + return r.Close() + } + return nil +} + +type DiscardReadCloser struct { + RC io.ReadCloser + Discard int +} + +func (drc *DiscardReadCloser) Read(data []byte) (int, error) { + n, err := drc.RC.Read(data) + if drc.Discard == 0 || n <= 0 { + return n, err + } + + if n <= drc.Discard { + drc.Discard -= n + return 0, err + } + + realLen := n - drc.Discard + copy(data[0:realLen], data[drc.Discard:n]) + drc.Discard = 0 + return realLen, err +} + +func (drc *DiscardReadCloser) Close() error { + if rc, ok := drc.RC.(io.ReadCloser); ok { + return rc.Close() + } + return nil +} + +func worker(ctx context.Context, s *ObjectService, jobs <-chan *Jobs, results chan<- *Results) { + for j := range jobs { + j.Opt.ContentLength = j.Chunk.Size + + rt := j.RetryTimes + for { + // http.Request.Body can be Closed in request + fd, err := os.Open(j.FilePath) + var res Results + if err != nil { + res.err = err + res.PartNumber = j.Chunk.Number + res.Resp = nil + results <- &res + break + } + fd.Seek(j.Chunk.OffSet, os.SEEK_SET) + resp, err := s.UploadPart(ctx, j.Name, j.UploadId, j.Chunk.Number, + LimitReadCloser(fd, j.Chunk.Size), j.Opt) + res.PartNumber = j.Chunk.Number + res.Resp = resp + res.err = err + if err != nil { + rt-- + if rt == 0 { + results <- &res + break + } + if s.client.Conf.RetryOpt.AutoSwitchHost { + // 收不到报文 或者 不存在RequestId + if resp == nil || resp.Header.Get("X-Cos-Request-Id") == "" { + j.Opt.innerSwitchURL = toSwitchHost(s.client.BaseURL.BucketURL) + } + } + time.Sleep(time.Millisecond) + continue + } + results <- &res + break + } + } +} + +func downloadWorker(ctx context.Context, s *ObjectService, jobs <-chan *Jobs, results chan<- *Results) { + for j := range jobs { + opt := &RangeOptions{ + HasStart: true, + HasEnd: true, + Start: j.Chunk.OffSet, + End: j.Chunk.OffSet + j.Chunk.Size - 1, + } + j.DownOpt.Range = FormatRangeOptions(opt) + rt := j.RetryTimes + for { + var res Results + res.PartNumber = j.Chunk.Number + resp, err := s.Get(ctx, j.Name, j.DownOpt, j.VersionId...) + res.err = err + res.Resp = resp + if err != nil { + results <- &res + break + } + fd, err := os.OpenFile(j.FilePath, os.O_WRONLY, 0660) + if err != nil { + resp.Body.Close() + res.err = err + results <- &res + break + } + fd.Seek(j.Chunk.OffSet, os.SEEK_SET) + n, err := io.Copy(fd, LimitReadCloser(resp.Body, j.Chunk.Size)) + if n != j.Chunk.Size || err != nil { + fd.Close() + resp.Body.Close() + rt-- + if rt == 0 { + res.err = fmt.Errorf("io.Copy Failed, nread:%v, want:%v, err:%v", n, j.Chunk.Size, err) + results <- &res + break + } + time.Sleep(time.Millisecond) + continue + } + fd.Close() + resp.Body.Close() + results <- &res + break + } + } +} + +func DividePart(fileSize int64, last int) (int64, int64) { + partSize := int64(last * 1024 * 1024) + partNum := fileSize / partSize + for partNum >= 10000 { + partSize = partSize * 2 + partNum = fileSize / partSize + } + return partNum, partSize +} + +func SplitFileIntoChunks(filePath string, partSize int64) (int64, []Chunk, int, error) { + if filePath == "" { + return 0, nil, 0, errors.New("filePath invalid") + } + + file, err := os.Open(filePath) + if err != nil { + return 0, nil, 0, err + } + defer file.Close() + + stat, err := file.Stat() + if err != nil { + return 0, nil, 0, err + } + var partNum int64 + if partSize > 0 { + if partSize < 1024*1024 { + return 0, nil, 0, errors.New("partSize>=1048576 is required") + } + partNum = stat.Size() / partSize + if partNum >= 10000 { + return 0, nil, 0, errors.New("Too many parts, out of 10000") + } + } else { + partNum, partSize = DividePart(stat.Size(), 16) + } + + var chunks []Chunk + var chunk = Chunk{} + for i := int64(0); i < partNum; i++ { + chunk.Number = int(i + 1) + chunk.OffSet = i * partSize + chunk.Size = partSize + chunks = append(chunks, chunk) + } + + if stat.Size()%partSize > 0 { + chunk.Number = len(chunks) + 1 + chunk.OffSet = int64(len(chunks)) * partSize + chunk.Size = stat.Size() % partSize + chunks = append(chunks, chunk) + partNum++ + } + + return int64(stat.Size()), chunks, int(partNum), nil + +} + +func (s *ObjectService) getResumableUploadID(ctx context.Context, name string) (string, error) { + opt := &ObjectListUploadsOptions{ + Prefix: name, + EncodingType: "url", + } + res, _, err := s.ListUploads(ctx, opt) + if err != nil { + return "", err + } + if len(res.Upload) == 0 { + return "", nil + } + last := len(res.Upload) - 1 + for last >= 0 { + decodeKey, _ := decodeURIComponent(res.Upload[last].Key) + if decodeKey == name { + return decodeURIComponent(res.Upload[last].UploadID) + } + last = last - 1 + } + return "", nil +} + +func (s *ObjectService) checkUploadedParts(ctx context.Context, name, UploadID, filepath string, chunks []Chunk, partNum int) error { + var uploadedParts []Object + isTruncated := true + opt := &ObjectListPartsOptions{ + EncodingType: "url", + } + for isTruncated { + res, _, err := s.ListParts(ctx, name, UploadID, opt) + if err != nil { + return err + } + if len(res.Parts) > 0 { + uploadedParts = append(uploadedParts, res.Parts...) + } + isTruncated = res.IsTruncated + opt.PartNumberMarker = res.NextPartNumberMarker + } + fd, err := os.Open(filepath) + if err != nil { + return err + } + defer fd.Close() + // 某个分块出错, 重置chunks + ret := func(e error) error { + for i, _ := range chunks { + chunks[i].Done = false + chunks[i].ETag = "" + } + return e + } + for _, part := range uploadedParts { + partNumber := part.PartNumber + if partNumber > partNum { + return ret(errors.New("Part Number is not consistent")) + } + partNumber = partNumber - 1 + fd.Seek(chunks[partNumber].OffSet, os.SEEK_SET) + bs, err := ioutil.ReadAll(io.LimitReader(fd, chunks[partNumber].Size)) + if err != nil { + return ret(err) + } + localMD5 := fmt.Sprintf("\"%x\"", md5.Sum(bs)) + if localMD5 != part.ETag { + return ret(errors.New(fmt.Sprintf("CheckSum Failed in Part[%d]", part.PartNumber))) + } + chunks[partNumber].Done = true + chunks[partNumber].ETag = part.ETag + } + return nil +} + +// MultiUpload/Upload 为高级upload接口,并发分块上传 +// +// 当 partSize > 0 时,由调用者指定分块大小,否则由 SDK 自动切分,单位为MB +// 由调用者指定分块大小时,请确认分块数量不超过10000 +func (s *ObjectService) MultiUpload(ctx context.Context, name string, filepath string, opt *MultiUploadOptions) (*CompleteMultipartUploadResult, *Response, error) { + return s.Upload(ctx, name, filepath, opt) +} + +func (s *ObjectService) Upload(ctx context.Context, name string, filepath string, opt *MultiUploadOptions) (*CompleteMultipartUploadResult, *Response, error) { + if opt == nil { + opt = &MultiUploadOptions{} + } + var localcrc uint64 + // 1.Get the file chunk + totalBytes, chunks, partNum, err := SplitFileIntoChunks(filepath, opt.PartSize*1024*1024) + if err != nil { + return nil, nil, err + } + // 校验 + if s.client.Conf.EnableCRC && !opt.DisableChecksum { + fd, err := os.Open(filepath) + if err != nil { + return nil, nil, err + } + defer fd.Close() + localcrc, err = calCRC64(fd) + if err != nil { + return nil, nil, err + } + } + // filesize=0 , use simple upload + if partNum == 0 || partNum == 1 { + var opt0 *ObjectPutOptions + if opt.OptIni != nil { + opt0 = &ObjectPutOptions{ + opt.OptIni.ACLHeaderOptions, + opt.OptIni.ObjectPutHeaderOptions, + nil, + } + } + rsp, err := s.PutFromFile(ctx, name, filepath, opt0) + if err != nil { + return nil, rsp, err + } + result := &CompleteMultipartUploadResult{ + Location: fmt.Sprintf("%s/%s", s.client.BaseURL.BucketURL, name), + Key: name, + ETag: rsp.Header.Get("ETag"), + } + if rsp != nil && s.client.Conf.EnableCRC && !opt.DisableChecksum { + scoscrc := rsp.Header.Get("x-cos-hash-crc64ecma") + icoscrc, _ := strconv.ParseUint(scoscrc, 10, 64) + if icoscrc != localcrc { + return result, rsp, fmt.Errorf("verification failed, want:%v, return:%v, header:%+v", localcrc, icoscrc, rsp.Header) + } + } + return result, rsp, nil + } + + var uploadID string + resumableFlag := false + if opt.CheckPoint { + var err error + uploadID, err = s.getResumableUploadID(ctx, name) + if err == nil && uploadID != "" { + err = s.checkUploadedParts(ctx, name, uploadID, filepath, chunks, partNum) + resumableFlag = (err == nil) + } + } + + // 2.Init + optini := opt.OptIni + if !resumableFlag { + res, _, err := s.InitiateMultipartUpload(ctx, name, optini) + if err != nil { + return nil, nil, err + } + uploadID = res.UploadID + } + var poolSize int + if opt.ThreadPoolSize > 0 { + poolSize = opt.ThreadPoolSize + } else { + // Default is one + poolSize = 1 + } + + chjobs := make(chan *Jobs, 100) + chresults := make(chan *Results, 10000) + optcom := &CompleteMultipartUploadOptions{} + + // 3.Start worker + for w := 1; w <= poolSize; w++ { + go worker(ctx, s, chjobs, chresults) + } + + // progress started event + var listener ProgressListener + var consumedBytes int64 + if opt.OptIni != nil { + if opt.OptIni.ObjectPutHeaderOptions != nil { + listener = opt.OptIni.Listener + } + optcom.XOptionHeader, _ = deliverInitOptions(opt.OptIni) + } + event := newProgressEvent(ProgressStartedEvent, 0, 0, totalBytes) + progressCallback(listener, event) + + // 4.Push jobs + go func() { + for _, chunk := range chunks { + if chunk.Done { + continue + } + partOpt := &ObjectUploadPartOptions{} + if optini != nil && optini.ObjectPutHeaderOptions != nil { + partOpt.XCosSSECustomerAglo = optini.XCosSSECustomerAglo + partOpt.XCosSSECustomerKey = optini.XCosSSECustomerKey + partOpt.XCosSSECustomerKeyMD5 = optini.XCosSSECustomerKeyMD5 + partOpt.XCosTrafficLimit = optini.XCosTrafficLimit + partOpt.XOptionHeader = optini.XOptionHeader + } + job := &Jobs{ + Name: name, + RetryTimes: 3, + FilePath: filepath, + UploadId: uploadID, + Chunk: chunk, + Opt: partOpt, + } + chjobs <- job + } + close(chjobs) + }() + + // 5.Recv the resp etag to complete + err = nil + for i := 0; i < partNum; i++ { + if chunks[i].Done { + optcom.Parts = append(optcom.Parts, Object{ + PartNumber: chunks[i].Number, ETag: chunks[i].ETag}, + ) + if err == nil { + consumedBytes += chunks[i].Size + event = newProgressEvent(ProgressDataEvent, chunks[i].Size, consumedBytes, totalBytes) + progressCallback(listener, event) + } + continue + } + res := <-chresults + // Notice one part fail can not get the etag according. + if res.Resp == nil || res.err != nil { + // Some part already fail, can not to get the header inside. + err = fmt.Errorf("UploadID %s, part %d failed to get resp content. error: %s", uploadID, res.PartNumber, res.err.Error()) + continue + } + // Notice one part fail can not get the etag according. + etag := res.Resp.Header.Get("ETag") + optcom.Parts = append(optcom.Parts, Object{ + PartNumber: res.PartNumber, ETag: etag}, + ) + if err == nil { + consumedBytes += chunks[res.PartNumber-1].Size + event = newProgressEvent(ProgressDataEvent, chunks[res.PartNumber-1].Size, consumedBytes, totalBytes) + progressCallback(listener, event) + } + } + close(chresults) + if err != nil { + event = newProgressEvent(ProgressFailedEvent, 0, consumedBytes, totalBytes, err) + progressCallback(listener, event) + return nil, nil, err + } + sort.Sort(ObjectList(optcom.Parts)) + + event = newProgressEvent(ProgressCompletedEvent, 0, consumedBytes, totalBytes) + progressCallback(listener, event) + + v, resp, err := s.CompleteMultipartUpload(context.Background(), name, uploadID, optcom) + if err != nil { + return v, resp, err + } + + if resp != nil && s.client.Conf.EnableCRC && !opt.DisableChecksum { + scoscrc := resp.Header.Get("x-cos-hash-crc64ecma") + icoscrc, err := strconv.ParseUint(scoscrc, 10, 64) + if icoscrc != localcrc { + return v, resp, fmt.Errorf("verification failed, want:%v, return:%v, x-cos-hash-crc64ecma: %v, err:%v, header:%+v", localcrc, icoscrc, scoscrc, err, resp.Header) + } + } + return v, resp, err +} + +func SplitSizeIntoChunks(totalBytes int64, partSize int64) ([]Chunk, int, error) { + var partNum int64 + if partSize > 0 { + if partSize < 1024*1024 { + return nil, 0, errors.New("partSize>=1048576 is required") + } + partNum = totalBytes / partSize + if partNum >= 10000 { + return nil, 0, errors.New("Too manry parts, out of 10000") + } + } else { + partNum, partSize = DividePart(totalBytes, 16) + } + + var chunks []Chunk + var chunk = Chunk{} + for i := int64(0); i < partNum; i++ { + chunk.Number = int(i + 1) + chunk.OffSet = i * partSize + chunk.Size = partSize + chunks = append(chunks, chunk) + } + + if totalBytes%partSize > 0 { + chunk.Number = len(chunks) + 1 + chunk.OffSet = int64(len(chunks)) * partSize + chunk.Size = totalBytes % partSize + chunks = append(chunks, chunk) + partNum++ + } + + return chunks, int(partNum), nil +} + +func SplitSizeIntoChunksToDownload(totalBytes int64, partSize int64) ([]Chunk, int, error) { + var partNum int64 + if partSize > 0 { + if partSize < 1024*1024 { + return nil, 0, errors.New("partSize>=1048576 is required") + } + partNum = totalBytes / partSize + } else { + partNum, partSize = DividePart(totalBytes, 16) + } + + var chunks []Chunk + var chunk = Chunk{} + for i := int64(0); i < partNum; i++ { + chunk.Number = int(i + 1) + chunk.OffSet = i * partSize + chunk.Size = partSize + chunks = append(chunks, chunk) + } + + if totalBytes%partSize > 0 { + chunk.Number = len(chunks) + 1 + chunk.OffSet = int64(len(chunks)) * partSize + chunk.Size = totalBytes % partSize + chunks = append(chunks, chunk) + partNum++ + } + + return chunks, int(partNum), nil +} + +func (s *ObjectService) checkDownloadedParts(opt *MultiDownloadCPInfo, chfile string, chunks []Chunk) (*MultiDownloadCPInfo, bool) { + var defaultRes MultiDownloadCPInfo + defaultRes = *opt + + fd, err := os.Open(chfile) + // checkpoint 文件不存在 + if err != nil && os.IsNotExist(err) { + // 创建 checkpoint 文件 + fd, _ = os.OpenFile(chfile, os.O_RDONLY|os.O_CREATE|os.O_TRUNC, 0660) + fd.Close() + return &defaultRes, false + } + if err != nil { + return &defaultRes, false + } + defer fd.Close() + + var res MultiDownloadCPInfo + err = json.NewDecoder(fd).Decode(&res) + if err != nil { + return &defaultRes, false + } + // 与COS的文件比较 + if res.CRC64 != opt.CRC64 || res.ETag != opt.ETag || res.Size != opt.Size || res.LastModified != opt.LastModified || len(res.DownloadedBlocks) == 0 { + return &defaultRes, false + } + // len(chunks) 大于1,否则为简单下载, chunks[0].Size为partSize + partSize := chunks[0].Size + for _, v := range res.DownloadedBlocks { + index := v.From / partSize + to := chunks[index].OffSet + chunks[index].Size - 1 + if chunks[index].OffSet != v.From || to != v.To { + // 重置chunks + for i, _ := range chunks { + chunks[i].Done = false + } + return &defaultRes, false + } + chunks[index].Done = true + } + return &res, true +} + +func (s *ObjectService) Download(ctx context.Context, name string, filepath string, opt *MultiDownloadOptions, id ...string) (*Response, error) { + // key 校验 + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } + // 参数校验 + if opt == nil { + opt = &MultiDownloadOptions{} + } + if opt.Opt != nil && opt.Opt.Range != "" { + return nil, fmt.Errorf("Download doesn't support Range Options") + } + headOpt := &ObjectHeadOptions{} + if opt.Opt != nil { + headOpt.XCosSSECustomerAglo = opt.Opt.XCosSSECustomerAglo + headOpt.XCosSSECustomerKey = opt.Opt.XCosSSECustomerKey + headOpt.XCosSSECustomerKeyMD5 = opt.Opt.XCosSSECustomerKeyMD5 + headOpt.XOptionHeader = opt.Opt.XOptionHeader + } + resp, err := s.Head(ctx, name, headOpt, id...) + if err != nil { + return resp, err + } + // 获取文件长度和CRC + // 如果对象不存在x-cos-hash-crc64ecma,则跳过不做校验 + coscrc := resp.Header.Get("x-cos-hash-crc64ecma") + strTotalBytes := resp.Header.Get("Content-Length") + totalBytes, err := strconv.ParseInt(strTotalBytes, 10, 64) + if err != nil { + return resp, err + } + + // 切分 + chunks, partNum, err := SplitSizeIntoChunksToDownload(totalBytes, opt.PartSize*1024*1024) + if err != nil { + return resp, err + } + // 直接下载到文件 + if partNum == 0 || partNum == 1 { + rsp, err := s.GetToFile(ctx, name, filepath, opt.Opt, id...) + if err != nil { + return rsp, err + } + if coscrc != "" && s.client.Conf.EnableCRC && !opt.DisableChecksum { + icoscrc, _ := strconv.ParseUint(coscrc, 10, 64) + fd, err := os.Open(filepath) + if err != nil { + return rsp, err + } + defer fd.Close() + localcrc, err := calCRC64(fd) + if err != nil { + return rsp, err + } + if localcrc != icoscrc { + return rsp, fmt.Errorf("verification failed, want:%v, return:%v, header:%+v", icoscrc, localcrc, resp.Header) + } + } + return rsp, err + } + // 断点续载 + var resumableFlag bool + var resumableInfo *MultiDownloadCPInfo + var cpfd *os.File + var cpfile string + if opt.CheckPoint { + cpInfo := &MultiDownloadCPInfo{ + LastModified: resp.Header.Get("Last-Modified"), + ETag: resp.Header.Get("ETag"), + CRC64: coscrc, + Size: totalBytes, + } + cpfile = opt.CheckPointFile + if cpfile == "" { + cpfile = fmt.Sprintf("%s.cosresumabletask", filepath) + } + resumableInfo, resumableFlag = s.checkDownloadedParts(cpInfo, cpfile, chunks) + cpfd, err = os.OpenFile(cpfile, os.O_RDWR, 0660) + if err != nil { + return nil, fmt.Errorf("Open CheckPoint File[%v] Failed:%v", cpfile, err) + } + } + if !resumableFlag { + // 创建文件 + nfile, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660) + if err != nil { + if cpfd != nil { + cpfd.Close() + } + return resp, err + } + nfile.Close() + } + + var poolSize int + if opt.ThreadPoolSize > 0 { + poolSize = opt.ThreadPoolSize + } else { + poolSize = 1 + } + chjobs := make(chan *Jobs, 100) + chresults := make(chan *Results, 10000) + for w := 1; w <= poolSize; w++ { + go downloadWorker(ctx, s, chjobs, chresults) + } + + var listener ProgressListener + var consumedBytes int64 + if opt.Opt != nil && opt.Opt.Listener != nil { + listener = opt.Opt.Listener + } + event := newProgressEvent(ProgressStartedEvent, 0, 0, totalBytes) + progressCallback(listener, event) + + go func() { + for _, chunk := range chunks { + if chunk.Done { + continue + } + var downOpt ObjectGetOptions + if opt.Opt != nil { + downOpt = *opt.Opt + downOpt.Listener = nil // listener need to set nil + } + job := &Jobs{ + Name: name, + RetryTimes: 3, + FilePath: filepath, + Chunk: chunk, + DownOpt: &downOpt, + } + if len(id) > 0 { + job.VersionId = append(job.VersionId, id...) + } + chjobs <- job + } + close(chjobs) + }() + err = nil + for i := 0; i < partNum; i++ { + if chunks[i].Done { + if err == nil { + consumedBytes += chunks[i].Size + event = newProgressEvent(ProgressDataEvent, chunks[i].Size, consumedBytes, totalBytes) + progressCallback(listener, event) + } + continue + } + res := <-chresults + if res.Resp == nil || res.err != nil { + err = fmt.Errorf("part %d get resp Content. error: %s", res.PartNumber, res.err.Error()) + continue + } + // Dump CheckPoint Info + if opt.CheckPoint { + cpfd.Truncate(0) + cpfd.Seek(0, os.SEEK_SET) + resumableInfo.DownloadedBlocks = append(resumableInfo.DownloadedBlocks, DownloadedBlock{ + From: chunks[res.PartNumber-1].OffSet, + To: chunks[res.PartNumber-1].OffSet + chunks[res.PartNumber-1].Size - 1, + }) + json.NewEncoder(cpfd).Encode(resumableInfo) + } + + // 更新进度 + consumedBytes += chunks[res.PartNumber-1].Size + event = newProgressEvent(ProgressDataEvent, chunks[res.PartNumber-1].Size, consumedBytes, totalBytes) + progressCallback(listener, event) + } + close(chresults) + if cpfd != nil { + cpfd.Close() + } + if err != nil { + event = newProgressEvent(ProgressFailedEvent, 0, consumedBytes, totalBytes, err) + progressCallback(listener, event) + return nil, err + } + // 下载成功,删除checkpoint文件 + if opt.CheckPoint { + os.Remove(cpfile) + } + if coscrc != "" && s.client.Conf.EnableCRC && !opt.DisableChecksum { + icoscrc, _ := strconv.ParseUint(coscrc, 10, 64) + fd, err := os.Open(filepath) + if err != nil { + return resp, err + } + defer fd.Close() + localcrc, err := calCRC64(fd) + if err != nil { + return resp, err + } + if localcrc != icoscrc { + return resp, fmt.Errorf("verification failed, want:%v, return:%v, header:%+v", icoscrc, localcrc, resp.Header) + } + } + event = newProgressEvent(ProgressCompletedEvent, 0, consumedBytes, totalBytes) + progressCallback(listener, event) + + return resp, err +} + +type ObjectPutTaggingOptions struct { + XMLName xml.Name `xml:"Tagging" header:"-"` + TagSet []ObjectTaggingTag `xml:"TagSet>Tag,omitempty" header:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} +type ObjectTaggingTag BucketTaggingTag +type ObjectGetTaggingResult ObjectPutTaggingOptions + +func (s *ObjectService) PutTagging(ctx context.Context, name string, opt *ObjectPutTaggingOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?tagging&versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?tagging", encodeURIComponent(name)) + } else { + return nil, errors.New("wrong params") + } + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPut, + body: opt, + optHeader: opt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +type ObjectGetTaggingOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +func (s *ObjectService) GetTagging(ctx context.Context, name string, opt ...interface{}) (*ObjectGetTaggingResult, *Response, error) { + var optHeader *ObjectGetTaggingOptions + u := fmt.Sprintf("/%s?tagging", encodeURIComponent(name)) + if len(opt) > 2 { + return nil, nil, errors.New("wrong params") + } + for _, val := range opt { + if v, ok := val.(string); ok { + u = fmt.Sprintf("%s&versionId=%s", u, v) + } + if v, ok := val.(*ObjectGetTaggingOptions); ok { + optHeader = v + } + } + + var res ObjectGetTaggingResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optHeader: optHeader, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +func (s *ObjectService) DeleteTagging(ctx context.Context, name string, opt ...interface{}) (*Response, error) { + // When use "" string might call the delete bucket interface + if len(name) == 0 || name == "/" { + return nil, errors.New("empty object name") + } + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } + var optHeader *ObjectGetTaggingOptions + u := fmt.Sprintf("/%s?tagging", encodeURIComponent(name)) + if len(opt) > 2 { + return nil, errors.New("wrong params") + } + for _, val := range opt { + if v, ok := val.(string); ok { + u = fmt.Sprintf("%s&versionId=%s", u, v) + } + if v, ok := val.(*ObjectGetTaggingOptions); ok { + optHeader = v + } + } + + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodDelete, + optHeader: optHeader, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +type PutFetchTaskOptions struct { + Url string `json:"Url,omitempty" header:"-" xml:"-"` + Key string `json:"Key,omitempty" header:"-" xml:"-"` + MD5 string `json:"MD5,omitempty" header:"-" xml:"-"` + OnKeyExist string `json:"OnKeyExist,omitempty" header:"-" xml:"-"` + IgnoreSameKey bool `json:"IgnoreSameKey,omitempty" header:"-" xml:"-"` + SuccessCallbackUrl string `json:"SuccessCallbackUrl,omitempty" header:"-" xml:"-"` + FailureCallbackUrl string `json:"FailureCallbackUrl,omitempty" header:"-" xml:"-"` + XOptionHeader *http.Header `json:"-", xml:"-" header:"-,omitempty"` +} + +type PutFetchTaskResult struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` + RequestId string `json:"request_id,omitempty"` + Data struct { + TaskId string `json:"taskId,omitempty"` + } `json:"Data,omitempty"` +} + +type GetFetchTaskResult struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` + RequestId string `json:"request_id,omitempty"` + Data struct { + Code string `json:"code,omitempty"` + Message string `json:"msg,omitempty"` + Percent int `json:"percent,omitempty"` + Status string `json:"status,omitempty"` + } `json:"data,omitempty"` +} + +type innerFetchTaskHeader struct { + XOptionHeader *http.Header `json:"-", xml:"-" header:"-,omitempty"` +} + +func (s *ObjectService) PutFetchTask(ctx context.Context, bucket string, opt *PutFetchTaskOptions) (*PutFetchTaskResult, *Response, error) { + var buf bytes.Buffer + var res PutFetchTaskResult + if opt == nil { + opt = &PutFetchTaskOptions{} + } + header := innerFetchTaskHeader{ + XOptionHeader: &http.Header{}, + } + if opt.XOptionHeader != nil { + header.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + header.XOptionHeader.Set("Content-Type", "application/json") + bs, err := json.Marshal(opt) + if err != nil { + return nil, nil, err + } + reader := bytes.NewBuffer(bs) + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.FetchURL, + uri: fmt.Sprintf("/%s/", bucket), + method: http.MethodPost, + optHeader: &header, + body: reader, + result: &buf, + } + resp, err := s.client.send(ctx, sendOpt) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +func (s *ObjectService) GetFetchTask(ctx context.Context, bucket string, taskid string) (*GetFetchTaskResult, *Response, error) { + var buf bytes.Buffer + var res GetFetchTaskResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.FetchURL, + uri: fmt.Sprintf("/%s/%s", bucket, encodeURIComponent(taskid)), + method: http.MethodGet, + result: &buf, + } + resp, err := s.client.send(ctx, sendOpt) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type ObjectPutSymlinkOptions struct { + SymlinkTarget string `header:"x-cos-symlink-target" url:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +type ObjectGetSymlinkOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +func (s *ObjectService) PutSymlink(ctx context.Context, name string, opt *ObjectPutSymlinkOptions) (*Response, error) { + if opt == nil || opt.SymlinkTarget == "" { + return nil, errors.New("SymlinkTarget is empty") + } + copt := &ObjectPutSymlinkOptions{ + SymlinkTarget: encodeURIComponent(opt.SymlinkTarget), + XOptionHeader: opt.XOptionHeader, + } + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?symlink", + method: http.MethodPut, + optHeader: copt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *ObjectService) GetSymlink(ctx context.Context, name string, opt *ObjectGetSymlinkOptions) (string, *Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?symlink", + method: http.MethodGet, + } + resp, err := s.client.doRetry(ctx, sendOpt) + if err != nil || resp == nil { + return "", resp, err + } + return resp.Header.Get("x-cos-symlink-target"), resp, err +} + +type ObjectPutFromURLOptions struct { + PartSize int + QueueSize int + InitOptions *InitiateMultipartUploadOptions +} + +func (s *ObjectService) PutFromURL(ctx context.Context, name string, downloadURL string, opt *ObjectPutFromURLOptions) (*CompleteMultipartUploadResult, *Response, error) { + if opt == nil { + opt = &ObjectPutFromURLOptions{} + } + // init + v, resp, err := s.InitiateMultipartUpload(ctx, name, opt.InitOptions) + if err != nil { + return nil, resp, err + } + uploadId := v.UploadID + var isErr bool + defer func() { + if isErr { + s.AbortMultipartUpload(ctx, name, uploadId, nil) + } + }() + // request from url + req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadURL, nil) + if err != nil { + isErr = true + return nil, nil, err + } + rsp, err := http.DefaultClient.Do(req) + if err != nil || rsp == nil { + isErr = true + return nil, nil, err + } + defer rsp.Body.Close() + if rsp.StatusCode > 299 { + isErr = true + return nil, &Response{rsp}, fmt.Errorf("the status code of downloadURL response is failed: %d", rsp.StatusCode) + } + factory := newPartFactory(opt.PartSize, opt.QueueSize) + partChannel, errChannel := factory.Produce(rsp.Body) + defer factory.Close() + + comOpt := &CompleteMultipartUploadOptions{} + var partNumber int + for { + select { + case part, ok := <-partChannel: + if !ok { + partChannel = nil + break + } + partNumber++ + resp, err := s.UploadPart(ctx, name, uploadId, partNumber, part, nil) + if err != nil { + isErr = true + return nil, resp, err + } + comOpt.Parts = append(comOpt.Parts, Object{ + PartNumber: partNumber, + ETag: resp.Header.Get("ETag"), + }) + case err, ok := <-errChannel: + if !ok { + errChannel = nil + break + } + if err != nil { + isErr = true + return nil, nil, fmt.Errorf("url download failed: %v", err) + } + } + if partChannel == nil && errChannel == nil { + break + } + } + res, resp, err := s.CompleteMultipartUpload(ctx, name, uploadId, comOpt) + if err != nil { + isErr = true + } + return res, resp, err +} + +type partFactory struct { + partSize int + queueSize int + current *bytes.Buffer + partChannel chan *bytes.Buffer + errChannel chan error + cancelChannel chan struct{} +} + +const CHUNK_SIZE = 1024 * 1024 + +func newPartFactory(partSize int, queueSize int) *partFactory { + if partSize <= 0 { + partSize = 8 + } + if queueSize <= 0 { + queueSize = 10 + } + return &partFactory{ + partSize: partSize * 1024 * 1024, + queueSize: queueSize, + current: bytes.NewBuffer(nil), + } +} + +func (pf *partFactory) Produce(reader io.ReadCloser) (<-chan *bytes.Buffer, <-chan error) { + pf.cancelChannel = make(chan struct{}, 1) + pf.partChannel = make(chan *bytes.Buffer, pf.queueSize) + pf.errChannel = make(chan error, 1) + + go pf.Run(reader) + return pf.partChannel, pf.errChannel +} + +func (pf *partFactory) Close() { + pf.cancelChannel <- struct{}{} +} + +func (pf *partFactory) Run(reader io.ReadCloser) { + var total, parts int + defer func() { + close(pf.errChannel) + close(pf.partChannel) + }() + buf := make([]byte, CHUNK_SIZE) + for { + select { + case <-pf.cancelChannel: + return + default: + n, err := reader.Read(buf) + total += n + if n > 0 { + part, e := pf.Write(buf[:n]) + if e != nil { + pf.errChannel <- e + return + } + if part != nil { + parts++ + select { + case pf.partChannel <- part: + case <-pf.cancelChannel: + return + } + } + } + if err != nil && err != io.EOF { + pf.errChannel <- err + return + } + if err == io.EOF || n == 0 { + if pf.current.Len() > 0 { + parts++ + select { + case pf.partChannel <- pf.current: + case <-pf.cancelChannel: + return + } + } + return + } + } + } +} + +func (pf *partFactory) Write(p []byte) (*bytes.Buffer, error) { + var res *bytes.Buffer + for nwrite := 0; nwrite < len(p); { + if pf.current.Len() == pf.partSize { + res = pf.current + pf.current = bytes.NewBuffer(nil) + } + end := len(p) + // 大于缓存区大小 + if pf.current.Len()+end-nwrite > pf.partSize { + end = nwrite + pf.partSize - pf.current.Len() + } + nr, err := pf.current.Write(p[nwrite:end]) + if err != nil { + return res, err + } + nwrite += nr + } + return res, nil +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/object_acl.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_acl.go new file mode 100644 index 00000000000..a55cf4ac9cf --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_acl.go @@ -0,0 +1,84 @@ +package cos + +import ( + "context" + "errors" + "fmt" + "net/http" +) + +// ObjectGetACLResult is the result of GetObjectACL +type ObjectGetACLResult = ACLXml + +// GetACL Get Object ACL接口实现使用API读取Object的ACL表,只有所有者有权操作。 +// +// https://www.qcloud.com/document/product/436/7744 +func (s *ObjectService) GetACL(ctx context.Context, name string, id ...string) (*ObjectGetACLResult, *Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?acl&versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?acl", encodeURIComponent(name)) + } else { + return nil, nil, errors.New("wrong params") + } + var res ObjectGetACLResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + if err == nil { + decodeACL(resp, &res) + } + return &res, resp, err +} + +// ObjectPutACLOptions the options of put object acl +type ObjectPutACLOptions struct { + Header *ACLHeaderOptions `url:"-" xml:"-"` + Body *ACLXml `url:"-" header:"-"` +} + +// PutACL 使用API写入Object的ACL表,您可以通过Header:"x-cos-acl", "x-cos-grant-read" , +// "x-cos-grant-write" ,"x-cos-grant-full-control"传入ACL信息, +// 也可以通过body以XML格式传入ACL信息,但是只能选择Header和Body其中一种,否则,返回冲突。 +// +// Put Object ACL是一个覆盖操作,传入新的ACL将覆盖原有ACL。只有所有者有权操作。 +// +// "x-cos-acl":枚举值为public-read,private;public-read意味这个Object有公有读私有写的权限, +// private意味这个Object有私有读写的权限。 +// +// "x-cos-grant-read":意味被赋予权限的用户拥有该Object的读权限 +// +// "x-cos-grant-write":意味被赋予权限的用户拥有该Object的写权限 +// +// "x-cos-grant-full-control":意味被赋予权限的用户拥有该Object的读写权限 +// +// https://www.qcloud.com/document/product/436/7748 +func (s *ObjectService) PutACL(ctx context.Context, name string, opt *ObjectPutACLOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?acl&versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?acl", encodeURIComponent(name)) + } else { + return nil, errors.New("wrong params") + } + header := opt.Header + body := opt.Body + if body != nil { + header = nil + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPut, + optHeader: header, + body: body, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go new file mode 100644 index 00000000000..185d5f25d75 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go @@ -0,0 +1,647 @@ +package cos + +import ( + "bytes" + "context" + "encoding/xml" + "errors" + "fmt" + "hash/crc64" + "io" + "net/http" + "net/url" + "sort" + "strings" + "time" +) + +// InitiateMultipartUploadOptions is the option of InitateMultipartUpload +type InitiateMultipartUploadOptions struct { + *ACLHeaderOptions + *ObjectPutHeaderOptions +} + +// InitiateMultipartUploadResult is the result of InitateMultipartUpload +type InitiateMultipartUploadResult struct { + XMLName xml.Name `xml:"InitiateMultipartUploadResult"` + Bucket string + Key string + UploadID string `xml:"UploadId"` +} + +// InitiateMultipartUpload 请求实现初始化分片上传,成功执行此请求以后会返回Upload ID用于后续的Upload Part请求。 +// +// https://www.qcloud.com/document/product/436/7746 +func (s *ObjectService) InitiateMultipartUpload(ctx context.Context, name string, opt *InitiateMultipartUploadOptions) (*InitiateMultipartUploadResult, *Response, error) { + var buff bytes.Buffer + var res InitiateMultipartUploadResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?uploads", + method: http.MethodPost, + optHeader: opt, + result: &buff, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + if err == nil { + err = xml.Unmarshal(buff.Bytes(), &res) + if err != nil { + // xml body存在非法字符(key存在非法字符) + if _, ok := err.(*xml.SyntaxError); ok { + err = UnmarshalInitMultiUploadResult(buff.Bytes(), &res) + return &res, resp, err + } + } + } + return &res, resp, err +} + +// ObjectUploadPartOptions is the options of upload-part +type ObjectUploadPartOptions struct { + Expect string `header:"Expect,omitempty" url:"-"` + XCosContentSHA1 string `header:"x-cos-content-sha1,omitempty" url:"-"` + ContentLength int64 `header:"Content-Length,omitempty" url:"-"` + ContentMD5 string `header:"Content-MD5,omitempty" url:"-"` + XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + + XCosTrafficLimit int `header:"x-cos-traffic-limit,omitempty" url:"-" xml:"-"` + + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` + // 上传进度, ProgressCompleteEvent不能表示对应API调用成功,API是否调用成功的判断标准为返回err==nil + Listener ProgressListener `header:"-" url:"-" xml:"-"` + + // Upload方法使用 + innerSwitchURL *url.URL `header:"-" url:"-" xml:"-"` +} + +// UploadPart 请求实现在初始化以后的分块上传,支持的块的数量为1到10000,块的大小为1 MB 到5 GB。 +// 在每次请求Upload Part时候,需要携带partNumber和uploadID,partNumber为块的编号,支持乱序上传。 +// +// 当传入uploadID和partNumber都相同的时候,后传入的块将覆盖之前传入的块。当uploadID不存在时会返回404错误,NoSuchUpload. +// +// 当 r 不是 bytes.Buffer/bytes.Reader/strings.Reader 时,必须指定 opt.ContentLength +// +// https://www.qcloud.com/document/product/436/7750 +func (s *ObjectService) UploadPart(ctx context.Context, name, uploadID string, partNumber int, r io.Reader, uopt *ObjectUploadPartOptions) (*Response, error) { + if (r == nil || r == http.NoBody) && uopt != nil && uopt.ContentLength != 0 { + return nil, fmt.Errorf("ContentLength must be 0 when reader is nil or http.NoBody.") + } + if err := CheckReaderLen(r); err != nil { + return nil, err + } + // opt 不为 nil + opt := CloneObjectUploadPartOptions(uopt) + totalBytes, err := GetReaderLen(r) + if err != nil && opt.Listener != nil { + if opt.ContentLength == 0 { + return nil, err + } + totalBytes = opt.ContentLength + } + // 分块上传不支持 Chunk 上传 + if err == nil { + // 非bytes.Buffer/bytes.Reader/strings.Reader/os.File 由用户指定ContentLength, 或使用 Chunk 上传 + if opt != nil && opt.ContentLength == 0 && IsLenReader(r) { + opt.ContentLength = totalBytes + } + } + // 如果是io.Seeker,则重试 + count := 1 + var position int64 + if seeker, ok := r.(io.Seeker); ok { + // 记录原始位置 + position, err = seeker.Seek(0, io.SeekCurrent) + if err == nil && s.client.Conf.RetryOpt.Count > 0 { + count = s.client.Conf.RetryOpt.Count + } + } + var resp *Response + var retrieable bool + sUrl := s.client.BaseURL.BucketURL + if opt.innerSwitchURL != nil { + sUrl = opt.innerSwitchURL + } + retryErr := &RetryError{} + for nr := 0; nr < count; nr++ { + var reader io.Reader + if r != nil && r != http.NoBody { + tReader := TeeReader(r, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + tReader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + } + if opt != nil && opt.Listener != nil { + tReader.listener = opt.Listener + } + reader = tReader + } + u := fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID) + sendOpt := sendOptions{ + baseURL: sUrl, + uri: u, + method: http.MethodPut, + optHeader: opt, + body: reader, + } + // 把上一次错误记录下来 + if err != nil { + retryErr.Add(err) + } + resp, err = s.client.send(ctx, &sendOpt) + sUrl, retrieable = s.client.CheckRetrieable(sUrl, resp, err, nr >= count-2) + if retrieable && nr+1 < count { + if seeker, ok := r.(io.Seeker); ok { + _, e := seeker.Seek(position, io.SeekStart) + if e != nil { + break + } + continue + } + } + break + } + if err != nil { + if _, ok := err.(*ErrorResponse); !ok { + retryErr.Add(err) + err = retryErr + } + } + + return resp, err +} + +// ObjectListPartsOptions is the option of ListParts +type ObjectListPartsOptions struct { + EncodingType string `url:"encoding-type,omitempty"` + MaxParts string `url:"max-parts,omitempty"` + PartNumberMarker string `url:"part-number-marker,omitempty"` +} + +// ObjectListPartsResult is the result of ListParts +type ObjectListPartsResult struct { + XMLName xml.Name `xml:"ListPartsResult"` + Bucket string + EncodingType string `xml:"Encoding-type,omitempty"` + Key string + UploadID string `xml:"UploadId"` + Initiator *Initiator `xml:"Initiator,omitempty"` + Owner *Owner `xml:"Owner,omitempty"` + StorageClass string + PartNumberMarker string + NextPartNumberMarker string `xml:"NextPartNumberMarker,omitempty"` + MaxParts string + IsTruncated bool + Parts []Object `xml:"Part,omitempty"` +} + +// ListParts 用来查询特定分块上传中的已上传的块。 +// +// https://www.qcloud.com/document/product/436/7747 +func (s *ObjectService) ListParts(ctx context.Context, name, uploadID string, opt *ObjectListPartsOptions) (*ObjectListPartsResult, *Response, error) { + u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID) + var res ObjectListPartsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + result: &res, + optQuery: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +// CompleteMultipartUploadOptions is the option of CompleteMultipartUpload +type CompleteMultipartUploadOptions struct { + XMLName xml.Name `xml:"CompleteMultipartUpload" header:"-" url:"-"` + Parts []Object `xml:"Part" header:"-" url:"-"` + XOptionHeader *http.Header `header:"-,omitempty" xml:"-" url:"-"` +} + +// CompleteMultipartUploadResult is the result CompleteMultipartUpload +type CompleteMultipartUploadResult struct { + XMLName xml.Name `xml:"CompleteMultipartUploadResult"` + Location string + Bucket string + Key string + ETag string +} + +// ObjectList can used for sort the parts which needs in complete upload part +// sort.Sort(cos.ObjectList(opt.Parts)) +type ObjectList []Object + +func (o ObjectList) Len() int { + return len(o) +} + +func (o ObjectList) Swap(i, j int) { + o[i], o[j] = o[j], o[i] +} + +func (o ObjectList) Less(i, j int) bool { // rewrite the Less method from small to big + return o[i].PartNumber < o[j].PartNumber +} + +// CompleteMultipartUpload 用来实现完成整个分块上传。当您已经使用Upload Parts上传所有块以后,你可以用该API完成上传。 +// 在使用该API时,您必须在Body中给出每一个块的PartNumber和ETag,用来校验块的准确性。 +// +// 由于分块上传的合并需要数分钟时间,因而当合并分块开始的时候,COS就立即返回200的状态码,在合并的过程中, +// COS会周期性的返回空格信息来保持连接活跃,直到合并完成,COS会在Body中返回合并后块的内容。 +// +// 当上传块小于1 MB的时候,在调用该请求时,会返回400 EntityTooSmall; +// 当上传块编号不连续的时候,在调用该请求时,会返回400 InvalidPart; +// 当请求Body中的块信息没有按序号从小到大排列的时候,在调用该请求时,会返回400 InvalidPartOrder; +// 当UploadId不存在的时候,在调用该请求时,会返回404 NoSuchUpload。 +// +// 建议您及时完成分块上传或者舍弃分块上传,因为已上传但是未终止的块会占用存储空间进而产生存储费用。 +// +// https://www.qcloud.com/document/product/436/7742 +func (s *ObjectService) CompleteMultipartUpload(ctx context.Context, name, uploadID string, opt *CompleteMultipartUploadOptions) (*CompleteMultipartUploadResult, *Response, error) { + u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID) + var buff bytes.Buffer + var res CompleteMultipartUploadResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPost, + optHeader: opt, + body: opt, + result: &buff, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + // If the error occurs during the copy operation, the error response is embedded in the 200 OK response. This means that a 200 OK response can contain either a success or an error. + if err == nil && resp.StatusCode == 200 { + err = xml.Unmarshal(buff.Bytes(), &res) + if err != nil { + // xml body存在非法字符(key存在非法字符) + if _, ok := err.(*xml.SyntaxError); ok { + err = UnmarshalCompleteMultiUploadResult(buff.Bytes(), &res) + if err != nil { + return &res, resp, err + } + } + } + if res.ETag == "" { + return &res, resp, fmt.Errorf("response 200 OK, but body contains an error, %v", buff.Bytes()) + } + } + return &res, resp, err +} + +type AbortMultipartUploadOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// AbortMultipartUpload 用来实现舍弃一个分块上传并删除已上传的块。当您调用Abort Multipart Upload时, +// 如果有正在使用这个Upload Parts上传块的请求,则Upload Parts会返回失败。当该UploadID不存在时,会返回404 NoSuchUpload。 +// +// 建议您及时完成分块上传或者舍弃分块上传,因为已上传但是未终止的块会占用存储空间进而产生存储费用。 +// +// https://www.qcloud.com/document/product/436/7740 +func (s *ObjectService) AbortMultipartUpload(ctx context.Context, name, uploadID string, opt ...*AbortMultipartUploadOptions) (*Response, error) { + if len(name) == 0 || name == "/" { + return nil, errors.New("empty object name") + } + // When use "" string might call the delete bucket interface + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } + + var optHeader *AbortMultipartUploadOptions + if len(opt) > 0 { + optHeader = opt[0] + } + u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodDelete, + optHeader: optHeader, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +// ObjectCopyPartOptions is the options of copy-part +type ObjectCopyPartOptions struct { + XCosCopySource string `header:"x-cos-copy-source" url:"-"` + XCosCopySourceRange string `header:"x-cos-copy-source-range,omitempty" url:"-"` + XCosCopySourceIfModifiedSince string `header:"x-cos-copy-source-If-Modified-Since,omitempty" url:"-"` + XCosCopySourceIfUnmodifiedSince string `header:"x-cos-copy-source-If-Unmodified-Since,omitempty" url:"-"` + XCosCopySourceIfMatch string `header:"x-cos-copy-source-If-Match,omitempty" url:"-"` + XCosCopySourceIfNoneMatch string `header:"x-cos-copy-source-If-None-Match,omitempty" url:"-"` + // SSE-C + XCosCopySourceSSECustomerAglo string `header:"x-cos-copy-source-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosCopySourceSSECustomerKey string `header:"x-cos-copy-source-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosCopySourceSSECustomerKeyMD5 string `header:"x-cos-copy-source-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + //兼容其他自定义头部 + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +// CopyPartResult is the result CopyPart +type CopyPartResult struct { + XMLName xml.Name `xml:"CopyPartResult"` + ETag string + LastModified string +} + +// CopyPart 请求实现在初始化以后的分块上传,支持的块的数量为1到10000,块的大小为1 MB 到5 GB。 +// 在每次请求Upload Part时候,需要携带partNumber和uploadID,partNumber为块的编号,支持乱序上传。 +// ObjectCopyPartOptions的XCosCopySource为必填参数,格式为-.cos..myqcloud.com/ +// ObjectCopyPartOptions的XCosCopySourceRange指定源的Range,格式为bytes=- +// +// 当传入uploadID和partNumber都相同的时候,后传入的块将覆盖之前传入的块。当uploadID不存在时会返回404错误,NoSuchUpload. +// +// https://www.qcloud.com/document/product/436/7750 +func (s *ObjectService) CopyPart(ctx context.Context, name, uploadID string, partNumber int, sourceURL string, opt *ObjectCopyPartOptions) (*CopyPartResult, *Response, error) { + if strings.HasPrefix(sourceURL, "http://") || strings.HasPrefix(sourceURL, "https://") { + return nil, nil, errors.New("sourceURL format is invalid.") + } + surl := strings.SplitN(sourceURL, "/", 2) + if len(surl) < 2 { + return nil, nil, errors.New(fmt.Sprintf("x-cos-copy-source format error: %s", sourceURL)) + } + var u string + keyAndVer := strings.SplitN(surl[1], "?", 2) + if len(keyAndVer) < 2 { + u = fmt.Sprintf("%s/%s", surl[0], encodeURIComponent(surl[1], []byte{'/'})) + } else { + u = fmt.Sprintf("%v/%v?%v", surl[0], encodeURIComponent(keyAndVer[0], []byte{'/'}), encodeURIComponent(keyAndVer[1], []byte{'='})) + } + + opt = cloneObjectCopyPartOptions(opt) + opt.XCosCopySource = u + + u = fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID) + var res CopyPartResult + var bs bytes.Buffer + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPut, + optHeader: opt, + result: &bs, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + + if err == nil { // 请求正常 + err = xml.Unmarshal(bs.Bytes(), &res) // body 正常返回 + // If the error occurs during the copy operation, the error response is embedded in the 200 OK response. This means that a 200 OK response can contain either a success or an error. + if resp != nil && resp.StatusCode == 200 { + if err != nil { + resErr := &ErrorResponse{Response: resp.Response} + xml.Unmarshal(bs.Bytes(), resErr) + return &res, resp, resErr + } + } + } + + return &res, resp, err +} + +type ObjectListUploadsOptions struct { + Delimiter string `url:"delimiter,omitempty"` + EncodingType string `url:"encoding-type,omitempty"` + Prefix string `url:"prefix,omitempty"` + MaxUploads int `url:"max-uploads,omitempty"` + KeyMarker string `url:"key-marker,omitempty"` + UploadIdMarker string `url:"upload-id-marker,omitempty"` +} + +type ObjectListUploadsResult struct { + XMLName xml.Name `xml:"ListMultipartUploadsResult"` + Bucket string `xml:"Bucket,omitempty"` + EncodingType string `xml:"Encoding-Type,omitempty"` + KeyMarker string `xml:"KeyMarker,omitempty"` + UploadIdMarker string `xml:"UploadIdMarker,omitempty"` + NextKeyMarker string `xml:"NextKeyMarker,omitempty"` + NextUploadIdMarker string `xml:"NextUploadIdMarker,omitempty"` + MaxUploads string `xml:"MaxUploads,omitempty"` + IsTruncated bool `xml:"IsTruncated,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + Delimiter string `xml:"Delimiter,omitempty"` + Upload []ListUploadsResultUpload `xml:"Upload,omitempty"` + CommonPrefixes []string `xml:"CommonPrefixes>Prefix,omitempty"` +} + +type ListUploadsResultUpload struct { + Key string `xml:"Key,omitempty"` + UploadID string `xml:"UploadId,omitempty"` + StorageClass string `xml:"StorageClass,omitempty"` + Initiator *Initiator `xml:"Initiator,omitempty"` + Owner *Owner `xml:"Owner,omitempty"` + Initiated string `xml:"Initiated,omitempty"` +} + +func (s *ObjectService) ListUploads(ctx context.Context, opt *ObjectListUploadsOptions) (*ObjectListUploadsResult, *Response, error) { + var res ObjectListUploadsResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?uploads", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return &res, resp, err +} + +type MultiCopyOptions struct { + OptCopy *ObjectCopyOptions + PartSize int64 + ThreadPoolSize int + useMulti bool // use for ut +} + +type CopyJobs struct { + Name string + UploadId string + RetryTimes int + Chunk Chunk + Opt *ObjectCopyPartOptions +} + +type CopyResults struct { + PartNumber int + Resp *Response + err error + res *CopyPartResult +} + +func copyworker(ctx context.Context, s *ObjectService, jobs <-chan *CopyJobs, results chan<- *CopyResults) { + for j := range jobs { + var copyres CopyResults + j.Opt.XCosCopySourceRange = fmt.Sprintf("bytes=%d-%d", j.Chunk.OffSet, j.Chunk.OffSet+j.Chunk.Size-1) + rt := j.RetryTimes + for { + res, resp, err := s.CopyPart(ctx, j.Name, j.UploadId, j.Chunk.Number, j.Opt.XCosCopySource, j.Opt) + copyres.PartNumber = j.Chunk.Number + copyres.Resp = resp + copyres.err = err + copyres.res = res + if err != nil { + rt-- + if rt == 0 { + results <- ©res + break + } + if resp != nil && resp.StatusCode < 499 && resp.StatusCode >= 400 { + results <- ©res + break + } + time.Sleep(10 * time.Millisecond) + continue + } + results <- ©res + break + } + } +} + +func (s *ObjectService) innerHead(ctx context.Context, sourceURL string, opt *ObjectHeadOptions, id []string) (*Response, error) { + surl := strings.SplitN(sourceURL, "/", 2) + if len(surl) < 2 { + return nil, fmt.Errorf("sourceURL format error: %s", sourceURL) + } + + u, err := url.Parse(fmt.Sprintf("http://%s", surl[0])) + if err != nil { + return nil, err + } + b := &BaseURL{BucketURL: u} + client := NewClient(b, &http.Client{ + Transport: s.client.client.Transport, + }) + if len(id) > 0 { + return client.Object.Head(ctx, surl[1], nil, id[0]) + } else { + keyAndVer := strings.SplitN(surl[1], "?", 2) + if len(keyAndVer) < 2 { + // 不存在versionId + return client.Object.Head(ctx, surl[1], nil) + } else { + q, err := url.ParseQuery(keyAndVer[1]) + if err != nil { + return nil, fmt.Errorf("sourceURL format error: %s", sourceURL) + } + return client.Object.Head(ctx, keyAndVer[0], nil, q.Get("versionId")) + } + } + return nil, fmt.Errorf("Head Err") +} + +// 如果源对象大于5G,则采用分块复制的方式进行拷贝,此时源对象的元信息如果COPY +func (s *ObjectService) MultiCopy(ctx context.Context, name string, sourceURL string, opt *MultiCopyOptions, id ...string) (*ObjectCopyResult, *Response, error) { + if strings.HasPrefix(sourceURL, "http://") || strings.HasPrefix(sourceURL, "https://") { + return nil, nil, errors.New("sourceURL format is invalid.") + } + + resp, err := s.innerHead(ctx, sourceURL, nil, id) + if err != nil { + return nil, nil, err + } + totalBytes := resp.ContentLength + var u string + if len(id) == 1 { + u = fmt.Sprintf("%s?versionId=%s", sourceURL, id[0]) + } else if len(id) == 0 { + u = sourceURL + } else { + return nil, nil, errors.New("wrong params") + } + + if opt == nil { + opt = &MultiCopyOptions{} + } + chunks, partNum, err := SplitSizeIntoChunks(totalBytes, opt.PartSize*1024*1024) + if err != nil { + return nil, nil, err + } + + if partNum == 0 || (totalBytes <= singleUploadMaxLength && !opt.useMulti) { + if len(id) > 0 { + return s.Copy(ctx, name, sourceURL, opt.OptCopy, id[0]) + } else { + return s.Copy(ctx, name, sourceURL, opt.OptCopy) + } + } + optini := CopyOptionsToMulti(opt.OptCopy) + var uploadID string + res, _, err := s.InitiateMultipartUpload(ctx, name, optini) + if err != nil { + return nil, nil, err + } + uploadID = res.UploadID + + var poolSize int + if opt.ThreadPoolSize > 0 { + poolSize = opt.ThreadPoolSize + } else { + poolSize = 1 + } + + chjobs := make(chan *CopyJobs, 100) + chresults := make(chan *CopyResults, 10000) + optcom := &CompleteMultipartUploadOptions{} + + for w := 1; w <= poolSize; w++ { + go copyworker(ctx, s, chjobs, chresults) + } + + go func() { + for _, chunk := range chunks { + partOpt := &ObjectCopyPartOptions{ + XCosCopySource: u, + } + if opt.OptCopy != nil && opt.OptCopy.ObjectCopyHeaderOptions != nil { + partOpt.XCosCopySourceIfModifiedSince = opt.OptCopy.XCosCopySourceIfModifiedSince + partOpt.XCosCopySourceIfUnmodifiedSince = opt.OptCopy.XCosCopySourceIfUnmodifiedSince + partOpt.XCosCopySourceIfMatch = opt.OptCopy.XCosCopySourceIfMatch + partOpt.XCosCopySourceIfNoneMatch = opt.OptCopy.XCosCopySourceIfNoneMatch + partOpt.XCosCopySourceSSECustomerAglo = opt.OptCopy.XCosCopySourceSSECustomerAglo + partOpt.XCosCopySourceSSECustomerKey = opt.OptCopy.XCosCopySourceSSECustomerKey + partOpt.XCosCopySourceSSECustomerKeyMD5 = opt.OptCopy.XCosCopySourceSSECustomerKeyMD5 + } + job := &CopyJobs{ + Name: name, + RetryTimes: 3, + UploadId: uploadID, + Chunk: chunk, + Opt: partOpt, + } + chjobs <- job + } + close(chjobs) + }() + err = nil + for i := 0; i < partNum; i++ { + res := <-chresults + if res.res == nil || res.err != nil { + err = fmt.Errorf("UploadID %s, part %d failed to get resp content. error: %s", uploadID, res.PartNumber, res.err.Error()) + continue + } + etag := res.res.ETag + optcom.Parts = append(optcom.Parts, Object{ + PartNumber: res.PartNumber, ETag: etag}, + ) + } + close(chresults) + if err != nil { + return nil, nil, err + } + sort.Sort(ObjectList(optcom.Parts)) + + v, resp, err := s.CompleteMultipartUpload(ctx, name, uploadID, optcom) + if err != nil { + s.AbortMultipartUpload(ctx, name, uploadID) + return nil, resp, err + } + cpres := &ObjectCopyResult{ + ETag: v.ETag, + CRC64: resp.Header.Get("x-cos-hash-crc64ecma"), + VersionId: resp.Header.Get("x-cos-version-id"), + } + return cpres, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/object_select.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_select.go new file mode 100644 index 00000000000..64a4e2fd276 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_select.go @@ -0,0 +1,445 @@ +package cos + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/xml" + "fmt" + "hash/crc32" + "io" + "io/ioutil" + "net/http" + "os" + "time" +) + +type JSONInputSerialization struct { + Type string `xml:"Type,omitempty"` +} + +type CSVInputSerialization struct { + RecordDelimiter string `xml:"RecordDelimiter,omitempty"` + FieldDelimiter string `xml:"FieldDelimiter,omitempty"` + QuoteCharacter string `xml:"QuoteCharacter,omitempty"` + QuoteEscapeCharacter string `xml:"QuoteEscapeCharacter,omitempty"` + AllowQuotedRecordDelimiter string `xml:"AllowQuotedRecordDelimiter,omitempty"` + FileHeaderInfo string `xml:"FileHeaderInfo,omitempty"` + Comments string `xml:"Comments,omitempty"` +} + +type SelectInputSerialization struct { + CompressionType string `xml:"CompressionType,omitempty"` + CSV *CSVInputSerialization `xml:"CSV,omitempty"` + JSON *JSONInputSerialization `xml:"JSON,omitempty"` +} + +type JSONOutputSerialization struct { + RecordDelimiter string `xml:"RecordDelimiter,omitempty"` +} + +type CSVOutputSerialization struct { + QuoteFields string `xml:"QuoteFields,omitempty"` + RecordDelimiter string `xml:"RecordDelimiter,omitempty"` + FieldDelimiter string `xml:"FieldDelimiter,omitempty"` + QuoteCharacter string `xml:"QuoteCharacter,omitempty"` + QuoteEscapeCharacter string `xml:"QuoteEscapeCharacter,omitempty"` +} + +type SelectOutputSerialization struct { + CSV *CSVOutputSerialization `xml:"CSV,omitempty"` + JSON *JSONOutputSerialization `xml:"JSON,omitempty"` +} + +type ObjectSelectOptions struct { + XMLName xml.Name `xml:"SelectRequest"` + Expression string `xml:"Expression"` + ExpressionType string `xml:"ExpressionType"` + InputSerialization *SelectInputSerialization `xml:"InputSerialization"` + OutputSerialization *SelectOutputSerialization `xml:"OutputSerialization"` + RequestProgress string `xml:"RequestProgress>Enabled,omitempty"` +} + +func (s *ObjectService) Select(ctx context.Context, name string, opt *ObjectSelectOptions) (io.ReadCloser, error) { + u := fmt.Sprintf("/%s?select&select-type=2", encodeURIComponent(name)) + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPost, + body: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + if err != nil { + return nil, err + } + result := &ObjectSelectResponse{ + Headers: resp.Header, + Body: resp.Body, + StatusCode: resp.StatusCode, + Frame: &ObjectSelectResult{ + NextFrame: true, + Payload: []byte{}, + }, + Finish: false, + } + + return result, nil +} + +func (s *ObjectService) SelectToFile(ctx context.Context, name, file string, opt *ObjectSelectOptions) (*ObjectSelectResponse, error) { + resp, err := s.Select(ctx, name, opt) + if err != nil { + return nil, err + } + res, _ := resp.(*ObjectSelectResponse) + defer func() { + io.Copy(ioutil.Discard, resp) + resp.Close() + }() + + fd, err := os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.FileMode(0664)) + if err != nil { + return res, err + } + + _, err = io.Copy(fd, resp) + fd.Close() + res.Finish = true + return res, err +} + +const ( + kReadTimeout = 3 + kMessageType = ":message-type" + kEventType = ":event-type" + kContentType = ":content-type" + + kRecordsFrameType = iota + kContinuationFrameType + kProgressFrameType + kStatsFrameType + kEndFrameType + kErrorFrameType +) + +type ProgressFrame struct { + XMLName xml.Name `xml:"Progress"` + BytesScanned int `xml:"BytesScanned"` + BytesProcessed int `xml:"BytesProcessed"` + BytesReturned int `xml:"BytesReturned"` +} + +type StatsFrame struct { + XMLName xml.Name `xml:"Stats"` + BytesScanned int `xml:"BytesScanned"` + BytesProcessed int `xml:"BytesProcessed"` + BytesReturned int `xml:"BytesReturned"` +} + +type DataFrame struct { + ContentType string + ConsumedBytesLength int32 + LeftBytesLength int32 +} + +type ErrorFrame struct { + Code string + Message string +} + +func (e *ErrorFrame) Error() string { + return fmt.Sprintf("Error Code: %s, Error Message: %s", e.Code, e.Message) +} + +type ObjectSelectResult struct { + TotalFrameLength int32 + TotalHeaderLength int32 + NextFrame bool + FrameType int + Payload []byte + DataFrame DataFrame + ProgressFrame ProgressFrame + StatsFrame StatsFrame + ErrorFrame *ErrorFrame +} + +type ObjectSelectResponse struct { + StatusCode int + Headers http.Header + Body io.ReadCloser + Frame *ObjectSelectResult + Finish bool +} + +func (osr *ObjectSelectResponse) Read(p []byte) (n int, err error) { + n, err = osr.readFrames(p) + return +} +func (osr *ObjectSelectResponse) Close() error { + return osr.Body.Close() +} + +func (osr *ObjectSelectResponse) readFrames(p []byte) (int, error) { + if osr.Finish { + return 0, io.EOF + } + if osr.Frame.ErrorFrame != nil { + return 0, osr.Frame.ErrorFrame + } + + var err error + var nlen int + dlen := len(p) + + for nlen < dlen { + if osr.Frame.NextFrame == true { + osr.Frame.NextFrame = false + err := osr.analysisPrelude() + if err != nil { + return nlen, err + } + err = osr.analysisHeader() + if err != nil { + return nlen, err + } + } + switch osr.Frame.FrameType { + case kRecordsFrameType: + n, err := osr.analysisRecords(p[nlen:]) + if err != nil { + return nlen, err + } + nlen += n + case kContinuationFrameType: + err = osr.payloadChecksum("ContinuationFrame") + if err != nil { + return nlen, err + } + case kProgressFrameType: + err := osr.analysisXml(&osr.Frame.ProgressFrame) + if err != nil { + return nlen, err + } + case kStatsFrameType: + err := osr.analysisXml(&osr.Frame.StatsFrame) + if err != nil { + return nlen, err + } + case kEndFrameType: + err = osr.payloadChecksum("EndFrame") + if err != nil { + return nlen, err + } + osr.Finish = true + return nlen, io.EOF + case kErrorFrameType: + return nlen, osr.Frame.ErrorFrame + } + } + return nlen, err +} + +func (osr *ObjectSelectResponse) analysisPrelude() error { + frame := make([]byte, 12) + _, err := osr.fixedLengthRead(frame, kReadTimeout) + if err != nil { + return err + } + + var preludeCRC uint32 + bytesToInt(frame[0:4], &osr.Frame.TotalFrameLength) + bytesToInt(frame[4:8], &osr.Frame.TotalHeaderLength) + bytesToInt(frame[8:12], &preludeCRC) + osr.Frame.Payload = append(osr.Frame.Payload, frame...) + + return checksum(frame[0:8], preludeCRC, "Prelude") +} + +func (osr *ObjectSelectResponse) analysisHeader() error { + var nlen int32 + headers := make(map[string]string) + for nlen < osr.Frame.TotalHeaderLength { + var headerNameLen int8 + var headerValueLen int16 + bHeaderNameLen := make([]byte, 1) + _, err := osr.fixedLengthRead(bHeaderNameLen, kReadTimeout) + if err != nil { + return err + } + nlen += 1 + bytesToInt(bHeaderNameLen, &headerNameLen) + osr.Frame.Payload = append(osr.Frame.Payload, bHeaderNameLen...) + + bHeaderName := make([]byte, headerNameLen) + _, err = osr.fixedLengthRead(bHeaderName, kReadTimeout) + if err != nil { + return err + } + nlen += int32(headerNameLen) + headerName := string(bHeaderName) + osr.Frame.Payload = append(osr.Frame.Payload, bHeaderName...) + + bValueTypeLen := make([]byte, 3) + _, err = osr.fixedLengthRead(bValueTypeLen, kReadTimeout) + if err != nil { + return err + } + nlen += 3 + bytesToInt(bValueTypeLen[1:], &headerValueLen) + osr.Frame.Payload = append(osr.Frame.Payload, bValueTypeLen...) + + bHeaderValue := make([]byte, headerValueLen) + _, err = osr.fixedLengthRead(bHeaderValue, kReadTimeout) + if err != nil { + return err + } + nlen += int32(headerValueLen) + headers[headerName] = string(bHeaderValue) + osr.Frame.Payload = append(osr.Frame.Payload, bHeaderValue...) + } + htype, ok := headers[kMessageType] + if !ok { + return fmt.Errorf("header parse failed, no message-type, headers: %+v\n", headers) + } + switch { + case htype == "error": + osr.Frame.FrameType = kErrorFrameType + osr.Frame.ErrorFrame = &ErrorFrame{} + osr.Frame.ErrorFrame.Code, _ = headers[":error-code"] + osr.Frame.ErrorFrame.Message, _ = headers[":error-message"] + case htype == "event": + hevent, ok := headers[kEventType] + if !ok { + return fmt.Errorf("header parse failed, no event-type, headers: %+v\n", headers) + } + switch { + case hevent == "Records": + hContentType, ok := headers[kContentType] + if ok { + osr.Frame.DataFrame.ContentType = hContentType + } + osr.Frame.FrameType = kRecordsFrameType + case hevent == "Cont": + osr.Frame.FrameType = kContinuationFrameType + case hevent == "Progress": + osr.Frame.FrameType = kProgressFrameType + case hevent == "Stats": + osr.Frame.FrameType = kStatsFrameType + case hevent == "End": + osr.Frame.FrameType = kEndFrameType + default: + return fmt.Errorf("header parse failed, invalid event-type, headers: %+v\n", headers) + } + default: + return fmt.Errorf("header parse failed, invalid message-type: headers: %+v\n", headers) + } + return nil +} + +func (osr *ObjectSelectResponse) analysisRecords(data []byte) (int, error) { + var needReadLength int32 + dlen := int32(len(data)) + restLen := osr.Frame.TotalFrameLength - 16 - osr.Frame.TotalHeaderLength - osr.Frame.DataFrame.ConsumedBytesLength + if dlen <= restLen { + needReadLength = dlen + } else { + needReadLength = restLen + } + n, err := osr.fixedLengthRead(data[:needReadLength], kReadTimeout) + if err != nil { + return n, fmt.Errorf("read data frame error: %s", err.Error()) + } + osr.Frame.DataFrame.ConsumedBytesLength += int32(n) + osr.Frame.Payload = append(osr.Frame.Payload, data[:needReadLength]...) + // 读完了一帧数据并填充到data中了 + if osr.Frame.DataFrame.ConsumedBytesLength == osr.Frame.TotalFrameLength-16-osr.Frame.TotalHeaderLength { + osr.Frame.DataFrame.ConsumedBytesLength = 0 + err = osr.payloadChecksum("RecordFrame") + } + return n, err +} + +func (osr *ObjectSelectResponse) analysisXml(frame interface{}) error { + payloadLength := osr.Frame.TotalFrameLength - 16 - osr.Frame.TotalHeaderLength + bFrame := make([]byte, payloadLength) + _, err := osr.fixedLengthRead(bFrame, kReadTimeout) + if err != nil { + return err + } + err = xml.Unmarshal(bFrame, frame) + if err != nil { + return err + } + osr.Frame.Payload = append(osr.Frame.Payload, bFrame...) + return osr.payloadChecksum("XmlFrame") +} + +// 调用payloadChecksum时,表示该帧已读完,开始读取下一帧内容 +func (osr *ObjectSelectResponse) payloadChecksum(ftype string) error { + bcrc := make([]byte, 4) + _, err := osr.fixedLengthRead(bcrc, kReadTimeout) + if err != nil { + return err + } + var res uint32 + bytesToInt(bcrc, &res) + err = checksum(osr.Frame.Payload, res, ftype) + + osr.Frame.NextFrame = true + osr.Frame.Payload = []byte{} + + return err +} + +type chanReadIO struct { + readLen int + err error +} + +func (osr *ObjectSelectResponse) fixedLengthRead(p []byte, read_timeout int64) (int, error) { + timeout := time.Duration(read_timeout) + r := osr.Body + ch := make(chan chanReadIO, 1) + go func(p []byte) { + var needLen int + readChan := chanReadIO{} + needLen = len(p) + for { + n, err := r.Read(p[readChan.readLen:needLen]) + readChan.readLen += n + if err != nil { + readChan.err = err + ch <- readChan + close(ch) + return + } + + if readChan.readLen == needLen { + break + } + } + ch <- readChan + close(ch) + }(p) + + select { + case <-time.After(time.Second * timeout): + return 0, fmt.Errorf("requestId: %s, readLen timeout, timeout is %d(second),need read:%d", osr.Headers.Get("x-cos-request-id"), timeout, len(p)) + case result := <-ch: + return result.readLen, result.err + } +} + +func bytesToInt(b []byte, ret interface{}) { + binBuf := bytes.NewBuffer(b) + binary.Read(binBuf, binary.BigEndian, ret) +} + +func checksum(b []byte, rec uint32, ftype string) error { + c := crc32.ChecksumIEEE(b) + if c != rec { + return fmt.Errorf("parse type: %v, checksum failed, cal: %v, rec: %v\n", ftype, c, rec) + } + return nil +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/progress.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/progress.go new file mode 100644 index 00000000000..3fae1fe98c5 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/progress.go @@ -0,0 +1,160 @@ +package cos + +import ( + "fmt" + "hash" + "io" +) + +type ProgressEventType int + +const ( + // 数据开始传输 + ProgressStartedEvent ProgressEventType = iota + // 数据传输中 + ProgressDataEvent + // 数据传输完成, 但不能表示对应API调用完成 + ProgressCompletedEvent + // 只有在数据传输时发生错误才会返回 + ProgressFailedEvent +) + +type ProgressEvent struct { + EventType ProgressEventType + RWBytes int64 + ConsumedBytes int64 + TotalBytes int64 + Err error +} + +func newProgressEvent(eventType ProgressEventType, rwBytes, consumed, total int64, err ...error) *ProgressEvent { + event := &ProgressEvent{ + EventType: eventType, + RWBytes: rwBytes, + ConsumedBytes: consumed, + TotalBytes: total, + } + if len(err) > 0 { + event.Err = err[0] + } + return event +} + +// 用户自定义Listener需要实现该方法 +type ProgressListener interface { + ProgressChangedCallback(event *ProgressEvent) +} + +func progressCallback(listener ProgressListener, event *ProgressEvent) { + if listener != nil && event != nil { + listener.ProgressChangedCallback(event) + } +} + +type teeReader struct { + reader io.Reader + writer io.Writer + consumedBytes int64 + totalBytes int64 + listener ProgressListener + disableCheckSum bool +} + +func (r *teeReader) Read(p []byte) (int, error) { + if r.consumedBytes == 0 { + event := newProgressEvent(ProgressStartedEvent, 0, r.consumedBytes, r.totalBytes) + progressCallback(r.listener, event) + } + + n, err := r.reader.Read(p) + if err != nil && err != io.EOF { + event := newProgressEvent(ProgressFailedEvent, 0, r.consumedBytes, r.totalBytes, err) + progressCallback(r.listener, event) + } + if n > 0 { + r.consumedBytes += int64(n) + if r.writer != nil { + if n, err := r.writer.Write(p[:n]); err != nil { + return n, err + } + } + if r.listener != nil { + event := newProgressEvent(ProgressDataEvent, int64(n), r.consumedBytes, r.totalBytes) + progressCallback(r.listener, event) + } + } + + if err == io.EOF { + event := newProgressEvent(ProgressCompletedEvent, int64(n), r.consumedBytes, r.totalBytes) + progressCallback(r.listener, event) + } + + return n, err +} + +func (r *teeReader) Close() error { + if rc, ok := r.reader.(io.ReadCloser); ok { + return rc.Close() + } + return nil +} + +func (r *teeReader) Size() int64 { + return r.totalBytes +} + +func (r *teeReader) Crc64() uint64 { + if r.writer != nil { + if th, ok := r.writer.(hash.Hash64); ok { + return th.Sum64() + } + } + return 0 +} + +func (r *teeReader) Sum() []byte { + if r.writer != nil { + if th, ok := r.writer.(hash.Hash); ok { + return th.Sum(nil) + } + } + return []byte{} +} + +func TeeReader(reader io.Reader, writer io.Writer, total int64, listener ProgressListener) *teeReader { + return &teeReader{ + reader: reader, + writer: writer, + consumedBytes: 0, + totalBytes: total, + listener: listener, + disableCheckSum: false, + } +} + +type FixedLengthReader interface { + io.Reader + Size() int64 +} + +type DefaultProgressListener struct { +} + +func (l *DefaultProgressListener) ProgressChangedCallback(event *ProgressEvent) { + switch event.EventType { + case ProgressStartedEvent: + fmt.Printf("Transfer Start [ConsumedBytes/TotalBytes: %d/%d]\n", + event.ConsumedBytes, event.TotalBytes) + case ProgressDataEvent: + fmt.Printf("\rTransfer Data [ConsumedBytes/TotalBytes: %d/%d, %d%%]", + event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes) + case ProgressCompletedEvent: + fmt.Printf("\nTransfer Complete [ConsumedBytes/TotalBytes: %d/%d]\n", + event.ConsumedBytes, event.TotalBytes) + case ProgressFailedEvent: + fmt.Printf("\nTransfer Failed [ConsumedBytes/TotalBytes: %d/%d] [Err: %v]\n", + event.ConsumedBytes, event.TotalBytes, event.Err) + default: + fmt.Printf("Progress Changed Error: unknown progress event type\n") + } +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/service.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/service.go new file mode 100644 index 00000000000..483af72af16 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/service.go @@ -0,0 +1,53 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +// Service 相关 API +type ServiceService service + +// ServiceGetResult is the result of Get Service +type ServiceGetResult struct { + XMLName xml.Name `xml:"ListAllMyBucketsResult"` + Owner *Owner `xml:"Owner"` + Buckets []Bucket `xml:"Buckets>Bucket,omitempty"` + Marker string `xml:"Marker"` + NextMarker string `xml:"NextMarker"` + IsTruncated bool `xml:"IsTruncated"` +} + +type ServiceGetOptions struct { + TagKey string `url:"tagkey,omitempty"` + TagValue string `url:"tagvalue,omitempty"` + MaxKeys int64 `url:"max-keys,omitempty"` + Marker string `url:"marker,omitempty"` + Range string `url:"range,omitempty"` + CreateTime int64 `url:"create-time,omitempty"` + Region string `url:"region,omitempty"` +} + +// Get Service 接口实现获取该用户下所有Bucket列表。 +// +// 该API接口需要使用Authorization签名认证, +// 且只能获取签名中AccessID所属账户的Bucket列表。 +// +// https://www.qcloud.com/document/product/436/8291 +func (s *ServiceService) Get(ctx context.Context, opt ...*ServiceGetOptions) (*ServiceGetResult, *Response, error) { + var sopt *ServiceGetOptions + if len(opt) > 0 { + sopt = opt[0] + } + var res ServiceGetResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.ServiceURL, + uri: "/", + method: http.MethodGet, + optQuery: sopt, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/thanos-io/objstore/client/factory.go b/vendor/github.com/thanos-io/objstore/client/factory.go new file mode 100644 index 00000000000..f0a2287e41d --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/client/factory.go @@ -0,0 +1,85 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package client + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/thanos-io/objstore" + "github.com/thanos-io/objstore/providers/azure" + "github.com/thanos-io/objstore/providers/bos" + "github.com/thanos-io/objstore/providers/cos" + "github.com/thanos-io/objstore/providers/filesystem" + "github.com/thanos-io/objstore/providers/gcs" + "github.com/thanos-io/objstore/providers/obs" + "github.com/thanos-io/objstore/providers/oci" + "github.com/thanos-io/objstore/providers/oss" + "github.com/thanos-io/objstore/providers/s3" + "github.com/thanos-io/objstore/providers/swift" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/pkg/errors" + "gopkg.in/yaml.v2" +) + +type BucketConfig struct { + Type objstore.ObjProvider `yaml:"type"` + Config interface{} `yaml:"config"` + Prefix string `yaml:"prefix" default:""` +} + +// NewBucket initializes and returns new object storage clients. +// NOTE: confContentYaml can contain secrets. +func NewBucket(logger log.Logger, confContentYaml []byte, component string, wrapRoundtripper func(http.RoundTripper) http.RoundTripper) (objstore.Bucket, error) { + level.Info(logger).Log("msg", "loading bucket configuration") + bucketConf := &BucketConfig{} + if err := yaml.UnmarshalStrict(confContentYaml, bucketConf); err != nil { + return nil, errors.Wrap(err, "parsing config YAML file") + } + + return NewBucketFromConfig(logger, bucketConf, component, wrapRoundtripper) +} + +// NewBucketFromConfig creates an objstore.Bucket from an existing BucketConfig object. +func NewBucketFromConfig(logger log.Logger, bucketConf *BucketConfig, component string, wrapRoundtripper func(http.RoundTripper) http.RoundTripper) (objstore.Bucket, error) { + config, err := yaml.Marshal(bucketConf.Config) + if err != nil { + return nil, errors.Wrap(err, "marshal content of bucket configuration") + } + + var bucket objstore.Bucket + switch strings.ToUpper(string(bucketConf.Type)) { + case string(objstore.GCS): + bucket, err = gcs.NewBucket(context.Background(), logger, config, component, wrapRoundtripper) + case string(objstore.S3): + bucket, err = s3.NewBucket(logger, config, component, wrapRoundtripper) + case string(objstore.AZURE): + bucket, err = azure.NewBucket(logger, config, component, wrapRoundtripper) + case string(objstore.SWIFT): + bucket, err = swift.NewContainer(logger, config, wrapRoundtripper) + case string(objstore.COS): + bucket, err = cos.NewBucket(logger, config, component, wrapRoundtripper) + case string(objstore.ALIYUNOSS): + bucket, err = oss.NewBucket(logger, config, component, wrapRoundtripper) + case string(objstore.FILESYSTEM): + bucket, err = filesystem.NewBucketFromConfig(config) + case string(objstore.BOS): + bucket, err = bos.NewBucket(logger, config, component) + case string(objstore.OCI): + bucket, err = oci.NewBucket(logger, config, wrapRoundtripper) + case string(objstore.OBS): + bucket, err = obs.NewBucket(logger, config) + default: + return nil, errors.Errorf("bucket with type %s is not supported", bucketConf.Type) + } + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("create %s client", bucketConf.Type)) + } + + return objstore.NewPrefixedBucket(bucket, bucketConf.Prefix), nil +} diff --git a/vendor/github.com/thanos-io/objstore/clientutil/parse.go b/vendor/github.com/thanos-io/objstore/clientutil/parse.go new file mode 100644 index 00000000000..759c42d29c8 --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/clientutil/parse.go @@ -0,0 +1,65 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package clientutil + +import ( + "net/http" + "strconv" + "time" + + "github.com/pkg/errors" +) + +// ParseContentLength returns the content length (in bytes) parsed from the Content-Length +// HTTP header in input. +func ParseContentLength(m http.Header) (int64, error) { + const name = "Content-Length" + + v, ok := m[name] + if !ok { + return 0, errors.Errorf("%s header not found", name) + } + + if len(v) == 0 { + return 0, errors.Errorf("%s header has no values", name) + } + + ret, err := strconv.ParseInt(v[0], 10, 64) + if err != nil { + return 0, errors.Wrapf(err, "convert %s", name) + } + + return ret, nil +} + +// ParseLastModified returns the timestamp parsed from the Last-Modified +// HTTP header in input. +// Passing an second parameter, named f, to specify the time format. +// If f is empty then RFC3339 will be used as default format. +func ParseLastModified(m http.Header, f string) (time.Time, error) { + const ( + name = "Last-Modified" + defaultFormat = time.RFC3339 + ) + + v, ok := m[name] + if !ok { + return time.Time{}, errors.Errorf("%s header not found", name) + } + + if len(v) == 0 { + return time.Time{}, errors.Errorf("%s header has no values", name) + } + + if f == "" { + f = defaultFormat + } + + mod, err := time.Parse(f, v[0]) + if err != nil { + return time.Time{}, errors.Wrapf(err, "parse %s", name) + } + + return mod, nil +} diff --git a/vendor/github.com/thanos-io/objstore/providers/bos/bos.go b/vendor/github.com/thanos-io/objstore/providers/bos/bos.go new file mode 100644 index 00000000000..be7a1b3c5fc --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/providers/bos/bos.go @@ -0,0 +1,443 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package bos + +import ( + "context" + "fmt" + "io" + "math" + "math/rand" + "net/http" + "os" + "strings" + "testing" + "time" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/services/bos" + "github.com/baidubce/bce-sdk-go/services/bos/api" + "github.com/go-kit/log" + "github.com/pkg/errors" + "gopkg.in/yaml.v2" + + "github.com/thanos-io/objstore" +) + +// partSize 128MB. +const partSize = 1024 * 1024 * 128 + +// Bucket implements the store.Bucket interface against bos-compatible(Baidu Object Storage) APIs. +type Bucket struct { + logger log.Logger + client *bos.Client + name string +} + +// Config encapsulates the necessary config values to instantiate an bos client. +type Config struct { + Bucket string `yaml:"bucket"` + Endpoint string `yaml:"endpoint"` + AccessKey string `yaml:"access_key"` + SecretKey string `yaml:"secret_key"` +} + +func (conf *Config) validate() error { + if conf.Bucket == "" || + conf.Endpoint == "" || + conf.AccessKey == "" || + conf.SecretKey == "" { + return errors.New("insufficient BOS configuration information") + } + + return nil +} + +// parseConfig unmarshal a buffer into a Config with default HTTPConfig values. +func parseConfig(conf []byte) (Config, error) { + config := Config{} + if err := yaml.Unmarshal(conf, &config); err != nil { + return Config{}, err + } + + return config, nil +} + +// NewBucket new bos bucket. +func NewBucket(logger log.Logger, conf []byte, component string) (*Bucket, error) { + // TODO(https://github.com/thanos-io/objstore/pull/150): Add support for roundtripper wrapper. + if logger == nil { + logger = log.NewNopLogger() + } + + config, err := parseConfig(conf) + if err != nil { + return nil, errors.Wrap(err, "parsing BOS configuration") + } + + return NewBucketWithConfig(logger, config, component) +} + +// NewBucketWithConfig returns a new Bucket using the provided bos config struct. +func NewBucketWithConfig(logger log.Logger, config Config, component string) (*Bucket, error) { + if err := config.validate(); err != nil { + return nil, errors.Wrap(err, "validating BOS configuration") + } + + client, err := bos.NewClient(config.AccessKey, config.SecretKey, config.Endpoint) + if err != nil { + return nil, errors.Wrap(err, "creating BOS client") + } + + client.Config.UserAgent = fmt.Sprintf("thanos-%s", component) + + bkt := &Bucket{ + logger: logger, + client: client, + name: config.Bucket, + } + return bkt, nil +} + +func (b *Bucket) Provider() objstore.ObjProvider { return objstore.BOS } + +// Name returns the bucket name for the provider. +func (b *Bucket) Name() string { + return b.name +} + +// Delete removes the object with the given name. +func (b *Bucket) Delete(_ context.Context, name string) error { + return b.client.DeleteObject(b.name, name) +} + +// Upload the contents of the reader as an object into the bucket. +func (b *Bucket) Upload(_ context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + size, err := objstore.TryToGetSize(r) + if err != nil { + return errors.Wrapf(err, "getting size of %s", name) + } + + uploadOpts := objstore.ApplyObjectUploadOptions(opts...) + partNums, lastSlice := int(math.Floor(float64(size)/partSize)), size%partSize + if partNums == 0 { + body, err := bce.NewBodyFromSizedReader(r, lastSlice) + if err != nil { + return errors.Wrapf(err, "failed to create SizedReader for %s", name) + } + + if _, err := b.client.PutObject(b.name, name, body, &api.PutObjectArgs{ContentType: uploadOpts.ContentType}); err != nil { + return errors.Wrapf(err, "failed to upload %s", name) + } + + return nil + } + + result, err := b.client.InitiateMultipartUpload(b.name, name, uploadOpts.ContentType, nil) + if err != nil { + return errors.Wrapf(err, "failed to initiate MultipartUpload for %s", name) + } + + uploadEveryPart := func(partSize int64, part int, uploadId string) (string, error) { + body, err := bce.NewBodyFromSizedReader(r, partSize) + if err != nil { + return "", err + } + + etag, err := b.client.UploadPart(b.name, name, uploadId, part, body, nil) + if err != nil { + if err := b.client.AbortMultipartUpload(b.name, name, uploadId); err != nil { + return etag, err + } + return etag, err + } + return etag, nil + } + + var parts []api.UploadInfoType + + for part := 1; part <= partNums; part++ { + etag, err := uploadEveryPart(partSize, part, result.UploadId) + if err != nil { + return errors.Wrapf(err, "failed to upload part %d for %s", part, name) + } + parts = append(parts, api.UploadInfoType{PartNumber: part, ETag: etag}) + } + + if lastSlice != 0 { + etag, err := uploadEveryPart(lastSlice, partNums+1, result.UploadId) + if err != nil { + return errors.Wrapf(err, "failed to upload the last part for %s", name) + } + parts = append(parts, api.UploadInfoType{PartNumber: partNums + 1, ETag: etag}) + } + + if _, err := b.client.CompleteMultipartUploadFromStruct(b.name, name, result.UploadId, &api.CompleteMultipartUploadArgs{Parts: parts}); err != nil { + return errors.Wrapf(err, "failed to set %s upload completed", name) + } + return nil +} + +func (b *Bucket) SupportedIterOptions() []objstore.IterOptionType { + return []objstore.IterOptionType{objstore.Recursive, objstore.UpdatedAt} +} + +func (b *Bucket) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + if err := objstore.ValidateIterOptions(b.SupportedIterOptions(), options...); err != nil { + return err + } + + if dir != "" { + dir = strings.TrimSuffix(dir, objstore.DirDelim) + objstore.DirDelim + } + + delimiter := objstore.DirDelim + + params := objstore.ApplyIterOptions(options...) + if params.Recursive { + delimiter = "" + } + + var marker string + for { + if err := ctx.Err(); err != nil { + return err + } + + objects, err := b.client.ListObjects(b.name, &api.ListObjectsArgs{ + Delimiter: delimiter, + Marker: marker, + MaxKeys: 1000, + Prefix: dir, + }) + if err != nil { + return err + } + + marker = objects.NextMarker + for _, object := range objects.Contents { + attrs := objstore.IterObjectAttributes{ + Name: object.Key, + } + + if params.LastModified && object.LastModified != "" { + lastModified, err := time.Parse(time.RFC1123, object.LastModified) + if err != nil { + return fmt.Errorf("iter: get last modified: %w", err) + } + attrs.SetLastModified(lastModified) + } + + if err := f(attrs); err != nil { + return err + } + } + + for _, object := range objects.CommonPrefixes { + if err := f(objstore.IterObjectAttributes{Name: object.Prefix}); err != nil { + return err + } + } + if !objects.IsTruncated { + break + } + } + return nil +} + +// Iter calls f for each entry in the given directory. The argument to f is the full +// object name including the prefix of the inspected directory. +func (b *Bucket) Iter(ctx context.Context, dir string, f func(string) error, opts ...objstore.IterOption) error { + // Only include recursive option since attributes are not used in this method. + var filteredOpts []objstore.IterOption + for _, opt := range opts { + if opt.Type == objstore.Recursive { + filteredOpts = append(filteredOpts, opt) + break + } + } + + return b.IterWithAttributes(ctx, dir, func(attrs objstore.IterObjectAttributes) error { + return f(attrs.Name) + }, filteredOpts...) +} + +// Get returns a reader for the given object name. +func (b *Bucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { + return b.getRange(ctx, b.name, name, 0, -1) +} + +// GetRange returns a new range reader for the given object name and range. +func (b *Bucket) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + return b.getRange(ctx, b.name, name, off, length) +} + +// Exists checks if the given object exists in the bucket. +func (b *Bucket) Exists(_ context.Context, name string) (bool, error) { + _, err := b.client.GetObjectMeta(b.name, name) + if err != nil { + if b.IsObjNotFoundErr(err) { + return false, nil + } + return false, errors.Wrapf(err, "getting object metadata of %s", name) + } + return true, nil +} + +func (b *Bucket) Close() error { + return nil +} + +// ObjectSize returns the size of the specified object. +func (b *Bucket) ObjectSize(_ context.Context, name string) (uint64, error) { + objMeta, err := b.client.GetObjectMeta(b.name, name) + if err != nil { + return 0, err + } + return uint64(objMeta.ContentLength), nil +} + +// Attributes returns information about the specified object. +func (b *Bucket) Attributes(_ context.Context, name string) (objstore.ObjectAttributes, error) { + objMeta, err := b.client.GetObjectMeta(b.name, name) + if err != nil { + return objstore.ObjectAttributes{}, errors.Wrapf(err, "gettting objectmeta of %s", name) + } + + lastModified, err := time.Parse(time.RFC1123, objMeta.LastModified) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + return objstore.ObjectAttributes{ + Size: objMeta.ContentLength, + LastModified: lastModified, + }, nil +} + +// IsObjNotFoundErr returns true if error means that object is not found. Relevant to Get operations. +func (b *Bucket) IsObjNotFoundErr(err error) bool { + switch bosErr := errors.Cause(err).(type) { + case *bce.BceServiceError: + if bosErr.StatusCode == http.StatusNotFound || bosErr.Code == "NoSuchKey" { + return true + } + } + return false +} + +// IsAccessDeniedErr returns true if access to object is denied. +func (b *Bucket) IsAccessDeniedErr(_ error) bool { + return false +} + +func (b *Bucket) getRange(_ context.Context, bucketName, objectKey string, off, length int64) (io.ReadCloser, error) { + if len(objectKey) == 0 { + return nil, errors.Errorf("given object name should not empty") + } + + ranges := []int64{off} + if length != -1 { + ranges = append(ranges, off+length-1) + } + + obj, err := b.client.GetObject(bucketName, objectKey, map[string]string{}, ranges...) + if err != nil { + return nil, err + } + + return objstore.ObjectSizerReadCloser{ + ReadCloser: obj.Body, + Size: func() (int64, error) { + return obj.ContentLength, nil + }, + }, err +} + +func configFromEnv() Config { + c := Config{ + Bucket: os.Getenv("BOS_BUCKET"), + Endpoint: os.Getenv("BOS_ENDPOINT"), + AccessKey: os.Getenv("BOS_ACCESS_KEY"), + SecretKey: os.Getenv("BOS_SECRET_KEY"), + } + return c +} + +// NewTestBucket creates test bkt client that before returning creates temporary bucket. +// In a close function it empties and deletes the bucket. +func NewTestBucket(t testing.TB) (objstore.Bucket, func(), error) { + c := configFromEnv() + if err := validateForTest(c); err != nil { + return nil, nil, err + } + + if c.Bucket != "" { + if os.Getenv("THANOS_ALLOW_EXISTING_BUCKET_USE") == "" { + return nil, nil, errors.New("BOS_BUCKET is defined. Normally this tests will create temporary bucket " + + "and delete it after test. Unset BOS_BUCKET env variable to use default logic. If you really want to run " + + "tests against provided (NOT USED!) bucket, set THANOS_ALLOW_EXISTING_BUCKET_USE=true. WARNING: That bucket " + + "needs to be manually cleared. This means that it is only useful to run one test in a time. This is due " + + "to safety (accidentally pointing prod bucket for test) as well as BOS not being fully strong consistent.") + } + + bc, err := yaml.Marshal(c) + if err != nil { + return nil, nil, err + } + + b, err := NewBucket(log.NewNopLogger(), bc, "thanos-e2e-test") + if err != nil { + return nil, nil, err + } + + if err := b.Iter(context.Background(), "", func(f string) error { + return errors.Errorf("bucket %s is not empty", c.Bucket) + }); err != nil { + return nil, nil, errors.Wrapf(err, "checking bucket %s", c.Bucket) + } + + t.Log("WARNING. Reusing", c.Bucket, "BOS bucket for BOS tests. Manual cleanup afterwards is required") + return b, func() {}, nil + } + + src := rand.NewSource(time.Now().UnixNano()) + tmpBucketName := strings.Replace(fmt.Sprintf("test_%x", src.Int63()), "_", "-", -1) + + if len(tmpBucketName) >= 31 { + tmpBucketName = tmpBucketName[:31] + } + + c.Bucket = tmpBucketName + bc, err := yaml.Marshal(c) + if err != nil { + return nil, nil, err + } + + b, err := NewBucket(log.NewNopLogger(), bc, "thanos-e2e-test") + if err != nil { + return nil, nil, err + } + + if _, err := b.client.PutBucket(b.name); err != nil { + return nil, nil, err + } + + t.Log("created temporary BOS bucket for BOS tests with name", tmpBucketName) + return b, func() { + objstore.EmptyBucket(t, context.Background(), b) + if err := b.client.DeleteBucket(b.name); err != nil { + t.Logf("deleting bucket %s failed: %s", tmpBucketName, err) + } + }, nil +} + +func validateForTest(conf Config) error { + if conf.Endpoint == "" || + conf.AccessKey == "" || + conf.SecretKey == "" { + return errors.New("insufficient BOS configuration information") + } + return nil +} diff --git a/vendor/github.com/thanos-io/objstore/providers/cos/cos.go b/vendor/github.com/thanos-io/objstore/providers/cos/cos.go new file mode 100644 index 00000000000..9ac96bfda70 --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/providers/cos/cos.go @@ -0,0 +1,594 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package cos + +import ( + "context" + "fmt" + "io" + "math" + "math/rand" + "net/http" + "net/url" + "os" + "strings" + "testing" + "time" + + "github.com/efficientgo/core/logerrcapture" + "github.com/go-kit/log" + "github.com/pkg/errors" + "github.com/prometheus/common/model" + "github.com/tencentyun/cos-go-sdk-v5" + "gopkg.in/yaml.v2" + + "github.com/thanos-io/objstore" + "github.com/thanos-io/objstore/clientutil" + "github.com/thanos-io/objstore/exthttp" +) + +// DirDelim is the delimiter used to model a directory structure in an object store bucket. +const dirDelim = "/" + +// Bucket implements the store.Bucket interface against cos-compatible(Tencent Object Storage) APIs. +type Bucket struct { + logger log.Logger + client *cos.Client + name string +} + +// DefaultConfig is the default config for an cos client. default tune the `MaxIdleConnsPerHost`. +var DefaultConfig = Config{ + HTTPConfig: exthttp.HTTPConfig{ + IdleConnTimeout: model.Duration(90 * time.Second), + ResponseHeaderTimeout: model.Duration(2 * time.Minute), + TLSHandshakeTimeout: model.Duration(10 * time.Second), + ExpectContinueTimeout: model.Duration(1 * time.Second), + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + MaxConnsPerHost: 0, + }, +} + +// Config encapsulates the necessary config values to instantiate an cos client. +type Config struct { + Bucket string `yaml:"bucket"` + Region string `yaml:"region"` + AppId string `yaml:"app_id"` + Endpoint string `yaml:"endpoint"` + SecretKey string `yaml:"secret_key"` + SecretId string `yaml:"secret_id"` + MaxRetries int `yaml:"max_retries"` + HTTPConfig exthttp.HTTPConfig `yaml:"http_config"` +} + +// Validate checks to see if mandatory cos config options are set. +func (conf *Config) validate() error { + if conf.Endpoint != "" { + if _, err := url.Parse(conf.Endpoint); err != nil { + return errors.Wrap(err, "parse endpoint") + } + if conf.SecretId == "" || + conf.SecretKey == "" { + return errors.New("secret_id or secret_key is empty") + } + return nil + } + if conf.Bucket == "" || + conf.AppId == "" || + conf.Region == "" || + conf.SecretId == "" || + conf.SecretKey == "" { + return errors.New("insufficient cos configuration information") + } + return nil +} + +// parseConfig unmarshal a buffer into a Config with default HTTPConfig values. +func parseConfig(conf []byte) (Config, error) { + config := DefaultConfig + if err := yaml.Unmarshal(conf, &config); err != nil { + return Config{}, err + } + + return config, nil +} + +// NewBucket returns a new Bucket using the provided cos configuration. +func NewBucket(logger log.Logger, conf []byte, component string, wrapRoundtripper func(http.RoundTripper) http.RoundTripper) (*Bucket, error) { + if logger == nil { + logger = log.NewNopLogger() + } + + config, err := parseConfig(conf) + if err != nil { + return nil, errors.Wrap(err, "parsing cos configuration") + } + return NewBucketWithConfig(logger, config, component, wrapRoundtripper) +} + +// NewBucketWithConfig returns a new Bucket using the provided cos config values. +func NewBucketWithConfig(logger log.Logger, config Config, component string, wrapRoundtripper func(http.RoundTripper) http.RoundTripper) (*Bucket, error) { + if err := config.validate(); err != nil { + return nil, errors.Wrap(err, "validate cos configuration") + } + + var bucketURL *url.URL + var err error + if config.Endpoint != "" { + bucketURL, err = url.Parse(config.Endpoint) + if err != nil { + return nil, errors.Wrap(err, "parse endpoint") + } + } else { + bucketURL, err = cos.NewBucketURL(fmt.Sprintf("%s-%s", config.Bucket, config.AppId), config.Region, true) + if err != nil { + return nil, errors.Wrap(err, "create bucket") + } + } + b := &cos.BaseURL{BucketURL: bucketURL} + var rt http.RoundTripper + rt, err = exthttp.DefaultTransport(config.HTTPConfig) + if err != nil { + return nil, err + } + if config.HTTPConfig.Transport != nil { + rt = config.HTTPConfig.Transport + } + if wrapRoundtripper != nil { + rt = wrapRoundtripper(rt) + } + client := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: config.SecretId, + SecretKey: config.SecretKey, + Transport: rt, + }, + }) + + if config.MaxRetries > 0 { + client.Conf.RetryOpt.Count = config.MaxRetries + } + + bkt := &Bucket{ + logger: logger, + client: client, + name: config.Bucket, + } + return bkt, nil +} + +func (b *Bucket) Provider() objstore.ObjProvider { return objstore.COS } + +// Name returns the bucket name for COS. +func (b *Bucket) Name() string { + return b.name +} + +// Attributes returns information about the specified object. +func (b *Bucket) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { + resp, err := b.client.Object.Head(ctx, name, nil) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + size, err := clientutil.ParseContentLength(resp.Header) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + // tencent cos return Last-Modified header in RFC1123 format. + // see api doc for details: https://intl.cloud.tencent.com/document/product/436/7729 + mod, err := clientutil.ParseLastModified(resp.Header, time.RFC1123) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + return objstore.ObjectAttributes{ + Size: size, + LastModified: mod, + }, nil +} + +var ( + _ cos.FixedLengthReader = (*fixedLengthReader)(nil) +) + +type fixedLengthReader struct { + io.Reader + size int64 +} + +func newFixedLengthReader(r io.Reader, size int64) io.Reader { + return fixedLengthReader{ + Reader: io.LimitReader(r, size), + size: size, + } +} + +// Size implement cos.FixedLengthReader interface. +func (r fixedLengthReader) Size() int64 { + return r.size +} + +// Upload the contents of the reader as an object into the bucket. +func (b *Bucket) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + size, err := objstore.TryToGetSize(r) + if err != nil { + return errors.Wrapf(err, "getting size of %s", name) + } + uploadOpts := objstore.ApplyObjectUploadOptions(opts...) + + // partSize 128MB. + const partSize = 1024 * 1024 * 128 + partNums, lastSlice := int(math.Floor(float64(size)/partSize)), size%partSize + if partNums == 0 { + cosOpts := &cos.ObjectPutOptions{ + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ + ContentType: uploadOpts.ContentType, + }, + } + if _, err := b.client.Object.Put(ctx, name, r, cosOpts); err != nil { + return errors.Wrapf(err, "Put object: %s", name) + } + return nil + } + // 1. init. + cosOpts := &cos.InitiateMultipartUploadOptions{ + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ + ContentType: uploadOpts.ContentType, + }, + } + result, _, err := b.client.Object.InitiateMultipartUpload(ctx, name, cosOpts) + if err != nil { + return errors.Wrapf(err, "InitiateMultipartUpload %s", name) + } + uploadEveryPart := func(partSize int64, part int, uploadID string) (string, error) { + r := newFixedLengthReader(r, partSize) + resp, err := b.client.Object.UploadPart(ctx, name, uploadID, part, r, &cos.ObjectUploadPartOptions{ + ContentLength: partSize, + }) + if err != nil { + if _, err := b.client.Object.AbortMultipartUpload(ctx, name, uploadID); err != nil { + return "", err + } + return "", err + } + etag := resp.Header.Get("ETag") + return etag, nil + } + optcom := &cos.CompleteMultipartUploadOptions{} + // 2. upload parts. + for part := 1; part <= partNums; part++ { + etag, err := uploadEveryPart(partSize, part, result.UploadID) + if err != nil { + return errors.Wrapf(err, "uploadPart %d, %s", part, name) + } + optcom.Parts = append(optcom.Parts, cos.Object{ + PartNumber: part, ETag: etag}, + ) + } + // 3. upload last part. + if lastSlice != 0 { + part := partNums + 1 + etag, err := uploadEveryPart(lastSlice, part, result.UploadID) + if err != nil { + return errors.Wrapf(err, "uploadPart %d, %s", part, name) + } + optcom.Parts = append(optcom.Parts, cos.Object{ + PartNumber: part, ETag: etag}, + ) + } + // 4. complete. + if _, _, err := b.client.Object.CompleteMultipartUpload(ctx, name, result.UploadID, optcom); err != nil { + return errors.Wrapf(err, "CompleteMultipartUpload %s", name) + } + return nil +} + +// Delete removes the object with the given name. +func (b *Bucket) Delete(ctx context.Context, name string) error { + if _, err := b.client.Object.Delete(ctx, name); err != nil { + return errors.Wrap(err, "delete cos object") + } + return nil +} + +func (b *Bucket) SupportedIterOptions() []objstore.IterOptionType { + return []objstore.IterOptionType{objstore.Recursive} +} + +// Iter calls f for each entry in the given directory. The argument to f is the full +// object name including the prefix of the inspected directory. +func (b *Bucket) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { + if dir != "" { + dir = strings.TrimSuffix(dir, dirDelim) + dirDelim + } + + for object := range b.listObjects(ctx, dir, options...) { + if object.err != nil { + return object.err + } + if object.key == "" { + continue + } + if err := f(object.key); err != nil { + return err + } + } + + return nil +} + +func (b *Bucket) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + if err := objstore.ValidateIterOptions(b.SupportedIterOptions(), options...); err != nil { + return err + } + + return b.Iter(ctx, dir, func(name string) error { + return f(objstore.IterObjectAttributes{Name: name}) + }, options...) +} + +func (b *Bucket) getRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + if name == "" { + return nil, errors.New("given object name should not empty") + } + + opts := &cos.ObjectGetOptions{} + if length != -1 { + if err := setRange(opts, off, off+length-1); err != nil { + return nil, err + } + } else if off > 0 { + if err := setRange(opts, off, 0); err != nil { + return nil, err + } + } + + resp, err := b.client.Object.Get(ctx, name, opts) + if err != nil { + return nil, err + } + if _, err := resp.Body.Read(nil); err != nil { + logerrcapture.ExhaustClose(b.logger, resp.Body, "cos get range obj close") + return nil, err + } + // Add size info into reader to pass it to Upload function. + return objstore.ObjectSizerReadCloser{ + ReadCloser: resp.Body, + Size: func() (int64, error) { + return resp.ContentLength, nil + }, + }, nil +} + +// Get returns a reader for the given object name. +func (b *Bucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { + return b.getRange(ctx, name, 0, -1) +} + +// GetRange returns a new range reader for the given object name and range. +func (b *Bucket) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + return b.getRange(ctx, name, off, length) +} + +// Exists checks if the given object exists in the bucket. +func (b *Bucket) Exists(ctx context.Context, name string) (bool, error) { + if _, err := b.client.Object.Head(ctx, name, nil); err != nil { + if b.IsObjNotFoundErr(err) { + return false, nil + } + return false, errors.Wrap(err, "head cos object") + } + + return true, nil +} + +// IsObjNotFoundErr returns true if error means that object is not found. Relevant to Get operations. +func (b *Bucket) IsObjNotFoundErr(err error) bool { + switch tmpErr := errors.Cause(err).(type) { + case *cos.ErrorResponse: + if tmpErr.Code == "NoSuchKey" || + (tmpErr.Response != nil && tmpErr.Response.StatusCode == http.StatusNotFound) { + return true + } + return false + default: + return false + } +} + +// IsAccessDeniedErr returns true if access to object is denied. +func (b *Bucket) IsAccessDeniedErr(_ error) bool { + return false +} + +func (b *Bucket) Close() error { return nil } + +type objectInfo struct { + key string + err error +} + +func (b *Bucket) listObjects(ctx context.Context, objectPrefix string, options ...objstore.IterOption) <-chan objectInfo { + objectsCh := make(chan objectInfo, 1) + + // If recursive iteration is enabled we should pass an empty delimiter. + delimiter := dirDelim + if objstore.ApplyIterOptions(options...).Recursive { + delimiter = "" + } + + go func(objectsCh chan<- objectInfo) { + defer close(objectsCh) + var marker string + for { + result, _, err := b.client.Bucket.Get(ctx, &cos.BucketGetOptions{ + Prefix: objectPrefix, + MaxKeys: 1000, + Marker: marker, + Delimiter: delimiter, + }) + if err != nil { + select { + case objectsCh <- objectInfo{ + err: err, + }: + case <-ctx.Done(): + } + return + } + + for _, object := range result.Contents { + select { + case objectsCh <- objectInfo{ + key: object.Key, + }: + case <-ctx.Done(): + return + } + } + + // The result of CommonPrefixes contains the objects + // that have the same keys between Prefix and the key specified by delimiter. + for _, obj := range result.CommonPrefixes { + select { + case objectsCh <- objectInfo{ + key: obj, + }: + case <-ctx.Done(): + return + } + } + + if !result.IsTruncated { + return + } + + marker = result.NextMarker + } + }(objectsCh) + return objectsCh +} + +func setRange(opts *cos.ObjectGetOptions, start, end int64) error { + if start == 0 && end < 0 { + opts.Range = fmt.Sprintf("bytes=%d", end) + } else if 0 < start && end == 0 { + opts.Range = fmt.Sprintf("bytes=%d-", start) + } else if 0 <= start && start <= end { + opts.Range = fmt.Sprintf("bytes=%d-%d", start, end) + } else { + return errors.Errorf("Invalid range specified: start=%d end=%d", start, end) + } + return nil +} + +func configFromEnv() Config { + c := Config{ + Bucket: os.Getenv("COS_BUCKET"), + AppId: os.Getenv("COS_APP_ID"), + Region: os.Getenv("COS_REGION"), + Endpoint: os.Getenv("COS_ENDPOINT"), + SecretId: os.Getenv("COS_SECRET_ID"), + SecretKey: os.Getenv("COS_SECRET_KEY"), + } + + return c +} + +// NewTestBucket creates test bkt client that before returning creates temporary bucket. +// In a close function it empties and deletes the bucket. +func NewTestBucket(t testing.TB) (objstore.Bucket, func(), error) { + c := configFromEnv() + if err := validateForTest(c); err != nil { + return nil, nil, err + } + + if c.Bucket != "" { + if os.Getenv("THANOS_ALLOW_EXISTING_BUCKET_USE") == "" { + return nil, nil, errors.New("COS_BUCKET is defined. Normally this tests will create temporary bucket " + + "and delete it after test. Unset COS_BUCKET env variable to use default logic. If you really want to run " + + "tests against provided (NOT USED!) bucket, set THANOS_ALLOW_EXISTING_BUCKET_USE=true. WARNING: That bucket " + + "needs to be manually cleared. This means that it is only useful to run one test in a time. This is due " + + "to safety (accidentally pointing prod bucket for test) as well as COS not being fully strong consistent.") + } + + bc, err := yaml.Marshal(c) + if err != nil { + return nil, nil, err + } + + b, err := NewBucket(log.NewNopLogger(), bc, "thanos-e2e-test", nil) + if err != nil { + return nil, nil, err + } + + if err := b.Iter(context.Background(), "", func(_ string) error { + return errors.Errorf("bucket %s is not empty", c.Bucket) + }); err != nil { + return nil, nil, errors.Wrapf(err, "cos check bucket %s", c.Bucket) + } + + t.Log("WARNING. Reusing", c.Bucket, "COS bucket for COS tests. Manual cleanup afterwards is required") + return b, func() {}, nil + } + c.Bucket = createTemporaryTestBucketName(t) + + bc, err := yaml.Marshal(c) + if err != nil { + return nil, nil, err + } + + b, err := NewBucket(log.NewNopLogger(), bc, "thanos-e2e-test", nil) + if err != nil { + return nil, nil, err + } + + if _, err := b.client.Bucket.Put(context.Background(), nil); err != nil { + return nil, nil, err + } + t.Log("created temporary COS bucket for COS tests with name", c.Bucket) + + return b, func() { + objstore.EmptyBucket(t, context.Background(), b) + if _, err := b.client.Bucket.Delete(context.Background()); err != nil { + t.Logf("deleting bucket %s failed: %s", c.Bucket, err) + } + }, nil +} + +func validateForTest(conf Config) error { + if conf.Endpoint != "" { + if _, err := url.Parse(conf.Endpoint); err != nil { + return errors.Wrap(err, "parse endpoint") + } + if conf.SecretId == "" || + conf.SecretKey == "" { + return errors.New("secret_id or secret_key is empty") + } + return nil + } + if conf.AppId == "" || + conf.Region == "" || + conf.SecretId == "" || + conf.SecretKey == "" { + return errors.New("insufficient cos configuration information") + } + return nil +} + +// createTemporaryTestBucketName create a temp cos bucket for test. +// Bucket Naming Conventions: https://intl.cloud.tencent.com/document/product/436/13312#overview +func createTemporaryTestBucketName(t testing.TB) string { + src := rand.New(rand.NewSource(time.Now().UnixNano())) + name := fmt.Sprintf("test_%x_%s", src.Int31(), strings.ToLower(t.Name())) + name = strings.NewReplacer("_", "-", "/", "-").Replace(name) + const maxLength = 50 + if len(name) >= maxLength { + name = name[:maxLength] + } + return strings.TrimSuffix(name, "-") +} diff --git a/vendor/github.com/thanos-io/objstore/providers/obs/obs.go b/vendor/github.com/thanos-io/objstore/providers/obs/obs.go new file mode 100644 index 00000000000..b6036fed99a --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/providers/obs/obs.go @@ -0,0 +1,451 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package obs + +import ( + "context" + "io" + "math" + "os" + "strings" + "testing" + "time" + + "github.com/thanos-io/objstore" + "github.com/thanos-io/objstore/exthttp" + + "github.com/go-kit/log" + "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" + "github.com/pkg/errors" + "github.com/prometheus/common/model" + "gopkg.in/yaml.v2" +) + +const DirDelim = "/" + +const ( + MinMultipartUploadSize int64 = 1024 * 1024 * 100 + PartSize int64 = 1024 * 1024 * 100 +) + +var DefaultConfig = Config{ + HTTPConfig: exthttp.HTTPConfig{ + IdleConnTimeout: model.Duration(90 * time.Second), + ResponseHeaderTimeout: model.Duration(2 * time.Minute), + TLSHandshakeTimeout: model.Duration(10 * time.Second), + ExpectContinueTimeout: model.Duration(1 * time.Second), + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + MaxConnsPerHost: 0, + }, +} + +type Config struct { + Bucket string `yaml:"bucket"` + Endpoint string `yaml:"endpoint"` + AccessKey string `yaml:"access_key"` + SecretKey string `yaml:"secret_key"` + MaxRetries int `yaml:"max_retries"` + HTTPConfig exthttp.HTTPConfig `yaml:"http_config"` +} + +func (conf *Config) validate() error { + if conf.Endpoint == "" { + return errors.New("no obs endpoint in config file") + } + + if conf.AccessKey == "" && conf.SecretKey != "" { + return errors.New("no obs access_key specified") + } + + if conf.AccessKey != "" && conf.SecretKey == "" { + return errors.New("no obs secret_key specified") + } + + if conf.AccessKey == "" && conf.SecretKey == "" { + return errors.New("no obs secret_key and access_key specified") + } + return nil +} + +type Bucket struct { + logger log.Logger + client *obs.ObsClient + name string +} + +func NewBucket(logger log.Logger, conf []byte) (*Bucket, error) { + // TODO(https://github.com/thanos-io/objstore/pull/150): Add support for roundtripper wrapper. + config, err := parseConfig(conf) + if err != nil { + return nil, errors.Wrap(err, "parsing cos configuration") + } + return NewBucketWithConfig(logger, config) +} + +func parseConfig(conf []byte) (Config, error) { + config := DefaultConfig + if err := yaml.UnmarshalStrict(conf, &config); err != nil { + return Config{}, err + } + + return config, nil +} + +func NewBucketWithConfig(logger log.Logger, config Config) (*Bucket, error) { + if err := config.validate(); err != nil { + return nil, errors.Wrap(err, "validate obs config err") + } + + rt, err := exthttp.DefaultTransport(config.HTTPConfig) + if err != nil { + return nil, errors.Wrap(err, "get http transport err") + } + + var client *obs.ObsClient + if config.MaxRetries > 0 { + client, err = obs.New(config.AccessKey, config.SecretKey, config.Endpoint, obs.WithHttpTransport(rt), obs.WithMaxRetryCount(config.MaxRetries)) + } else { + client, err = obs.New(config.AccessKey, config.SecretKey, config.Endpoint, obs.WithHttpTransport(rt)) + } + + if err != nil { + return nil, errors.Wrap(err, "initialize obs client err") + } + + bkt := &Bucket{ + logger: logger, + client: client, + name: config.Bucket, + } + return bkt, nil +} + +func (b *Bucket) Provider() objstore.ObjProvider { return objstore.OBS } + +// Name returns the bucket name for the provider. +func (b *Bucket) Name() string { + return b.name +} + +// Delete removes the object with the given name. +func (b *Bucket) Delete(ctx context.Context, name string) error { + input := &obs.DeleteObjectInput{Bucket: b.name, Key: name} + _, err := b.client.DeleteObject(input) + return err +} + +// Upload the contents of the reader as an object into the bucket. +func (b *Bucket) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + size, err := objstore.TryToGetSize(r) + + if err != nil { + return errors.Wrapf(err, "failed to get size apriori to upload %s", name) + } + + if size <= 0 { + return errors.New("object size must be provided") + } + + uploadOpts := objstore.ApplyObjectUploadOptions(opts...) + if size <= MinMultipartUploadSize { + err = b.putObjectSingle(name, r, uploadOpts) + if err != nil { + return err + } + } else { + var initOutput *obs.InitiateMultipartUploadOutput + initOutput, err = b.initiateMultipartUpload(name, uploadOpts) + if err != nil { + return err + } + + uploadId := initOutput.UploadId + defer func() { + if err != nil { + if _, err = b.client.AbortMultipartUpload(&obs.AbortMultipartUploadInput{ + UploadId: uploadId, + Bucket: b.name, + Key: name, + }); err != nil { + err = errors.Wrap(err, "failed to abort multipart upload") + return + } + } + }() + parts, err := b.multipartUpload(size, name, uploadId, r) + if err != nil { + return err + } + + _, err = b.client.CompleteMultipartUpload(&obs.CompleteMultipartUploadInput{ + Bucket: b.name, + Key: name, + UploadId: uploadId, + Parts: parts, + }) + if err != nil { + return errors.Wrap(err, "failed to complete multipart upload") + } + } + return nil +} + +func (b *Bucket) putObjectSingle(key string, body io.Reader, opts objstore.UploadObjectParams) error { + input := &obs.PutObjectInput{} + input.Bucket = b.name + input.Key = key + input.Body = body + input.ContentType = opts.ContentType + _, err := b.client.PutObject(input) + if err != nil { + return errors.Wrap(err, "failed to upload object") + } + return nil +} + +func (b *Bucket) initiateMultipartUpload(key string, opts objstore.UploadObjectParams) (output *obs.InitiateMultipartUploadOutput, err error) { + initInput := &obs.InitiateMultipartUploadInput{} + initInput.Bucket = b.name + initInput.Key = key + initInput.ContentType = opts.ContentType + initOutput, err := b.client.InitiateMultipartUpload(initInput) + if err != nil { + return nil, errors.Wrap(err, "failed to init multipart upload job") + } + return initOutput, nil +} + +func (b *Bucket) multipartUpload(size int64, key, uploadId string, body io.Reader) ([]obs.Part, error) { + partSum := int(math.Ceil(float64(size) / float64(PartSize))) + lastPart := size % PartSize + parts := make([]obs.Part, 0, partSum) + for i := 1; i <= partSum; i++ { + partSize := PartSize + if i == partSum { + partSize = lastPart + } + output, err := b.client.UploadPart(&obs.UploadPartInput{ + Bucket: b.name, + Key: key, + UploadId: uploadId, + Body: body, + PartNumber: i, + PartSize: partSize, + Offset: int64(i-1) * PartSize, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to multipart upload") + } + parts = append(parts, obs.Part{PartNumber: output.PartNumber, ETag: output.ETag}) + } + return parts, nil +} + +func (b *Bucket) Close() error { return nil } + +func (b *Bucket) SupportedIterOptions() []objstore.IterOptionType { + return []objstore.IterOptionType{objstore.Recursive} +} + +// Iter calls f for each entry in the given directory (not recursive.) +func (b *Bucket) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { + if dir != "" { + dir = strings.TrimSuffix(dir, DirDelim) + DirDelim + } + + input := &obs.ListObjectsInput{} + input.Bucket = b.name + input.Prefix = dir + input.Delimiter = DirDelim + if objstore.ApplyIterOptions(options...).Recursive { + input.Delimiter = "" + } + for { + output, err := b.client.ListObjects(input) + if err != nil { + return errors.Wrap(err, "failed to list object") + } + for _, content := range output.Contents { + if err := f(content.Key); err != nil { + return errors.Wrapf(err, "failed to call iter function for object %s", content.Key) + } + } + for _, topDir := range output.CommonPrefixes { + if err := f(topDir); err != nil { + return errors.Wrapf(err, "failed to call iter function for top dir object %s", topDir) + } + } + + if !output.IsTruncated { + break + } + + input.Marker = output.NextMarker + } + return nil +} + +func (b *Bucket) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + if err := objstore.ValidateIterOptions(b.SupportedIterOptions(), options...); err != nil { + return err + } + + return b.Iter(ctx, dir, func(name string) error { + return f(objstore.IterObjectAttributes{Name: name}) + }, options...) +} + +// Get returns a reader for the given object name. +func (b *Bucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { + return b.getRange(ctx, name, 0, -1) +} + +// GetRange returns a new range reader for the given object name and range. +func (b *Bucket) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + return b.getRange(ctx, name, off, length) +} + +func (b *Bucket) getRange(_ context.Context, name string, off, length int64) (io.ReadCloser, error) { + if strings.TrimSpace(name) == "" { + return nil, errors.New("object name cannot be empty") + } + input := &obs.GetObjectInput{} + input.Bucket = b.name + input.Key = name + if off < 0 { + return nil, errors.New("incorrect offset") + } + input.RangeStart = off + input.RangeEnd = math.MaxInt64 + if length != -1 { + input.RangeEnd = off + length - 1 + } + output, err := b.client.GetObject(input) + if err != nil { + return nil, errors.Wrap(err, "failed to get object") + } + return objstore.ObjectSizerReadCloser{ + ReadCloser: output.Body, + Size: func() (int64, error) { + return output.ContentLength, nil + }, + }, nil +} + +// Exists checks if the given object exists in the bucket. +func (b *Bucket) Exists(ctx context.Context, name string) (bool, error) { + _, err := b.client.GetObjectMetadata(&obs.GetObjectMetadataInput{ + Bucket: b.name, + Key: name, + }) + if err != nil { + if b.IsObjNotFoundErr(err) { + return false, nil + } + return false, errors.Wrap(err, "failed to get object metadata") + } + return true, nil +} + +// IsObjNotFoundErr returns true if error means that object is not found. Relevant to Get operations. +func (b *Bucket) IsObjNotFoundErr(err error) bool { + if oriErr, ok := errors.Cause(err).(obs.ObsError); ok { + if oriErr.Status == "404 Not Found" { + return true + } + } + return false +} + +// IsAccessDeniedErr returns true if access to object is denied. +func (b *Bucket) IsAccessDeniedErr(_ error) bool { + return false +} + +// Attributes returns information about the specified object. +func (b *Bucket) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { + output, err := b.client.GetObjectMetadata(&obs.GetObjectMetadataInput{ + Bucket: b.name, + Key: name, + }) + if err != nil { + return objstore.ObjectAttributes{}, errors.Wrap(err, "failed to get object metadata") + } + return objstore.ObjectAttributes{ + Size: output.ContentLength, + LastModified: output.LastModified, + }, nil +} + +// NewTestBucket creates test bkt client that before returning creates temporary bucket. +func NewTestBucket(t testing.TB, location string) (objstore.Bucket, func(), error) { + c := configFromEnv() + if c.Endpoint == "" || c.AccessKey == "" || c.SecretKey == "" { + return nil, nil, errors.New("insufficient obs test configuration information") + } + + if c.Bucket != "" && os.Getenv("THANOS_ALLOW_EXISTING_BUCKET_USE") == "" { + return nil, nil, errors.New("OBS_BUCKET is defined. Normally this tests will create temporary bucket " + + "and delete it after test. Unset OBS_BUCKET env variable to use default logic. If you really want to run " + + "tests against provided (NOT USED!) bucket, set THANOS_ALLOW_EXISTING_BUCKET_USE=true.") + } + return NewTestBucketFromConfig(t, c, false, location) +} + +func NewTestBucketFromConfig(t testing.TB, c Config, reuseBucket bool, location string) (objstore.Bucket, func(), error) { + ctx := context.Background() + + bc, err := yaml.Marshal(c) + if err != nil { + return nil, nil, err + } + b, err := NewBucket(log.NewNopLogger(), bc) + if err != nil { + return nil, nil, err + } + + bktToCreate := c.Bucket + if c.Bucket != "" && reuseBucket { + if err := b.Iter(ctx, "", func(_ string) error { + return errors.Errorf("bucket %s is not empty", c.Bucket) + }); err != nil { + return nil, nil, err + } + + t.Log("WARNING. Reusing", c.Bucket, "OBS bucket for OBS tests. Manual cleanup afterwards is required") + return b, func() {}, nil + } + + if c.Bucket == "" { + bktToCreate = objstore.CreateTemporaryTestBucketName(t) + } + + _, err = b.client.CreateBucket(&obs.CreateBucketInput{ + Bucket: bktToCreate, + BucketLocation: obs.BucketLocation{Location: location}, + }) + if err != nil { + return nil, nil, err + } + b.name = bktToCreate + t.Log("created temporary OBS bucket for OBS tests with name", bktToCreate) + + return b, func() { + objstore.EmptyBucket(t, ctx, b) + if _, err := b.client.DeleteBucket(bktToCreate); err != nil { + t.Logf("deleting bucket %s failed: %s", bktToCreate, err) + } + }, nil +} + +func configFromEnv() Config { + c := Config{ + Bucket: os.Getenv("OBS_BUCKET"), + Endpoint: os.Getenv("OBS_ENDPOINT"), + AccessKey: os.Getenv("OBS_ACCESS_KEY"), + SecretKey: os.Getenv("OBS_SECRET_KEY"), + } + return c +} diff --git a/vendor/github.com/thanos-io/objstore/providers/oci/helper.go b/vendor/github.com/thanos-io/objstore/providers/oci/helper.go new file mode 100644 index 00000000000..891d744749a --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/providers/oci/helper.go @@ -0,0 +1,276 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package oci + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "net/http" + "os" + "strconv" + "strings" + "time" + + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/objectstorage" + "github.com/pkg/errors" + "github.com/prometheus/common/model" + "github.com/thanos-io/objstore" +) + +func CustomTransport(config Config) *http.Transport { + return &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + + IdleConnTimeout: time.Duration(config.HTTPConfig.IdleConnTimeout), + ResponseHeaderTimeout: time.Duration(config.HTTPConfig.ResponseHeaderTimeout), + TLSHandshakeTimeout: time.Duration(config.HTTPConfig.TLSHandshakeTimeout), + ExpectContinueTimeout: time.Duration(config.HTTPConfig.ExpectContinueTimeout), + TLSClientConfig: &tls.Config{InsecureSkipVerify: config.HTTPConfig.InsecureSkipVerify}, + MaxIdleConns: config.HTTPConfig.MaxIdleConns, + MaxIdleConnsPerHost: config.HTTPConfig.MaxIdleConnsPerHost, + MaxConnsPerHost: config.HTTPConfig.MaxConnsPerHost, + DisableCompression: config.HTTPConfig.DisableCompression, + } +} + +func getNamespace(client objectstorage.ObjectStorageClient, requestMetadata common.RequestMetadata) (namespace *string, err error) { + response, err := client.GetNamespace( + context.Background(), + objectstorage.GetNamespaceRequest{RequestMetadata: requestMetadata}, + ) + if err != nil { + return nil, err + } + return response.Value, nil +} + +func getObject(ctx context.Context, bkt Bucket, objectName string, byteRange string) (response objectstorage.GetObjectResponse, err error) { + if len(objectName) == 0 { + err = fmt.Errorf("value cannot be empty for field ObjectName in path") + return + } + request := objectstorage.GetObjectRequest{ + NamespaceName: &bkt.namespace, + BucketName: &bkt.name, + ObjectName: &objectName, + RequestMetadata: bkt.requestMetadata, + } + if byteRange != "" { + request.Range = &byteRange + } + return bkt.client.GetObject(ctx, request) +} + +func listAllObjects(ctx context.Context, bkt Bucket, prefix string, options ...objstore.IterOption) (objectNames []string, err error) { + var allObjectNames []string + var nextStartWith *string = nil + init := true + + for init || nextStartWith != nil { + init = false + objectNames, nextStartWith, err = listObjects(ctx, bkt, prefix, nextStartWith) + if err != nil { + return nil, err + } + + if objstore.ApplyIterOptions(options...).Recursive { + for _, objectName := range objectNames { + if strings.HasSuffix(objectName, DirDelim) { + subObjectNames, err := listAllObjects(ctx, bkt, objectName, options...) + if err != nil { + return nil, err + } + allObjectNames = append(allObjectNames, subObjectNames...) + } else { + allObjectNames = append(allObjectNames, objectName) + } + } + } else { + allObjectNames = append(allObjectNames, objectNames...) + } + } + return allObjectNames, nil +} + +func listObjects(ctx context.Context, bkt Bucket, prefix string, start *string) (objectNames []string, nextStartWith *string, err error) { + request := objectstorage.ListObjectsRequest{ + NamespaceName: &bkt.namespace, + BucketName: &bkt.name, + Delimiter: common.String(DirDelim), + Prefix: &prefix, + Start: start, + RequestMetadata: bkt.requestMetadata, + } + response, err := bkt.client.ListObjects(ctx, request) + if err != nil { + return nil, nil, err + } + + for _, object := range response.ListObjects.Objects { + objectNames = append(objectNames, *object.Name) + } + objectNames = append(objectNames, response.ListObjects.Prefixes...) + + return objectNames, response.NextStartWith, nil +} + +func (config *Config) validateConfig() (err error) { + var errMsg []string + + if config.Tenancy == "" { + errMsg = append(errMsg, "no OCI tenancy ocid specified") + } + if config.User == "" { + errMsg = append(errMsg, "no OCI user ocid specified") + } + if config.Region == "" { + errMsg = append(errMsg, "no OCI region specified") + } + if config.Fingerprint == "" { + errMsg = append(errMsg, "no OCI fingerprint specified") + } + if config.PrivateKey == "" { + errMsg = append(errMsg, "no OCI privatekey specified") + } + + if len(errMsg) > 0 { + return errors.New(strings.Join(errMsg, ", ")) + } + + return +} + +func getRequestMetadata(maxRequestRetries int, requestRetryInterval int) common.RequestMetadata { + if maxRequestRetries <= 1 { + retryPolicy := common.NoRetryPolicy() + return common.RequestMetadata{ + RetryPolicy: &retryPolicy, + } + } + retryPolicy := common.NewRetryPolicyWithOptions(common.WithMaximumNumberAttempts(uint(maxRequestRetries)), + common.WithFixedBackoff(time.Duration(requestRetryInterval)*time.Second)) + return common.RequestMetadata{ + RetryPolicy: &retryPolicy, + } +} + +func getConfigFromEnv() (config Config, err error) { + config = Config{ + Provider: strings.ToLower(os.Getenv("OCI_PROVIDER")), + Bucket: os.Getenv("OCI_BUCKET"), + Compartment: os.Getenv("OCI_COMPARTMENT"), + Tenancy: os.Getenv("OCI_TENANCY_OCID"), + User: os.Getenv("OCI_USER_OCID"), + Region: os.Getenv("OCI_REGION"), + Fingerprint: os.Getenv("OCI_FINGERPRINT"), + PrivateKey: os.Getenv("OCI_PRIVATEKEY"), + Passphrase: os.Getenv("OCI_PASSPHRASE"), + } + + // [Optional] Override the default part size of 128 MiB, value is in bytes. The max part size is 50GiB + if os.Getenv("OCI_PART_SIZE") != "" { + partSize, err := strconv.ParseInt(os.Getenv("OCI_PART_SIZE"), 10, 64) + if err != nil { + return Config{}, err + } + config.PartSize = partSize + } + + if os.Getenv("OCI_MAX_REQUEST_RETRIES") != "" { + maxRequestRetries, err := strconv.Atoi(os.Getenv("OCI_MAX_REQUEST_RETRIES")) + if err != nil { + return Config{}, err + } + config.MaxRequestRetries = maxRequestRetries + } + + if os.Getenv("OCI_REQUEST_RETRY_INTERVAL") != "" { + requestRetryInterval, err := strconv.Atoi(os.Getenv("OCI_REQUEST_RETRY_INTERVAL")) + if err != nil { + return Config{}, err + } + config.RequestRetryInterval = requestRetryInterval + } + + if os.Getenv("HTTP_CONFIG_IDLE_CONN_TIMEOUT") != "" { + idleConnTimeout, err := model.ParseDuration(os.Getenv("HTTP_CONFIG_IDLE_CONN_TIMEOUT")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.IdleConnTimeout = idleConnTimeout + } + + if os.Getenv("HTTP_CONFIG_RESPONSE_HEADER_TIMEOUT") != "" { + responseHeaderTimeout, err := model.ParseDuration(os.Getenv("HTTP_CONFIG_RESPONSE_HEADER_TIMEOUT")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.ResponseHeaderTimeout = responseHeaderTimeout + } + + if os.Getenv("HTTP_CONFIG_TLS_HANDSHAKE_TIMEOUT") != "" { + tlsHandshakeTimeout, err := model.ParseDuration(os.Getenv("HTTP_CONFIG_TLS_HANDSHAKE_TIMEOUT")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.TLSHandshakeTimeout = tlsHandshakeTimeout + } + + if os.Getenv("HTTP_CONFIG_EXPECT_CONTINUE_TIMEOUT") != "" { + expectContinueTimeout, err := model.ParseDuration(os.Getenv("HTTP_CONFIG_EXPECT_CONTINUE_TIMEOUT")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.ExpectContinueTimeout = expectContinueTimeout + } + + if os.Getenv("HTTP_CONFIG_INSECURE_SKIP_VERIFY") != "" { + insecureSkipVerify, err := strconv.ParseBool(os.Getenv("HTTP_CONFIG_INSECURE_SKIP_VERIFY")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.InsecureSkipVerify = insecureSkipVerify + } + + if os.Getenv("HTTP_CONFIG_MAX_IDLE_CONNS") != "" { + maxIdleConns, err := strconv.Atoi(os.Getenv("HTTP_CONFIG_MAX_IDLE_CONNS")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.MaxIdleConns = maxIdleConns + } + + if os.Getenv("HTTP_CONFIG_MAX_IDLE_CONNS_PER_HOST") != "" { + maxIdleConnsPerHost, err := strconv.Atoi(os.Getenv("HTTP_CONFIG_MAX_IDLE_CONNS_PER_HOST")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.MaxIdleConnsPerHost = maxIdleConnsPerHost + } + + if os.Getenv("HTTP_CONFIG_MAX_CONNS_PER_HOST") != "" { + maxConnsPerHost, err := strconv.Atoi(os.Getenv("HTTP_CONFIG_MAX_CONNS_PER_HOST")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.MaxConnsPerHost = maxConnsPerHost + } + + if os.Getenv("HTTP_CONFIG_DISABLE_COMPRESSION") != "" { + disableCompression, err := strconv.ParseBool(os.Getenv("HTTP_CONFIG_DISABLE_COMPRESSION")) + if err != nil { + return Config{}, err + } + config.HTTPConfig.DisableCompression = disableCompression + } + + return config, nil +} diff --git a/vendor/github.com/thanos-io/objstore/providers/oci/oci.go b/vendor/github.com/thanos-io/objstore/providers/oci/oci.go new file mode 100644 index 00000000000..edea003dfaa --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/providers/oci/oci.go @@ -0,0 +1,438 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package oci + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "strings" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/common/auth" + "github.com/oracle/oci-go-sdk/v65/objectstorage" + "github.com/oracle/oci-go-sdk/v65/objectstorage/transfer" + "github.com/pkg/errors" + "github.com/prometheus/common/model" + "gopkg.in/yaml.v2" + + "github.com/thanos-io/objstore" +) + +// DirDelim is the delimiter used to model a directory structure in an object store bucket. +const DirDelim = "/" + +type Provider string + +const ( + defaultConfigProvider = Provider("default") + instancePrincipalConfigProvider = Provider("instance-principal") + rawConfigProvider = Provider("raw") + okeWorkloadIdentityConfigProvider = Provider("oke-workload-identity") +) + +var DefaultConfig = Config{ + HTTPConfig: HTTPConfig{ + IdleConnTimeout: model.Duration(90 * time.Second), + ResponseHeaderTimeout: model.Duration(2 * time.Minute), + TLSHandshakeTimeout: model.Duration(10 * time.Second), + ExpectContinueTimeout: model.Duration(1 * time.Second), + InsecureSkipVerify: false, + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + MaxConnsPerHost: 0, + DisableCompression: false, + ClientTimeout: 90 * time.Second, + }, +} + +// HTTPConfig stores the http.Transport configuration for the OCI client. +type HTTPConfig struct { + IdleConnTimeout model.Duration `yaml:"idle_conn_timeout"` + ResponseHeaderTimeout model.Duration `yaml:"response_header_timeout"` + InsecureSkipVerify bool `yaml:"insecure_skip_verify"` + + TLSHandshakeTimeout model.Duration `yaml:"tls_handshake_timeout"` + ExpectContinueTimeout model.Duration `yaml:"expect_continue_timeout"` + MaxIdleConns int `yaml:"max_idle_conns"` + MaxIdleConnsPerHost int `yaml:"max_idle_conns_per_host"` + MaxConnsPerHost int `yaml:"max_conns_per_host"` + DisableCompression bool `yaml:"disable_compression"` + ClientTimeout time.Duration `yaml:"client_timeout"` + Transport http.RoundTripper `yaml:"-"` +} + +// Config stores the configuration for oci bucket. +type Config struct { + Provider string `yaml:"provider"` + Bucket string `yaml:"bucket"` + Compartment string `yaml:"compartment_ocid"` + Tenancy string `yaml:"tenancy_ocid"` + User string `yaml:"user_ocid"` + Region string `yaml:"region"` + Fingerprint string `yaml:"fingerprint"` + PrivateKey string `yaml:"privatekey"` + Passphrase string `yaml:"passphrase"` + PartSize int64 `yaml:"part_size"` + MaxRequestRetries int `yaml:"max_request_retries"` + RequestRetryInterval int `yaml:"request_retry_interval"` + HTTPConfig HTTPConfig `yaml:"http_config"` +} + +// Bucket implements the store.Bucket interface against OCI APIs. +type Bucket struct { + logger log.Logger + name string + namespace string + client *objectstorage.ObjectStorageClient + partSize int64 + requestMetadata common.RequestMetadata +} + +func (b *Bucket) Provider() objstore.ObjProvider { return objstore.OCI } + +// Name returns the bucket name for the provider. +func (b *Bucket) Name() string { + return b.name +} + +func (b *Bucket) SupportedIterOptions() []objstore.IterOptionType { + return []objstore.IterOptionType{objstore.Recursive} +} + +// Iter calls f for each entry in the given directory. The argument to f is the full +// object name including the prefix of the inspected directory. +func (b *Bucket) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { + // Ensure the object name actually ends with a dir suffix. Otherwise we'll just iterate the + // object itself as one prefix item. + if dir != "" { + dir = strings.TrimSuffix(dir, DirDelim) + DirDelim + } + + objectNames, err := listAllObjects(ctx, *b, dir, options...) + if err != nil { + return errors.Wrapf(err, "cannot list objects in directory '%s'", dir) + } + + level.Debug(b.logger).Log("NumberOfObjects", len(objectNames)) + + for _, objectName := range objectNames { + if objectName == "" || objectName == dir { + continue + } + + if err := f(objectName); err != nil { + return err + } + } + + return nil +} + +func (b *Bucket) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + if err := objstore.ValidateIterOptions(b.SupportedIterOptions(), options...); err != nil { + return err + } + + return b.Iter(ctx, dir, func(name string) error { + return f(objstore.IterObjectAttributes{Name: name}) + }, options...) +} + +// Get returns a reader for the given object name. +func (b *Bucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { + response, err := getObject(ctx, *b, name, "") + if err != nil { + return nil, err + } + return objstore.ObjectSizerReadCloser{ + ReadCloser: response.Content, + Size: func() (int64, error) { + return *response.ContentLength, nil + }, + }, nil +} + +// GetRange returns a new range reader for the given object name and range. +func (b *Bucket) GetRange(ctx context.Context, name string, offset, length int64) (io.ReadCloser, error) { + level.Debug(b.logger).Log("msg", "getting object", "name", name, "off", offset, "length", length) + + // A single byte range to fetch, as described in RFC 7233 (https://tools.ietf.org/html/rfc7233#section-2.1). + byteRange := "" + + if offset >= 0 { + if length > 0 { + byteRange = fmt.Sprintf("bytes=%d-%d", offset, offset+length-1) + } else { + byteRange = fmt.Sprintf("bytes=%d-", offset) + } + } else { + if length > 0 { + byteRange = fmt.Sprintf("bytes=-%d", length) + } else { + return nil, errors.New(fmt.Sprintf("invalid range specified: offset=%d length=%d", offset, length)) + } + } + + level.Debug(b.logger).Log("byteRange", byteRange) + + response, err := getObject(ctx, *b, name, byteRange) + if err != nil { + return nil, err + } + return objstore.ObjectSizerReadCloser{ReadCloser: response.Content, + Size: func() (int64, error) { + return *response.ContentLength, nil + }, + }, nil +} + +// Upload the contents of the reader as an object into the bucket. +// Upload should be idempotent. +func (b *Bucket) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) (err error) { + req := transfer.UploadStreamRequest{ + UploadRequest: transfer.UploadRequest{ + NamespaceName: common.String(b.namespace), + BucketName: common.String(b.name), + ObjectName: &name, + EnableMultipartChecksumVerification: common.Bool(true), // TODO: should we check? + ObjectStorageClient: b.client, + RequestMetadata: b.requestMetadata, + }, + StreamReader: r, + } + if b.partSize > 0 { + req.UploadRequest.PartSize = &b.partSize + } + + uploadOptions := objstore.ApplyObjectUploadOptions(opts...) + if uploadOptions.ContentType != "" { + req.UploadRequest.ContentType = &uploadOptions.ContentType + } + + uploadManager := transfer.NewUploadManager() + _, err = uploadManager.UploadStream(ctx, req) + + return err +} + +// Exists checks if the given object exists in the bucket. +func (b *Bucket) Exists(ctx context.Context, name string) (bool, error) { + _, err := getObject(ctx, *b, name, "") + if err != nil { + if b.IsObjNotFoundErr(err) { + return false, nil + } + return false, errors.Wrapf(err, "cannot get OCI object '%s'", name) + } + return true, nil +} + +// Delete removes the object with the given name. +// If object does not exists in the moment of deletion, Delete should throw error. +func (b *Bucket) Delete(ctx context.Context, name string) (err error) { + request := objectstorage.DeleteObjectRequest{ + NamespaceName: &b.namespace, + BucketName: &b.name, + ObjectName: &name, + RequestMetadata: b.requestMetadata, + } + _, err = b.client.DeleteObject(ctx, request) + return err +} + +// IsObjNotFoundErr returns true if error means that object is not found. Relevant to Get operations. +func (b *Bucket) IsObjNotFoundErr(err error) bool { + failure, isServiceError := common.IsServiceError(err) + if isServiceError { + k := failure.GetHTTPStatusCode() + match := k == http.StatusNotFound + level.Debug(b.logger).Log("msg", match) + return failure.GetHTTPStatusCode() == http.StatusNotFound + } + return false +} + +// IsAccessDeniedErr returns true if access to object is denied. +func (b *Bucket) IsAccessDeniedErr(err error) bool { + failure, isServiceError := common.IsServiceError(err) + if isServiceError { + return failure.GetHTTPStatusCode() == http.StatusForbidden + } + return false +} + +// ObjectSize returns the size of the specified object. +func (b *Bucket) ObjectSize(ctx context.Context, name string) (uint64, error) { + response, err := getObject(ctx, *b, name, "") + if err != nil { + return 0, err + } + return uint64(*response.ContentLength), nil +} + +// Close closes bucket. +func (b *Bucket) Close() error { + return nil +} + +// Attributes returns information about the specified object. +func (b *Bucket) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { + response, err := getObject(ctx, *b, name, "") + if err != nil { + return objstore.ObjectAttributes{}, err + } + return objstore.ObjectAttributes{ + Size: *response.ContentLength, + LastModified: response.LastModified.Time, + }, nil +} + +// createBucket creates bucket. +func (b *Bucket) createBucket(ctx context.Context, compartmentId string) (err error) { + request := objectstorage.CreateBucketRequest{ + NamespaceName: &b.namespace, + RequestMetadata: b.requestMetadata, + } + request.CompartmentId = &compartmentId + request.Name = &b.name + request.Metadata = make(map[string]string) + request.PublicAccessType = objectstorage.CreateBucketDetailsPublicAccessTypeNopublicaccess + _, err = b.client.CreateBucket(ctx, request) + return err +} + +// deleteBucket deletes bucket. +func (b *Bucket) deleteBucket(ctx context.Context) (err error) { + request := objectstorage.DeleteBucketRequest{ + NamespaceName: &b.namespace, + BucketName: &b.name, + RequestMetadata: b.requestMetadata, + } + _, err = b.client.DeleteBucket(ctx, request) + return err +} + +// NewBucket returns a new Bucket using the provided oci config values. +func NewBucket(logger log.Logger, ociConfig []byte, wrapRoundtripper func(http.RoundTripper) http.RoundTripper) (*Bucket, error) { + level.Debug(logger).Log("msg", "creating new oci bucket connection") + var config = DefaultConfig + var configurationProvider common.ConfigurationProvider + var err error + + if err := yaml.Unmarshal(ociConfig, &config); err != nil { + return nil, errors.Wrapf(err, "unable to unmarshal the given oci configurations") + } + + provider := Provider(strings.ToLower(config.Provider)) + level.Info(logger).Log("msg", "creating OCI client", "provider", provider) + switch provider { + case defaultConfigProvider: + configurationProvider = common.DefaultConfigProvider() + case instancePrincipalConfigProvider: + configurationProvider, err = auth.InstancePrincipalConfigurationProvider() + if err != nil { + return nil, errors.Wrapf(err, "unable to create OCI instance principal config provider") + } + case rawConfigProvider: + if err := config.validateConfig(); err != nil { + return nil, errors.Wrapf(err, "invalid oci configurations") + } + configurationProvider = common.NewRawConfigurationProvider(config.Tenancy, config.User, config.Region, + config.Fingerprint, config.PrivateKey, &config.Passphrase) + case okeWorkloadIdentityConfigProvider: + if err := os.Setenv(auth.ResourcePrincipalVersionEnvVar, auth.ResourcePrincipalVersion2_2); err != nil { + return nil, errors.Wrapf(err, "unable to set environment variable: %s", auth.ResourcePrincipalVersionEnvVar) + } + if err := os.Setenv(auth.ResourcePrincipalRegionEnvVar, config.Region); err != nil { + return nil, errors.Wrapf(err, "unable to set environment variable: %s", auth.ResourcePrincipalRegionEnvVar) + } + + configurationProvider, err = auth.OkeWorkloadIdentityConfigurationProvider() + if err != nil { + return nil, errors.Wrapf(err, "unable to create OKE workload identity config provider") + } + default: + return nil, fmt.Errorf("unsupported OCI provider: %s", provider) + } + + client, err := objectstorage.NewObjectStorageClientWithConfigurationProvider(configurationProvider) + if err != nil { + return nil, errors.Wrapf(err, "unable to create ObjectStorage client with the given oci configurations") + } + var rt http.RoundTripper + rt = CustomTransport(config) + if config.HTTPConfig.Transport != nil { + rt = config.HTTPConfig.Transport + } + if wrapRoundtripper != nil { + rt = wrapRoundtripper(rt) + } + httpClient := http.Client{ + Transport: rt, + Timeout: config.HTTPConfig.ClientTimeout, + } + client.HTTPClient = &httpClient + + requestMetadata := getRequestMetadata(config.MaxRequestRetries, config.RequestRetryInterval) + + level.Info(logger).Log("msg", "getting namespace, it might take some time") + namespace, err := getNamespace(client, requestMetadata) + if err != nil { + return nil, err + } + level.Debug(logger).Log("msg", fmt.Sprintf("Oracle Cloud Infrastructure tenancy namespace: %s", *namespace)) + + bkt := Bucket{ + logger: logger, + name: config.Bucket, + namespace: *namespace, + client: &client, + partSize: config.PartSize, + requestMetadata: requestMetadata, + } + + return &bkt, nil +} + +// NewTestBucket creates test bkt client that before returning creates temporary bucket. +// In a close function it empties and deletes the bucket. +func NewTestBucket(t testing.TB) (objstore.Bucket, func(), error) { + config, err := getConfigFromEnv() + if err != nil { + return nil, nil, err + } + + ociConfig, err := yaml.Marshal(config) + if err != nil { + return nil, nil, err + } + + bkt, err := NewBucket(log.NewNopLogger(), ociConfig, nil) + if err != nil { + return nil, nil, err + } + + ctx := context.Background() + bkt.name = objstore.CreateTemporaryTestBucketName(t) + if err := bkt.createBucket(ctx, config.Compartment); err != nil { + t.Errorf("failed to create temporary Oracle Cloud Infrastructure bucket '%s' for testing", bkt.name) + return nil, nil, err + } + + t.Logf("created temporary Oracle Cloud Infrastructure bucket '%s' for testing", bkt.name) + return bkt, func() { + objstore.EmptyBucket(t, ctx, bkt) + if err := bkt.deleteBucket(ctx); err != nil { + t.Logf("failed to delete temporary Oracle Cloud Infrastructure bucket %s for testing: %s", bkt.name, err) + } + t.Logf("deleted temporary Oracle Cloud Infrastructure bucket '%s' for testing", bkt.name) + }, nil +} diff --git a/vendor/github.com/thanos-io/objstore/providers/oss/oss.go b/vendor/github.com/thanos-io/objstore/providers/oss/oss.go new file mode 100644 index 00000000000..4941a4516f8 --- /dev/null +++ b/vendor/github.com/thanos-io/objstore/providers/oss/oss.go @@ -0,0 +1,430 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package oss + +import ( + "context" + "fmt" + "io" + "math" + "math/rand" + "net/http" + "os" + "strconv" + "strings" + "testing" + "time" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + alioss "github.com/aliyun/aliyun-oss-go-sdk/oss" + "github.com/go-kit/log" + "github.com/pkg/errors" + "gopkg.in/yaml.v2" + + "github.com/thanos-io/objstore" + "github.com/thanos-io/objstore/clientutil" + "github.com/thanos-io/objstore/exthttp" +) + +// PartSize is a part size for multi part upload. +const PartSize = 1024 * 1024 * 128 + +// Config stores the configuration for oss bucket. +type Config struct { + Endpoint string `yaml:"endpoint"` + Bucket string `yaml:"bucket"` + AccessKeyID string `yaml:"access_key_id"` + AccessKeySecret string `yaml:"access_key_secret"` +} + +// Bucket implements the store.Bucket interface. +type Bucket struct { + name string + logger log.Logger + client *alioss.Client + config Config + bucket *alioss.Bucket +} + +func NewTestBucket(t testing.TB) (objstore.Bucket, func(), error) { + c := Config{ + Endpoint: os.Getenv("ALIYUNOSS_ENDPOINT"), + Bucket: os.Getenv("ALIYUNOSS_BUCKET"), + AccessKeyID: os.Getenv("ALIYUNOSS_ACCESS_KEY_ID"), + AccessKeySecret: os.Getenv("ALIYUNOSS_ACCESS_KEY_SECRET"), + } + + if c.Endpoint == "" || c.AccessKeyID == "" || c.AccessKeySecret == "" { + return nil, nil, errors.New("aliyun oss endpoint or access_key_id or access_key_secret " + + "is not present in config file") + } + if c.Bucket != "" && os.Getenv("THANOS_ALLOW_EXISTING_BUCKET_USE") == "true" { + t.Log("ALIYUNOSS_BUCKET is defined. Normally this tests will create temporary bucket " + + "and delete it after test. Unset ALIYUNOSS_BUCKET env variable to use default logic. If you really want to run " + + "tests against provided (NOT USED!) bucket, set THANOS_ALLOW_EXISTING_BUCKET_USE=true.") + return NewTestBucketFromConfig(t, c, true) + } + return NewTestBucketFromConfig(t, c, false) +} + +func (b *Bucket) Provider() objstore.ObjProvider { return objstore.ALIYUNOSS } + +// Upload the contents of the reader as an object into the bucket. +func (b *Bucket) Upload(_ context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + // TODO(https://github.com/thanos-io/thanos/issues/678): Remove guessing length when minio provider will support multipart upload without this. + size, err := objstore.TryToGetSize(r) + if err != nil { + return errors.Wrapf(err, "failed to get size apriori to upload %s", name) + } + + uploadOpts := objstore.ApplyObjectUploadOptions(opts...) + + chunksnum, lastslice := int(math.Floor(float64(size)/PartSize)), size%PartSize + + ncloser := io.NopCloser(r) + switch chunksnum { + case 0: + if err := b.bucket.PutObject(name, ncloser, oss.ContentType(uploadOpts.ContentType)); err != nil { + return errors.Wrap(err, "failed to upload oss object") + } + default: + { + init, err := b.bucket.InitiateMultipartUpload(name, oss.ContentType(uploadOpts.ContentType)) + if err != nil { + return errors.Wrap(err, "failed to initiate multi-part upload") + } + chunk := 0 + uploadEveryPart := func(everypartsize int64, cnk int) (alioss.UploadPart, error) { + prt, err := b.bucket.UploadPart(init, ncloser, everypartsize, cnk) + if err != nil { + if err := b.bucket.AbortMultipartUpload(init); err != nil { + return prt, errors.Wrap(err, "failed to abort multi-part upload") + } + + return prt, errors.Wrap(err, "failed to upload multi-part chunk") + } + return prt, nil + } + var parts []alioss.UploadPart + for ; chunk < chunksnum; chunk++ { + part, err := uploadEveryPart(PartSize, chunk+1) + if err != nil { + return errors.Wrap(err, "failed to upload every part") + } + parts = append(parts, part) + } + if lastslice != 0 { + part, err := uploadEveryPart(lastslice, chunksnum+1) + if err != nil { + return errors.Wrap(err, "failed to upload the last chunk") + } + parts = append(parts, part) + } + if _, err := b.bucket.CompleteMultipartUpload(init, parts); err != nil { + return errors.Wrap(err, "failed to set multi-part upload completive") + } + } + } + return nil +} + +// Delete removes the object with the given name. +func (b *Bucket) Delete(ctx context.Context, name string) error { + if err := b.bucket.DeleteObject(name); err != nil { + return errors.Wrap(err, "delete oss object") + } + return nil +} + +// Attributes returns information about the specified object. +func (b *Bucket) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { + m, err := b.bucket.GetObjectMeta(name) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + size, err := clientutil.ParseContentLength(m) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + // aliyun oss return Last-Modified header in RFC1123 format. + // see api doc for details: https://www.alibabacloud.com/help/doc-detail/31985.htm + mod, err := clientutil.ParseLastModified(m, time.RFC1123) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + return objstore.ObjectAttributes{ + Size: size, + LastModified: mod, + }, nil +} + +// NewBucket returns a new Bucket using the provided oss config values. +func NewBucket(logger log.Logger, conf []byte, component string, wrapRoundtripper func(http.RoundTripper) http.RoundTripper) (*Bucket, error) { + var config Config + if err := yaml.Unmarshal(conf, &config); err != nil { + return nil, errors.Wrap(err, "parse aliyun oss config file failed") + } + return NewBucketWithConfig(logger, config, component, wrapRoundtripper) +} + +// NewBucketWithConfig returns a new Bucket using the provided oss config struct. +func NewBucketWithConfig(logger log.Logger, config Config, component string, wrapRoundtripper func(http.RoundTripper) http.RoundTripper) (*Bucket, error) { + if err := validate(config); err != nil { + return nil, err + } + var clientOptions []alioss.ClientOption + if wrapRoundtripper != nil { + rt, err := exthttp.DefaultTransport(exthttp.DefaultHTTPConfig) + if err != nil { + return nil, err + } + clientOptions = append(clientOptions, func(client *alioss.Client) { + client.HTTPClient = &http.Client{ + Transport: wrapRoundtripper(rt), + } + }) + } + client, err := alioss.New(config.Endpoint, config.AccessKeyID, config.AccessKeySecret, clientOptions...) + if err != nil { + return nil, errors.Wrap(err, "create aliyun oss client failed") + } + bk, err := client.Bucket(config.Bucket) + if err != nil { + return nil, errors.Wrapf(err, "use aliyun oss bucket %s failed", config.Bucket) + } + + bkt := &Bucket{ + logger: logger, + client: client, + name: config.Bucket, + config: config, + bucket: bk, + } + return bkt, nil +} + +// validate checks to see the config options are set. +func validate(config Config) error { + if config.Endpoint == "" || config.Bucket == "" { + return errors.New("aliyun oss endpoint or bucket is not present in config file") + } + if config.AccessKeyID == "" || config.AccessKeySecret == "" { + return errors.New("aliyun oss access_key_id or access_key_secret is not present in config file") + } + + return nil +} + +func (b *Bucket) SupportedIterOptions() []objstore.IterOptionType { + return []objstore.IterOptionType{objstore.Recursive} +} + +// Iter calls f for each entry in the given directory. The argument to f is the full +// object name including the prefix of the inspected directory. +func (b *Bucket) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { + if dir != "" { + dir = strings.TrimSuffix(dir, objstore.DirDelim) + objstore.DirDelim + } + + delimiter := alioss.Delimiter(objstore.DirDelim) + if objstore.ApplyIterOptions(options...).Recursive { + delimiter = nil + } + + marker := alioss.Marker("") + for { + if err := ctx.Err(); err != nil { + return errors.Wrap(err, "context closed while iterating bucket") + } + objects, err := b.bucket.ListObjects(alioss.Prefix(dir), delimiter, marker) + if err != nil { + return errors.Wrap(err, "listing aliyun oss bucket failed") + } + marker = alioss.Marker(objects.NextMarker) + + for _, object := range objects.Objects { + if err := f(object.Key); err != nil { + return errors.Wrapf(err, "callback func invoke for object %s failed ", object.Key) + } + } + + for _, object := range objects.CommonPrefixes { + if err := f(object); err != nil { + return errors.Wrapf(err, "callback func invoke for directory %s failed", object) + } + } + if !objects.IsTruncated { + break + } + } + + return nil +} + +func (b *Bucket) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + if err := objstore.ValidateIterOptions(b.SupportedIterOptions(), options...); err != nil { + return err + } + + return b.Iter(ctx, dir, func(name string) error { + return f(objstore.IterObjectAttributes{Name: name}) + }, options...) +} + +func (b *Bucket) Name() string { + return b.name +} + +func NewTestBucketFromConfig(t testing.TB, c Config, reuseBucket bool) (objstore.Bucket, func(), error) { + if c.Bucket == "" { + src := rand.NewSource(time.Now().UnixNano()) + + bktToCreate := strings.ReplaceAll(fmt.Sprintf("test_%s_%x", strings.ToLower(t.Name()), src.Int63()), "_", "-") + if len(bktToCreate) >= 63 { + bktToCreate = bktToCreate[:63] + } + testclient, err := alioss.New(c.Endpoint, c.AccessKeyID, c.AccessKeySecret) + if err != nil { + return nil, nil, errors.Wrap(err, "create aliyun oss client failed") + } + + if err := testclient.CreateBucket(bktToCreate); err != nil { + return nil, nil, errors.Wrapf(err, "create aliyun oss bucket %s failed", bktToCreate) + } + c.Bucket = bktToCreate + } + + bc, err := yaml.Marshal(c) + if err != nil { + return nil, nil, err + } + + b, err := NewBucket(log.NewNopLogger(), bc, "thanos-aliyun-oss-test", nil) + if err != nil { + return nil, nil, err + } + + if reuseBucket { + if err := b.Iter(context.Background(), "", func(_ string) error { + return errors.Errorf("bucket %s is not empty", c.Bucket) + }); err != nil { + return nil, nil, errors.Wrapf(err, "oss check bucket %s", c.Bucket) + } + + t.Log("WARNING. Reusing", c.Bucket, "Aliyun OSS bucket for OSS tests. Manual cleanup afterwards is required") + return b, func() {}, nil + } + + return b, func() { + objstore.EmptyBucket(t, context.Background(), b) + if err := b.client.DeleteBucket(c.Bucket); err != nil { + t.Logf("deleting bucket %s failed: %s", c.Bucket, err) + } + }, nil +} + +func (b *Bucket) Close() error { return nil } + +func (b *Bucket) setRange(start, end int64, name string) (alioss.Option, error) { + var opt alioss.Option + if 0 <= start && start <= end { + header, err := b.bucket.GetObjectMeta(name) + if err != nil { + return nil, err + } + + size, err := strconv.ParseInt(header["Content-Length"][0], 10, 64) + if err != nil { + return nil, err + } + + if end > size { + end = size - 1 + } + + opt = alioss.Range(start, end) + } else { + return nil, errors.Errorf("Invalid range specified: start=%d end=%d", start, end) + } + return opt, nil +} + +func (b *Bucket) getRange(_ context.Context, name string, off, length int64) (io.ReadCloser, error) { + if name == "" { + return nil, errors.New("given object name should not empty") + } + + var opts []alioss.Option + if length != -1 { + opt, err := b.setRange(off, off+length-1, name) + if err != nil { + return nil, err + } + opts = append(opts, opt) + } + + resp, err := b.bucket.DoGetObject(&oss.GetObjectRequest{ObjectKey: name}, opts) + if err != nil { + return nil, err + } + + size, err := clientutil.ParseContentLength(resp.Response.Headers) + if err == nil { + return objstore.ObjectSizerReadCloser{ + ReadCloser: resp.Response, + Size: func() (int64, error) { + return size, nil + }, + }, nil + } + + return resp.Response, nil +} + +// Get returns a reader for the given object name. +func (b *Bucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { + return b.getRange(ctx, name, 0, -1) +} + +func (b *Bucket) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + return b.getRange(ctx, name, off, length) +} + +// Exists checks if the given object exists in the bucket. +func (b *Bucket) Exists(ctx context.Context, name string) (bool, error) { + exists, err := b.bucket.IsObjectExist(name) + if err != nil { + if b.IsObjNotFoundErr(err) { + return false, nil + } + return false, errors.Wrap(err, "cloud not check if object exists") + } + + return exists, nil +} + +// IsObjNotFoundErr returns true if error means that object is not found. Relevant to Get operations. +func (b *Bucket) IsObjNotFoundErr(err error) bool { + switch aliErr := errors.Cause(err).(type) { + case alioss.ServiceError: + if aliErr.StatusCode == http.StatusNotFound { + return true + } + } + return false +} + +// IsAccessDeniedErr returns true if access to object is denied. +func (b *Bucket) IsAccessDeniedErr(err error) bool { + switch aliErr := errors.Cause(err).(type) { + case alioss.ServiceError: + if aliErr.StatusCode == http.StatusForbidden { + return true + } + } + return false +} diff --git a/vendor/github.com/thanos-io/promql-engine/engine/engine.go b/vendor/github.com/thanos-io/promql-engine/engine/engine.go index 2749a3cb6a3..f18a93a85ed 100644 --- a/vendor/github.com/thanos-io/promql-engine/engine/engine.go +++ b/vendor/github.com/thanos-io/promql-engine/engine/engine.go @@ -500,10 +500,7 @@ func (q *Query) Explain() *ExplainOutputNode { } func (q *Query) Analyze() *AnalyzeOutputNode { - if observableRoot, ok := model.Unwrap(q.exec).(telemetry.ObservableVectorOperator); ok { - return analyzeQuery(observableRoot) - } - return nil + return analyzeQuery(q.exec) } type compatibilityQuery struct { diff --git a/vendor/github.com/thanos-io/promql-engine/engine/explain.go b/vendor/github.com/thanos-io/promql-engine/engine/explain.go index 0f22f68b69d..003593dad07 100644 --- a/vendor/github.com/thanos-io/promql-engine/engine/explain.go +++ b/vendor/github.com/thanos-io/promql-engine/engine/explain.go @@ -22,6 +22,7 @@ type ExplainableQuery interface { type AnalyzeOutputNode struct { OperatorTelemetry telemetry.OperatorTelemetry `json:"telemetry,omitempty"` + OperatorID *uint64 `json:"operatorId,omitempty"` Children []*AnalyzeOutputNode `json:"children,omitempty"` once sync.Once @@ -32,7 +33,6 @@ type AnalyzeOutputNode struct { type ExplainOutputNode struct { OperatorName string `json:"name,omitempty"` - OperatorID *uint64 `json:"operatorId,omitempty"` Children []ExplainOutputNode `json:"children,omitempty"` } @@ -84,17 +84,28 @@ func (a *AnalyzeOutputNode) aggregateSamples() { }) } -func analyzeQuery(obsv telemetry.ObservableVectorOperator) *AnalyzeOutputNode { +func analyzeQuery(op model.VectorOperator) *AnalyzeOutputNode { + var operatorID *uint64 + if ider, ok := op.(model.OperatorIDer); ok { + id := ider.OperatorID() + operatorID = &id + } + obsv, ok := model.Unwrap(op).(telemetry.ObservableVectorOperator) + if !ok { + return nil + } + children := obsv.Explain() var childTelemetry []*AnalyzeOutputNode for _, child := range children { - if obsChild, ok := model.Unwrap(child).(telemetry.ObservableVectorOperator); ok { - childTelemetry = append(childTelemetry, analyzeQuery(obsChild)) + if node := analyzeQuery(child); node != nil { + childTelemetry = append(childTelemetry, node) } } return &AnalyzeOutputNode{ OperatorTelemetry: obsv, + OperatorID: operatorID, Children: childTelemetry, } } @@ -107,13 +118,8 @@ func explainVector(v model.VectorOperator) *ExplainOutputNode { children = append(children, *explainVector(vector)) } - node := &ExplainOutputNode{ + return &ExplainOutputNode{ OperatorName: v.String(), Children: children, } - if id, ok := v.(model.OperatorIDer); ok { - operatorID := id.OperatorID() - node.OperatorID = &operatorID - } - return node } diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/block.go b/vendor/github.com/thanos-io/thanos/pkg/block/block.go index 29e3abf4bdd..d5ef88aa7f7 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/block.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/block.go @@ -240,6 +240,19 @@ func Delete(ctx context.Context, logger log.Logger, bkt objstore.Bucket, id ulid level.Debug(logger).Log("msg", "deleted file", "file", deletionMarkFile, "bucket", bkt.Name()) } + // Some object storages represent directories as explicit empty objects. + // We try to delete the directory marker objects themselves after all their contents are removed. + directoryMarkerPaths := []string{ + path.Join(id.String(), ChunksDirname) + objstore.DirDelim, + id.String() + objstore.DirDelim, + } + + for _, p := range directoryMarkerPaths { + if err := bkt.Delete(ctx, p); err != nil && !bkt.IsObjNotFoundErr(err) { + level.Debug(logger).Log("msg", "failed to delete directory marker object", "dir", p, "err", err) + } + } + return nil } diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go b/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go index fe25e3c62c4..fd7d51941b6 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/fetcher.go @@ -6,6 +6,7 @@ package block import ( "context" "encoding/json" + "fmt" "io" "maps" "os" @@ -16,10 +17,12 @@ import ( "sync" "time" + "github.com/VictoriaMetrics/easyproto" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/golang/groupcache/singleflight" "github.com/oklog/ulid/v2" + objstoretracing "github.com/thanos-io/objstore/tracing/opentracing" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" @@ -28,11 +31,14 @@ import ( "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/relabel" "github.com/thanos-io/objstore" + "github.com/thanos-io/objstore/client" "golang.org/x/sync/errgroup" "gopkg.in/yaml.v2" "github.com/thanos-io/thanos/pkg/block/metadata" + "github.com/thanos-io/thanos/pkg/component" "github.com/thanos-io/thanos/pkg/errutil" + "github.com/thanos-io/thanos/pkg/exthttp" "github.com/thanos-io/thanos/pkg/extprom" "github.com/thanos-io/thanos/pkg/model" "github.com/thanos-io/thanos/pkg/runutil" @@ -770,12 +776,24 @@ var _ MetadataFilter = &LabelShardedMetaFilter{} // LabelShardedMetaFilter represents struct that allows sharding. // Not go-routine safe. type LabelShardedMetaFilter struct { - relabelConfig []*relabel.Config -} - -// NewLabelShardedMetaFilter creates LabelShardedMetaFilter. -func NewLabelShardedMetaFilter(relabelConfig []*relabel.Config) *LabelShardedMetaFilter { - return &LabelShardedMetaFilter{relabelConfig: relabelConfig} + relabelConfig []*relabel.Config + dedupReplicaLabels map[string]struct{} +} + +// NewLabelShardedMetaFilter creates LabelShardedMetaFilter. Dedup replica labels are here +// to remove a footgun. For example, imagine that some tenant in Receiver is replicated to two +// nodes (repllica factor of 2). There are also two Compactors where dedup replica labels are also +// used in hashmod calculations to shard the work across two instances. Then, without this hashmod +// separates two streams of the same (replicated) tenant_id data into multiple compactors. Later on, they +// remove replica labels and then they get picked up by vertical compaction. This leads to a lot of extra +// work and "error mark already exists". So, to remove this footgun we should just remove dedup replica +// labels here. +func NewLabelShardedMetaFilter(relabelConfig []*relabel.Config, dedupReplicaLabels ...string) *LabelShardedMetaFilter { + dedup := make(map[string]struct{}, len(dedupReplicaLabels)) + for _, l := range dedupReplicaLabels { + dedup[l] = struct{}{} + } + return &LabelShardedMetaFilter{relabelConfig: relabelConfig, dedupReplicaLabels: dedup} } // Special label that will have an ULID of the meta.json being referenced to. @@ -789,6 +807,9 @@ func (f *LabelShardedMetaFilter) Filter(_ context.Context, metas map[ulid.ULID]* b.Set(BlockIDLabel, id.String()) for k, v := range m.Thanos.Labels { + if _, ok := f.dedupReplicaLabels[k]; ok { + continue + } b.Set(k, v) } @@ -1034,6 +1055,211 @@ func (f *ConsistencyDelayMetaFilter) Filter(_ context.Context, metas map[ulid.UL return nil } +// IgnoreParquetConvertedBlocksFilter is a filter that filters out blocks that have been converted into Parquet blocks. +// It takes a look at the metadata files inside of a given bucket and then filters them out during syncing. +type IgnoreParquetConvertedBlocksFilter struct { + bkt objstore.InstrumentedBucketReader + concurrency int + logger log.Logger +} + +func NewIgnoreParquetConvertedBlocksFilter(logger log.Logger, config []byte, concurrency int, reg prometheus.Registerer) (*IgnoreParquetConvertedBlocksFilter, error) { + if len(config) == 0 { + return &IgnoreParquetConvertedBlocksFilter{}, nil + } + customBktConfig := exthttp.DefaultCustomBucketConfig() + if err := yaml.Unmarshal(config, &customBktConfig); err != nil { + return nil, errors.Wrap(err, "parsing config YAML file") + } + bkt, err := client.NewBucket(logger, config, component.Store.String(), exthttp.CreateHedgedTransportWithConfig(customBktConfig)) + if err != nil { + return nil, err + } + insBkt := objstoretracing.WrapWithTraces(objstore.WrapWithMetrics(bkt, reg, bkt.Name())) + + return &IgnoreParquetConvertedBlocksFilter{bkt: insBkt, concurrency: concurrency, logger: logger}, nil +} + +const parquetMetaFileName = "meta.pb" + +const msPerDay = int64(24 * 60 * 60 * 1000) + +func (f *IgnoreParquetConvertedBlocksFilter) Filter(ctx context.Context, metas map[ulid.ULID]*metadata.Meta, synced GaugeVec, modified GaugeVec) error { + if f.bkt == nil { + return nil + } + + var ( + eg errgroup.Group + ch = make(chan string, f.concurrency) + mtx sync.Mutex + allMigratedBlocks = make(map[ulid.ULID]struct{}) + merrs errutil.MultiError + ) + + for range f.concurrency { + eg.Go(func() error { + for path := range ch { + migratedBlocks, err := f.readMigratedBlocksFromParquetMetadata(ctx, path) + if err != nil { + mtx.Lock() + merrs.Add(fmt.Errorf("failed to read parquet metadata from %s: %w", path, err)) + mtx.Unlock() + + continue + } + + mtx.Lock() + for id := range migratedBlocks { + allMigratedBlocks[id] = struct{}{} + } + mtx.Unlock() + } + return nil + }) + } + + eg.Go(func() error { + defer close(ch) + + return f.bkt.Iter(ctx, "", func(name string) error { + if path.Base(name) == parquetMetaFileName { + select { + case ch <- name: + case <-ctx.Done(): + return ctx.Err() + } + } + return nil + }, objstore.WithRecursiveIter()) + }) + + if err := eg.Wait(); err != nil { + return errors.Wrap(err, "iterate bucket for parquet metadata") + } + + if len(merrs) > 0 { + return errors.Wrap(merrs.Err(), "read parquet metadata files") + } + + // NOTE(GiedriusS): we need to be extra careful here because Parquet converter trims chunks exactly to the day's range. + // The input to the Parquet converter might not be aligned exactly so we NEED to have some overlap. + // So, only delete metas if the migrated blocks cover each day *fully*. + for id := range filterMigratedBlocksByDayCoverage(allMigratedBlocks, metas) { + delete(metas, id) + synced.WithLabelValues("parquet-converted").Inc() + } + + return nil +} + +func filterMigratedBlocksByDayCoverage(migratedBlocks map[ulid.ULID]struct{}, metas map[ulid.ULID]*metadata.Meta) map[ulid.ULID]struct{} { + type blockRange struct { + id ulid.ULID + minTime, maxTime int64 + } + var blocks []blockRange + for id := range migratedBlocks { + meta, exists := metas[id] + if !exists { + continue + } + blocks = append(blocks, blockRange{id: id, minTime: meta.MinTime, maxTime: meta.MaxTime}) + } + if len(blocks) == 0 { + return map[ulid.ULID]struct{}{} + } + + sort.Slice(blocks, func(i, j int) bool { + return blocks[i].minTime < blocks[j].minTime + }) + + fullyCoveredDays := make(map[int64]struct{}) + firstDay := (blocks[0].minTime / msPerDay) * msPerDay + lastDay := (blocks[len(blocks)-1].maxTime / msPerDay) * msPerDay + for day := firstDay; day <= lastDay; day += msPerDay { + dayEnd := day + msPerDay - 1 + coverage := day - 1 + for _, b := range blocks { + if b.maxTime <= day { + continue + } + if b.minTime > dayEnd { + break + } + effectiveMin := max(b.minTime, day) + if effectiveMin > coverage+1 { + break + } + if effectiveMax := min(b.maxTime, dayEnd); effectiveMax > coverage { + coverage = effectiveMax + } + } + if coverage >= dayEnd { + fullyCoveredDays[day] = struct{}{} + } + } + + result := make(map[ulid.ULID]struct{}) + for _, b := range blocks { + startDay := (b.minTime / msPerDay) * msPerDay + endDay := (b.maxTime / msPerDay) * msPerDay + + canDelete := true + for day := startDay; day <= endDay; day += msPerDay { + effectiveMin := max(b.minTime, day) + effectiveMax := min(b.maxTime, day+msPerDay-1) + if effectiveMax <= effectiveMin { + continue + } + if _, ok := fullyCoveredDays[day]; !ok { + canDelete = false + break + } + } + if canDelete { + result[b.id] = struct{}{} + } + } + return result +} + +func (f *IgnoreParquetConvertedBlocksFilter) readMigratedBlocksFromParquetMetadata(ctx context.Context, path string) (map[ulid.ULID]struct{}, error) { + migratedBlocks := make(map[ulid.ULID]struct{}) + r, err := f.bkt.Get(ctx, path) + if err != nil { + return nil, errors.Wrapf(err, "get parquet metadata file: %v", path) + } + defer runutil.CloseWithLogOnErr(f.logger, r, "close bkt get") + + content, err := io.ReadAll(r) + if err != nil { + return nil, errors.Wrapf(err, "read parquet metadata file: %v", path) + } + + var fc easyproto.FieldContext + for len(content) > 0 { + content, err = fc.NextField(content) + if err != nil { + return nil, errors.Wrapf(err, "read next field from parquet metadata file: %v", path) + } + switch fc.FieldNum { + case 6: + u, ok := fc.String() + if !ok { + return nil, errors.Wrapf(err, "read convertedFromBLIDs field from parquet metadata file: %v", path) + } + id, err := ulid.Parse(u) + if err != nil { + return nil, errors.Wrapf(err, "parse block ID %q from parquet metadata file: %v", u, path) + } + migratedBlocks[id] = struct{}{} + } + } + + return migratedBlocks, nil +} + // IgnoreDeletionMarkFilter is a filter that filters out the blocks that are marked for deletion after a given delay. // The delay duration is to make sure that the replacement block can be fetched before we filter out the old block. // Delay is not considered when computing DeletionMarkBlocks map. @@ -1191,46 +1417,3 @@ func ParseRelabelConfig(contentYaml []byte, supportedActions map[relabel.Action] return relabelConfig, nil } - -var _ MetadataFilter = &ParquetMigratedMetaFilter{} - -// ParquetMigratedMetaFilter is a metadata filter that filters out blocks that have been -// migrated to parquet format. The filter checks for the presence of the parquet_migrated -// extension key with a value of true. -// Not go-routine safe. -type ParquetMigratedMetaFilter struct { - logger log.Logger -} - -// NewParquetMigratedMetaFilter creates a new ParquetMigratedMetaFilter. -func NewParquetMigratedMetaFilter(logger log.Logger) *ParquetMigratedMetaFilter { - return &ParquetMigratedMetaFilter{ - logger: logger, - } -} - -// Filter filters out blocks that have been marked as migrated to parquet format. -func (f *ParquetMigratedMetaFilter) Filter(_ context.Context, metas map[ulid.ULID]*metadata.Meta, synced GaugeVec, modified GaugeVec) error { - for id, meta := range metas { - if meta.Thanos.Extensions == nil { - continue - } - - extensionsMap, ok := meta.Thanos.Extensions.(map[string]any) - if !ok { - continue - } - - parquetMigrated, exists := extensionsMap[metadata.ParquetMigratedExtensionKey] - if !exists { - continue - } - - if migratedBool, ok := parquetMigrated.(bool); ok && migratedBool { - level.Debug(f.logger).Log("msg", "filtering out parquet migrated block", "block", id) - synced.WithLabelValues(ParquetMigratedMeta).Inc() - delete(metas, id) - } - } - return nil -} diff --git a/vendor/github.com/thanos-io/thanos/pkg/block/index.go b/vendor/github.com/thanos-io/thanos/pkg/block/index.go index ab0480779c3..cd110ac57fa 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/block/index.go +++ b/vendor/github.com/thanos-io/thanos/pkg/block/index.go @@ -373,7 +373,7 @@ func GatherIndexHealthStats(ctx context.Context, logger log.Logger, fn string, m seriesLifeDurationWithoutSingleSampleSeries.Add(seriesLifeTimeMs) } } - if p.Err() != nil { + if err := p.Err(); err != nil { return stats, errors.Wrap(err, "walk postings") } diff --git a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/redis_client.go b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/redis_client.go index 35059f07d4c..a57286edfec 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/cacheutil/redis_client.go +++ b/vendor/github.com/thanos-io/thanos/pkg/cacheutil/redis_client.go @@ -56,6 +56,8 @@ type TLSConfig struct { ServerName string `yaml:"server_name"` // Disable target certificate validation. InsecureSkipVerify bool `yaml:"insecure_skip_verify"` + // Minimum TLS version to use when connecting to the targets. Supported values are "1.0", "1.1", "1.2", "1.3". + MinVersion string `yaml:"min_version"` } // RedisClientConfig is the config accepted by RedisClient. @@ -63,6 +65,9 @@ type RedisClientConfig struct { // Addr specifies the addresses of redis server. Addr string `yaml:"addr"` + // Prefix used for all redis keys (optional). + Prefix string `yaml:"prefix"` + // Use the specified Username to authenticate the current connection // with one of the connections defined in the ACL list when connecting // to a Redis 6.0 instance, or greater, that is using the Redis ACL system. @@ -134,6 +139,12 @@ func (c *RedisClientConfig) validate() error { if (c.TLSConfig.CertFile != "") != (c.TLSConfig.KeyFile != "") { return errors.New("both client key and certificate must be provided") } + + if c.TLSConfig.MinVersion != "" { + if _, err := thanos_tls.GetTlsVersion(c.TLSConfig.MinVersion); err != nil { + return errors.Wrapf(err, "tls_config.min_version invalid") + } + } } if err := c.SetAsyncCircuitBreaker.validate(); err != nil { @@ -187,9 +198,8 @@ func NewRedisClientWithConfig(logger log.Logger, name string, config RedisClient var tlsConfig *tls.Config if config.TLSEnabled { userTLSConfig := config.TLSConfig - tlsClientConfig, err := thanos_tls.NewClientConfig(logger, userTLSConfig.CertFile, userTLSConfig.KeyFile, - userTLSConfig.CAFile, userTLSConfig.ServerName, userTLSConfig.InsecureSkipVerify) + userTLSConfig.CAFile, userTLSConfig.ServerName, userTLSConfig.InsecureSkipVerify, userTLSConfig.MinVersion) if err != nil { return nil, err @@ -211,6 +221,9 @@ func NewRedisClientWithConfig(logger log.Logger, name string, config RedisClient ConnWriteTimeout: config.WriteTimeout, DisableCache: clientSideCacheDisabled, TLSConfig: tlsConfig, + SendToReplicas: func(cmd rueidis.Completed) bool { + return cmd.IsReadOnly() + }, } if config.MasterName != "" { @@ -256,6 +269,7 @@ func NewRedisClientWithConfig(logger log.Logger, name string, config RedisClient // SetAsync implement RemoteCacheClient. func (c *RedisClient) SetAsync(key string, value []byte, ttl time.Duration) error { + key = c.addPrefix(key) return c.p.EnqueueAsync(func() { start := time.Now() err := c.setAsyncCircuitBreaker.Execute(func() error { @@ -278,7 +292,7 @@ func (c *RedisClient) SetMulti(data map[string][]byte, ttl time.Duration) { sets := make(rueidis.Commands, 0, len(data)) ittl := int64(ttl.Seconds()) for k, v := range data { - sets = append(sets, c.client.B().Setex().Key(k).Seconds(ittl).Value(rueidis.BinaryString(v)).Build()) + sets = append(sets, c.client.B().Setex().Key(c.addPrefix(k)).Seconds(ittl).Value(rueidis.BinaryString(v)).Build()) } for _, resp := range c.client.DoMulti(context.Background(), sets...) { if err := resp.Error(); err != nil { @@ -295,7 +309,6 @@ func (c *RedisClient) GetMulti(ctx context.Context, keys []string) map[string][] return nil } start := time.Now() - results := make(map[string][]byte, len(keys)) if c.config.ReadTimeout > 0 { timeoutCtx, cancel := context.WithTimeout(ctx, c.config.ReadTimeout) @@ -303,6 +316,20 @@ func (c *RedisClient) GetMulti(ctx context.Context, keys []string) map[string][] ctx = timeoutCtx } + var results map[string][]byte + if c.config.Prefix == "" { + results = c.getMulti(ctx, keys) + } else { + results = c.getMultiPrefixed(ctx, keys) + } + + c.durationGetMulti.Observe(time.Since(start).Seconds()) + return results +} + +// getMulti fetches keys as-is. +func (c *RedisClient) getMulti(ctx context.Context, keys []string) map[string][]byte { + results := make(map[string][]byte, len(keys)) // NOTE(GiedriusS): TTL is the default one in case PTTL fails. 8 hours should be good enough IMHO. resps, err := rueidis.MGetCache(c.client, ctx, 8*time.Hour, keys) if err != nil { @@ -313,7 +340,20 @@ func (c *RedisClient) GetMulti(ctx context.Context, keys []string) map[string][] results[key] = stringToBytes(val) } } - c.durationGetMulti.Observe(time.Since(start).Seconds()) + return results +} + +// getMultiPrefixed fetches keys with the configured prefix, mapping results back to the original keys. +func (c *RedisClient) getMultiPrefixed(ctx context.Context, keys []string) map[string][]byte { + prefixedKeys := make([]string, len(keys)) + for i, k := range keys { + prefixedKeys[i] = c.config.Prefix + k + } + prefixed := c.getMulti(ctx, prefixedKeys) + results := make(map[string][]byte, len(prefixed)) + for k, v := range prefixed { + results[strings.TrimPrefix(k, c.config.Prefix)] = v + } return results } @@ -323,6 +363,13 @@ func (c *RedisClient) Stop() { c.client.Close() } +func (c *RedisClient) addPrefix(key string) string { + if c.config.Prefix == "" { + return key + } + return c.config.Prefix + key +} + // stringToBytes converts string to byte slice (copied from vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go). func stringToBytes(s string) []byte { return *(*[]byte)(unsafe.Pointer( diff --git a/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go b/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go index 9b666f0f762..2c887979995 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go +++ b/vendor/github.com/thanos-io/thanos/pkg/compact/compact.go @@ -910,10 +910,11 @@ type Compactor interface { // Compact plans and runs a single compaction against the group. The compacted result // is uploaded into the bucket the blocks were retrieved from. -func (cg *Group) Compact(ctx context.Context, dir string, planner Planner, comp Compactor, blockDeletableChecker BlockDeletableChecker, compactionLifecycleCallback CompactionLifecycleCallback) (shouldRerun bool, compIDs []ulid.ULID, rerr error) { +func (cg *Group) Compact(ctx context.Context, dir *os.Root, planner Planner, comp Compactor, blockDeletableChecker BlockDeletableChecker, compactionLifecycleCallback CompactionLifecycleCallback) (shouldRerun bool, compIDs []ulid.ULID, rerr error) { cg.compactionRunsStarted.Inc() - subDir := filepath.Join(dir, cg.Key()) + subPath := cg.Key() + subDir := filepath.Join(dir.Name(), subPath) defer func() { // Leave the compact directory for inspection if it is a halt error @@ -921,12 +922,12 @@ func (cg *Group) Compact(ctx context.Context, dir string, planner Planner, comp if rerr != nil { return } - if err := os.RemoveAll(subDir); err != nil { + if err := dir.RemoveAll(subPath); err != nil { level.Error(cg.logger).Log("msg", "failed to remove compaction group work directory", "path", subDir, "err", err) } }() - if err := os.MkdirAll(subDir, 0750); err != nil { + if err := dir.MkdirAll(subPath, 0750); err != nil { return false, nil, errors.Wrap(err, "create compaction group dir") } @@ -1481,7 +1482,16 @@ func NewBucketCompactorWithCheckerAndCallback( // Compact runs compaction over bucket. func (c *BucketCompactor) Compact(ctx context.Context) (rerr error) { + if err := os.MkdirAll(c.compactDir, 0750); err != nil { + return errors.Wrap(err, "create compact root directory") + } + dir, err := os.OpenRoot(c.compactDir) + if err != nil { + return errors.Wrap(err, "open compact root directory") + } + defer func() { + runutil.CloseWithLogOnErr(c.logger, dir, "compact root directory") // Do not remove the compactDir if an error has occurred // because potentially on the next run we would not have to download // everything again. @@ -1510,7 +1520,7 @@ func (c *BucketCompactor) Compact(ctx context.Context) (rerr error) { for i := 0; i < c.concurrency; i++ { wg.Go(func() { for g := range groupChan { - shouldRerunGroup, _, err := g.Compact(workCtx, c.compactDir, c.planner, c.comp, c.blockDeletableChecker, c.compactionLifecycleCallback) + shouldRerunGroup, _, err := g.Compact(workCtx, dir, c.planner, c.comp, c.blockDeletableChecker, c.compactionLifecycleCallback) if err == nil { if shouldRerunGroup { mtx.Lock() diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/godns/resolver.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/godns/resolver.go index a03bf87c94d..577de88f39f 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/godns/resolver.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/godns/resolver.go @@ -4,7 +4,9 @@ package godns import ( + "context" "net" + "net/netip" "github.com/pkg/errors" ) @@ -14,6 +16,24 @@ type Resolver struct { *net.Resolver } +func (r *Resolver) LookupIPAddrByNetwork(ctx context.Context, network, host string) ([]net.IPAddr, error) { + ips, err := r.LookupIP(ctx, network, host) + if err != nil { + return nil, err + } + // LookupIP returns bare IPs, so preserve the zone from scoped IP literals. + var zone string + if addr, err := netip.ParseAddr(host); err == nil { + zone = addr.Zone() + } + + result := make([]net.IPAddr, len(ips)) + for i, ip := range ips { + result[i] = net.IPAddr{IP: ip, Zone: zone} + } + return result, nil +} + // IsNotFound checkout if DNS record is not found. func (r *Resolver) IsNotFound(err error) bool { if err == nil { diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go index bd42f62c9de..7323467687a 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns/resolver.go @@ -68,6 +68,57 @@ func (r *Resolver) LookupIPAddr(_ context.Context, host string) ([]net.IPAddr, e return r.lookupIPAddr(host, 1, 8) } +func (r *Resolver) LookupIPAddrByNetwork(ctx context.Context, network, host string) ([]net.IPAddr, error) { + var qtype dns.Type + switch network { + case "ip6": + qtype = dns.Type(dns.TypeAAAA) + case "ip4": + qtype = dns.Type(dns.TypeA) + default: + return nil, errors.Errorf("unsupported network %q", network) + } + return r.lookupIPAddrByNetwork(ctx, host, qtype, 1, 8) +} + +func (r *Resolver) lookupIPAddrByNetwork(ctx context.Context, host string, qtype dns.Type, currIteration, maxIterations int) ([]net.IPAddr, error) { + if currIteration > maxIterations { + return nil, errors.Errorf("maximum number of recursive iterations reached (%d)", maxIterations) + } + + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + + response, err := r.lookupWithSearchPath(host, qtype) + if err != nil { + return nil, err + } + + var result []net.IPAddr + for _, record := range response.Answer { + switch addr := record.(type) { + case *dns.A: + result = append(result, net.IPAddr{IP: addr.A}) + case *dns.AAAA: + result = append(result, net.IPAddr{IP: addr.AAAA}) + case *dns.CNAME: + addrs, err := r.lookupIPAddrByNetwork(ctx, addr.Target, qtype, currIteration+1, maxIterations) + if err != nil { + return nil, errors.Wrapf(err, "recursively resolve %s", addr.Target) + } + result = append(result, addrs...) + } + } + + if len(result) == 0 { + return nil, ErrNoSuchHost + } + return result, nil +} + func (r *Resolver) lookupIPAddr(host string, currIteration, maxIterations int) ([]net.IPAddr, error) { // We want to protect from infinite loops when resolving DNS records recursively. if currIteration > maxIterations { diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go index 478d8990eb3..33af0c45107 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/provider.go @@ -110,6 +110,7 @@ func GetQTypeName(addr string) (qtype, name string) { // Resolve stores a list of provided addresses or their DNS records if requested. // Addresses prefixed with `dns+` or `dnssrv+` will be resolved through respective DNS lookup (A/AAAA or SRV). +// Addresses prefixed with `dnsdualstack+` will resolve both A and AAAA records. // For non-SRV records, it will return an error if a port is not supplied. func (p *Provider) Resolve(ctx context.Context, addrs []string, flushOld bool) error { resolvedAddrs := map[string][]string{} diff --git a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go index 0025178607f..d764999d6ea 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go +++ b/vendor/github.com/thanos-io/thanos/pkg/discovery/dns/resolver.go @@ -13,6 +13,8 @@ import ( "github.com/go-kit/log/level" "github.com/pkg/errors" + + "github.com/thanos-io/thanos/pkg/errutil" ) type QType string @@ -24,18 +26,22 @@ const ( SRV = QType("dnssrv") // SRVNoA qtype performs SRV lookup without any A/AAAA lookup for each SRV result. SRVNoA = QType("dnssrvnoa") + // ADualStack qtype performs both A and AAAA lookup, returning all addresses. + ADualStack = QType("dnsdualstack") ) type Resolver interface { // Resolve performs a DNS lookup and returns a list of records. // name is the domain name to be resolved. - // qtype is the query type. Accepted values are `dns` for A/AAAA lookup and `dnssrv` for SRV lookup. + // qtype is the query type. Accepted values are `dns` for A/AAAA lookup, `dnssrv` for SRV lookup, + // `dnssrvnoa` for SRV lookup without A/AAAA, and `dnsdualstack` for combined A and AAAA lookup. // If scheme is passed through name, it is preserved on IP results. Resolve(ctx context.Context, name string, qtype QType) ([]string, error) } type ipLookupResolver interface { LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) + LookupIPAddrByNetwork(ctx context.Context, network, host string) ([]net.IPAddr, error) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error) IsNotFound(err error) bool } @@ -127,6 +133,31 @@ func (s *dnsSD) Resolve(ctx context.Context, name string, qtype QType) ([]string res = append(res, appendScheme(scheme, net.JoinHostPort(resIP.String(), resPort))) } } + case ADualStack: + if port == "" { + return nil, errors.Errorf("missing port in address given for dnsdualstack lookup: %v", name) + } + var ips []net.IPAddr + lookupErrs := errutil.MultiError{} + + for _, network := range []string{"ip6", "ip4"} { + addrs, err := s.resolver.LookupIPAddrByNetwork(ctx, network, host) + if err != nil { + if !s.resolver.IsNotFound(err) { + lookupErrs.Add(err) + } + continue + } + ips = append(ips, addrs...) + } + + if err := lookupErrs.Err(); len(ips) == 0 && err != nil { + return nil, errors.Wrapf(err, "lookup IP addresses (dual-stack) %q", host) + } + + for _, ip := range ips { + res = append(res, appendScheme(scheme, net.JoinHostPort(ip.String(), port))) + } default: return nil, errors.Errorf("invalid lookup scheme %q", qtype) } diff --git a/vendor/github.com/thanos-io/thanos/pkg/exemplars/exemplarspb/custom.go b/vendor/github.com/thanos-io/thanos/pkg/exemplars/exemplarspb/custom.go index b636d98faf0..b56dc2c860d 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/exemplars/exemplarspb/custom.go +++ b/vendor/github.com/thanos-io/thanos/pkg/exemplars/exemplarspb/custom.go @@ -17,7 +17,8 @@ import ( // ExemplarStore wraps the ExemplarsClient and contains the info of external labels. type ExemplarStore struct { ExemplarsClient - LabelSets []labels.Labels + LabelSets []labels.Labels + SupportsExternalLabels bool } // UnmarshalJSON implements json.Unmarshaler. diff --git a/vendor/github.com/thanos-io/thanos/pkg/extgrpc/snappy/snappy.go b/vendor/github.com/thanos-io/thanos/pkg/extgrpc/snappy/snappy.go index 4ff5a11b34c..c784aea5f41 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/extgrpc/snappy/snappy.go +++ b/vendor/github.com/thanos-io/thanos/pkg/extgrpc/snappy/snappy.go @@ -50,36 +50,10 @@ func (c *compressor) Compress(w io.Writer) (io.WriteCloser, error) { return writeCloser{wr, &c.writersPool}, nil } -var decompressBuf = sync.Pool{} - func (c *compressor) Decompress(r io.Reader) (io.Reader, error) { - var readBuf []byte - - dbuf := decompressBuf.Get() - if dbuf == nil { - buf := make([]byte, 512) - readBuf = buf - } else { - readBuf = *dbuf.(*[]byte) - } - - return &reader{r, &c.readersPool, readBuf}, nil -} - -var _ io.WriterTo = (*reader)(nil) - -func (r *reader) Read(p []byte) (n int, err error) { - panic("not implemented, use WriteTo instead") -} - -func (r *reader) WriteTo(w io.Writer) (int64, error) { - defer decompressBuf.Put(&r.readBuf) - - snappyReader := r.snappyReaderPool.Get().(*snappy.Reader) - snappyReader.Reset(r.reader) - defer r.snappyReaderPool.Put(snappyReader) - - return io.CopyBuffer(w, snappyReader, r.readBuf) + dr := c.readersPool.Get().(*snappy.Reader) + dr.Reset(r) + return reader{dr, &c.readersPool}, nil } type writeCloser struct { @@ -104,8 +78,24 @@ func (w writeCloser) Close() error { } type reader struct { - reader io.Reader - snappyReaderPool *sync.Pool + reader *snappy.Reader + pool *sync.Pool +} - readBuf []byte +func (r reader) Read(p []byte) (n int, err error) { + n, err = r.reader.Read(p) + if err == io.EOF { + r.reader.Reset(nil) + r.pool.Put(r.reader) + } + return n, err +} + +func (r reader) ReadByte() (n byte, err error) { + n, err = r.reader.ReadByte() + if err == io.EOF { + r.reader.Reset(nil) + r.pool.Put(r.reader) + } + return n, err } diff --git a/vendor/github.com/thanos-io/thanos/pkg/filter/cuckoo.go b/vendor/github.com/thanos-io/thanos/pkg/filter/cuckoo.go index 0cdce6dc943..395067ba9fe 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/filter/cuckoo.go +++ b/vendor/github.com/thanos-io/thanos/pkg/filter/cuckoo.go @@ -28,7 +28,7 @@ func (f *CuckooMetricNameStoreFilter) Matches(matchers []*labels.Matcher) bool { for _, m := range matchers { if m.Type == labels.MatchEqual && m.Name == labels.MetricName { - return f.filter.Lookup([]byte(m.Value)) + return f.filter.Lookup(unsafe.Slice(unsafe.StringData(m.Value), len(m.Value))) } } diff --git a/vendor/github.com/thanos-io/thanos/pkg/logging/journald.go b/vendor/github.com/thanos-io/thanos/pkg/logging/journald.go new file mode 100644 index 00000000000..a72af6bcae0 --- /dev/null +++ b/vendor/github.com/thanos-io/thanos/pkg/logging/journald.go @@ -0,0 +1,120 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package logging + +import ( + "fmt" + "strings" + "unicode" + + "github.com/coreos/go-systemd/v22/journal" +) + +type journalWriter interface { + Send(message string, priority journal.Priority, vars map[string]string) error +} + +type systemdJournalWriter struct{} + +func (s *systemdJournalWriter) Send(message string, priority journal.Priority, vars map[string]string) error { + return journal.Send(message, priority, vars) +} + +// journaldLogger implements go-kit/log.Logger interface for systemd journal integration. +type journaldLogger struct { + writer journalWriter +} + +func newJournaldLogger() *journaldLogger { + return &journaldLogger{writer: &systemdJournalWriter{}} +} + +// Log implements log.Logger. It maps "level" field to journald priority, +// "msg" to MESSAGE, and other fields to THANOS_ structured fields. +// It ensures all field keys are valid journald field names. +// If no "msg" is provided, falls back to "err" value for MESSAGE to comply +// with journald specification requiring a non-empty MESSAGE field. +func (l *journaldLogger) Log(keyvals ...interface{}) error { + var ( + lvl string + msg string + errVal string + vars = make(map[string]string) + varsLen = len(keyvals) + ) + + for i := 0; i < varsLen; i += 2 { + key := toString(keyvals[i]) + var val interface{} + if i+1 < varsLen { + val = keyvals[i+1] + } else { + // Drop orphan keys without values + continue + } + + switch key { + case "level": + lvl = toString(val) + case "msg": + msg = toString(val) + case "err": + errVal = toString(val) + vars[toJournalField(key)] = errVal + default: + vars[toJournalField(key)] = toString(val) + } + } + + // Ensure MESSAGE field is not empty per journald spec. + // Use error value as fallback if no explicit message is provided. + if msg == "" { + if errVal != "" { + msg = errVal + } else { + msg = "(no message)" + } + } + + priority := journal.PriInfo + switch lvl { + case "error": + priority = journal.PriErr + case "warn": + priority = journal.PriWarning + case "debug": + priority = journal.PriDebug + } + + return l.writer.Send(msg, priority, vars) +} + +func toString(v interface{}) string { + switch val := v.(type) { + case string: + return val + case error: + return val.Error() + case fmt.Stringer: + return val.String() + default: + return fmt.Sprintf("%v", val) + } +} + +func toJournalField(key string) string { + var b strings.Builder + b.Grow(len(key) + 7) + b.WriteString("THANOS_") + + mapped := strings.Map(func(r rune) rune { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + return r + } + return '_' + }, key) + + b.WriteString(strings.ToUpper(mapped)) + return b.String() +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/logging/logger.go b/vendor/github.com/thanos-io/thanos/pkg/logging/logger.go index 63a876b85c0..1f1be0fd08b 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/logging/logger.go +++ b/vendor/github.com/thanos-io/thanos/pkg/logging/logger.go @@ -6,13 +6,16 @@ package logging import ( "os" + "github.com/coreos/go-systemd/v22/journal" "github.com/go-kit/log" "github.com/go-kit/log/level" + "github.com/pkg/errors" ) const ( - LogFormatLogfmt = "logfmt" - LogFormatJSON = "json" + LogFormatLogfmt = "logfmt" + LogFormatJSON = "json" + LogFormatJournald = "journald" ) type LevelLogger struct { @@ -25,7 +28,7 @@ type LevelLogger struct { // empty, the debug name is also appended as a field to all log lines. Panics // if the log level is not error, warn, info or debug. Log level is expected to // be validated before passed to this function. -func NewLogger(logLevel, logFormat, debugName string) log.Logger { +func NewLogger(logLevel, logFormat, debugName string) (log.Logger, error) { var ( logger log.Logger lvl level.Option @@ -47,8 +50,15 @@ func NewLogger(logLevel, logFormat, debugName string) log.Logger { } logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) - if logFormat == LogFormatJSON { + switch logFormat { + case LogFormatJSON: logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) + case LogFormatJournald: + if journal.Enabled() { + logger = newJournaldLogger() + } else { + return nil, errors.New("journald log format requested but systemd journal is not available") + } } // Sort the logger chain to avoid expensive log.Valuer evaluation for disallowed level. @@ -63,5 +73,5 @@ func NewLogger(logLevel, logFormat, debugName string) log.Logger { return LevelLogger{ Logger: logger, LogLevel: logLevel, - } + }, nil } diff --git a/vendor/github.com/thanos-io/thanos/pkg/pool/worker_pool.go b/vendor/github.com/thanos-io/thanos/pkg/pool/worker_pool.go index 6e3e77d7ab4..73187376fe3 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/pool/worker_pool.go +++ b/vendor/github.com/thanos-io/thanos/pkg/pool/worker_pool.go @@ -16,8 +16,12 @@ type WorkerPool interface { // Init initializes the worker pool. Init() - // Go waits until the next worker becomes available and executes the given work. - Go(work Work) + // Go waits until the next worker becomes available or the context is canceled. + // Returns ctx.Err() if the context is canceled before a worker slot is available. + Go(ctx context.Context, work Work) error + + // TryGo submits work without blocking. Returns false if the pool is at capacity. + TryGo(work Work) bool // Close cancels all workers and waits for them to finish. Close() @@ -60,9 +64,24 @@ func (p *workerPool) Init() { }) } -func (p *workerPool) Go(work Work) { +func (p *workerPool) Go(ctx context.Context, work Work) error { + p.Init() + select { + case p.workCh <- work: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} + +func (p *workerPool) TryGo(work Work) bool { p.Init() - p.workCh <- work + select { + case p.workCh <- work: + return true + default: + return false + } } func (p *workerPool) Close() { diff --git a/vendor/github.com/thanos-io/thanos/pkg/promclient/promclient.go b/vendor/github.com/thanos-io/thanos/pkg/promclient/promclient.go index 73e237334c9..9de3e9b5ca7 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/promclient/promclient.go +++ b/vendor/github.com/thanos-io/thanos/pkg/promclient/promclient.go @@ -959,15 +959,18 @@ func (c *Client) TargetsInGRPC(ctx context.Context, base *url.URL, stateTargets return v.Data, c.get2xxResultWithGRPCErrors(ctx, "/prom_targets HTTP[client]", &u, &v) } -func (c *Client) TSDBStatusInGRPC(ctx context.Context, base *url.URL, limit int) (*statuspb.TSDBStatisticsEntry, error) { +func (c *Client) TSDBStatusInGRPC(ctx context.Context, base *url.URL, limit int, matchers ...*labels.Matcher) (*statuspb.TSDBStatisticsEntry, error) { u := *base u.Path = path.Join(u.Path, "/api/v1/status/tsdb") + q := u.Query() + if len(matchers) > 0 { + q.Add("match[]", storepb.PromMatchersToString(matchers...)) + } if limit > 0 { - q := u.Query() q.Add("limit", strconv.Itoa(limit)) - u.RawQuery = q.Encode() } + u.RawQuery = q.Encode() var v struct { Data *statuspb.TSDBStatisticsEntry `json:"data"` diff --git a/vendor/github.com/thanos-io/thanos/pkg/query/endpointset.go b/vendor/github.com/thanos-io/thanos/pkg/query/endpointset.go index 582fb9735c4..5274d0161e7 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/query/endpointset.go +++ b/vendor/github.com/thanos-io/thanos/pkg/query/endpointset.go @@ -181,6 +181,15 @@ func (c *endpointSetNodeCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.connectionsDesc } +const noExtLabelsPlaceholder = "no_external_labels" + +func someExternalLabels(lbls string) string { + if lbls == "" { + return noExtLabelsPlaceholder + } + return lbls +} + func (c *endpointSetNodeCollector) hash(e endpointStat) uint64 { h := c.hasherPool.Get().(*xxhash.Digest) defer func() { @@ -192,7 +201,7 @@ func (c *endpointSetNodeCollector) hash(e endpointStat) uint64 { _, _ = h.Write([]byte(e.ip)) } if _, ok := c.labelsMap[string(ExternalLabels)]; ok { - _, _ = h.Write([]byte(e.extLset)) + _, _ = h.Write([]byte(someExternalLabels(e.extLset))) } if _, ok := c.labelsMap[string(StoreType)]; ok { _, _ = h.Write([]byte(e.component)) @@ -210,14 +219,21 @@ func (c *endpointSetNodeCollector) Collect(ch chan<- prometheus.Metric) { h := c.hash(e) occurrences[h]++ } + var alreadySeen = make(map[uint64]struct{}, len(occurrences)) for _, n := range c.storeNodes { h := c.hash(n) + _, seen := alreadySeen[h] + if seen { + continue + } + alreadySeen[h] = struct{}{} + lbls := make([]string, 0, len(c.labels)) for _, lbl := range c.labels { switch lbl { case string(ExternalLabels): - lbls = append(lbls, n.extLset) + lbls = append(lbls, someExternalLabels(n.extLset)) case string(StoreType): lbls = append(lbls, n.component) case string(IPPort): @@ -514,6 +530,8 @@ func (e *EndpointSet) GetStoreClients() []store.Client { addr: er.addr, metadata: er.metadata, status: er.status, + mtx: er.mtx, + logger: er.logger, }) er.mtx.RUnlock() } @@ -582,8 +600,9 @@ func (e *EndpointSet) GetExemplarsStores() []*exemplarspb.ExemplarStore { for _, er := range endpoints { if er.HasExemplarsAPI() { exemplarStores = append(exemplarStores, &exemplarspb.ExemplarStore{ - ExemplarsClient: exemplarspb.NewExemplarsClient(er.cc), - LabelSets: labelpb.ZLabelSetsToPromLabelSets(er.metadata.LabelSets...), + ExemplarsClient: exemplarspb.NewExemplarsClient(er.cc), + LabelSets: labelpb.ZLabelSetsToPromLabelSets(er.metadata.LabelSets...), + SupportsExternalLabels: er.ComponentType() == component.Query, }) } } @@ -633,7 +652,7 @@ func (e *EndpointSet) GetEndpointStatus() []EndpointStatus { type endpointRef struct { storepb.StoreClient - mtx sync.RWMutex + mtx *sync.RWMutex cc *grpc.ClientConn addr string isStrict bool @@ -659,6 +678,7 @@ func (e *EndpointSet) newEndpointRef(spec *GRPCEndpointSpec) (*endpointRef, erro addr: spec.Addr(), isStrict: spec.isStrictStatic, cc: conn, + mtx: &sync.RWMutex{}, }, nil } diff --git a/vendor/github.com/thanos-io/thanos/pkg/query/fanout/tracker.go b/vendor/github.com/thanos-io/thanos/pkg/query/fanout/tracker.go new file mode 100644 index 00000000000..e913e16f441 --- /dev/null +++ b/vendor/github.com/thanos-io/thanos/pkg/query/fanout/tracker.go @@ -0,0 +1,87 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package fanout + +import ( + "context" + "sort" + "sync" + "time" +) + +// StoreFanout describes a single endpoint that took part in a fan-out +// for one promql-engine operator, along with telemetry collected while +// streaming its response. +type StoreFanout struct { + EndpointAddr string + Duration time.Duration + BytesProcessed int64 + NumResponses int64 + Series int64 + Chunks int64 + Samples int64 +} + +// Tracker captures, per promql-engine operator ID, the list of stores that +// were fanned out to while serving Series() calls for that operator and the +// per-store telemetry of those fan-outs. +type Tracker struct { + mu sync.Mutex + byOpID map[uint64][]StoreFanout +} + +// NewTracker returns a new empty Tracker. +func NewTracker() *Tracker { + return &Tracker{byOpID: make(map[uint64][]StoreFanout)} +} + +// AddStore registers a single store and its telemetry under the given +// operator ID. +func (t *Tracker) AddStore(opID uint64, s StoreFanout) { + if t == nil { + return + } + t.mu.Lock() + defer t.mu.Unlock() + t.byOpID[opID] = append(t.byOpID[opID], s) +} + +// Get returns the stores fanned out to for the given operator ID. +func (t *Tracker) Get(opID *uint64) []StoreFanout { + if t == nil || opID == nil { + return nil + } + t.mu.Lock() + defer t.mu.Unlock() + src := t.byOpID[*opID] + if len(src) == 0 { + return nil + } + out := make([]StoreFanout, len(src)) + copy(out, src) + sort.Slice(out, func(i, j int) bool { + return out[i].EndpointAddr < out[j].EndpointAddr + }) + return out +} + +type ctxKey struct{} + +// NewContext returns a copy of ctx that carries the given Tracker so it can be +// retrieved by downstream code with FromContext. +func NewContext(ctx context.Context, t *Tracker) context.Context { + if t == nil { + return ctx + } + return context.WithValue(ctx, ctxKey{}, t) +} + +// FromContext returns the Tracker stored in ctx, or nil if none is present. +func FromContext(ctx context.Context) *Tracker { + if ctx == nil { + return nil + } + t, _ := ctx.Value(ctxKey{}).(*Tracker) + return t +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/query/querier.go b/vendor/github.com/thanos-io/thanos/pkg/query/querier.go index 3a648b63c8e..804526c30dc 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/query/querier.go +++ b/vendor/github.com/thanos-io/thanos/pkg/query/querier.go @@ -18,10 +18,12 @@ import ( "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/util/annotations" + enginemodel "github.com/thanos-io/promql-engine/execution/model" "github.com/thanos-io/thanos/pkg/dedup" "github.com/thanos-io/thanos/pkg/extprom" "github.com/thanos-io/thanos/pkg/gate" + "github.com/thanos-io/thanos/pkg/query/fanout" "github.com/thanos-io/thanos/pkg/store" "github.com/thanos-io/thanos/pkg/store/storepb" "github.com/thanos-io/thanos/pkg/tenancy" @@ -292,11 +294,19 @@ func (q *querier) Select(ctx context.Context, _ bool, hints *storage.SelectHints matchers[i] = m.String() } tenant := ctx.Value(tenancy.TenantKey) + opID, hasOpID := enginemodel.OperatorIDFromContext(ctx) + tracker := fanout.FromContext(ctx) // The context gets canceled as soon as query evaluation is completed by the engine. // We want to prevent this from happening for the async store API calls we make while preserving tracing context. // TODO(bwplotka): Does the above still is true? It feels weird to leave unfinished calls behind query API. ctx = tracing.CopyTraceContext(context.Background(), ctx) ctx = context.WithValue(ctx, tenancy.TenantKey, tenant) + if hasOpID { + ctx = enginemodel.ContextWithOperatorID(ctx, opID) + } + if tracker != nil { + ctx = fanout.NewContext(ctx, tracker) + } ctx, cancel := context.WithTimeout(ctx, q.selectTimeout) span, ctx := tracing.StartSpan(ctx, "querier_select", opentracing.Tags{ "minTime": hints.Start, diff --git a/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go b/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go index ff511a478a6..ceabb2dfec4 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go +++ b/vendor/github.com/thanos-io/thanos/pkg/shipper/shipper.go @@ -75,7 +75,7 @@ func newMetrics(reg prometheus.Registerer) *metrics { // them to a remote data store. type Shipper struct { logger log.Logger - dir string + dir *os.Root metrics *metrics bucket objstore.Bucket source metadata.SourceType @@ -204,7 +204,7 @@ func applyOptions(opts []Option) *shipperOptions { // New creates a new shipper that detects new TSDB blocks in dir and uploads them to // remote if necessary. It attaches the Thanos metadata section in each meta JSON file. // If uploadCompacted is enabled, it also uploads compacted blocks which are already in filesystem. -func New(bucket objstore.Bucket, dir string, opts ...Option) *Shipper { +func New(bucket objstore.Bucket, dir *os.Root, opts ...Option) *Shipper { options := applyOptions(opts) return &Shipper{ @@ -219,7 +219,7 @@ func New(bucket objstore.Bucket, dir string, opts ...Option) *Shipper { uploadCompacted: options.uploadCompacted, hashFunc: options.hashFunc, uploadConcurrency: options.uploadConcurrency, - metadataFilePath: filepath.Join(dir, filepath.Clean(options.metaFileName)), + metadataFilePath: filepath.Join(dir.Name(), filepath.Clean(options.metaFileName)), } } @@ -230,6 +230,11 @@ func (s *Shipper) SetLabels(lbls labels.Labels) { s.labels = func() labels.Labels { return lbls } } +// Close releases the os.Root directory handle held by the shipper. +func (s *Shipper) Close() error { + return s.dir.Close() +} + type lazyOverlapChecker struct { synced bool logger log.Logger @@ -298,6 +303,38 @@ func (c *lazyOverlapChecker) IsOverlapping(ctx context.Context, newMeta tsdb.Blo return nil } +func (s *Shipper) AreAllBlocksUploaded() (bool, error) { + s.mtx.RLock() + defer s.mtx.RUnlock() + + metas, _, err := s.blockMetasFromOldest() + if err != nil { + return false, errors.Wrap(err, "get block metas from oldest") + } + + if len(metas) == 0 { + return true, nil + } + + meta, err := ReadMetaFile(s.metadataFilePath) + if err != nil { + return false, errors.Wrap(err, "read meta file") + } + + uploaded := make(map[ulid.ULID]struct{}, len(meta.Uploaded)) + for _, id := range meta.Uploaded { + uploaded[id] = struct{}{} + } + + for _, m := range metas { + if _, ok := uploaded[m.ULID]; !ok { + return false, nil + } + } + + return true, nil +} + // Sync performs a single synchronization, which ensures all non-compacted local blocks have been uploaded // to the object bucket once. // @@ -443,23 +480,24 @@ func (s *Shipper) upload(ctx context.Context, meta *metadata.Meta) error { // We hard-link the files into a temporary upload directory so we are not affected // by other operations happening against the TSDB directory. - updir := filepath.Join(s.dir, "thanos", "upload", meta.ULID.String()) + updir := filepath.Join("thanos", "upload", meta.ULID.String()) // Remove updir just in case. - if err := os.RemoveAll(updir); err != nil { + if err := s.dir.RemoveAll(updir); err != nil { return errors.Wrap(err, "clean upload directory") } - if err := os.MkdirAll(updir, 0750); err != nil { + if err := s.dir.MkdirAll(updir, 0750); err != nil { return errors.Wrap(err, "create upload dir") } defer func() { - if err := os.RemoveAll(updir); err != nil { + if err := s.dir.RemoveAll(updir); err != nil { level.Error(s.logger).Log("msg", "failed to clean upload directory", "err", err) } }() - dir := filepath.Join(s.dir, meta.ULID.String()) - if err := hardlinkBlock(dir, updir); err != nil { + absUpdir := filepath.Join(s.dir.Name(), updir) + dir := filepath.Join(s.dir.Name(), meta.ULID.String()) + if err := hardlinkBlock(dir, absUpdir); err != nil { return errors.Wrap(err, "hard link block") } // Attach current labels and write a new meta file with Thanos extensions. @@ -469,24 +507,32 @@ func (s *Shipper) upload(ctx context.Context, meta *metadata.Meta) error { }) } meta.Thanos.Source = s.source - meta.Thanos.SegmentFiles = block.GetSegmentFiles(updir) - if err := meta.WriteToDir(s.logger, updir); err != nil { + meta.Thanos.SegmentFiles = block.GetSegmentFiles(absUpdir) + if err := meta.WriteToDir(s.logger, absUpdir); err != nil { return errors.Wrap(err, "write meta file") } var uploadOptions []objstore.UploadOption if s.uploadConcurrency > 0 { uploadOptions = append(uploadOptions, objstore.WithUploadConcurrency(s.uploadConcurrency)) } - return block.Upload(ctx, s.logger, s.bucket, updir, s.hashFunc, uploadOptions...) + return block.Upload(ctx, s.logger, s.bucket, absUpdir, s.hashFunc, uploadOptions...) } // blockMetasFromOldest returns the block meta of each block found in dir // sorted by minTime asc. func (s *Shipper) blockMetasFromOldest() (metas []*metadata.Meta, failedBlocks []string, _ error) { - fis, err := os.ReadDir(s.dir) + + dir, err := s.dir.Open(".") + if err != nil { + return nil, nil, errors.Wrap(err, "open dir") + } + defer runutil.CloseWithLogOnErr(s.logger, dir, "shipper dir") + + fis, err := dir.ReadDir(-1) if err != nil { return nil, nil, errors.Wrap(err, "read dir") } + names := make([]string, 0, len(fis)) for _, fi := range fis { names = append(names, fi.Name()) @@ -495,9 +541,9 @@ func (s *Shipper) blockMetasFromOldest() (metas []*metadata.Meta, failedBlocks [ if _, ok := block.IsBlockDir(n); !ok { continue } - dir := filepath.Join(s.dir, n) + dir := filepath.Join(s.dir.Name(), n) - fi, err := os.Stat(dir) + fi, err := s.dir.Stat(n) if err != nil { if s.skipCorruptedBlocks { level.Error(s.logger).Log("msg", "stat block", "err", err, "block", dir) diff --git a/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/custom.go b/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/custom.go index 0e183efd947..706bedb042f 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/custom.go +++ b/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/custom.go @@ -8,6 +8,8 @@ import ( "maps" "slices" + "github.com/prometheus/prometheus/tsdb" + "github.com/prometheus/prometheus/tsdb/index" v1 "github.com/prometheus/prometheus/web/api/v1" ) @@ -76,9 +78,11 @@ func mergeStatistics(a, b []Statistic, mergeFunc func(uint64, uint64) uint64) [] merged[stat.Name] = v } - return slices.SortedStableFunc(maps.Values(merged), func(a, b Statistic) int { - // Descending sort. - return cmp.Compare(b.Value, a.Value) + return slices.SortedFunc(maps.Values(merged), func(a, b Statistic) int { + if c := cmp.Compare(b.Value, a.Value); c != 0 { + return c + } + return cmp.Compare(a.Name, b.Name) }) } @@ -94,3 +98,51 @@ func ConvertToPrometheusTSDBStat(stats []Statistic) []v1.TSDBStat { return ret } + +// ToTSDBStats converts a TSDBStatisticsEntry to tsdb.Stats format. +// This is useful for components like Sidecar that receive statistics from Prometheus +// and need to convert them to the internal TSDB stats format. +// The limit parameter controls the maximum number of entries in each index stats slice. +// A limit of 0 or negative means no limit. +func (tse *TSDBStatisticsEntry) ToTSDBStats(limit int) tsdb.Stats { + stats := tsdb.Stats{ + NumSeries: tse.HeadStatistics.NumSeries, + MinTime: tse.HeadStatistics.MinTime, + MaxTime: tse.HeadStatistics.MaxTime, + } + + if len(tse.SeriesCountByMetricName) > 0 || + len(tse.LabelValueCountByLabelName) > 0 || + len(tse.SeriesCountByLabelValuePair) > 0 || + tse.HeadStatistics.NumLabelPairs > 0 { + + stats.IndexPostingStats = &index.PostingsStats{ + NumLabelPairs: int(tse.HeadStatistics.NumLabelPairs), + CardinalityMetricsStats: convertToIndexStats(tse.SeriesCountByMetricName, limit), + LabelValueStats: convertToIndexStats(tse.LabelValueCountByLabelName, limit), + LabelValuePairsStats: convertToIndexStats(tse.SeriesCountByLabelValuePair, limit), + } + } + + return stats +} + +// convertToIndexStats converts a slice of Statistic to index.Stat slice. +// The limit parameter controls the maximum number of entries returned. +// A limit of 0 or negative means no limit. +func convertToIndexStats(stats []Statistic, limit int) []index.Stat { + if len(stats) == 0 { + return nil + } + result := make([]index.Stat, len(stats)) + for i, s := range stats { + result[i] = index.Stat{ + Name: s.Name, + Count: s.Value, + } + } + if limit > 0 && limit < len(result) { + result = result[:limit] + } + return result +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.pb.go b/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.pb.go index ac7c8bdebc1..ee3884fc589 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.pb.go +++ b/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.pb.go @@ -30,9 +30,11 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type TSDBStatisticsRequest struct { + // Deprecated: use matchers instead. Tenant string `protobuf:"bytes,1,opt,name=tenant,proto3" json:"tenant,omitempty"` Limit int32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` PartialResponseStrategy storepb.PartialResponseStrategy `protobuf:"varint,3,opt,name=partial_response_strategy,json=partialResponseStrategy,proto3,enum=thanos.PartialResponseStrategy" json:"partial_response_strategy,omitempty"` + Matchers []storepb.LabelMatcher `protobuf:"bytes,4,rep,name=matchers,proto3" json:"matchers"` } func (m *TSDBStatisticsRequest) Reset() { *m = TSDBStatisticsRequest{} } @@ -329,53 +331,55 @@ func init() { func init() { proto.RegisterFile("status/statuspb/rpc.proto", fileDescriptor_d59a2444f79de84b) } var fileDescriptor_d59a2444f79de84b = []byte{ - // 733 bytes of a gzipped FileDescriptorProto + // 762 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x55, 0xcd, 0x4e, 0x1b, 0x49, - 0x10, 0xf6, 0xe0, 0x1f, 0x70, 0x59, 0x98, 0xa5, 0x97, 0x05, 0x63, 0xc4, 0x8c, 0xe5, 0x95, 0x90, - 0x0f, 0x2b, 0x7b, 0xe3, 0x28, 0x12, 0xc9, 0x71, 0xf2, 0x23, 0x22, 0x91, 0x88, 0xb4, 0x51, 0x0e, - 0x70, 0x18, 0xb5, 0x4d, 0xcb, 0x6e, 0xe1, 0xe9, 0x99, 0x4c, 0xf7, 0x24, 0x4c, 0xa4, 0xbc, 0x43, - 0x9e, 0x21, 0xcf, 0x90, 0x87, 0xe0, 0x90, 0x03, 0xc7, 0x9c, 0xac, 0x04, 0x6e, 0x7e, 0x84, 0x9c, - 0xa2, 0xe9, 0x1e, 0xff, 0xc6, 0xe6, 0x02, 0xd5, 0x55, 0x5f, 0xd5, 0xf7, 0x55, 0x4d, 0x77, 0x19, - 0x76, 0x85, 0x24, 0x32, 0x14, 0x0d, 0xfd, 0xcf, 0x6f, 0x37, 0x02, 0xbf, 0x53, 0xf7, 0x03, 0x4f, - 0x7a, 0x28, 0x27, 0x7b, 0x84, 0x7b, 0xa2, 0xbc, 0x2b, 0xa4, 0x17, 0xd0, 0x86, 0xfa, 0xeb, 0xb7, - 0x1b, 0x32, 0xf2, 0xa9, 0xd0, 0x90, 0xf2, 0x56, 0xd7, 0xeb, 0x7a, 0xca, 0x6c, 0xc4, 0x96, 0xf6, - 0x56, 0xbf, 0x18, 0xf0, 0xcf, 0x69, 0xeb, 0x99, 0xdd, 0x92, 0x44, 0x32, 0x21, 0x59, 0x47, 0x60, - 0xfa, 0x2e, 0xa4, 0x42, 0xa2, 0x6d, 0xc8, 0x49, 0xca, 0x09, 0x97, 0x25, 0xa3, 0x62, 0xd4, 0xf2, - 0x38, 0x39, 0xa1, 0x2d, 0xc8, 0xf6, 0x99, 0xcb, 0x64, 0x69, 0xa5, 0x62, 0xd4, 0xb2, 0x58, 0x1f, - 0xd0, 0x39, 0xec, 0xfa, 0x24, 0x90, 0x8c, 0xf4, 0x9d, 0x80, 0x0a, 0xdf, 0xe3, 0x82, 0x3a, 0x42, - 0x06, 0x44, 0xd2, 0x6e, 0x54, 0x4a, 0x57, 0x8c, 0x5a, 0xb1, 0x69, 0xd5, 0xb5, 0xc8, 0xfa, 0x89, - 0x06, 0xe2, 0x04, 0xd7, 0x4a, 0x60, 0x78, 0xc7, 0x5f, 0x1c, 0xa8, 0x5e, 0xc1, 0xf6, 0xbc, 0x46, - 0x8d, 0x40, 0x87, 0x00, 0x62, 0xec, 0x55, 0x42, 0x0b, 0xcd, 0xed, 0x11, 0xcf, 0x6c, 0xce, 0x51, - 0x0a, 0x4f, 0x61, 0x51, 0x19, 0x56, 0x3f, 0x90, 0x80, 0x33, 0xde, 0x55, 0x8d, 0xe4, 0x8f, 0x52, - 0x78, 0xe4, 0xb0, 0xd7, 0x20, 0x17, 0x50, 0x11, 0xf6, 0x65, 0xf5, 0xab, 0x01, 0xc5, 0xd9, 0x32, - 0xe8, 0xc5, 0x1c, 0x65, 0xba, 0x56, 0x68, 0x1e, 0x2c, 0xa6, 0xac, 0x4f, 0xcc, 0xe7, 0x5c, 0x06, - 0xd1, 0xb4, 0x80, 0xf2, 0x19, 0x6c, 0xcc, 0x85, 0xd1, 0x5f, 0x90, 0xbe, 0xa4, 0x51, 0x32, 0xef, - 0xd8, 0x44, 0x0f, 0x20, 0xfb, 0x9e, 0xf4, 0x43, 0xaa, 0x34, 0x16, 0x9a, 0x7b, 0x8b, 0x79, 0x74, - 0x71, 0x8d, 0x7c, 0xb2, 0x72, 0x68, 0x54, 0xbf, 0x65, 0xe0, 0xef, 0x05, 0x10, 0x84, 0x61, 0xa3, - 0x47, 0xc9, 0x85, 0xb3, 0x7c, 0x66, 0x47, 0x94, 0x5c, 0x4c, 0xb2, 0xec, 0xcd, 0xeb, 0x81, 0x95, - 0x1a, 0x0e, 0xac, 0x7c, 0x2f, 0xf1, 0x0b, 0x5c, 0xec, 0xcd, 0x40, 0x90, 0x0f, 0x7b, 0x82, 0x06, - 0x8c, 0x0a, 0xa7, 0xe3, 0x85, 0x5c, 0x3a, 0xed, 0xc8, 0x71, 0xa9, 0x0c, 0x58, 0xc7, 0xe1, 0xc4, - 0x8d, 0x85, 0xc7, 0x03, 0xda, 0x1c, 0xd5, 0x1f, 0x27, 0xda, 0x56, 0x52, 0x7a, 0x47, 0x67, 0x3f, - 0x8d, 0x93, 0xed, 0xe8, 0x95, 0x4a, 0x7d, 0x4d, 0x5c, 0x8a, 0x97, 0x05, 0xd0, 0x47, 0xb0, 0xfa, - 0xa4, 0x4d, 0xfb, 0x8e, 0x6a, 0x78, 0x42, 0xab, 0x9d, 0x8a, 0x35, 0xbd, 0x8c, 0xb5, 0x9a, 0xb0, - 0x96, 0x15, 0xf8, 0x6d, 0x5c, 0x20, 0x21, 0x38, 0x8e, 0x1d, 0x8a, 0xf8, 0x9e, 0x18, 0x92, 0xb0, - 0xef, 0x52, 0xd7, 0x0b, 0x22, 0x87, 0x71, 0xa7, 0x1d, 0x49, 0x2a, 0xe6, 0x98, 0x33, 0xcb, 0x98, - 0x2b, 0x09, 0x73, 0x49, 0xe7, 0xbf, 0xe4, 0x76, 0x9c, 0x3d, 0xcd, 0xbb, 0x34, 0x82, 0x3e, 0x41, - 0x65, 0x7e, 0xc6, 0xd3, 0x13, 0xf0, 0x09, 0x0b, 0x4a, 0xd9, 0x65, 0xc4, 0xff, 0x26, 0xc4, 0x7b, - 0x33, 0xf3, 0x3c, 0x1e, 0xf7, 0x78, 0x42, 0x58, 0x80, 0xef, 0x0b, 0x56, 0x7f, 0x19, 0x50, 0x9c, - 0xbd, 0x18, 0xe8, 0x3f, 0x00, 0x1e, 0xba, 0x8e, 0xce, 0x52, 0x97, 0x28, 0x63, 0xaf, 0xc7, 0x17, - 0x85, 0x87, 0x6e, 0x4b, 0x39, 0xf1, 0xc4, 0x44, 0x8f, 0x61, 0x23, 0x46, 0x6b, 0xcd, 0xb1, 0x5a, - 0xa1, 0x2e, 0x74, 0xda, 0xde, 0x1c, 0x0e, 0xac, 0x75, 0x1e, 0xba, 0x8a, 0x30, 0xe6, 0x12, 0x78, - 0xf6, 0x88, 0x1a, 0x50, 0xe8, 0xf4, 0x42, 0x7e, 0xa9, 0x3b, 0x57, 0xab, 0x24, 0x6d, 0x17, 0x87, - 0x03, 0x0b, 0x94, 0x5b, 0x09, 0xc6, 0x53, 0x36, 0x3a, 0x80, 0x35, 0x97, 0x71, 0x47, 0x32, 0xf5, - 0x31, 0x62, 0x74, 0x61, 0x38, 0xb0, 0x56, 0x5d, 0xc6, 0x4f, 0x99, 0x4b, 0xf1, 0xc8, 0x50, 0x38, - 0x72, 0xa5, 0x71, 0xd9, 0x29, 0x1c, 0xb9, 0x4a, 0x70, 0xda, 0xa8, 0x3e, 0x82, 0xfc, 0xb8, 0x6f, - 0x84, 0x20, 0xa3, 0xbe, 0xb2, 0x7e, 0xa2, 0xca, 0x8e, 0x17, 0xe2, 0xe4, 0x8d, 0x66, 0x92, 0x67, - 0xd8, 0x3c, 0x87, 0x5c, 0x4b, 0xed, 0x69, 0xf4, 0xe6, 0x8f, 0x15, 0xb2, 0xbf, 0xf8, 0x19, 0x27, - 0x9b, 0xb7, 0x6c, 0x2e, 0x0b, 0xeb, 0xa5, 0xf7, 0xbf, 0x61, 0x1f, 0x5c, 0xff, 0x34, 0x53, 0xd7, - 0xb7, 0xa6, 0x71, 0x73, 0x6b, 0x1a, 0x3f, 0x6e, 0x4d, 0xe3, 0xf3, 0x9d, 0x99, 0xba, 0xb9, 0x33, - 0x53, 0xdf, 0xef, 0xcc, 0xd4, 0xd9, 0xda, 0xe8, 0x07, 0xa2, 0x9d, 0x53, 0x4b, 0xfe, 0xe1, 0xef, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x12, 0x23, 0x65, 0x33, 0x3a, 0x06, 0x00, 0x00, + 0x10, 0xf6, 0xe0, 0x1f, 0xec, 0xb2, 0x30, 0x4b, 0x2f, 0x0b, 0xc6, 0x88, 0x19, 0xcb, 0x2b, 0x21, + 0x1f, 0x56, 0xf6, 0xae, 0x57, 0xbb, 0x62, 0xf7, 0x38, 0xbb, 0x89, 0x88, 0x04, 0x11, 0x69, 0xa3, + 0x1c, 0xe0, 0x30, 0x6a, 0x9b, 0x96, 0x3d, 0xc2, 0xd3, 0x33, 0x99, 0xee, 0x49, 0x98, 0x48, 0x79, + 0x87, 0x3c, 0x4c, 0x1e, 0x82, 0x43, 0x0e, 0x1c, 0xa3, 0x1c, 0xac, 0x04, 0x6e, 0x7e, 0x84, 0x9c, + 0xa2, 0xee, 0x1e, 0xff, 0xc6, 0xe6, 0x62, 0x57, 0x57, 0x7d, 0x55, 0x5f, 0x55, 0x75, 0x75, 0x0d, + 0xec, 0x71, 0x41, 0x44, 0xc4, 0x9b, 0xfa, 0x2f, 0xe8, 0x34, 0xc3, 0xa0, 0xdb, 0x08, 0x42, 0x5f, + 0xf8, 0x28, 0x27, 0xfa, 0x84, 0xf9, 0xbc, 0xb2, 0xc7, 0x85, 0x1f, 0xd2, 0xa6, 0xfa, 0x0d, 0x3a, + 0x4d, 0x11, 0x07, 0x94, 0x6b, 0x48, 0x65, 0xbb, 0xe7, 0xf7, 0x7c, 0x25, 0x36, 0xa5, 0xa4, 0xb5, + 0xb5, 0xcf, 0x06, 0xfc, 0x72, 0xde, 0xfe, 0xdf, 0x6e, 0x0b, 0x22, 0x5c, 0x2e, 0xdc, 0x2e, 0xc7, + 0xf4, 0x55, 0x44, 0xb9, 0x40, 0x3b, 0x90, 0x13, 0x94, 0x11, 0x26, 0xca, 0x46, 0xd5, 0xa8, 0x17, + 0x70, 0x72, 0x42, 0xdb, 0x90, 0x1d, 0xb8, 0x9e, 0x2b, 0xca, 0x6b, 0x55, 0xa3, 0x9e, 0xc5, 0xfa, + 0x80, 0x2e, 0x61, 0x2f, 0x20, 0xa1, 0x70, 0xc9, 0xc0, 0x09, 0x29, 0x0f, 0x7c, 0xc6, 0xa9, 0xc3, + 0x45, 0x48, 0x04, 0xed, 0xc5, 0xe5, 0x74, 0xd5, 0xa8, 0x97, 0x5a, 0x56, 0x43, 0x27, 0xd9, 0x38, + 0xd3, 0x40, 0x9c, 0xe0, 0xda, 0x09, 0x0c, 0xef, 0x06, 0xcb, 0x0d, 0xe8, 0x6f, 0xc8, 0x7b, 0x44, + 0x74, 0xfb, 0x34, 0xe4, 0xe5, 0x4c, 0x35, 0x5d, 0x2f, 0xb6, 0xb6, 0xc7, 0xb1, 0x4e, 0x48, 0x87, + 0x0e, 0x4e, 0xb5, 0xd1, 0xce, 0xdc, 0x0e, 0xad, 0x14, 0x9e, 0x60, 0x6b, 0x37, 0xb0, 0xb3, 0x58, + 0x9b, 0x8e, 0x8c, 0x8e, 0x00, 0xf8, 0x44, 0xab, 0x0a, 0x2c, 0xb6, 0x76, 0xc6, 0x31, 0xe7, 0x7d, + 0x8e, 0x53, 0x78, 0x06, 0x8b, 0x2a, 0xb0, 0xfe, 0x86, 0x84, 0xcc, 0x65, 0x3d, 0xd5, 0x80, 0xc2, + 0x71, 0x0a, 0x8f, 0x15, 0x76, 0x1e, 0x72, 0x21, 0xe5, 0xd1, 0x40, 0xd4, 0x3e, 0x18, 0x50, 0x9a, + 0x0f, 0x83, 0x9e, 0x2e, 0x50, 0xca, 0x32, 0x0e, 0x97, 0x53, 0x36, 0xa6, 0xe2, 0x13, 0x26, 0xc2, + 0x78, 0x36, 0x81, 0xca, 0x05, 0x6c, 0x2e, 0x98, 0xd1, 0x4f, 0x90, 0xbe, 0xa6, 0x71, 0x72, 0x4f, + 0x52, 0x44, 0x7f, 0x40, 0xf6, 0x35, 0x19, 0x44, 0x54, 0xe5, 0x58, 0x6c, 0xed, 0x2f, 0xe7, 0xd1, + 0xc1, 0x35, 0xf2, 0xdf, 0xb5, 0x23, 0xa3, 0xf6, 0x31, 0x03, 0x3f, 0x2f, 0x81, 0x20, 0x0c, 0x9b, + 0x7d, 0x4a, 0xae, 0x9c, 0xd5, 0x3d, 0x3b, 0xa6, 0xe4, 0x6a, 0xea, 0x65, 0x6f, 0xc9, 0x9b, 0x18, + 0x0d, 0xad, 0x42, 0x3f, 0xd1, 0x73, 0x5c, 0xea, 0xcf, 0x41, 0x50, 0x00, 0xfb, 0x9c, 0x86, 0x2e, + 0xe5, 0x4e, 0xd7, 0x8f, 0x98, 0x70, 0x3a, 0xb1, 0xe3, 0x51, 0x11, 0xba, 0x5d, 0x87, 0x11, 0x4f, + 0x26, 0x2e, 0x1b, 0xb4, 0x35, 0x8e, 0x3f, 0x71, 0xb4, 0xad, 0x24, 0xf4, 0xae, 0xf6, 0xfe, 0x4f, + 0x3a, 0xdb, 0xf1, 0xa9, 0x72, 0x7d, 0x4e, 0x3c, 0x8a, 0x57, 0x19, 0xd0, 0x5b, 0xb0, 0x06, 0x72, + 0x5c, 0x1c, 0x55, 0xf0, 0x94, 0x56, 0x2b, 0x15, 0x6b, 0x7a, 0x15, 0x6b, 0x2d, 0x61, 0xad, 0x28, + 0xf0, 0x4b, 0x19, 0x20, 0x21, 0x50, 0x13, 0xa8, 0x88, 0x1f, 0xb1, 0x21, 0x01, 0x07, 0x1e, 0xf5, + 0xfc, 0x30, 0x76, 0x5c, 0xe6, 0x74, 0x62, 0x41, 0xf9, 0x02, 0x73, 0x66, 0x15, 0x73, 0x35, 0x61, + 0x2e, 0x6b, 0xff, 0x67, 0xcc, 0x96, 0xde, 0xb3, 0xbc, 0x2b, 0x2d, 0xe8, 0x1d, 0x54, 0x17, 0x7b, + 0x3c, 0xdb, 0x81, 0x80, 0xb8, 0x61, 0x39, 0xbb, 0x8a, 0xf8, 0xd7, 0x84, 0x78, 0x7f, 0xae, 0x9f, + 0x27, 0x93, 0x1a, 0xcf, 0x88, 0x1b, 0xe2, 0xc7, 0x8c, 0xb5, 0x6f, 0x06, 0x94, 0xe6, 0x07, 0x03, + 0xfd, 0x06, 0xc0, 0x22, 0xcf, 0xd1, 0x5e, 0x6a, 0x88, 0x32, 0xf6, 0x86, 0x1c, 0x14, 0x16, 0x79, + 0x6d, 0xa5, 0xc4, 0x53, 0x11, 0xfd, 0x03, 0x9b, 0x12, 0xad, 0x73, 0x96, 0xd9, 0x72, 0x35, 0xd0, + 0x69, 0x7b, 0x6b, 0x34, 0xb4, 0x36, 0x58, 0xe4, 0x29, 0x42, 0xc9, 0xc5, 0xf1, 0xfc, 0x11, 0x35, + 0xa1, 0xd8, 0xed, 0x47, 0xec, 0x5a, 0x57, 0xae, 0x56, 0x50, 0xda, 0x2e, 0x8d, 0x86, 0x16, 0x28, + 0xb5, 0x4a, 0x18, 0xcf, 0xc8, 0xe8, 0x10, 0xf2, 0x9e, 0xcb, 0x1c, 0xe1, 0xaa, 0xcb, 0x90, 0xe8, + 0xe2, 0x68, 0x68, 0xad, 0x7b, 0x2e, 0x3b, 0x77, 0x3d, 0x8a, 0xc7, 0x82, 0xc2, 0x91, 0x1b, 0x8d, + 0xcb, 0xce, 0xe0, 0xc8, 0x4d, 0x82, 0xd3, 0x42, 0xed, 0x2f, 0x28, 0x4c, 0xea, 0x46, 0x08, 0x32, + 0xea, 0x96, 0xf5, 0x13, 0x55, 0xb2, 0x5c, 0xa4, 0xd3, 0x37, 0x9a, 0x49, 0x9e, 0x61, 0xeb, 0x12, + 0x72, 0x6d, 0xb5, 0xdf, 0xd1, 0x8b, 0x1f, 0x56, 0xc8, 0xc1, 0xf2, 0x67, 0x9c, 0x6c, 0xec, 0x8a, + 0xb9, 0xca, 0xac, 0x97, 0xde, 0xef, 0x86, 0x7d, 0x78, 0xfb, 0xd5, 0x4c, 0xdd, 0xde, 0x9b, 0xc6, + 0xdd, 0xbd, 0x69, 0x7c, 0xb9, 0x37, 0x8d, 0xf7, 0x0f, 0x66, 0xea, 0xee, 0xc1, 0x4c, 0x7d, 0x7a, + 0x30, 0x53, 0x17, 0xf9, 0xf1, 0x87, 0xa5, 0x93, 0x53, 0x1f, 0x87, 0x3f, 0xbf, 0x07, 0x00, 0x00, + 0xff, 0xff, 0x44, 0xda, 0x03, 0xcd, 0x72, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -507,6 +511,20 @@ func (m *TSDBStatisticsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Matchers) > 0 { + for iNdEx := len(m.Matchers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Matchers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRpc(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } if m.PartialResponseStrategy != 0 { i = encodeVarintRpc(dAtA, i, uint64(m.PartialResponseStrategy)) i-- @@ -842,6 +860,12 @@ func (m *TSDBStatisticsRequest) Size() (n int) { if m.PartialResponseStrategy != 0 { n += 1 + sovRpc(uint64(m.PartialResponseStrategy)) } + if len(m.Matchers) > 0 { + for _, e := range m.Matchers { + l = e.Size() + n += 1 + l + sovRpc(uint64(l)) + } + } return n } @@ -1081,6 +1105,40 @@ func (m *TSDBStatisticsRequest) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Matchers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRpc + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRpc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Matchers = append(m.Matchers, storepb.LabelMatcher{}) + if err := m.Matchers[len(m.Matchers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRpc(dAtA[iNdEx:]) diff --git a/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.proto b/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.proto index a7d26f8607e..f00b215ace1 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.proto +++ b/vendor/github.com/thanos-io/thanos/pkg/status/statuspb/rpc.proto @@ -29,9 +29,11 @@ service Status { } message TSDBStatisticsRequest { + // Deprecated: use matchers instead. string tenant = 1; int32 limit = 2; PartialResponseStrategy partial_response_strategy = 3; + repeated thanos.LabelMatcher matchers = 4 [(gogoproto.nullable) = false]; } message TSDBStatisticsResponse { diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go b/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go index 853d9dcd24b..09f2e2492c2 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/bucket.go @@ -90,18 +90,6 @@ const ( chunkBytesPoolMinSize = 64 * 1024 // 64 KiB chunkBytesPoolMaxSize = 64 * 1024 * 1024 // 64 MiB - // CompatibilityTypeLabelName is an artificial label that Store Gateway can optionally advertise. This is required for compatibility - // with pre v0.8.0 Querier. Previous Queriers was strict about duplicated external labels of all StoreAPIs that had any labels. - // Now with newer Store Gateway advertising all the external labels it has access to, there was simple case where - // Querier was blocking Store Gateway as duplicate with sidecar. - // - // Newer Queriers are not strict, no duplicated external labels check is there anymore. - // Additionally newer Queriers removes/ignore this exact labels from UI and querying. - // - // This label name is intentionally against Prometheus label style. - // TODO(bwplotka): Remove it at some point. - CompatibilityTypeLabelName = "@thanos_compatibility_store_type" - // DefaultPostingOffsetInMemorySampling represents default value for --store.index-header-posting-offsets-in-mem-sampling. // 32 value is chosen as it's a good balance for common setups. Sampling that is not too large (too many CPU cycles) and // not too small (too much memory). @@ -430,9 +418,8 @@ type BucketStore struct { partitioner Partitioner - filterConfig *FilterConfig - advLabelSets []labelpb.ZLabelSet - enableCompatibilityLabel bool + filterConfig *FilterConfig + advLabelSets []labelpb.ZLabelSet // Every how many posting offset entry we pool in heap memory. Default in Prometheus is 32. postingOffsetsInMemSampling int @@ -654,7 +641,6 @@ func NewBucketStore( bytesLimiterFactory BytesLimiterFactory, partitioner Partitioner, blockSyncConcurrency int, - enableCompatibilityLabel bool, postingOffsetsInMemSampling int, enableSeriesResponseHints bool, // TODO(pracucci) Thanos 0.12 and below doesn't gracefully handle new fields in SeriesResponse. Drop this flag and always enable hints once we can drop backward compatibility. lazyIndexReaderEnabled bool, @@ -681,7 +667,6 @@ func NewBucketStore( seriesLimiterFactory: seriesLimiterFactory, bytesLimiterFactory: bytesLimiterFactory, partitioner: partitioner, - enableCompatibilityLabel: enableCompatibilityLabel, postingOffsetsInMemSampling: postingOffsetsInMemSampling, enableSeriesResponseHints: enableSeriesResponseHints, enableChunkHashCalculation: enableChunkHashCalculation, @@ -1024,14 +1009,9 @@ func (s *BucketStore) TSDBInfos() []infopb.TSDBInfo { func (s *BucketStore) LabelSet() []labelpb.ZLabelSet { s.mtx.RLock() - labelSets := s.advLabelSets - s.mtx.RUnlock() - - if s.enableCompatibilityLabel && len(labelSets) > 0 { - labelSets = append(labelSets, labelpb.ZLabelSet{Labels: []labelpb.ZLabel{{Name: CompatibilityTypeLabelName, Value: "store"}}}) - } + defer s.mtx.RUnlock() - return labelSets + return s.advLabelSets } func (s *BucketStore) limitMinTime(mint int64) int64 { @@ -1722,6 +1702,7 @@ func (s *BucketStore) Series(req *storepb.SeriesRequest, seriesSrv storepb.Store false, s.metrics.emptyPostingCount.WithLabelValues(tenant), nil, + nil, ) } else { resp = newLazyRespSet( @@ -1735,6 +1716,7 @@ func (s *BucketStore) Series(req *storepb.SeriesRequest, seriesSrv storepb.Store false, s.metrics.emptyPostingCount.WithLabelValues(tenant), max(s.lazyRetrievalMaxBufferedResponses, 1), + nil, ) } @@ -2160,6 +2142,7 @@ func (s *BucketStore) LabelValues(ctx context.Context, req *storepb.LabelValuesR if !hasMetricNameEqMatcher && len(reqSeriesMatchersNoExtLabels) > 0 && !b.extLset.Has(req.Label) { m, err := labels.NewMatcher(labels.MatchNotEqual, req.Label, "") if err != nil { + s.mtx.RUnlock() return nil, status.Error(codes.InvalidArgument, err.Error()) } diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.pb.go b/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.pb.go index 3dd6d97299c..4523766ef81 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.pb.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.pb.go @@ -136,30 +136,118 @@ func (m *ZLabelSet) XXX_DiscardUnknown() { var xxx_messageInfo_ZLabelSet proto.InternalMessageInfo +// SymTableLabel is one label encoded as two references into a SymbolTable. +type SymTableLabel struct { + NameRef uint32 `protobuf:"varint,1,opt,name=name_ref,json=nameRef,proto3" json:"name_ref,omitempty"` + ValueRef uint32 `protobuf:"varint,2,opt,name=value_ref,json=valueRef,proto3" json:"value_ref,omitempty"` +} + +func (m *SymTableLabel) Reset() { *m = SymTableLabel{} } +func (m *SymTableLabel) String() string { return proto.CompactTextString(m) } +func (*SymTableLabel) ProtoMessage() {} +func (*SymTableLabel) Descriptor() ([]byte, []int) { + return fileDescriptor_cdcc9e7dae4870e8, []int{3} +} +func (m *SymTableLabel) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SymTableLabel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SymTableLabel.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SymTableLabel) XXX_Merge(src proto.Message) { + xxx_messageInfo_SymTableLabel.Merge(m, src) +} +func (m *SymTableLabel) XXX_Size() int { + return m.Size() +} +func (m *SymTableLabel) XXX_DiscardUnknown() { + xxx_messageInfo_SymTableLabel.DiscardUnknown(m) +} + +var xxx_messageInfo_SymTableLabel proto.InternalMessageInfo + +// SymbolTable is the dedup table used by SymTableLabel. The bytes of every +// interned symbol are packed end-to-end; offsets[i] is the end +// offset of symbol `i`, so symbol `i` is `table[offsets[i-1]:offsets[i]]` +// (with offsets[-1] := 0). +type SymbolTable struct { + Offsets []uint32 `protobuf:"varint,1,rep,packed,name=offsets,proto3" json:"offsets,omitempty"` + Table []byte `protobuf:"bytes,2,opt,name=table,proto3" json:"table,omitempty"` +} + +func (m *SymbolTable) Reset() { *m = SymbolTable{} } +func (m *SymbolTable) String() string { return proto.CompactTextString(m) } +func (*SymbolTable) ProtoMessage() {} +func (*SymbolTable) Descriptor() ([]byte, []int) { + return fileDescriptor_cdcc9e7dae4870e8, []int{4} +} +func (m *SymbolTable) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SymbolTable) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SymbolTable.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SymbolTable) XXX_Merge(src proto.Message) { + xxx_messageInfo_SymbolTable.Merge(m, src) +} +func (m *SymbolTable) XXX_Size() int { + return m.Size() +} +func (m *SymbolTable) XXX_DiscardUnknown() { + xxx_messageInfo_SymbolTable.DiscardUnknown(m) +} + +var xxx_messageInfo_SymbolTable proto.InternalMessageInfo + func init() { proto.RegisterType((*Label)(nil), "thanos.Label") proto.RegisterType((*LabelSet)(nil), "thanos.LabelSet") proto.RegisterType((*ZLabelSet)(nil), "thanos.ZLabelSet") + proto.RegisterType((*SymTableLabel)(nil), "thanos.SymTableLabel") + proto.RegisterType((*SymbolTable)(nil), "thanos.SymbolTable") } func init() { proto.RegisterFile("store/labelpb/types.proto", fileDescriptor_cdcc9e7dae4870e8) } var fileDescriptor_cdcc9e7dae4870e8 = []byte{ - // 212 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2c, 0x2e, 0xc9, 0x2f, - 0x4a, 0xd5, 0xcf, 0x49, 0x4c, 0x4a, 0xcd, 0x29, 0x48, 0xd2, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, - 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2b, 0xc9, 0x48, 0xcc, 0xcb, 0x2f, 0x96, 0x12, 0x49, - 0xcf, 0x4f, 0xcf, 0x07, 0x0b, 0xe9, 0x83, 0x58, 0x10, 0x59, 0x25, 0x43, 0x2e, 0x56, 0x1f, 0x90, - 0x26, 0x21, 0x21, 0x2e, 0x96, 0xbc, 0xc4, 0xdc, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, - 0x30, 0x5b, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, 0x34, 0x55, 0x82, 0x09, 0x2c, 0x08, 0xe1, - 0x28, 0x99, 0x73, 0x71, 0x80, 0xb5, 0x04, 0xa7, 0x96, 0x08, 0x69, 0x73, 0xb1, 0x81, 0xed, 0x2c, - 0x96, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0xe2, 0xd5, 0x83, 0xd8, 0xa6, 0x07, 0x56, 0xe1, 0xc4, - 0x72, 0xe2, 0x9e, 0x3c, 0x43, 0x10, 0x54, 0x89, 0x92, 0x13, 0x17, 0x67, 0x14, 0x5c, 0xa7, 0x29, - 0x7e, 0x9d, 0x7c, 0x20, 0x9d, 0xb7, 0xee, 0xc9, 0xb3, 0x41, 0x74, 0xc0, 0xcc, 0x70, 0x52, 0x3d, - 0xf1, 0x50, 0x8e, 0xe1, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, - 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0xd8, 0xa1, - 0x01, 0x90, 0xc4, 0x06, 0xf6, 0x9d, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x80, 0xe8, 0x16, - 0x18, 0x01, 0x00, 0x00, + // 299 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x31, 0x4b, 0xc3, 0x40, + 0x14, 0xc7, 0x73, 0xb5, 0x4d, 0x9b, 0x57, 0xe3, 0x70, 0x74, 0x48, 0x15, 0xae, 0x25, 0x20, 0x14, + 0x84, 0x04, 0x15, 0x71, 0x72, 0xc9, 0xe2, 0xe2, 0x74, 0x71, 0xea, 0x22, 0x09, 0x5c, 0xea, 0x90, + 0xf4, 0x42, 0x72, 0x0a, 0xf9, 0x16, 0x7e, 0xac, 0x8c, 0x1d, 0xc5, 0xa1, 0x68, 0xf2, 0x45, 0xe4, + 0xde, 0xd5, 0x8e, 0x6e, 0xf7, 0x7f, 0xef, 0xfd, 0xfe, 0xef, 0xcf, 0x3b, 0x98, 0xd7, 0x4a, 0x56, + 0x22, 0xcc, 0x93, 0x54, 0xe4, 0x65, 0x1a, 0xaa, 0xa6, 0x14, 0x75, 0x50, 0x56, 0x52, 0x49, 0x6a, + 0xab, 0xd7, 0x64, 0x2b, 0xeb, 0xf3, 0xd9, 0x46, 0x6e, 0x24, 0x96, 0x42, 0xfd, 0x32, 0x5d, 0xff, + 0x1a, 0x46, 0x4f, 0x1a, 0xa2, 0x14, 0x86, 0xdb, 0xa4, 0x10, 0x1e, 0x59, 0x92, 0x95, 0xc3, 0xf1, + 0x4d, 0x67, 0x30, 0x7a, 0x4f, 0xf2, 0x37, 0xe1, 0x0d, 0xb0, 0x68, 0x84, 0x7f, 0x0f, 0x13, 0x44, + 0x62, 0xa1, 0xe8, 0x15, 0xd8, 0xb8, 0xb3, 0xf6, 0xc8, 0xf2, 0x64, 0x35, 0xbd, 0x71, 0x03, 0xb3, + 0x2d, 0xc0, 0x89, 0x68, 0xd8, 0xee, 0x17, 0x16, 0x3f, 0x8c, 0xf8, 0x11, 0x38, 0xeb, 0x23, 0x79, + 0xf7, 0x3f, 0x79, 0xa6, 0xc9, 0xaf, 0xfd, 0xc2, 0x36, 0xc4, 0xd1, 0xe3, 0x11, 0xdc, 0xb8, 0x29, + 0x9e, 0x93, 0x34, 0x17, 0x26, 0xf7, 0x1c, 0x26, 0x3a, 0xeb, 0x4b, 0x25, 0x32, 0xcc, 0xee, 0xf2, + 0xb1, 0xd6, 0x5c, 0x64, 0xf4, 0x02, 0x1c, 0x4c, 0x8c, 0xbd, 0x01, 0xf6, 0x26, 0x58, 0xe0, 0x22, + 0xf3, 0x1f, 0x60, 0x1a, 0x37, 0x45, 0x2a, 0x73, 0xf4, 0xa2, 0x1e, 0x8c, 0x65, 0x96, 0xd5, 0x42, + 0x99, 0x3c, 0x2e, 0xff, 0x93, 0xfa, 0x08, 0x4a, 0x8f, 0xa0, 0xc3, 0x29, 0x37, 0x22, 0xba, 0x6c, + 0x7f, 0x98, 0xd5, 0x76, 0x8c, 0xec, 0x3a, 0x46, 0xbe, 0x3b, 0x46, 0x3e, 0x7a, 0x66, 0xed, 0x7a, + 0x66, 0x7d, 0xf6, 0xcc, 0x5a, 0x8f, 0x0f, 0x1f, 0x91, 0xda, 0x78, 0xe5, 0xdb, 0xdf, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xc5, 0xa5, 0x8e, 0x97, 0xa0, 0x01, 0x00, 0x00, } func (m *Label) Marshal() (dAtA []byte, err error) { @@ -273,6 +361,87 @@ func (m *ZLabelSet) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SymTableLabel) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SymTableLabel) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SymTableLabel) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ValueRef != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ValueRef)) + i-- + dAtA[i] = 0x10 + } + if m.NameRef != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.NameRef)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *SymbolTable) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SymbolTable) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SymbolTable) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Table) > 0 { + i -= len(m.Table) + copy(dAtA[i:], m.Table) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Table))) + i-- + dAtA[i] = 0x12 + } + if len(m.Offsets) > 0 { + dAtA2 := make([]byte, len(m.Offsets)*10) + var j1 int + for _, num := range m.Offsets { + for num >= 1<<7 { + dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA2[j1] = uint8(num) + j1++ + } + i -= j1 + copy(dAtA[i:], dAtA2[:j1]) + i = encodeVarintTypes(dAtA, i, uint64(j1)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { offset -= sovTypes(v) base := offset @@ -331,6 +500,41 @@ func (m *ZLabelSet) Size() (n int) { return n } +func (m *SymTableLabel) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.NameRef != 0 { + n += 1 + sovTypes(uint64(m.NameRef)) + } + if m.ValueRef != 0 { + n += 1 + sovTypes(uint64(m.ValueRef)) + } + return n +} + +func (m *SymbolTable) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Offsets) > 0 { + l = 0 + for _, e := range m.Offsets { + l += sovTypes(uint64(e)) + } + n += 1 + sovTypes(uint64(l)) + l + } + l = len(m.Table) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -619,6 +823,254 @@ func (m *ZLabelSet) Unmarshal(dAtA []byte) error { } return nil } +func (m *SymTableLabel) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SymTableLabel: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SymTableLabel: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NameRef", wireType) + } + m.NameRef = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NameRef |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValueRef", wireType) + } + m.ValueRef = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValueRef |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SymbolTable) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SymbolTable: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SymbolTable: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Offsets = append(m.Offsets, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Offsets) == 0 { + m.Offsets = make([]uint32, 0, elementCount) + } + for iNdEx < postIndex { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Offsets = append(m.Offsets, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Offsets", wireType) + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Table", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Table = append(m.Table[:0], dAtA[iNdEx:postIndex]...) + if m.Table == nil { + m.Table = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTypes(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.proto b/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.proto index 65aa195ec12..a9c6b44051c 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.proto +++ b/vendor/github.com/thanos-io/thanos/pkg/store/labelpb/types.proto @@ -31,3 +31,18 @@ message LabelSet { message ZLabelSet { repeated Label labels = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "ZLabel"]; } + +// SymTableLabel is one label encoded as two references into a SymbolTable. +message SymTableLabel { + uint32 name_ref = 1; + uint32 value_ref = 2; +} + +// SymbolTable is the dedup table used by SymTableLabel. The bytes of every +// interned symbol are packed end-to-end; offsets[i] is the end +// offset of symbol `i`, so symbol `i` is `table[offsets[i-1]:offsets[i]]` +// (with offsets[-1] := 0). +message SymbolTable { + repeated uint32 offsets = 1; + bytes table = 2; +} diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go b/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go index ae8b16e27b0..3a5fa414f60 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/proxy.go @@ -23,8 +23,11 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + enginemodel "github.com/thanos-io/promql-engine/execution/model" + "github.com/thanos-io/thanos/pkg/component" "github.com/thanos-io/thanos/pkg/info/infopb" + "github.com/thanos-io/thanos/pkg/query/fanout" storecache "github.com/thanos-io/thanos/pkg/store/cache" "github.com/thanos-io/thanos/pkg/store/labelpb" "github.com/thanos-io/thanos/pkg/store/storepb" @@ -45,6 +48,11 @@ const StoreMatcherKey = ctxKey(0) // This can happen with Query servers trees and external labels. var ErrorNoStoresMatched = errors.New("No StoreAPIs matched for this query") +// ErrorNoStoresAvailable is returned if we have an empty list of stores. +// This happens either when we didn't yet complete any discovery +// or when all stores disappear suddenly. +var ErrorNoStoresAvailable = errors.New("No StoreAPIs available") + // Client holds meta information about a store. type Client interface { // StoreClient to access the store. @@ -195,7 +203,7 @@ func NewProxyStore( } func (s *ProxyStore) LabelSet() []labelpb.ZLabelSet { - stores := s.storesForTSDBSelector() + stores := s.storesForTSDBSelector(s.stores()) if len(stores) == 0 { // We always want to enforce announcing the subset of data that // selector-labels represents. If no stores match the filter, @@ -243,7 +251,7 @@ func (s *ProxyStore) LabelSet() []labelpb.ZLabelSet { } func (s *ProxyStore) TimeRange() (int64, int64) { - stores := s.storesForTSDBSelector() + stores := s.storesForTSDBSelector(s.stores()) if len(stores) == 0 { return math.MinInt64, math.MaxInt64 } @@ -263,7 +271,7 @@ func (s *ProxyStore) TimeRange() (int64, int64) { } func (s *ProxyStore) TSDBInfos() []infopb.TSDBInfo { - stores := s.storesForTSDBSelector() + stores := s.storesForTSDBSelector(s.stores()) infos := make([]infopb.TSDBInfo, 0) for _, st := range stores { infos = append(infos, st.TSDBInfos()...) @@ -306,7 +314,14 @@ func (s *ProxyStore) Series(originalRequest *storepb.SeriesRequest, seriesSrv st ctx = metadata.AppendToOutgoingContext(ctx, tenancy.DefaultTenantHeader, tenant) level.Debug(s.logger).Log("msg", "Tenant info in Series()", "tenant", tenant) - stores, storeLabelSets, storeDebugMsgs := s.matchingStores(ctx, originalRequest.MinTime, originalRequest.MaxTime, matchers) + // There are no stores registered at all and partial results are disabled, return an error. + stores := s.stores() + if len(stores) == 0 && (originalRequest.PartialResponseDisabled || originalRequest.PartialResponseStrategy == storepb.PartialResponseStrategy_ABORT) { + level.Debug(reqLogger).Log("err", ErrorNoStoresAvailable) + return ErrorNoStoresAvailable + } + + stores, storeLabelSets, storeDebugMsgs := s.matchingStores(ctx, stores, originalRequest.MinTime, originalRequest.MaxTime, matchers) if len(stores) == 0 { level.Debug(reqLogger).Log("err", ErrorNoStoresMatched, "stores", strings.Join(storeDebugMsgs, ";")) return nil @@ -329,14 +344,33 @@ func (s *ProxyStore) Series(originalRequest *storepb.SeriesRequest, seriesSrv st ResponseBatchSize: originalRequest.ResponseBatchSize, } + tracker := fanout.FromContext(ctx) + opID, opIDOK := enginemodel.OperatorIDFromContext(ctx) + storeResponses := make([]respSet, 0, len(stores)) for _, st := range stores { + var reporter statsReporter + + if tracker != nil && opIDOK { + _, storeAddr, _ := storeInfo(st) + reporter = func(rs RespSetStats) { + tracker.AddStore(opID, fanout.StoreFanout{ + EndpointAddr: storeAddr, + Duration: rs.Duration, + BytesProcessed: rs.BytesProcessed, + NumResponses: rs.NumResponses, + Series: rs.Series, + Chunks: rs.Chunks, + Samples: rs.Samples, + }) + } + } - respSet, err := newAsyncRespSet(ctx, st, r, s.responseTimeout, s.retrievalStrategy, &s.buffers, r.ShardInfo, reqLogger, s.metrics.emptyStreamResponses, s.lazyRetrievalMaxBufferedResponses) + respSet, err := newAsyncRespSet(ctx, st, r, s.responseTimeout, s.retrievalStrategy, &s.buffers, r.ShardInfo, reqLogger, s.metrics.emptyStreamResponses, s.lazyRetrievalMaxBufferedResponses, reporter) if err != nil { level.Error(reqLogger).Log("err", err) - if !r.PartialResponseDisabled || r.PartialResponseStrategy == storepb.PartialResponseStrategy_WARN { + if !r.PartialResponseDisabled && r.PartialResponseStrategy != storepb.PartialResponseStrategy_ABORT { if err := srv.Send(storepb.NewWarnSeriesResponse(err)); err != nil { return err } @@ -411,7 +445,7 @@ func (s *ProxyStore) LabelNames(ctx context.Context, originalRequest *storepb.La ctx = metadata.AppendToOutgoingContext(ctx, tenancy.DefaultTenantHeader, tenant) level.Debug(s.logger).Log("msg", "Tenant info in LabelNames()", "tenant", tenant) - stores, storeLabelSets, storeDebugMsgs := s.matchingStores(ctx, originalRequest.Start, originalRequest.End, matchers) + stores, storeLabelSets, storeDebugMsgs := s.matchingStores(ctx, s.stores(), originalRequest.Start, originalRequest.End, matchers) if len(stores) == 0 { level.Debug(reqLogger).Log("err", ErrorNoStoresMatched, "stores", strings.Join(storeDebugMsgs, ";")) return &storepb.LabelNamesResponse{}, nil @@ -419,6 +453,7 @@ func (s *ProxyStore) LabelNames(ctx context.Context, originalRequest *storepb.La storeMatchers, _ := storepb.PromMatchersToMatchers(matchers...) // Error would be returned by matchesExternalLabels, so skip check. r := &storepb.LabelNamesRequest{ PartialResponseDisabled: originalRequest.PartialResponseDisabled, + PartialResponseStrategy: originalRequest.PartialResponseStrategy, Start: originalRequest.Start, End: originalRequest.End, Matchers: append(storeMatchers, MatchersForLabelSets(storeLabelSets)...), @@ -445,7 +480,7 @@ func (s *ProxyStore) LabelNames(ctx context.Context, originalRequest *storepb.La resp, err := st.LabelNames(spanCtx, r) if err != nil { err = errors.Wrapf(err, "fetch label names from store %s", st) - if r.PartialResponseDisabled { + if r.PartialResponseDisabled || r.PartialResponseStrategy == storepb.PartialResponseStrategy_ABORT { return err } @@ -513,7 +548,7 @@ func (s *ProxyStore) LabelValues(ctx context.Context, originalRequest *storepb.L ctx = metadata.AppendToOutgoingContext(ctx, tenancy.DefaultTenantHeader, tenant) level.Debug(reqLogger).Log("msg", "Tenant info in LabelValues()", "tenant", tenant) - stores, storeLabelSets, storeDebugMsgs := s.matchingStores(ctx, originalRequest.Start, originalRequest.End, matchers) + stores, storeLabelSets, storeDebugMsgs := s.matchingStores(ctx, s.stores(), originalRequest.Start, originalRequest.End, matchers) if len(stores) == 0 { level.Debug(reqLogger).Log("err", ErrorNoStoresMatched, "stores", strings.Join(storeDebugMsgs, ";")) return &storepb.LabelValuesResponse{}, nil @@ -522,6 +557,7 @@ func (s *ProxyStore) LabelValues(ctx context.Context, originalRequest *storepb.L r := &storepb.LabelValuesRequest{ Label: originalRequest.Label, PartialResponseDisabled: originalRequest.PartialResponseDisabled, + PartialResponseStrategy: originalRequest.PartialResponseStrategy, Start: originalRequest.Start, End: originalRequest.End, Matchers: append(storeMatchers, MatchersForLabelSets(storeLabelSets)...), @@ -549,7 +585,7 @@ func (s *ProxyStore) LabelValues(ctx context.Context, originalRequest *storepb.L resp, err := st.LabelValues(spanCtx, r) if err != nil { err = errors.Wrapf(err, "fetch label values from store %s", st) - if r.PartialResponseDisabled { + if r.PartialResponseDisabled || r.PartialResponseStrategy == storepb.PartialResponseStrategy_ABORT { return err } @@ -593,9 +629,9 @@ func storeInfo(st Client) (storeID string, storeAddr string, isLocalStore bool) // storesForTSDBSelector returns stores that match the TSDBSelector filtering criteria. // This centralizes the TSDBSelector filtering logic used across all ProxyStore methods // for cases where we don't need additional matchers or time range filtering. -func (s *ProxyStore) storesForTSDBSelector() []Client { +func (s *ProxyStore) storesForTSDBSelector(stores []Client) []Client { var filteredStores []Client - for _, st := range s.stores() { + for _, st := range stores { matches, _ := s.tsdbSelector.MatchLabelSets(st.LabelSets()...) if matches { filteredStores = append(filteredStores, st) @@ -606,13 +642,13 @@ func (s *ProxyStore) storesForTSDBSelector() []Client { // TODO: consider moving the following functions into something like "pkg/pruneutils" since it is also used for exemplars. -func (s *ProxyStore) matchingStores(ctx context.Context, minTime, maxTime int64, matchers []*labels.Matcher) ([]Client, []labels.Labels, []string) { +func (s *ProxyStore) matchingStores(ctx context.Context, allStores []Client, minTime, maxTime int64, matchers []*labels.Matcher) ([]Client, []labels.Labels, []string) { var ( stores []Client storeLabelSets []labels.Labels storeDebugMsgs []string ) - for _, st := range s.storesForTSDBSelector() { + for _, st := range s.storesForTSDBSelector(allStores) { // We might be able to skip the store if its meta information indicates it cannot have series matching our query. if ok, reason := storeMatches(ctx, s.debugLogging, st, minTime, maxTime, matchers...); !ok { if s.debugLogging { @@ -689,7 +725,7 @@ func storeMatchDebugMetadata(s Client, debugLogging bool, storeDebugMatchers [][ match := false for _, sm := range storeDebugMatchers { - match = match || LabelSetsMatch(sm, labels.FromStrings("__address__", addr)) + match = match || matchersMatchAddress(sm, addr) } if !match { const s string = "__address__ does not match debug store metadata matchers" @@ -701,6 +737,18 @@ func storeMatchDebugMetadata(s Client, debugLogging bool, storeDebugMatchers [][ return true, "" } +// matchersMatchAddress reports whether the matchers match a label set that only +// contains __address__=addr. It mirrors LabelSetsMatch for that single synthetic +// label without allocating a labels.Labels for every store on every request. +func matchersMatchAddress(matchers []*labels.Matcher, addr string) bool { + for _, m := range matchers { + if m.Name == "__address__" && !m.Matches(addr) { + return false + } + } + return true +} + // LabelSetsMatch returns false if all label-sets do not match the matchers (aka: OR is between all label-sets). func LabelSetsMatch(matchers []*labels.Matcher, lset ...labels.Labels) bool { if len(lset) == 0 { diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/proxy_merge.go b/vendor/github.com/thanos-io/thanos/pkg/store/proxy_merge.go index 9af24ce0a66..3ff1a563e8e 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/proxy_merge.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/proxy_merge.go @@ -34,6 +34,30 @@ type seriesStream interface { At() *storepb.SeriesResponse } +// RespSetStats captures per-store telemetry collected while streaming a +// Series response from a single StoreAPI endpoint. It is reported once, at +// the end of the stream, via the optional statsReporter passed to +// newLazyRespSet / newEagerRespSet. +type RespSetStats struct { + Duration time.Duration + BytesProcessed int64 + NumResponses int64 + Series int64 + Chunks int64 + Samples int64 +} + +// statsReporter is an optional callback invoked once per StoreAPI fan-out when +// streaming finishes. A nil reporter is a no-op. +type statsReporter func(RespSetStats) + +func reportStats(r statsReporter, s RespSetStats) { + if r == nil { + return + } + r(s) +} + type responseDeduplicator struct { h seriesStream @@ -393,6 +417,7 @@ func newLazyRespSet( applySharding bool, emptyStreamResponses prometheus.Counter, fixedBufferSize int, + reportStatsFn statsReporter, ) respSet { bufferedResponsesMtx := &sync.Mutex{} @@ -420,8 +445,10 @@ func newLazyRespSet( } go func(st string, l *lazyRespSet) { + startTime := time.Now() bytesProcessed := 0 seriesStats := &storepb.SeriesStatsCounter{} + numResponses := 0 defer func() { l.span.SetTag("processed.series", seriesStats.Series) @@ -430,10 +457,18 @@ func newLazyRespSet( l.span.SetTag("processed.bytes", bytesProcessed) l.span.Finish() + reportStats(reportStatsFn, RespSetStats{ + Duration: time.Since(startTime), + BytesProcessed: int64(bytesProcessed), + NumResponses: int64(numResponses), + Series: int64(seriesStats.Series), + Chunks: int64(seriesStats.Chunks), + Samples: int64(seriesStats.Samples), + }) + close(l.donec) }() - numResponses := 0 defer func() { if numResponses == 0 { emptyStreamResponses.Inc() @@ -555,6 +590,7 @@ func newAsyncRespSet( logger log.Logger, emptyStreamResponses prometheus.Counter, lazyRetrievalMaxBufferedResponses int, + reportStatsFn statsReporter, ) (respSet, error) { var ( @@ -622,6 +658,7 @@ func newAsyncRespSet( applySharding, emptyStreamResponses, lazyRetrievalMaxBufferedResponses, + reportStatsFn, ), nil case EagerRetrieval: return newEagerRespSet( @@ -635,6 +672,7 @@ func newAsyncRespSet( applySharding, emptyStreamResponses, labelsToRemove, + reportStatsFn, ), nil default: panic(fmt.Sprintf("unsupported retrieval strategy %s", retrievalStrategy)) @@ -676,6 +714,7 @@ func newEagerRespSet( applySharding bool, emptyStreamResponses prometheus.Counter, removeLabels map[string]struct{}, + reportStatsFn statsReporter, ) respSet { ret := &eagerRespSet{ span: span, @@ -700,8 +739,10 @@ func newEagerRespSet( // Start a goroutine and immediately buffer everything. go func(l *eagerRespSet) { + startTime := time.Now() seriesStats := &storepb.SeriesStatsCounter{} bytesProcessed := 0 + numResponses := 0 defer func() { l.span.SetTag("processed.series", seriesStats.Series) @@ -709,10 +750,19 @@ func newEagerRespSet( l.span.SetTag("processed.samples", seriesStats.Samples) l.span.SetTag("processed.bytes", bytesProcessed) l.span.Finish() + + reportStats(reportStatsFn, RespSetStats{ + Duration: time.Since(startTime), + BytesProcessed: int64(bytesProcessed), + NumResponses: int64(numResponses), + Series: int64(seriesStats.Series), + Chunks: int64(seriesStats.Chunks), + Samples: int64(seriesStats.Samples), + }) + ret.wg.Done() }() - numResponses := 0 defer func() { if numResponses == 0 { emptyStreamResponses.Inc() diff --git a/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go b/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go index babf702cd05..c48abd373d8 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go +++ b/vendor/github.com/thanos-io/thanos/pkg/store/tsdb.go @@ -72,7 +72,7 @@ type TSDBStore struct { maxBytesPerFrame int matcherCache storecache.MatchersCache - extLset labels.Labels + extLsetAsLabelSets []labels.Labels startStoreFilterUpdate bool storeFilter filter.StoreFilter mtx sync.RWMutex @@ -110,13 +110,13 @@ func NewTSDBStore( } st := &TSDBStore{ - logger: logger, - db: db, - component: component, - extLset: extLset, - maxBytesPerFrame: RemoteReadFrameLimit, - storeFilter: filter.AllowAllStoreFilter{}, - close: func() {}, + logger: logger, + db: db, + component: component, + extLsetAsLabelSets: []labels.Labels{extLset}, + maxBytesPerFrame: RemoteReadFrameLimit, + storeFilter: filter.AllowAllStoreFilter{}, + close: func() {}, buffers: sync.Pool{New: func() any { b := make([]byte, 0, initialBufSize) return &b @@ -167,14 +167,23 @@ func (s *TSDBStore) SetExtLset(extLset labels.Labels) { s.mtx.Lock() defer s.mtx.Unlock() - s.extLset = extLset + s.extLsetAsLabelSets = []labels.Labels{extLset} } func (s *TSDBStore) getExtLset() labels.Labels { s.mtx.RLock() defer s.mtx.RUnlock() - return s.extLset + return s.extLsetAsLabelSets[0] +} + +// ExtLabelSets returns the external labels exposed by this store as a slice of +// label sets. Read-only. +func (s *TSDBStore) ExtLabelSets() []labels.Labels { + s.mtx.RLock() + defer s.mtx.RUnlock() + + return s.extLsetAsLabelSets } func (s *TSDBStore) LabelSet() []labelpb.ZLabelSet { @@ -300,7 +309,7 @@ func (s *TSDBStore) Series(r *storepb.SeriesRequest, seriesSrv storepb.Store_Ser for _, lbl := range r.WithoutReplicaLabels { extLsetToRemove[lbl] = struct{}{} } - finalExtLset := rmLabels(s.extLset.Copy(), extLsetToRemove) + finalExtLset := rmLabels(s.extLsetAsLabelSets[0].Copy(), extLsetToRemove) // Stream at most one series per frame; series may be split over multiple frames according to maxBytesInFrame. for set.Next() { diff --git a/vendor/github.com/thanos-io/thanos/pkg/tenancy/tenancy.go b/vendor/github.com/thanos-io/thanos/pkg/tenancy/tenancy.go index cb1f01a96dd..8ebf2551aed 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/tenancy/tenancy.go +++ b/vendor/github.com/thanos-io/thanos/pkg/tenancy/tenancy.go @@ -40,7 +40,7 @@ const ( func IsTenantValid(tenant string) error { if tenant != path.Base(tenant) { - return errors.New("Tenant name not valid") + return errors.New("tenant name not valid") } return nil } diff --git a/vendor/github.com/thanos-io/thanos/pkg/tls/options.go b/vendor/github.com/thanos-io/thanos/pkg/tls/options.go index 3b6a52e5246..f36e844aa64 100644 --- a/vendor/github.com/thanos-io/thanos/pkg/tls/options.go +++ b/vendor/github.com/thanos-io/thanos/pkg/tls/options.go @@ -19,8 +19,11 @@ import ( "github.com/pkg/errors" ) +// AllowedTLSVersions is for global lists the TLS versions allowed to be used. +var AllowedTLSVersions = []string{"1.0", "1.1", "1.2", "1.3"} + // NewServerConfig provides new server TLS configuration. -func NewServerConfig(logger log.Logger, certPath, keyPath, clientCA, tlsMinVersion string) (*tls.Config, error) { +func NewServerConfig(logger log.Logger, certPath, keyPath, clientCA, tlsMinVersion string, ciphers []string, curves []string) (*tls.Config, error) { if keyPath == "" && certPath == "" { if clientCA != "" { return nil, errors.New("when a client CA is used a server key and certificate must also be provided") @@ -36,7 +39,7 @@ func NewServerConfig(logger log.Logger, certPath, keyPath, clientCA, tlsMinVersi return nil, errors.New("both server key and certificate must be provided") } - minTlsVersion, err := getTlsVersion(tlsMinVersion) + minTlsVersion, err := GetTlsVersion(tlsMinVersion) if err != nil { return nil, err } @@ -44,6 +47,19 @@ func NewServerConfig(logger log.Logger, certPath, keyPath, clientCA, tlsMinVersi tlsCfg := &tls.Config{ MinVersion: minTlsVersion, } + + cipherSuiteIDs, err := getCipherSuiteIDs(ciphers) + if err != nil { + return nil, err + } + tlsCfg.CipherSuites = cipherSuiteIDs + + curveIDs, err := getCurveIDs(curves) + if err != nil { + return nil, err + } + tlsCfg.CurvePreferences = curveIDs + // Certificate is loaded during server startup to check for any errors. certificate, err := tls.LoadX509KeyPair(certPath, keyPath) if err != nil { @@ -113,7 +129,8 @@ func (m *serverTLSManager) getCertificate(clientHello *tls.ClientHelloInfo) (*tl } // NewClientConfig provides new client TLS configuration. -func NewClientConfig(logger log.Logger, cert, key, caCert, serverName string, skipVerify bool) (*tls.Config, error) { +// minTLSVersion must be one of 1.0, 1.1, 1.2, 1.3 per GetTlsVersion(). +func NewClientConfig(logger log.Logger, cert, key, caCert, serverName string, skipVerify bool, minTLSVersion string) (*tls.Config, error) { var certPool *x509.CertPool if caCert != "" { caPEM, err := os.ReadFile(filepath.Clean(caCert)) @@ -125,18 +142,31 @@ func NewClientConfig(logger log.Logger, cert, key, caCert, serverName string, sk if !certPool.AppendCertsFromPEM(caPEM) { return nil, errors.Wrap(err, "building client CA") } - level.Info(logger).Log("msg", "TLS client using provided certificate pool") + level.Debug(logger).Log("msg", "TLS client using provided certificate pool") } else { var err error certPool, err = x509.SystemCertPool() if err != nil { return nil, errors.Wrap(err, "reading system certificate pool") } - level.Info(logger).Log("msg", "TLS client using system certificate pool") + level.Debug(logger).Log("msg", "TLS client using system certificate pool") } + var ( + mtlsVersion uint16 + err error + ) + + if minTLSVersion != "" { + mtlsVersion, err = GetTlsVersion(minTLSVersion) + if err != nil { + return nil, err + } + level.Debug(logger).Log("msg", fmt.Sprintf("setting minimum TLS version to %s", minTLSVersion)) + } tlsCfg := &tls.Config{ - RootCAs: certPool, + RootCAs: certPool, + MinVersion: mtlsVersion, } if serverName != "" { @@ -158,7 +188,7 @@ func NewClientConfig(logger log.Logger, cert, key, caCert, serverName string, sk } tlsCfg.GetClientCertificate = mngr.getClientCertificate - level.Info(logger).Log("msg", "TLS client authentication enabled") + level.Debug(logger).Log("msg", "TLS client authentication enabled") } return tlsCfg, nil } @@ -213,7 +243,66 @@ func (validOption validOption) joinString() string { return strings.Join(keys, ", ") } -func getTlsVersion(tlsMinVersion string) (uint16, error) { +func getCipherSuiteIDs(ciphers []string) ([]uint16, error) { + if len(ciphers) == 0 { + return nil, nil + } + + supported := tls.CipherSuites() + cipherMap := make(map[string]uint16, len(supported)) + for _, cs := range supported { + cipherMap[cs.Name] = cs.ID + } + validNames := make([]string, 0, len(cipherMap)) + for n := range cipherMap { + validNames = append(validNames, n) + } + sort.Strings(validNames) + + ids := make([]uint16, 0, len(ciphers)) + for _, name := range ciphers { + id, ok := cipherMap[name] + if !ok { + return nil, errors.New(fmt.Sprintf("invalid cipher suite: %s, valid values are %s", name, strings.Join(validNames, ", "))) + } + ids = append(ids, id) + } + return ids, nil +} + +func getCurveIDs(curves []string) ([]tls.CurveID, error) { + if len(curves) == 0 { + return nil, nil + } + + // Manual mapping since crypto/tls doesn't provide enumeration + curveMap := map[string]tls.CurveID{ + "CurveP256": tls.CurveP256, + "CurveP384": tls.CurveP384, + "CurveP521": tls.CurveP521, + "X25519": tls.X25519, + "X25519MLKEM768": tls.X25519MLKEM768, + "SecP256r1MLKEM768": tls.SecP256r1MLKEM768, + "SecP384r1MLKEM1024": tls.SecP384r1MLKEM1024, + } + validNames := make([]string, 0, len(curveMap)) + for n := range curveMap { + validNames = append(validNames, n) + } + sort.Strings(validNames) + + ids := make([]tls.CurveID, 0, len(curves)) + for _, name := range curves { + id, ok := curveMap[name] + if !ok { + return nil, errors.New(fmt.Sprintf("invalid curve: %s, valid values are %s", name, strings.Join(validNames, ", "))) + } + ids = append(ids, id) + } + return ids, nil +} + +func GetTlsVersion(tlsMinVersion string) (uint16, error) { validOption := validOption{ tlsOption: map[string]uint16{ diff --git a/vendor/github.com/youmark/pkcs8/.gitignore b/vendor/github.com/youmark/pkcs8/.gitignore new file mode 100644 index 00000000000..836562412fe --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/vendor/github.com/youmark/pkcs8/LICENSE b/vendor/github.com/youmark/pkcs8/LICENSE new file mode 100644 index 00000000000..c939f448100 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 youmark + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/youmark/pkcs8/README b/vendor/github.com/youmark/pkcs8/README new file mode 100644 index 00000000000..376fcaf64e6 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/README @@ -0,0 +1 @@ +pkcs8 package: implement PKCS#8 private key parsing and conversion as defined in RFC5208 and RFC5958 diff --git a/vendor/github.com/youmark/pkcs8/README.md b/vendor/github.com/youmark/pkcs8/README.md new file mode 100644 index 00000000000..ef6c7625712 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/README.md @@ -0,0 +1,22 @@ +pkcs8 +=== +OpenSSL can generate private keys in both "traditional format" and PKCS#8 format. Newer applications are advised to use more secure PKCS#8 format. Go standard crypto package provides a [function](http://golang.org/pkg/crypto/x509/#ParsePKCS8PrivateKey) to parse private key in PKCS#8 format. There is a limitation to this function. It can only handle unencrypted PKCS#8 private keys. To use this function, the user has to save the private key in file without encryption, which is a bad practice to leave private keys unprotected on file systems. In addition, Go standard package lacks the functions to convert RSA/ECDSA private keys into PKCS#8 format. + +pkcs8 package fills the gap here. It implements functions to process private keys in PKCS#8 format, as defined in [RFC5208](https://tools.ietf.org/html/rfc5208) and [RFC5958](https://tools.ietf.org/html/rfc5958). It can handle both unencrypted PKCS#8 PrivateKeyInfo format and EncryptedPrivateKeyInfo format with PKCS#5 (v2.0) algorithms. + + +[**Godoc**](http://godoc.org/github.com/youmark/pkcs8) + +## Installation +Supports Go 1.10+. Release v1.1 is the last release supporting Go 1.9 + +```text +go get github.com/youmark/pkcs8 +``` +## dependency +This package depends on golang.org/x/crypto/pbkdf2 and golang.org/x/crypto/scrypt packages. Use the following command to retrieve them +```text +go get golang.org/x/crypto/pbkdf2 +go get golang.org/x/crypto/scrypt +``` + diff --git a/vendor/github.com/youmark/pkcs8/cipher.go b/vendor/github.com/youmark/pkcs8/cipher.go new file mode 100644 index 00000000000..2946c93e89c --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/cipher.go @@ -0,0 +1,60 @@ +package pkcs8 + +import ( + "bytes" + "crypto/cipher" + "encoding/asn1" +) + +type cipherWithBlock struct { + oid asn1.ObjectIdentifier + ivSize int + keySize int + newBlock func(key []byte) (cipher.Block, error) +} + +func (c cipherWithBlock) IVSize() int { + return c.ivSize +} + +func (c cipherWithBlock) KeySize() int { + return c.keySize +} + +func (c cipherWithBlock) OID() asn1.ObjectIdentifier { + return c.oid +} + +func (c cipherWithBlock) Encrypt(key, iv, plaintext []byte) ([]byte, error) { + block, err := c.newBlock(key) + if err != nil { + return nil, err + } + return cbcEncrypt(block, key, iv, plaintext) +} + +func (c cipherWithBlock) Decrypt(key, iv, ciphertext []byte) ([]byte, error) { + block, err := c.newBlock(key) + if err != nil { + return nil, err + } + return cbcDecrypt(block, key, iv, ciphertext) +} + +func cbcEncrypt(block cipher.Block, key, iv, plaintext []byte) ([]byte, error) { + mode := cipher.NewCBCEncrypter(block, iv) + paddingLen := block.BlockSize() - (len(plaintext) % block.BlockSize()) + ciphertext := make([]byte, len(plaintext)+paddingLen) + copy(ciphertext, plaintext) + copy(ciphertext[len(plaintext):], bytes.Repeat([]byte{byte(paddingLen)}, paddingLen)) + mode.CryptBlocks(ciphertext, ciphertext) + return ciphertext, nil +} + +func cbcDecrypt(block cipher.Block, key, iv, ciphertext []byte) ([]byte, error) { + mode := cipher.NewCBCDecrypter(block, iv) + plaintext := make([]byte, len(ciphertext)) + mode.CryptBlocks(plaintext, ciphertext) + // TODO: remove padding + return plaintext, nil +} diff --git a/vendor/github.com/youmark/pkcs8/cipher_3des.go b/vendor/github.com/youmark/pkcs8/cipher_3des.go new file mode 100644 index 00000000000..5629664409d --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/cipher_3des.go @@ -0,0 +1,24 @@ +package pkcs8 + +import ( + "crypto/des" + "encoding/asn1" +) + +var ( + oidDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7} +) + +func init() { + RegisterCipher(oidDESEDE3CBC, func() Cipher { + return TripleDESCBC + }) +} + +// TripleDESCBC is the 168-bit key 3DES cipher in CBC mode. +var TripleDESCBC = cipherWithBlock{ + ivSize: des.BlockSize, + keySize: 24, + newBlock: des.NewTripleDESCipher, + oid: oidDESEDE3CBC, +} diff --git a/vendor/github.com/youmark/pkcs8/cipher_aes.go b/vendor/github.com/youmark/pkcs8/cipher_aes.go new file mode 100644 index 00000000000..c0372d1eeba --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/cipher_aes.go @@ -0,0 +1,84 @@ +package pkcs8 + +import ( + "crypto/aes" + "encoding/asn1" +) + +var ( + oidAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2} + oidAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6} + oidAES192CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 22} + oidAES192GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 26} + oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42} + oidAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46} +) + +func init() { + RegisterCipher(oidAES128CBC, func() Cipher { + return AES128CBC + }) + RegisterCipher(oidAES128GCM, func() Cipher { + return AES128GCM + }) + RegisterCipher(oidAES192CBC, func() Cipher { + return AES192CBC + }) + RegisterCipher(oidAES192GCM, func() Cipher { + return AES192GCM + }) + RegisterCipher(oidAES256CBC, func() Cipher { + return AES256CBC + }) + RegisterCipher(oidAES256GCM, func() Cipher { + return AES256GCM + }) +} + +// AES128CBC is the 128-bit key AES cipher in CBC mode. +var AES128CBC = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 16, + newBlock: aes.NewCipher, + oid: oidAES128CBC, +} + +// AES128GCM is the 128-bit key AES cipher in GCM mode. +var AES128GCM = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 16, + newBlock: aes.NewCipher, + oid: oidAES128GCM, +} + +// AES192CBC is the 192-bit key AES cipher in CBC mode. +var AES192CBC = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 24, + newBlock: aes.NewCipher, + oid: oidAES192CBC, +} + +// AES192GCM is the 912-bit key AES cipher in GCM mode. +var AES192GCM = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 24, + newBlock: aes.NewCipher, + oid: oidAES192GCM, +} + +// AES256CBC is the 256-bit key AES cipher in CBC mode. +var AES256CBC = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 32, + newBlock: aes.NewCipher, + oid: oidAES256CBC, +} + +// AES256GCM is the 256-bit key AES cipher in GCM mode. +var AES256GCM = cipherWithBlock{ + ivSize: aes.BlockSize, + keySize: 32, + newBlock: aes.NewCipher, + oid: oidAES256GCM, +} diff --git a/vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go b/vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go new file mode 100644 index 00000000000..79697dd82bb --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/kdf_pbkdf2.go @@ -0,0 +1,91 @@ +package pkcs8 + +import ( + "crypto" + "crypto/sha1" + "crypto/sha256" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "hash" + + "golang.org/x/crypto/pbkdf2" +) + +var ( + oidPKCS5PBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} + oidHMACWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7} + oidHMACWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9} +) + +func init() { + RegisterKDF(oidPKCS5PBKDF2, func() KDFParameters { + return new(pbkdf2Params) + }) +} + +func newHashFromPRF(ai pkix.AlgorithmIdentifier) (func() hash.Hash, error) { + switch { + case len(ai.Algorithm) == 0 || ai.Algorithm.Equal(oidHMACWithSHA1): + return sha1.New, nil + case ai.Algorithm.Equal(oidHMACWithSHA256): + return sha256.New, nil + default: + return nil, errors.New("pkcs8: unsupported hash function") + } +} + +func newPRFParamFromHash(h crypto.Hash) (pkix.AlgorithmIdentifier, error) { + switch h { + case crypto.SHA1: + return pkix.AlgorithmIdentifier{ + Algorithm: oidHMACWithSHA1, + Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil + case crypto.SHA256: + return pkix.AlgorithmIdentifier{ + Algorithm: oidHMACWithSHA256, + Parameters: asn1.RawValue{Tag: asn1.TagNull}}, nil + } + return pkix.AlgorithmIdentifier{}, errors.New("pkcs8: unsupported hash function") +} + +type pbkdf2Params struct { + Salt []byte + IterationCount int + PRF pkix.AlgorithmIdentifier `asn1:"optional"` +} + +func (p pbkdf2Params) DeriveKey(password []byte, size int) (key []byte, err error) { + h, err := newHashFromPRF(p.PRF) + if err != nil { + return nil, err + } + return pbkdf2.Key(password, p.Salt, p.IterationCount, size, h), nil +} + +// PBKDF2Opts contains options for the PBKDF2 key derivation function. +type PBKDF2Opts struct { + SaltSize int + IterationCount int + HMACHash crypto.Hash +} + +func (p PBKDF2Opts) DeriveKey(password, salt []byte, size int) ( + key []byte, params KDFParameters, err error) { + + key = pbkdf2.Key(password, salt, p.IterationCount, size, p.HMACHash.New) + prfParam, err := newPRFParamFromHash(p.HMACHash) + if err != nil { + return nil, nil, err + } + params = pbkdf2Params{salt, p.IterationCount, prfParam} + return key, params, nil +} + +func (p PBKDF2Opts) GetSaltSize() int { + return p.SaltSize +} + +func (p PBKDF2Opts) OID() asn1.ObjectIdentifier { + return oidPKCS5PBKDF2 +} diff --git a/vendor/github.com/youmark/pkcs8/kdf_scrypt.go b/vendor/github.com/youmark/pkcs8/kdf_scrypt.go new file mode 100644 index 00000000000..36c4f4f5951 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/kdf_scrypt.go @@ -0,0 +1,62 @@ +package pkcs8 + +import ( + "encoding/asn1" + + "golang.org/x/crypto/scrypt" +) + +var ( + oidScrypt = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11591, 4, 11} +) + +func init() { + RegisterKDF(oidScrypt, func() KDFParameters { + return new(scryptParams) + }) +} + +type scryptParams struct { + Salt []byte + CostParameter int + BlockSize int + ParallelizationParameter int +} + +func (p scryptParams) DeriveKey(password []byte, size int) (key []byte, err error) { + return scrypt.Key(password, p.Salt, p.CostParameter, p.BlockSize, + p.ParallelizationParameter, size) +} + +// ScryptOpts contains options for the scrypt key derivation function. +type ScryptOpts struct { + SaltSize int + CostParameter int + BlockSize int + ParallelizationParameter int +} + +func (p ScryptOpts) DeriveKey(password, salt []byte, size int) ( + key []byte, params KDFParameters, err error) { + + key, err = scrypt.Key(password, salt, p.CostParameter, p.BlockSize, + p.ParallelizationParameter, size) + if err != nil { + return nil, nil, err + } + params = scryptParams{ + BlockSize: p.BlockSize, + CostParameter: p.CostParameter, + ParallelizationParameter: p.ParallelizationParameter, + Salt: salt, + } + return key, params, nil +} + +func (p ScryptOpts) GetSaltSize() int { + return p.SaltSize +} + +func (p ScryptOpts) OID() asn1.ObjectIdentifier { + return oidScrypt +} diff --git a/vendor/github.com/youmark/pkcs8/pkcs8.go b/vendor/github.com/youmark/pkcs8/pkcs8.go new file mode 100644 index 00000000000..f27f6275234 --- /dev/null +++ b/vendor/github.com/youmark/pkcs8/pkcs8.go @@ -0,0 +1,309 @@ +// Package pkcs8 implements functions to parse and convert private keys in PKCS#8 format, as defined in RFC5208 and RFC5958 +package pkcs8 + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" +) + +// DefaultOpts are the default options for encrypting a key if none are given. +// The defaults can be changed by the library user. +var DefaultOpts = &Opts{ + Cipher: AES256CBC, + KDFOpts: PBKDF2Opts{ + SaltSize: 8, + IterationCount: 10000, + HMACHash: crypto.SHA256, + }, +} + +// KDFOpts contains options for a key derivation function. +// An implementation of this interface must be specified when encrypting a PKCS#8 key. +type KDFOpts interface { + // DeriveKey derives a key of size bytes from the given password and salt. + // It returns the key and the ASN.1-encodable parameters used. + DeriveKey(password, salt []byte, size int) (key []byte, params KDFParameters, err error) + // GetSaltSize returns the salt size specified. + GetSaltSize() int + // OID returns the OID of the KDF specified. + OID() asn1.ObjectIdentifier +} + +// KDFParameters contains parameters (salt, etc.) for a key deriviation function. +// It must be a ASN.1-decodable structure. +// An implementation of this interface is created when decoding an encrypted PKCS#8 key. +type KDFParameters interface { + // DeriveKey derives a key of size bytes from the given password. + // It uses the salt from the decoded parameters. + DeriveKey(password []byte, size int) (key []byte, err error) +} + +var kdfs = make(map[string]func() KDFParameters) + +// RegisterKDF registers a function that returns a new instance of the given KDF +// parameters. This allows the library to support client-provided KDFs. +func RegisterKDF(oid asn1.ObjectIdentifier, params func() KDFParameters) { + kdfs[oid.String()] = params +} + +// Cipher represents a cipher for encrypting the key material. +type Cipher interface { + // IVSize returns the IV size of the cipher, in bytes. + IVSize() int + // KeySize returns the key size of the cipher, in bytes. + KeySize() int + // Encrypt encrypts the key material. + Encrypt(key, iv, plaintext []byte) ([]byte, error) + // Decrypt decrypts the key material. + Decrypt(key, iv, ciphertext []byte) ([]byte, error) + // OID returns the OID of the cipher specified. + OID() asn1.ObjectIdentifier +} + +var ciphers = make(map[string]func() Cipher) + +// RegisterCipher registers a function that returns a new instance of the given +// cipher. This allows the library to support client-provided ciphers. +func RegisterCipher(oid asn1.ObjectIdentifier, cipher func() Cipher) { + ciphers[oid.String()] = cipher +} + +// Opts contains options for encrypting a PKCS#8 key. +type Opts struct { + Cipher Cipher + KDFOpts KDFOpts +} + +// Unecrypted PKCS8 +var ( + oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} +) + +type encryptedPrivateKeyInfo struct { + EncryptionAlgorithm pkix.AlgorithmIdentifier + EncryptedData []byte +} + +type pbes2Params struct { + KeyDerivationFunc pkix.AlgorithmIdentifier + EncryptionScheme pkix.AlgorithmIdentifier +} + +type privateKeyInfo struct { + Version int + PrivateKeyAlgorithm pkix.AlgorithmIdentifier + PrivateKey []byte +} + +func parseKeyDerivationFunc(keyDerivationFunc pkix.AlgorithmIdentifier) (KDFParameters, error) { + oid := keyDerivationFunc.Algorithm.String() + newParams, ok := kdfs[oid] + if !ok { + return nil, fmt.Errorf("pkcs8: unsupported KDF (OID: %s)", oid) + } + params := newParams() + _, err := asn1.Unmarshal(keyDerivationFunc.Parameters.FullBytes, params) + if err != nil { + return nil, errors.New("pkcs8: invalid KDF parameters") + } + return params, nil +} + +func parseEncryptionScheme(encryptionScheme pkix.AlgorithmIdentifier) (Cipher, []byte, error) { + oid := encryptionScheme.Algorithm.String() + newCipher, ok := ciphers[oid] + if !ok { + return nil, nil, fmt.Errorf("pkcs8: unsupported cipher (OID: %s)", oid) + } + cipher := newCipher() + var iv []byte + if _, err := asn1.Unmarshal(encryptionScheme.Parameters.FullBytes, &iv); err != nil { + return nil, nil, errors.New("pkcs8: invalid cipher parameters") + } + return cipher, iv, nil +} + +// ParsePrivateKey parses a DER-encoded PKCS#8 private key. +// Password can be nil. +// This is equivalent to ParsePKCS8PrivateKey. +func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, error) { + // No password provided, assume the private key is unencrypted + if len(password) == 0 { + privateKey, err := x509.ParsePKCS8PrivateKey(der) + return privateKey, nil, err + } + + // Use the password provided to decrypt the private key + var privKey encryptedPrivateKeyInfo + if _, err := asn1.Unmarshal(der, &privKey); err != nil { + return nil, nil, errors.New("pkcs8: only PKCS #5 v2.0 supported") + } + + if !privKey.EncryptionAlgorithm.Algorithm.Equal(oidPBES2) { + return nil, nil, errors.New("pkcs8: only PBES2 supported") + } + + var params pbes2Params + if _, err := asn1.Unmarshal(privKey.EncryptionAlgorithm.Parameters.FullBytes, ¶ms); err != nil { + return nil, nil, errors.New("pkcs8: invalid PBES2 parameters") + } + + cipher, iv, err := parseEncryptionScheme(params.EncryptionScheme) + if err != nil { + return nil, nil, err + } + + kdfParams, err := parseKeyDerivationFunc(params.KeyDerivationFunc) + if err != nil { + return nil, nil, err + } + + keySize := cipher.KeySize() + symkey, err := kdfParams.DeriveKey(password, keySize) + if err != nil { + return nil, nil, err + } + + encryptedKey := privKey.EncryptedData + decryptedKey, err := cipher.Decrypt(symkey, iv, encryptedKey) + if err != nil { + return nil, nil, err + } + + key, err := x509.ParsePKCS8PrivateKey(decryptedKey) + if err != nil { + return nil, nil, errors.New("pkcs8: incorrect password") + } + return key, kdfParams, nil +} + +// MarshalPrivateKey encodes a private key into DER-encoded PKCS#8 with the given options. +// Password can be nil. +func MarshalPrivateKey(priv interface{}, password []byte, opts *Opts) ([]byte, error) { + if len(password) == 0 { + return x509.MarshalPKCS8PrivateKey(priv) + } + + if opts == nil { + opts = DefaultOpts + } + + // Convert private key into PKCS8 format + pkey, err := x509.MarshalPKCS8PrivateKey(priv) + if err != nil { + return nil, err + } + + encAlg := opts.Cipher + salt := make([]byte, opts.KDFOpts.GetSaltSize()) + _, err = rand.Read(salt) + if err != nil { + return nil, err + } + iv := make([]byte, encAlg.IVSize()) + _, err = rand.Read(iv) + if err != nil { + return nil, err + } + key, kdfParams, err := opts.KDFOpts.DeriveKey(password, salt, encAlg.KeySize()) + if err != nil { + return nil, err + } + + encryptedKey, err := encAlg.Encrypt(key, iv, pkey) + if err != nil { + return nil, err + } + + marshalledParams, err := asn1.Marshal(kdfParams) + if err != nil { + return nil, err + } + keyDerivationFunc := pkix.AlgorithmIdentifier{ + Algorithm: opts.KDFOpts.OID(), + Parameters: asn1.RawValue{FullBytes: marshalledParams}, + } + marshalledIV, err := asn1.Marshal(iv) + if err != nil { + return nil, err + } + encryptionScheme := pkix.AlgorithmIdentifier{ + Algorithm: encAlg.OID(), + Parameters: asn1.RawValue{FullBytes: marshalledIV}, + } + + encryptionAlgorithmParams := pbes2Params{ + EncryptionScheme: encryptionScheme, + KeyDerivationFunc: keyDerivationFunc, + } + marshalledEncryptionAlgorithmParams, err := asn1.Marshal(encryptionAlgorithmParams) + if err != nil { + return nil, err + } + encryptionAlgorithm := pkix.AlgorithmIdentifier{ + Algorithm: oidPBES2, + Parameters: asn1.RawValue{FullBytes: marshalledEncryptionAlgorithmParams}, + } + + encryptedPkey := encryptedPrivateKeyInfo{ + EncryptionAlgorithm: encryptionAlgorithm, + EncryptedData: encryptedKey, + } + + return asn1.Marshal(encryptedPkey) +} + +// ParsePKCS8PrivateKey parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. +func ParsePKCS8PrivateKey(der []byte, v ...[]byte) (interface{}, error) { + var password []byte + if len(v) > 0 { + password = v[0] + } + privateKey, _, err := ParsePrivateKey(der, password) + return privateKey, err +} + +// ParsePKCS8PrivateKeyRSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. +func ParsePKCS8PrivateKeyRSA(der []byte, v ...[]byte) (*rsa.PrivateKey, error) { + key, err := ParsePKCS8PrivateKey(der, v...) + if err != nil { + return nil, err + } + typedKey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("key block is not of type RSA") + } + return typedKey, nil +} + +// ParsePKCS8PrivateKeyECDSA parses encrypted/unencrypted private keys in PKCS#8 format. To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter. +func ParsePKCS8PrivateKeyECDSA(der []byte, v ...[]byte) (*ecdsa.PrivateKey, error) { + key, err := ParsePKCS8PrivateKey(der, v...) + if err != nil { + return nil, err + } + typedKey, ok := key.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("key block is not of type ECDSA") + } + return typedKey, nil +} + +// ConvertPrivateKeyToPKCS8 converts the private key into PKCS#8 format. +// To encrypt the private key, the password of []byte type should be provided as the second parameter. +// +// The only supported key types are RSA and ECDSA (*rsa.PrivateKey or *ecdsa.PrivateKey for priv) +func ConvertPrivateKeyToPKCS8(priv interface{}, v ...[]byte) ([]byte, error) { + var password []byte + if len(v) > 0 { + password = v[0] + } + return MarshalPrivateKey(priv, password, nil) +} diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go new file mode 100644 index 00000000000..b332122033b --- /dev/null +++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -0,0 +1,30 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package pbkdf2 implements the key derivation function PBKDF2 as defined in +// RFC 8018 (PKCS #5 v2.1). +// +// This package is a wrapper for the PBKDF2 implementation in the +// [crypto/pbkdf2] package. It is [frozen] and is not accepting new features. +// +// [frozen]: https://go.dev/wiki/Frozen +package pbkdf2 + +import ( + "crypto/pbkdf2" + "hash" +) + +// Key derives a key from the password, salt and iteration count, returning a +// []byte of length keylen that can be used as cryptographic key. The key is +// derived based on the method described as PBKDF2 with the HMAC variant using +// the supplied hash function. +func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { + out, err := pbkdf2.Key(h, string(password), salt, iter, keyLen) + if err != nil { + // FIPS 140 enforcement, or an invalid key length. + panic(err) + } + return out +} diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go new file mode 100644 index 00000000000..b422b7d7fd8 --- /dev/null +++ b/vendor/golang.org/x/crypto/scrypt/scrypt.go @@ -0,0 +1,215 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package scrypt implements the scrypt key derivation function as defined in +// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard +// Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf). +package scrypt + +import ( + "crypto/sha256" + "encoding/binary" + "errors" + "math/bits" + + "golang.org/x/crypto/pbkdf2" +) + +const maxInt = int(^uint(0) >> 1) + +// blockCopy copies n numbers from src into dst. +func blockCopy(dst, src []uint32, n int) { + copy(dst, src[:n]) +} + +// blockXOR XORs numbers from dst with n numbers from src. +func blockXOR(dst, src []uint32, n int) { + for i, v := range src[:n] { + dst[i] ^= v + } +} + +// salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in, +// and puts the result into both tmp and out. +func salsaXOR(tmp *[16]uint32, in, out []uint32) { + w0 := tmp[0] ^ in[0] + w1 := tmp[1] ^ in[1] + w2 := tmp[2] ^ in[2] + w3 := tmp[3] ^ in[3] + w4 := tmp[4] ^ in[4] + w5 := tmp[5] ^ in[5] + w6 := tmp[6] ^ in[6] + w7 := tmp[7] ^ in[7] + w8 := tmp[8] ^ in[8] + w9 := tmp[9] ^ in[9] + w10 := tmp[10] ^ in[10] + w11 := tmp[11] ^ in[11] + w12 := tmp[12] ^ in[12] + w13 := tmp[13] ^ in[13] + w14 := tmp[14] ^ in[14] + w15 := tmp[15] ^ in[15] + + x0, x1, x2, x3, x4, x5, x6, x7, x8 := w0, w1, w2, w3, w4, w5, w6, w7, w8 + x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15 + + for i := 0; i < 8; i += 2 { + x4 ^= bits.RotateLeft32(x0+x12, 7) + x8 ^= bits.RotateLeft32(x4+x0, 9) + x12 ^= bits.RotateLeft32(x8+x4, 13) + x0 ^= bits.RotateLeft32(x12+x8, 18) + + x9 ^= bits.RotateLeft32(x5+x1, 7) + x13 ^= bits.RotateLeft32(x9+x5, 9) + x1 ^= bits.RotateLeft32(x13+x9, 13) + x5 ^= bits.RotateLeft32(x1+x13, 18) + + x14 ^= bits.RotateLeft32(x10+x6, 7) + x2 ^= bits.RotateLeft32(x14+x10, 9) + x6 ^= bits.RotateLeft32(x2+x14, 13) + x10 ^= bits.RotateLeft32(x6+x2, 18) + + x3 ^= bits.RotateLeft32(x15+x11, 7) + x7 ^= bits.RotateLeft32(x3+x15, 9) + x11 ^= bits.RotateLeft32(x7+x3, 13) + x15 ^= bits.RotateLeft32(x11+x7, 18) + + x1 ^= bits.RotateLeft32(x0+x3, 7) + x2 ^= bits.RotateLeft32(x1+x0, 9) + x3 ^= bits.RotateLeft32(x2+x1, 13) + x0 ^= bits.RotateLeft32(x3+x2, 18) + + x6 ^= bits.RotateLeft32(x5+x4, 7) + x7 ^= bits.RotateLeft32(x6+x5, 9) + x4 ^= bits.RotateLeft32(x7+x6, 13) + x5 ^= bits.RotateLeft32(x4+x7, 18) + + x11 ^= bits.RotateLeft32(x10+x9, 7) + x8 ^= bits.RotateLeft32(x11+x10, 9) + x9 ^= bits.RotateLeft32(x8+x11, 13) + x10 ^= bits.RotateLeft32(x9+x8, 18) + + x12 ^= bits.RotateLeft32(x15+x14, 7) + x13 ^= bits.RotateLeft32(x12+x15, 9) + x14 ^= bits.RotateLeft32(x13+x12, 13) + x15 ^= bits.RotateLeft32(x14+x13, 18) + } + x0 += w0 + x1 += w1 + x2 += w2 + x3 += w3 + x4 += w4 + x5 += w5 + x6 += w6 + x7 += w7 + x8 += w8 + x9 += w9 + x10 += w10 + x11 += w11 + x12 += w12 + x13 += w13 + x14 += w14 + x15 += w15 + + out[0], tmp[0] = x0, x0 + out[1], tmp[1] = x1, x1 + out[2], tmp[2] = x2, x2 + out[3], tmp[3] = x3, x3 + out[4], tmp[4] = x4, x4 + out[5], tmp[5] = x5, x5 + out[6], tmp[6] = x6, x6 + out[7], tmp[7] = x7, x7 + out[8], tmp[8] = x8, x8 + out[9], tmp[9] = x9, x9 + out[10], tmp[10] = x10, x10 + out[11], tmp[11] = x11, x11 + out[12], tmp[12] = x12, x12 + out[13], tmp[13] = x13, x13 + out[14], tmp[14] = x14, x14 + out[15], tmp[15] = x15, x15 +} + +func blockMix(tmp *[16]uint32, in, out []uint32, r int) { + blockCopy(tmp[:], in[(2*r-1)*16:], 16) + for i := 0; i < 2*r; i += 2 { + salsaXOR(tmp, in[i*16:], out[i*8:]) + salsaXOR(tmp, in[i*16+16:], out[i*8+r*16:]) + } +} + +func integer(b []uint32, r int) uint64 { + j := (2*r - 1) * 16 + return uint64(b[j]) | uint64(b[j+1])<<32 +} + +func smix(b []byte, r, N int, v, xy []uint32) { + var tmp [16]uint32 + R := 32 * r + x := xy + y := xy[R:] + + j := 0 + for i := 0; i < R; i++ { + x[i] = binary.LittleEndian.Uint32(b[j:]) + j += 4 + } + for i := 0; i < N; i += 2 { + blockCopy(v[i*R:], x, R) + blockMix(&tmp, x, y, r) + + blockCopy(v[(i+1)*R:], y, R) + blockMix(&tmp, y, x, r) + } + for i := 0; i < N; i += 2 { + j := int(integer(x, r) & uint64(N-1)) + blockXOR(x, v[j*R:], R) + blockMix(&tmp, x, y, r) + + j = int(integer(y, r) & uint64(N-1)) + blockXOR(y, v[j*R:], R) + blockMix(&tmp, y, x, r) + } + j = 0 + for _, v := range x[:R] { + binary.LittleEndian.PutUint32(b[j:], v) + j += 4 + } +} + +// Key derives a key from the password, salt, and cost parameters, returning +// a byte slice of length keyLen that can be used as cryptographic key. +// +// N is a CPU/memory cost parameter, which must be a power of two greater than 1. +// r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the +// limits, the function returns a nil byte slice and an error. +// +// For example, you can get a derived key for e.g. AES-256 (which needs a +// 32-byte key) by doing: +// +// dk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) +// +// The recommended parameters for interactive logins as of 2017 are N=32768, r=8 +// and p=1. The parameters N, r, and p should be increased as memory latency and +// CPU parallelism increases; consider setting N to the highest power of 2 you +// can derive within 100 milliseconds. Remember to get a good random salt. +func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) { + if N <= 1 || N&(N-1) != 0 { + return nil, errors.New("scrypt: N must be > 1 and a power of 2") + } + if r <= 0 || p <= 0 { + return nil, errors.New("scrypt: parameters must be > 0") + } + if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r { + return nil, errors.New("scrypt: parameters are too large") + } + + xy := make([]uint32, 64*r) + v := make([]uint32, 32*N*r) + b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New) + + for i := 0; i < p; i++ { + smix(b[i*128*r:], r, N, v, xy) + } + + return pbkdf2.Key(password, b, 1, keyLen, sha256.New), nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 7fa03a7cdb1..56aa304aabb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -135,7 +135,7 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp # github.com/Masterminds/squirrel v1.5.4 ## explicit; go 1.14 github.com/Masterminds/squirrel -# github.com/VictoriaMetrics/easyproto v0.1.4 +# github.com/VictoriaMetrics/easyproto v1.1.3 ## explicit; go 1.18 github.com/VictoriaMetrics/easyproto # github.com/VictoriaMetrics/fastcache v1.13.3 @@ -158,6 +158,9 @@ github.com/alicebob/miniredis/v2/metro github.com/alicebob/miniredis/v2/proto github.com/alicebob/miniredis/v2/server github.com/alicebob/miniredis/v2/size +# github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible +## explicit +github.com/aliyun/aliyun-oss-go-sdk/oss # github.com/andybalholm/brotli v1.1.1 ## explicit; go 1.13 github.com/andybalholm/brotli @@ -293,6 +296,17 @@ github.com/aws/smithy-go/waiter # github.com/axiomhq/hyperloglog v0.2.6 ## explicit; go 1.23 github.com/axiomhq/hyperloglog +# github.com/baidubce/bce-sdk-go v0.9.230 +## explicit; go 1.11 +github.com/baidubce/bce-sdk-go/auth +github.com/baidubce/bce-sdk-go/bce +github.com/baidubce/bce-sdk-go/http +github.com/baidubce/bce-sdk-go/services/bos +github.com/baidubce/bce-sdk-go/services/bos/api +github.com/baidubce/bce-sdk-go/services/sts +github.com/baidubce/bce-sdk-go/services/sts/api +github.com/baidubce/bce-sdk-go/util +github.com/baidubce/bce-sdk-go/util/log # github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 ## explicit; go 1.20 github.com/bboreham/go-loser @@ -317,6 +331,9 @@ github.com/cenkalti/backoff/v5 # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 +# github.com/clbanning/mxj v1.8.4 +## explicit +github.com/clbanning/mxj # github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 ## explicit; go 1.24.6 github.com/cncf/xds/go/udpa/annotations @@ -564,6 +581,9 @@ github.com/gobwas/glob/syntax/ast github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings +# github.com/gofrs/flock v0.13.0 +## explicit; go 1.24.0 +github.com/gofrs/flock # github.com/gogo/googleapis v1.4.1 ## explicit; go 1.12 github.com/gogo/googleapis/google/rpc @@ -614,6 +634,9 @@ github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/value +# github.com/google/go-querystring v1.1.0 +## explicit; go 1.10 +github.com/google/go-querystring/query # github.com/google/pprof v0.0.0-20251213031049-b05bdaca462f ## explicit; go 1.24.9 github.com/google/pprof/profile @@ -727,6 +750,9 @@ github.com/hashicorp/memberlist # github.com/hashicorp/serf v0.10.1 ## explicit; go 1.12 github.com/hashicorp/serf/coordinate +# github.com/huaweicloud/huaweicloud-sdk-go-obs v3.25.4+incompatible +## explicit +github.com/huaweicloud/huaweicloud-sdk-go-obs/obs # github.com/jessevdk/go-flags v1.6.1 ## explicit; go 1.20 github.com/jessevdk/go-flags @@ -848,6 +874,9 @@ github.com/mitchellh/go-homedir # github.com/mitchellh/go-wordwrap v1.0.1 ## explicit; go 1.14 github.com/mitchellh/go-wordwrap +# github.com/mitchellh/mapstructure v1.5.0 +## explicit; go 1.14 +github.com/mitchellh/mapstructure # github.com/mitchellh/reflectwalk v1.0.2 ## explicit github.com/mitchellh/reflectwalk @@ -857,6 +886,9 @@ github.com/modern-go/concurrent # github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee ## explicit; go 1.12 github.com/modern-go/reflect2 +# github.com/mozillazg/go-httpheader v0.4.0 +## explicit; go 1.11 +github.com/mozillazg/go-httpheader # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 ## explicit github.com/munnerz/goautoneg @@ -904,6 +936,13 @@ github.com/opentracing/opentracing-go github.com/opentracing/opentracing-go/ext github.com/opentracing/opentracing-go/log github.com/opentracing/opentracing-go/mocktracer +# github.com/oracle/oci-go-sdk/v65 v65.93.1 +## explicit; go 1.13 +github.com/oracle/oci-go-sdk/v65/common +github.com/oracle/oci-go-sdk/v65/common/auth +github.com/oracle/oci-go-sdk/v65/common/utils +github.com/oracle/oci-go-sdk/v65/objectstorage +github.com/oracle/oci-go-sdk/v65/objectstorage/transfer # github.com/parquet-go/bitpack v1.0.0 ## explicit; go 1.24.0 github.com/parquet-go/bitpack @@ -1220,17 +1259,27 @@ github.com/stretchr/testify/assert github.com/stretchr/testify/assert/yaml github.com/stretchr/testify/mock github.com/stretchr/testify/require +# github.com/tencentyun/cos-go-sdk-v5 v0.7.66 +## explicit; go 1.12 +github.com/tencentyun/cos-go-sdk-v5 # github.com/thanos-io/objstore v0.0.0-20250804093838-71d60dfee488 ## explicit; go 1.24.0 github.com/thanos-io/objstore +github.com/thanos-io/objstore/client +github.com/thanos-io/objstore/clientutil github.com/thanos-io/objstore/exthttp github.com/thanos-io/objstore/providers/azure +github.com/thanos-io/objstore/providers/bos +github.com/thanos-io/objstore/providers/cos github.com/thanos-io/objstore/providers/filesystem github.com/thanos-io/objstore/providers/gcs +github.com/thanos-io/objstore/providers/obs +github.com/thanos-io/objstore/providers/oci +github.com/thanos-io/objstore/providers/oss github.com/thanos-io/objstore/providers/s3 github.com/thanos-io/objstore/providers/swift github.com/thanos-io/objstore/tracing/opentracing -# github.com/thanos-io/promql-engine v0.0.0-20260429105430-454f16264be9 +# github.com/thanos-io/promql-engine v0.0.0-20260513095632-c5f6038078e3 ## explicit; go 1.24.0 github.com/thanos-io/promql-engine/api github.com/thanos-io/promql-engine/compute @@ -1255,8 +1304,8 @@ github.com/thanos-io/promql-engine/ringbuffer github.com/thanos-io/promql-engine/storage github.com/thanos-io/promql-engine/storage/prometheus github.com/thanos-io/promql-engine/warnings -# github.com/thanos-io/thanos v0.41.0 -## explicit; go 1.25.0 +# github.com/thanos-io/thanos v0.42.0 +## explicit; go 1.26.0 github.com/thanos-io/thanos/pkg/api/query/querypb github.com/thanos-io/thanos/pkg/block github.com/thanos-io/thanos/pkg/block/indexheader @@ -1292,6 +1341,7 @@ github.com/thanos-io/thanos/pkg/model github.com/thanos-io/thanos/pkg/pool github.com/thanos-io/thanos/pkg/promclient github.com/thanos-io/thanos/pkg/query +github.com/thanos-io/thanos/pkg/query/fanout github.com/thanos-io/thanos/pkg/querysharding github.com/thanos-io/thanos/pkg/rules/rulespb github.com/thanos-io/thanos/pkg/runutil @@ -1394,6 +1444,9 @@ github.com/weaveworks/promrus # github.com/xhit/go-str2duration/v2 v2.1.0 ## explicit; go 1.13 github.com/xhit/go-str2duration/v2 +# github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 +## explicit; go 1.17 +github.com/youmark/pkcs8 # github.com/yuin/gopher-lua v1.1.1 ## explicit; go 1.17 github.com/yuin/gopher-lua @@ -1661,8 +1714,10 @@ golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 +golang.org/x/crypto/pbkdf2 golang.org/x/crypto/pkcs12 golang.org/x/crypto/pkcs12/internal/rc2 +golang.org/x/crypto/scrypt # golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa ## explicit; go 1.25.0 golang.org/x/exp/constraints @@ -1789,7 +1844,7 @@ google.golang.org/genproto/googleapis/api/httpbody google.golang.org/genproto/googleapis/api/label google.golang.org/genproto/googleapis/api/metric google.golang.org/genproto/googleapis/api/monitoredres -# google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa +# google.golang.org/genproto/googleapis/rpc v0.0.0-20260615183401-62b3387ff324 ## explicit; go 1.25.0 google.golang.org/genproto/googleapis/rpc/code google.golang.org/genproto/googleapis/rpc/errdetails