From 07719a1cebfa28a345d121a44a9e92bbf78a9945 Mon Sep 17 00:00:00 2001 From: Jason Del Ponte <961963+jasdel@users.noreply.github.com> Date: Thu, 24 Feb 2022 11:49:20 -0800 Subject: [PATCH] Add support for trailing checksum (#1600) Updates the SDK adding support Amazon S3 for trailing checksums computed with the aws-chunked content-encoding format. Adds a new internal service module, `checksum` to the SDK that API models decorated with the `httpChecksum` smithy trail will use. Co-authored-by: skotambkar --- Makefile | 2 + .../sdk-codegen/aws-models/s3.2006-03-01.json | 1520 ++++++++++++++--- .../aws/go/codegen/AwsGoDependency.java | 3 + .../go/codegen/AwsHttpChecksumGenerator.java | 482 ++++++ ...mithy.go.codegen.integration.GoIntegration | 1 + example/service/s3/listObjects/go.mod | 2 + example/service/s3/usingPrivateLink/go.mod | 2 + feature/s3/manager/download.go | 17 +- feature/s3/manager/go.mod | 2 + feature/s3/manager/integ_shared_test.go | 7 +- feature/s3/manager/integ_upload_test.go | 447 ++++- feature/s3/manager/upload.go | 179 +- service/internal/benchmark/go.mod | 2 + service/internal/checksum/LICENSE.txt | 202 +++ service/internal/checksum/algorithms.go | 323 ++++ service/internal/checksum/algorithms_test.go | 470 +++++ .../internal/checksum/aws_chunked_encoding.go | 389 +++++ .../checksum/aws_chunked_encoding_test.go | 507 ++++++ service/internal/checksum/go.mod | 11 + service/internal/checksum/go.sum | 13 + .../internal/checksum/go_module_metadata.go | 6 + service/internal/checksum/middleware_add.go | 185 ++ .../internal/checksum/middleware_add_test.go | 412 +++++ .../middleware_compute_input_checksum.go | 474 +++++ .../middleware_compute_input_checksum_test.go | 889 ++++++++++ .../checksum/middleware_setup_context.go | 117 ++ .../checksum/middleware_setup_context_test.go | 143 ++ .../checksum/middleware_validate_output.go | 126 ++ .../middleware_validate_output_test.go | 213 +++ service/internal/integrationtest/go.mod | 2 + .../integrationtest/s3/checksum_test.go | 491 ++++++ .../integrationtest/s3/presign_test.go | 50 +- service/s3/api_client.go | 48 + service/s3/api_op_AbortMultipartUpload.go | 11 +- service/s3/api_op_CompleteMultipartUpload.go | 107 +- service/s3/api_op_CopyObject.go | 42 +- service/s3/api_op_CreateBucket.go | 4 +- service/s3/api_op_CreateMultipartUpload.go | 26 +- service/s3/api_op_DeleteBucket.go | 3 +- ...i_op_DeleteBucketAnalyticsConfiguration.go | 3 +- service/s3/api_op_DeleteBucketCors.go | 3 +- service/s3/api_op_DeleteBucketEncryption.go | 3 +- ...i_op_DeleteBucketInventoryConfiguration.go | 3 +- service/s3/api_op_DeleteBucketLifecycle.go | 3 +- ...api_op_DeleteBucketMetricsConfiguration.go | 3 +- .../api_op_DeleteBucketOwnershipControls.go | 3 +- service/s3/api_op_DeleteBucketPolicy.go | 3 +- service/s3/api_op_DeleteBucketReplication.go | 3 +- service/s3/api_op_DeleteBucketTagging.go | 3 +- service/s3/api_op_DeleteBucketWebsite.go | 3 +- service/s3/api_op_DeleteObject.go | 13 +- service/s3/api_op_DeleteObjectTagging.go | 7 +- service/s3/api_op_DeleteObjects.go | 53 +- service/s3/api_op_DeletePublicAccessBlock.go | 3 +- ...api_op_GetBucketAccelerateConfiguration.go | 3 +- service/s3/api_op_GetBucketAcl.go | 3 +- .../api_op_GetBucketAnalyticsConfiguration.go | 3 +- service/s3/api_op_GetBucketCors.go | 12 +- service/s3/api_op_GetBucketEncryption.go | 3 +- .../api_op_GetBucketInventoryConfiguration.go | 3 +- .../api_op_GetBucketLifecycleConfiguration.go | 3 +- service/s3/api_op_GetBucketLocation.go | 3 +- service/s3/api_op_GetBucketLogging.go | 3 +- .../api_op_GetBucketMetricsConfiguration.go | 3 +- ...i_op_GetBucketNotificationConfiguration.go | 3 +- .../s3/api_op_GetBucketOwnershipControls.go | 3 +- service/s3/api_op_GetBucketPolicy.go | 3 +- service/s3/api_op_GetBucketPolicyStatus.go | 3 +- service/s3/api_op_GetBucketReplication.go | 3 +- service/s3/api_op_GetBucketRequestPayment.go | 3 +- service/s3/api_op_GetBucketTagging.go | 16 +- service/s3/api_op_GetBucketVersioning.go | 3 +- service/s3/api_op_GetBucketWebsite.go | 3 +- service/s3/api_op_GetObject.go | 98 +- service/s3/api_op_GetObjectAcl.go | 30 +- service/s3/api_op_GetObjectAttributes.go | 363 ++++ service/s3/api_op_GetObjectLegalHold.go | 23 +- .../s3/api_op_GetObjectLockConfiguration.go | 10 +- service/s3/api_op_GetObjectRetention.go | 13 +- service/s3/api_op_GetObjectTagging.go | 25 +- service/s3/api_op_GetObjectTorrent.go | 7 +- service/s3/api_op_GetPublicAccessBlock.go | 3 +- service/s3/api_op_HeadBucket.go | 7 +- service/s3/api_op_HeadObject.go | 84 +- ...pi_op_ListBucketAnalyticsConfigurations.go | 3 +- ...pi_op_ListBucketInventoryConfigurations.go | 3 +- .../api_op_ListBucketMetricsConfigurations.go | 3 +- service/s3/api_op_ListBuckets.go | 3 +- service/s3/api_op_ListMultipartUploads.go | 7 +- service/s3/api_op_ListObjectVersions.go | 3 +- service/s3/api_op_ListObjects.go | 7 +- service/s3/api_op_ListObjectsV2.go | 11 +- service/s3/api_op_ListParts.go | 45 +- ...api_op_PutBucketAccelerateConfiguration.go | 38 +- service/s3/api_op_PutBucketAcl.go | 41 +- .../api_op_PutBucketAnalyticsConfiguration.go | 3 +- service/s3/api_op_PutBucketCors.go | 41 +- service/s3/api_op_PutBucketEncryption.go | 48 +- .../api_op_PutBucketInventoryConfiguration.go | 3 +- .../api_op_PutBucketLifecycleConfiguration.go | 47 +- service/s3/api_op_PutBucketLogging.go | 41 +- .../api_op_PutBucketMetricsConfiguration.go | 3 +- ...i_op_PutBucketNotificationConfiguration.go | 31 +- .../s3/api_op_PutBucketOwnershipControls.go | 20 +- service/s3/api_op_PutBucketPolicy.go | 42 +- service/s3/api_op_PutBucketReplication.go | 41 +- service/s3/api_op_PutBucketRequestPayment.go | 41 +- service/s3/api_op_PutBucketTagging.go | 41 +- service/s3/api_op_PutBucketVersioning.go | 75 +- service/s3/api_op_PutBucketWebsite.go | 41 +- service/s3/api_op_PutObject.go | 112 +- service/s3/api_op_PutObjectAcl.go | 49 +- service/s3/api_op_PutObjectLegalHold.go | 55 +- .../s3/api_op_PutObjectLockConfiguration.go | 45 +- service/s3/api_op_PutObjectRetention.go | 50 +- service/s3/api_op_PutObjectTagging.go | 49 +- service/s3/api_op_PutPublicAccessBlock.go | 41 +- service/s3/api_op_RestoreObject.go | 46 +- service/s3/api_op_SelectObjectContent.go | 27 +- service/s3/api_op_UploadPart.go | 112 +- service/s3/api_op_UploadPartCopy.go | 22 +- service/s3/api_op_WriteGetObjectResponse.go | 64 +- service/s3/deserializers.go | 1258 ++++++++++++-- service/s3/generated.json | 2 + service/s3/go.mod | 3 + .../internal/customizations/presign_test.go | 47 + service/s3/serializers.go | 405 +++++ service/s3/types/enums.go | 64 + service/s3/types/types.go | 259 ++- service/s3/validators.go | 45 + 130 files changed, 11433 insertions(+), 785 deletions(-) create mode 100644 codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsHttpChecksumGenerator.java create mode 100644 service/internal/checksum/LICENSE.txt create mode 100644 service/internal/checksum/algorithms.go create mode 100644 service/internal/checksum/algorithms_test.go create mode 100644 service/internal/checksum/aws_chunked_encoding.go create mode 100644 service/internal/checksum/aws_chunked_encoding_test.go create mode 100644 service/internal/checksum/go.mod create mode 100644 service/internal/checksum/go.sum create mode 100644 service/internal/checksum/go_module_metadata.go create mode 100644 service/internal/checksum/middleware_add.go create mode 100644 service/internal/checksum/middleware_add_test.go create mode 100644 service/internal/checksum/middleware_compute_input_checksum.go create mode 100644 service/internal/checksum/middleware_compute_input_checksum_test.go create mode 100644 service/internal/checksum/middleware_setup_context.go create mode 100644 service/internal/checksum/middleware_setup_context_test.go create mode 100644 service/internal/checksum/middleware_validate_output.go create mode 100644 service/internal/checksum/middleware_validate_output_test.go create mode 100644 service/internal/integrationtest/s3/checksum_test.go create mode 100644 service/s3/api_op_GetObjectAttributes.go diff --git a/Makefile b/Makefile index 17cfb5523c8..b139a334603 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ # Lint rules to ignore LINTIGNORESINGLEFIGHT='internal/sync/singleflight/singleflight.go:.+error should be the last type' +LINT_IGNORE_S3MANAGER_INPUT='feature/s3/manager/upload.go:.+struct field SSEKMSKeyId should be SSEKMSKeyID' UNIT_TEST_TAGS= BUILD_TAGS=-tags "example,codegen,integration,ec2env,perftest" @@ -447,6 +448,7 @@ lint: @echo "go lint SDK and vendor packages" @lint=`golint ./...`; \ dolint=`echo "$$lint" | grep -E -v \ + -e ${LINT_IGNORE_S3MANAGER_INPUT} \ -e ${LINTIGNORESINGLEFIGHT}`; \ echo "$$dolint"; \ if [ "$$dolint" != "" ]; then exit 1; fi diff --git a/codegen/sdk-codegen/aws-models/s3.2006-03-01.json b/codegen/sdk-codegen/aws-models/s3.2006-03-01.json index 5c306b3a61b..8ce0ad3bea0 100644 --- a/codegen/sdk-codegen/aws-models/s3.2006-03-01.json +++ b/codegen/sdk-codegen/aws-models/s3.2006-03-01.json @@ -85,7 +85,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name to which the upload was taking place.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name to which the upload was taking place.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -115,7 +115,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -369,6 +369,9 @@ { "target": "com.amazonaws.s3#GetObjectAcl" }, + { + "target": "com.amazonaws.s3#GetObjectAttributes" + }, { "target": "com.amazonaws.s3#GetObjectLegalHold" }, @@ -1043,7 +1046,7 @@ "QuoteEscapeCharacter": { "target": "com.amazonaws.s3#QuoteEscapeCharacter", "traits": { - "smithy.api#documentation": "

A single character used for escaping the quotation mark character inside an already\n escaped value. For example, the value \"\"\" a , b \"\"\" is parsed as \" a , b \".

" + "smithy.api#documentation": "

A single character used for escaping the quotation mark character inside an already\n escaped value. For example, the value \"\"\" a , b \"\"\" is parsed as \" a , b\n \".

" } }, "RecordDelimiter": { @@ -1116,6 +1119,90 @@ "com.amazonaws.s3#CacheControl": { "type": "string" }, + "com.amazonaws.s3#Checksum": { + "type": "structure", + "members": { + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Contains all the possible checksum or digest values for an object.

" + } + }, + "com.amazonaws.s3#ChecksumAlgorithm": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "value": "CRC32", + "name": "CRC32" + }, + { + "value": "CRC32C", + "name": "CRC32C" + }, + { + "value": "SHA1", + "name": "SHA1" + }, + { + "value": "SHA256", + "name": "SHA256" + } + ] + } + }, + "com.amazonaws.s3#ChecksumAlgorithmList": { + "type": "list", + "member": { + "target": "com.amazonaws.s3#ChecksumAlgorithm" + } + }, + "com.amazonaws.s3#ChecksumCRC32": { + "type": "string" + }, + "com.amazonaws.s3#ChecksumCRC32C": { + "type": "string" + }, + "com.amazonaws.s3#ChecksumMode": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "value": "ENABLED", + "name": "ENABLED" + } + ] + } + }, + "com.amazonaws.s3#ChecksumSHA1": { + "type": "string" + }, + "com.amazonaws.s3#ChecksumSHA256": { + "type": "string" + }, "com.amazonaws.s3#Code": { "type": "string" }, @@ -1171,7 +1258,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket that contains the newly created object. Does not return the access point ARN or access point alias if used.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The name of the bucket that contains the newly created object. Does not return the access point ARN or access point alias if used.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

" } }, "Key": { @@ -1183,14 +1270,38 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the object expiration is configured, this will contain the expiration date\n (expiry-date) and rule ID (rule-id). The value of rule-id is URL encoded.

", + "smithy.api#documentation": "

If the object expiration is configured, this will contain the expiration date\n (expiry-date) and rule ID (rule-id). The value of\n rule-id is URL-encoded.

", "smithy.api#httpHeader": "x-amz-expiration" } }, "ETag": { "target": "com.amazonaws.s3#ETag", "traits": { - "smithy.api#documentation": "

Entity tag that identifies the newly created object's data. Objects with different\n object data will have different entity tags. The entity tag is an opaque string. The entity\n tag may or may not be an MD5 digest of the object data. If the entity tag is not an MD5\n digest of the object data, it will contain one or more nonhexadecimal characters and/or\n will consist of less than 32 or more than 32 hexadecimal digits.

" + "smithy.api#documentation": "

Entity tag that identifies the newly created object's data. Objects with different\n object data will have different entity tags. The entity tag is an opaque string. The entity\n tag may or may not be an MD5 digest of the object data. If the entity tag is not an MD5\n digest of the object data, it will contain one or more nonhexadecimal characters and/or\n will consist of less than 32 or more than 32 hexadecimal digits. For more information about\n how the entity tag is calculated, see\n Checking\n object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ServerSideEncryption": { @@ -1238,7 +1349,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

Name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -1267,6 +1378,34 @@ "smithy.api#required": {} } }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32C checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 160-bit SHA-1 digest of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha256" + } + }, "RequestPayer": { "target": "com.amazonaws.s3#RequestPayer", "traits": { @@ -1276,9 +1415,30 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } + }, + "SSECustomerAlgorithm": { + "target": "com.amazonaws.s3#SSECustomerAlgorithm", + "traits": { + "smithy.api#documentation": "

The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object was created \n using a checksum algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" + } + }, + "SSECustomerKey": { + "target": "com.amazonaws.s3#SSECustomerKey", + "traits": { + "smithy.api#documentation": "

The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm. \n For more information, see\n Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" + } + }, + "SSECustomerKeyMD5": { + "target": "com.amazonaws.s3#SSECustomerKeyMD5", + "traits": { + "smithy.api#documentation": "

The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum \n algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" + } } } }, @@ -1307,6 +1467,30 @@ "smithy.api#documentation": "

Entity tag returned when the part was uploaded.

" } }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { @@ -1408,7 +1592,7 @@ } ], "traits": { - "smithy.api#documentation": "

Creates a copy of an object that is already stored in Amazon S3.

\n \n

You can store individual objects of up to 5 TB in Amazon S3. You create a copy of your\n object up to 5 GB in size in a single atomic action using this API. However, to copy\n an object greater than 5 GB, you must use the multipart upload Upload Part - Copy API.\n For more information, see Copy Object Using the REST Multipart Upload API.

\n
\n

All copy requests must be authenticated. Additionally, you must have\n read access to the source object and write\n access to the destination bucket. For more information, see REST Authentication. Both the Region\n that you want to copy the object from and the Region that you want to copy the object to\n must be enabled for your account.

\n

A copy request might return an error when Amazon S3 receives the copy request or while Amazon S3\n is copying the files. If the error occurs before the copy action starts, you receive a\n standard Amazon S3 error. If the error occurs during the copy operation, the error response is\n embedded in the 200 OK response. This means that a 200 OK\n response can contain either a success or an error. Design your application to parse the\n contents of the response and handle it appropriately.

\n

If the copy is successful, you receive a response with information about the copied\n object.

\n \n

If the request is an HTTP 1.1 request, the response is chunk encoded. If it were not,\n it would not contain the content-length, and you would need to read the entire\n body.

\n
\n

The copy request charge is based on the storage class and Region that you specify for\n the destination object. For pricing information, see Amazon S3 pricing.

\n \n

Amazon S3 transfer acceleration does not support cross-Region copies. If you request a\n cross-Region copy using a transfer acceleration endpoint, you get a 400 Bad\n Request error. For more information, see Transfer Acceleration.

\n
\n

\n Metadata\n

\n

When copying an object, you can preserve all metadata (default) or specify new metadata.\n However, the ACL is not preserved and is set to private for the user making the request. To\n override the default ACL setting, specify a new ACL when generating a copy request. For\n more information, see Using ACLs.

\n

To specify whether you want the object metadata copied from the source object or\n replaced with metadata provided in the request, you can optionally add the\n x-amz-metadata-directive header. When you grant permissions, you can use\n the s3:x-amz-metadata-directive condition key to enforce certain metadata\n behavior when objects are uploaded. For more information, see Specifying Conditions in a\n Policy in the Amazon S3 User Guide. For a complete list of\n Amazon S3-specific condition keys, see Actions, Resources, and Condition Keys for\n Amazon S3.

\n

\n \n x-amz-copy-source-if Headers\n

\n

To only copy an object under certain conditions, such as whether the Etag\n matches or whether the object was modified before or after a specified date, use the\n following request parameters:

\n \n

If both the x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the request\n and evaluate as follows, Amazon S3 returns 200 OK and copies the data:

\n \n\n

If both the x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the request and\n evaluate as follows, Amazon S3 returns the 412 Precondition Failed response\n code:

\n \n\n \n

All headers with the x-amz- prefix, including\n x-amz-copy-source, must be signed.

\n
\n

\n Server-side encryption\n

\n

When you perform a CopyObject operation, you can optionally use the appropriate encryption-related \n headers to encrypt the object using server-side encryption with Amazon Web Services managed encryption keys \n (SSE-S3 or SSE-KMS) or a customer-provided encryption key. With server-side encryption, Amazon S3 \n encrypts your data as it writes it to disks in its data centers and decrypts the data when \n you access it. For more information about server-side encryption, see Using\n Server-Side Encryption.

\n

If a target object uses SSE-KMS, you can enable an S3 Bucket Key for the object. For more\n information, see Amazon S3 Bucket Keys in the Amazon S3 User Guide.

\n

\n Access Control List (ACL)-Specific Request\n Headers\n

\n

When copying an object, you can optionally use headers to grant ACL-based permissions.\n By default, all objects are private. Only the owner has full access control. When adding a\n new object, you can grant permissions to individual Amazon Web Services accounts or to predefined groups\n defined by Amazon S3. These permissions are then added to the ACL on the object. For more\n information, see Access Control List (ACL) Overview and Managing ACLs Using the REST\n API.

\n

If the bucket that you're copying objects to uses the bucket owner enforced setting for\n S3 Object Ownership, ACLs are disabled and no longer affect permissions. Buckets that\n use this setting only accept PUT requests that don't specify an ACL or PUT requests that\n specify bucket owner full control ACLs, such as the bucket-owner-full-control canned\n ACL or an equivalent form of this ACL expressed in the XML format.

\n

For more information, see Controlling ownership of\n objects and disabling ACLs in the Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for Object Ownership, \n all objects written to the bucket by any account will be owned by the bucket owner.

\n
\n

\n Storage Class Options\n

\n

You can use the CopyObject action to change the storage class of an\n object that is already stored in Amazon S3 using the StorageClass parameter. For\n more information, see Storage\n Classes in the Amazon S3 User Guide.

\n

\n Versioning\n

\n

By default, x-amz-copy-source identifies the current version of an object\n to copy. If the current version is a delete marker, Amazon S3 behaves as if the object was\n deleted. To copy a different version, use the versionId subresource.

\n

If you enable versioning on the target bucket, Amazon S3 generates a unique version ID for\n the object being copied. This version ID is different from the version ID of the source\n object. Amazon S3 returns the version ID of the copied object in the\n x-amz-version-id response header in the response.

\n

If you do not enable versioning or suspend it on the target bucket, the version ID that\n Amazon S3 generates is always null.

\n

If the source object's storage class is GLACIER, you must restore a copy of this object\n before you can use it as a source object for the copy operation. For more information, see\n RestoreObject.

\n

The following operations are related to CopyObject:

\n \n

For more information, see Copying\n Objects.

", + "smithy.api#documentation": "

Creates a copy of an object that is already stored in Amazon S3.

\n \n

You can store individual objects of up to 5 TB in Amazon S3. You create a copy of your\n object up to 5 GB in size in a single atomic action using this API. However, to copy an\n object greater than 5 GB, you must use the multipart upload Upload Part - Copy\n (UploadPartCopy) API. For more information, see Copy Object Using the\n REST Multipart Upload API.

\n
\n

All copy requests must be authenticated. Additionally, you must have\n read access to the source object and write\n access to the destination bucket. For more information, see REST Authentication. Both the Region\n that you want to copy the object from and the Region that you want to copy the object to\n must be enabled for your account.

\n

A copy request might return an error when Amazon S3 receives the copy request or while Amazon S3\n is copying the files. If the error occurs before the copy action starts, you receive a\n standard Amazon S3 error. If the error occurs during the copy operation, the error response is\n embedded in the 200 OK response. This means that a 200 OK\n response can contain either a success or an error. Design your application to parse the\n contents of the response and handle it appropriately.

\n

If the copy is successful, you receive a response with information about the copied\n object.

\n \n

If the request is an HTTP 1.1 request, the response is chunk encoded. If it were not,\n it would not contain the content-length, and you would need to read the entire\n body.

\n
\n

The copy request charge is based on the storage class and Region that you specify for\n the destination object. For pricing information, see Amazon S3 pricing.

\n \n

Amazon S3 transfer acceleration does not support cross-Region copies. If you request a\n cross-Region copy using a transfer acceleration endpoint, you get a 400 Bad\n Request error. For more information, see Transfer Acceleration.

\n
\n

\n Metadata\n

\n

When copying an object, you can preserve all metadata (default) or specify new metadata.\n However, the ACL is not preserved and is set to private for the user making the request. To\n override the default ACL setting, specify a new ACL when generating a copy request. For\n more information, see Using ACLs.

\n

To specify whether you want the object metadata copied from the source object or\n replaced with metadata provided in the request, you can optionally add the\n x-amz-metadata-directive header. When you grant permissions, you can use\n the s3:x-amz-metadata-directive condition key to enforce certain metadata\n behavior when objects are uploaded. For more information, see Specifying Conditions in a\n Policy in the Amazon S3 User Guide. For a complete list of\n Amazon S3-specific condition keys, see Actions, Resources, and Condition Keys for\n Amazon S3.

\n

\n x-amz-copy-source-if Headers\n

\n

To only copy an object under certain conditions, such as whether the Etag\n matches or whether the object was modified before or after a specified date, use the\n following request parameters:

\n \n

If both the x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the request\n and evaluate as follows, Amazon S3 returns 200 OK and copies the data:

\n \n\n

If both the x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the request and\n evaluate as follows, Amazon S3 returns the 412 Precondition Failed response\n code:

\n \n\n \n

All headers with the x-amz- prefix, including\n x-amz-copy-source, must be signed.

\n
\n

\n Server-side encryption\n

\n

When you perform a CopyObject operation, you can optionally use the appropriate encryption-related \n headers to encrypt the object using server-side encryption with Amazon Web Services managed encryption keys \n (SSE-S3 or SSE-KMS) or a customer-provided encryption key. With server-side encryption, Amazon S3 \n encrypts your data as it writes it to disks in its data centers and decrypts the data when \n you access it. For more information about server-side encryption, see Using\n Server-Side Encryption.

\n

If a target object uses SSE-KMS, you can enable an S3 Bucket Key for the object. For more\n information, see Amazon S3 Bucket Keys in the Amazon S3 User Guide.

\n

\n Access Control List (ACL)-Specific Request\n Headers\n

\n

When copying an object, you can optionally use headers to grant ACL-based permissions.\n By default, all objects are private. Only the owner has full access control. When adding a\n new object, you can grant permissions to individual Amazon Web Services accounts or to predefined groups\n defined by Amazon S3. These permissions are then added to the ACL on the object. For more\n information, see Access Control List (ACL) Overview and Managing ACLs Using the REST\n API.

\n

If the bucket that you're copying objects to uses the bucket owner enforced setting for\n S3 Object Ownership, ACLs are disabled and no longer affect permissions. Buckets that\n use this setting only accept PUT requests that don't specify an ACL or PUT requests that\n specify bucket owner full control ACLs, such as the bucket-owner-full-control canned\n ACL or an equivalent form of this ACL expressed in the XML format.

\n

For more information, see Controlling ownership of\n objects and disabling ACLs in the Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for Object Ownership, \n all objects written to the bucket by any account will be owned by the bucket owner.

\n
\n

\n Checksums\n

\n

When copying an object, if it has a checksum, that checksum will be copied to the new object\n by default. When you copy the object over, you may optionally specify a different checksum\n algorithm to use with the x-amz-checksum-algorithm header.

\n

\n Storage Class Options\n

\n

You can use the CopyObject action to change the storage class of an\n object that is already stored in Amazon S3 using the StorageClass parameter. For\n more information, see Storage\n Classes in the Amazon S3 User Guide.

\n

\n Versioning\n

\n

By default, x-amz-copy-source identifies the current version of an object\n to copy. If the current version is a delete marker, Amazon S3 behaves as if the object was\n deleted. To copy a different version, use the versionId subresource.

\n

If you enable versioning on the target bucket, Amazon S3 generates a unique version ID for\n the object being copied. This version ID is different from the version ID of the source\n object. Amazon S3 returns the version ID of the copied object in the\n x-amz-version-id response header in the response.

\n

If you do not enable versioning or suspend it on the target bucket, the version ID that\n Amazon S3 generates is always null.

\n

If the source object's storage class is GLACIER, you must restore a copy of this object\n before you can use it as a source object for the copy operation. For more information, see\n RestoreObject.

\n

The following operations are related to CopyObject:

\n \n

For more information, see Copying\n Objects.

", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?x-id=CopyObject", @@ -1510,7 +1694,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the destination bucket.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the destination bucket.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -1522,6 +1706,13 @@ "smithy.api#httpHeader": "Cache-Control" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm you want Amazon S3 to use to create the checksum for the object. For more information, see\n Checking object integrity in\n the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-algorithm" + } + }, "ContentDisposition": { "target": "com.amazonaws.s3#ContentDisposition", "traits": { @@ -1553,7 +1744,7 @@ "CopySource": { "target": "com.amazonaws.s3#CopySource", "traits": { - "smithy.api#documentation": "

Specifies the source object for the copy operation. You specify the value in one of two\n formats, depending on whether you want to access the source object through an access point:

\n \n

To copy a specific version of an object, append ?versionId=\n to the value (for example,\n awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n If you don't specify a version ID, Amazon S3 copies the latest version of the source\n object.

", + "smithy.api#documentation": "

Specifies the source object for the copy operation. You specify the value in one of two\n formats, depending on whether you want to access the source object through an access point:

\n \n

To copy a specific version of an object, append ?versionId=\n to the value (for example,\n awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n If you don't specify a version ID, Amazon S3 copies the latest version of the source\n object.

", "smithy.api#httpHeader": "x-amz-copy-source", "smithy.api#required": {} } @@ -1764,21 +1955,21 @@ "ObjectLockLegalHoldStatus": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Specifies whether you want to apply a Legal Hold to the copied object.

", + "smithy.api#documentation": "

Specifies whether you want to apply a legal hold to the copied object.

", "smithy.api#httpHeader": "x-amz-object-lock-legal-hold" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "ExpectedSourceBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-source-expected-bucket-owner" } } @@ -1798,6 +1989,30 @@ "traits": { "smithy.api#documentation": "

Creation date of the object.

" } + }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } } }, "traits": { @@ -1818,6 +2033,30 @@ "traits": { "smithy.api#documentation": "

Date and time at which the object was uploaded.

" } + }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } } }, "traits": { @@ -1905,7 +2144,7 @@ "Location": { "target": "com.amazonaws.s3#Location", "traits": { - "smithy.api#documentation": "

Specifies the Region where the bucket will be created. If you are creating a bucket on\n the US East (N. Virginia) Region (us-east-1), you do not need to specify the\n location.

", + "smithy.api#documentation": "

A forward slash followed by the name of the bucket.

", "smithy.api#httpHeader": "Location" } } @@ -1996,7 +2235,7 @@ "target": "com.amazonaws.s3#CreateMultipartUploadOutput" }, "traits": { - "smithy.api#documentation": "

This action initiates a multipart upload and returns an upload ID. This upload ID is\n used to associate all of the parts in the specific multipart upload. You specify this\n upload ID in each of your subsequent upload part requests (see UploadPart). You also include this\n upload ID in the final request to either complete or abort the multipart upload\n request.

\n\n

For more information about multipart uploads, see Multipart Upload Overview.

\n\n

If you have configured a lifecycle rule to abort incomplete multipart uploads, the\n upload must complete within the number of days specified in the bucket lifecycle\n configuration. Otherwise, the incomplete multipart upload becomes eligible for an abort\n action and Amazon S3 aborts the multipart upload. For more information, see Aborting\n Incomplete Multipart Uploads Using a Bucket Lifecycle Policy.

\n\n

For information about the permissions required to use the multipart upload API, see\n Multipart Upload and\n Permissions.

\n\n

For request signing, multipart upload is just a series of regular requests. You initiate\n a multipart upload, send one or more requests to upload parts, and then complete the\n multipart upload process. You sign each request individually. There is nothing special\n about signing multipart upload requests. For more information about signing, see Authenticating\n Requests (Amazon Web Services Signature Version 4).

\n\n \n

After you initiate a multipart upload and upload one or more parts, to stop being\n charged for storing the uploaded parts, you must either complete or abort the multipart\n upload. Amazon S3 frees up the space used to store the parts and stop charging you for\n storing them only after you either complete or abort a multipart upload.

\n
\n\n

You can optionally request server-side encryption. For server-side encryption, Amazon S3\n encrypts your data as it writes it to disks in its data centers and decrypts it when you\n access it. You can provide your own encryption key, or use Amazon Web Services KMS keys or Amazon S3-managed encryption keys. If you choose to provide\n your own encryption key, the request headers you provide in UploadPart and UploadPartCopy requests must match the headers you used in the request to\n initiate the upload by using CreateMultipartUpload.

\n

To perform a multipart upload with encryption using an Amazon Web Services KMS key, the requester must\n have permission to the kms:Decrypt and kms:GenerateDataKey*\n actions on the key. These permissions are required because Amazon S3 must decrypt and read data\n from the encrypted file parts before it completes the multipart upload. For more\n information, see Multipart upload API\n and permissions in the Amazon S3 User Guide.

\n\n

If your Identity and Access Management (IAM) user or role is in the same Amazon Web Services account\n as the KMS key, then you must have these permissions on the key policy. If your IAM\n user or role belongs to a different account than the key, then you must have the\n permissions on both the key policy and your IAM user or role.

\n\n\n

For more information, see Protecting\n Data Using Server-Side Encryption.

\n\n
\n
Access Permissions
\n
\n

When copying an object, you can optionally specify the accounts or groups that\n should be granted specific permissions on the new object. There are two ways to\n grant the permissions using the request headers:

\n
    \n
  • \n

    Specify a canned ACL with the x-amz-acl request header. For\n more information, see Canned ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly with the\n x-amz-grant-read, x-amz-grant-read-acp,\n x-amz-grant-write-acp, and\n x-amz-grant-full-control headers. These parameters map to\n the set of permissions that Amazon S3 supports in an ACL. For more information,\n see Access Control List (ACL)\n Overview.

    \n
  • \n
\n

You can use either a canned ACL or specify access permissions explicitly. You\n cannot do both.

\n
\n
Server-Side- Encryption-Specific Request Headers
\n
\n

You can optionally tell Amazon S3 to encrypt data at rest using server-side\n encryption. Server-side encryption is for data encryption at rest. Amazon S3 encrypts\n your data as it writes it to disks in its data centers and decrypts it when you\n access it. The option you use depends on whether you want to use Amazon Web Services managed\n encryption keys or provide your own encryption key.

\n
    \n
  • \n

    Use encryption keys managed by Amazon S3 or customer managed key stored\n in Amazon Web Services Key Management Service (Amazon Web Services KMS) – If you want Amazon Web Services to manage the keys\n used to encrypt data, specify the following headers in the request.

    \n
      \n
    • \n

      x-amz-server-side-encryption

      \n
    • \n
    • \n

      x-amz-server-side-encryption-aws-kms-key-id

      \n
    • \n
    • \n

      x-amz-server-side-encryption-context

      \n
    • \n
    \n \n

    If you specify x-amz-server-side-encryption:aws:kms, but\n don't provide x-amz-server-side-encryption-aws-kms-key-id,\n Amazon S3 uses the Amazon Web Services managed key in Amazon Web Services KMS to protect the data.

    \n
    \n \n

    All GET and PUT requests for an object protected by Amazon Web Services KMS fail if\n you don't make them with SSL or by using SigV4.

    \n
    \n

    For more information about server-side encryption with KMS key (SSE-KMS),\n see Protecting Data Using Server-Side Encryption with KMS keys.

    \n
  • \n
  • \n

    Use customer-provided encryption keys – If you want to manage your own\n encryption keys, provide all the following headers in the request.

    \n
      \n
    • \n

      x-amz-server-side-encryption-customer-algorithm

      \n
    • \n
    • \n

      x-amz-server-side-encryption-customer-key

      \n
    • \n
    • \n

      x-amz-server-side-encryption-customer-key-MD5

      \n
    • \n
    \n

    For more information about server-side encryption with KMS keys (SSE-KMS),\n see Protecting Data Using Server-Side Encryption with KMS keys.

    \n
  • \n
\n
\n
Access-Control-List (ACL)-Specific Request Headers
\n
\n

You also can use the following access control–related headers with this\n operation. By default, all objects are private. Only the owner has full access\n control. When adding a new object, you can grant permissions to individual Amazon Web Services accounts or to predefined groups defined by Amazon S3. These permissions are then added\n to the access control list (ACL) on the object. For more information, see Using ACLs. With this\n operation, you can grant access permissions using one of the following two\n methods:

\n
    \n
  • \n

    Specify a canned ACL (x-amz-acl) — Amazon S3 supports a set of\n predefined ACLs, known as canned ACLs. Each canned ACL\n has a predefined set of grantees and permissions. For more information, see\n Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly — To explicitly grant access\n permissions to specific Amazon Web Services accounts or groups, use the following headers.\n Each header maps to specific permissions that Amazon S3 supports in an ACL. For\n more information, see Access\n Control List (ACL) Overview. In the header, you specify a list of\n grantees who get the specific permission. To grant permissions explicitly,\n use:

    \n
      \n
    • \n

      x-amz-grant-read

      \n
    • \n
    • \n

      x-amz-grant-write

      \n
    • \n
    • \n

      x-amz-grant-read-acp

      \n
    • \n
    • \n

      x-amz-grant-write-acp

      \n
    • \n
    • \n

      x-amz-grant-full-control

      \n
    • \n
    \n

    You specify each grantee as a type=value pair, where the type is one of\n the following:

    \n
      \n
    • \n

      \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

      \n
    • \n
    • \n

      \n uri – if you are granting permissions to a predefined\n group

      \n
    • \n
    • \n

      \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

      \n \n

      Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

      \n
        \n
      • \n

        US East (N. Virginia)

        \n
      • \n
      • \n

        US West (N. California)

        \n
      • \n
      • \n

        US West (Oregon)

        \n
      • \n
      • \n

        Asia Pacific (Singapore)

        \n
      • \n
      • \n

        Asia Pacific (Sydney)

        \n
      • \n
      • \n

        Asia Pacific (Tokyo)

        \n
      • \n
      • \n

        Europe (Ireland)

        \n
      • \n
      • \n

        South America (São Paulo)

        \n
      • \n
      \n

      For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

      \n
      \n
    • \n
    \n

    For example, the following x-amz-grant-read header grants the Amazon Web Services accounts identified by account IDs permissions to read object data and its metadata:

    \n

    \n x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" \n

    \n
  • \n
\n\n
\n
\n\n

The following operations are related to CreateMultipartUpload:

\n ", + "smithy.api#documentation": "

This action initiates a multipart upload and returns an upload ID. This upload ID is\n used to associate all of the parts in the specific multipart upload. You specify this\n upload ID in each of your subsequent upload part requests (see UploadPart). You also include this\n upload ID in the final request to either complete or abort the multipart upload\n request.

\n\n

For more information about multipart uploads, see Multipart Upload Overview.

\n\n

If you have configured a lifecycle rule to abort incomplete multipart uploads, the\n upload must complete within the number of days specified in the bucket lifecycle\n configuration. Otherwise, the incomplete multipart upload becomes eligible for an abort\n action and Amazon S3 aborts the multipart upload. For more information, see Aborting\n Incomplete Multipart Uploads Using a Bucket Lifecycle Policy.

\n\n

For information about the permissions required to use the multipart upload API, see\n Multipart Upload and\n Permissions.

\n\n

For request signing, multipart upload is just a series of regular requests. You initiate\n a multipart upload, send one or more requests to upload parts, and then complete the\n multipart upload process. You sign each request individually. There is nothing special\n about signing multipart upload requests. For more information about signing, see Authenticating\n Requests (Amazon Web Services Signature Version 4).

\n\n \n

After you initiate a multipart upload and upload one or more parts, to stop being\n charged for storing the uploaded parts, you must either complete or abort the multipart\n upload. Amazon S3 frees up the space used to store the parts and stop charging you for\n storing them only after you either complete or abort a multipart upload.

\n
\n\n

You can optionally request server-side encryption. For server-side encryption, Amazon S3\n encrypts your data as it writes it to disks in its data centers and decrypts it when you\n access it. You can provide your own encryption key, or use Amazon Web Services KMS keys or Amazon S3-managed encryption keys. If you choose to provide\n your own encryption key, the request headers you provide in UploadPart and UploadPartCopy requests must match the headers you used in the request to\n initiate the upload by using CreateMultipartUpload.

\n

To perform a multipart upload with encryption using an Amazon Web Services KMS key, the requester must\n have permission to the kms:Decrypt and kms:GenerateDataKey*\n actions on the key. These permissions are required because Amazon S3 must decrypt and read data\n from the encrypted file parts before it completes the multipart upload. For more\n information, see Multipart upload API\n and permissions in the Amazon S3 User Guide.

\n\n

If your Identity and Access Management (IAM) user or role is in the same Amazon Web Services account\n as the KMS key, then you must have these permissions on the key policy. If your IAM\n user or role belongs to a different account than the key, then you must have the\n permissions on both the key policy and your IAM user or role.

\n\n\n

For more information, see Protecting\n Data Using Server-Side Encryption.

\n\n
\n
Access Permissions
\n
\n

When copying an object, you can optionally specify the accounts or groups that\n should be granted specific permissions on the new object. There are two ways to\n grant the permissions using the request headers:

\n
    \n
  • \n

    Specify a canned ACL with the x-amz-acl request header. For\n more information, see Canned ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly with the\n x-amz-grant-read, x-amz-grant-read-acp,\n x-amz-grant-write-acp, and\n x-amz-grant-full-control headers. These parameters map to\n the set of permissions that Amazon S3 supports in an ACL. For more information,\n see Access Control List (ACL)\n Overview.

    \n
  • \n
\n

You can use either a canned ACL or specify access permissions explicitly. You\n cannot do both.

\n
\n
Server-Side- Encryption-Specific Request Headers
\n
\n

You can optionally tell Amazon S3 to encrypt data at rest using server-side\n encryption. Server-side encryption is for data encryption at rest. Amazon S3 encrypts\n your data as it writes it to disks in its data centers and decrypts it when you\n access it. The option you use depends on whether you want to use Amazon Web Services managed\n encryption keys or provide your own encryption key.

\n
    \n
  • \n

    Use encryption keys managed by Amazon S3 or customer managed key stored\n in Amazon Web Services Key Management Service (Amazon Web Services KMS) – If you want Amazon Web Services to manage the keys\n used to encrypt data, specify the following headers in the request.

    \n
      \n
    • \n

      \n x-amz-server-side-encryption\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-aws-kms-key-id\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-context\n

      \n
    • \n
    \n \n

    If you specify x-amz-server-side-encryption:aws:kms, but\n don't provide x-amz-server-side-encryption-aws-kms-key-id,\n Amazon S3 uses the Amazon Web Services managed key in Amazon Web Services KMS to protect the data.

    \n
    \n \n

    All GET and PUT requests for an object protected by Amazon Web Services KMS fail if\n you don't make them with SSL or by using SigV4.

    \n
    \n

    For more information about server-side encryption with KMS key (SSE-KMS),\n see Protecting Data Using Server-Side Encryption with KMS keys.

    \n
  • \n
  • \n

    Use customer-provided encryption keys – If you want to manage your own\n encryption keys, provide all the following headers in the request.

    \n
      \n
    • \n

      \n x-amz-server-side-encryption-customer-algorithm\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-customer-key\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-customer-key-MD5\n

      \n
    • \n
    \n

    For more information about server-side encryption with KMS keys (SSE-KMS),\n see Protecting Data Using Server-Side Encryption with KMS keys.

    \n
  • \n
\n
\n
Access-Control-List (ACL)-Specific Request Headers
\n
\n

You also can use the following access control–related headers with this\n operation. By default, all objects are private. Only the owner has full access\n control. When adding a new object, you can grant permissions to individual Amazon Web Services accounts or to predefined groups defined by Amazon S3. These permissions are then added\n to the access control list (ACL) on the object. For more information, see Using ACLs. With this\n operation, you can grant access permissions using one of the following two\n methods:

\n
    \n
  • \n

    Specify a canned ACL (x-amz-acl) — Amazon S3 supports a set of\n predefined ACLs, known as canned ACLs. Each canned ACL\n has a predefined set of grantees and permissions. For more information, see\n Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly — To explicitly grant access\n permissions to specific Amazon Web Services accounts or groups, use the following headers.\n Each header maps to specific permissions that Amazon S3 supports in an ACL. For\n more information, see Access\n Control List (ACL) Overview. In the header, you specify a list of\n grantees who get the specific permission. To grant permissions explicitly,\n use:

    \n
      \n
    • \n

      \n x-amz-grant-read\n

      \n
    • \n
    • \n

      \n x-amz-grant-write\n

      \n
    • \n
    • \n

      \n x-amz-grant-read-acp\n

      \n
    • \n
    • \n

      \n x-amz-grant-write-acp\n

      \n
    • \n
    • \n

      \n x-amz-grant-full-control\n

      \n
    • \n
    \n

    You specify each grantee as a type=value pair, where the type is one of\n the following:

    \n
      \n
    • \n

      \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

      \n
    • \n
    • \n

      \n uri – if you are granting permissions to a predefined\n group

      \n
    • \n
    • \n

      \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

      \n \n

      Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

      \n
        \n
      • \n

        US East (N. Virginia)

        \n
      • \n
      • \n

        US West (N. California)

        \n
      • \n
      • \n

        US West (Oregon)

        \n
      • \n
      • \n

        Asia Pacific (Singapore)

        \n
      • \n
      • \n

        Asia Pacific (Sydney)

        \n
      • \n
      • \n

        Asia Pacific (Tokyo)

        \n
      • \n
      • \n

        Europe (Ireland)

        \n
      • \n
      • \n

        South America (São Paulo)

        \n
      • \n
      \n

      For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

      \n
      \n
    • \n
    \n

    For example, the following x-amz-grant-read header grants the Amazon Web Services accounts identified by account IDs permissions to read object data and its metadata:

    \n

    \n x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" \n

    \n
  • \n
\n\n
\n
\n\n

The following operations are related to CreateMultipartUpload:

\n ", "smithy.api#http": { "method": "POST", "uri": "/{Bucket}/{Key+}?uploads&x-id=CreateMultipartUpload", @@ -2024,7 +2263,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated. Does not return the access point ARN or access point alias if used.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated. Does not return the access point ARN or access point alias if used.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#xmlName": "Bucket" } }, @@ -2087,6 +2326,13 @@ "traits": { "smithy.api#httpHeader": "x-amz-request-charged" } + }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

The algorithm that was used to create a checksum of the object.

", + "smithy.api#httpHeader": "x-amz-checksum-algorithm" + } } }, "traits": { @@ -2106,7 +2352,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which to initiate the upload

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which to initiate the upload

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -2289,16 +2535,23 @@ "ObjectLockLegalHoldStatus": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Specifies whether you want to apply a Legal Hold to the uploaded object.

", + "smithy.api#documentation": "

Specifies whether you want to apply a legal hold to the uploaded object.

", "smithy.api#httpHeader": "x-amz-object-lock-legal-hold" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } + }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm you want Amazon S3 to use to create the checksum for the object. For more information, see\n Checking object integrity in\n the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-algorithm" + } } } }, @@ -2416,7 +2669,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2450,7 +2703,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2484,7 +2737,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2561,7 +2814,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2595,7 +2848,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2637,7 +2890,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2671,7 +2924,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2705,7 +2958,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2739,7 +2992,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2759,7 +3012,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2793,7 +3046,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2827,7 +3080,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -2960,7 +3213,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name of the bucket containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name of the bucket containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -2996,14 +3249,14 @@ "BypassGovernanceRetention": { "target": "com.amazonaws.s3#BypassGovernanceRetention", "traits": { - "smithy.api#documentation": "

Indicates whether S3 Object Lock should bypass Governance-mode restrictions to process\n this operation. To use this header, you must have the s3:PutBucketPublicAccessBlock\n permission.

", + "smithy.api#documentation": "

Indicates whether S3 Object Lock should bypass Governance-mode restrictions to process\n this operation. To use this header, you must have the s3:BypassGovernanceRetention\n permission.

", "smithy.api#httpHeader": "x-amz-bypass-governance-retention" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -3044,7 +3297,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the objects from which to remove the tags.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the objects from which to remove the tags.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -3067,7 +3320,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -3082,13 +3335,16 @@ "target": "com.amazonaws.s3#DeleteObjectsOutput" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

This action enables you to delete multiple objects from a bucket using a single HTTP\n request. If you know the object keys that you want to delete, then this action provides\n a suitable alternative to sending individual delete requests, reducing per-request\n overhead.

\n\n

The request contains a list of up to 1000 keys that you want to delete. In the XML, you\n provide the object key names, and optionally, version IDs if you want to delete a specific\n version of the object from a versioning-enabled bucket. For each key, Amazon S3 performs a\n delete action and returns the result of that delete, success, or failure, in the\n response. Note that if the object specified in the request is not found, Amazon S3 returns the\n result as deleted.

\n\n

The action supports two modes for the response: verbose and quiet. By default, the\n action uses verbose mode in which the response includes the result of deletion of each\n key in your request. In quiet mode the response includes only keys where the delete\n action encountered an error. For a successful deletion, the action does not return\n any information about the delete in the response body.

\n\n

When performing this action on an MFA Delete enabled bucket, that attempts to delete\n any versioned objects, you must include an MFA token. If you do not provide one, the entire\n request will fail, even if there are non-versioned objects you are trying to delete. If you\n provide an invalid token, whether there are versioned keys in the request or not, the\n entire Multi-Object Delete request will fail. For information about MFA Delete, see MFA\n Delete.

\n\n

Finally, the Content-MD5 header is required for all Multi-Object Delete requests. Amazon\n S3 uses the header value to ensure that your request body has not been altered in\n transit.

\n\n

The following operations are related to DeleteObjects:

\n ", "smithy.api#http": { "method": "POST", "uri": "/{Bucket}?delete&x-id=DeleteObjects", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#DeleteObjectsOutput": { @@ -3126,7 +3382,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the objects to delete.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the objects to delete.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -3156,16 +3412,23 @@ "BypassGovernanceRetention": { "target": "com.amazonaws.s3#BypassGovernanceRetention", "traits": { - "smithy.api#documentation": "

Specifies whether you want to delete this object even if it has a Governance-type Object\n Lock in place. To use this header, you must have the s3:PutBucketPublicAccessBlock\n permission.

", + "smithy.api#documentation": "

Specifies whether you want to delete this object even if it has a Governance-type Object\n Lock in place. To use this header, you must have the s3:BypassGovernanceRetention\n permission.

", "smithy.api#httpHeader": "x-amz-bypass-governance-retention" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } + }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

\n

This checksum algorithm must be the same for all parts and it match the checksum\n value supplied in the CreateMultipartUpload request.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } } } }, @@ -3197,7 +3460,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -3335,7 +3598,7 @@ "KMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If the encryption type is aws:kms, this optional value specifies the ID of\n the symmetric customer managed key to use for encryption of job results. Amazon S3 only\n supports symmetric keys. For more information, see Using symmetric and\n asymmetric keys in the Amazon Web Services Key Management Service Developer Guide.

" + "smithy.api#documentation": "

If the encryption type is aws:kms, this optional value specifies the ID of\n the symmetric customer managed key to use for encryption of job results. Amazon S3 only\n supports symmetric keys. For more information, see Using symmetric and\n asymmetric keys in the Amazon Web Services Key Management Service Developer\n Guide.

" } }, "KMSContext": { @@ -3728,7 +3991,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -3786,7 +4049,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -3843,7 +4106,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -3858,7 +4121,7 @@ "target": "com.amazonaws.s3#GetBucketCorsOutput" }, "traits": { - "smithy.api#documentation": "

Returns the cors configuration information set for the bucket.

\n\n

To use this operation, you must have permission to perform the s3:GetBucketCORS action.\n By default, the bucket owner has this permission and can grant it to others.

\n\n

For more information about cors, see Enabling\n Cross-Origin Resource Sharing.

\n\n

The following operations are related to GetBucketCors:

\n ", + "smithy.api#documentation": "

Returns the Cross-Origin Resource Sharing (CORS) configuration information set for the\n bucket.

\n\n

To use this operation, you must have permission to perform the\n s3:GetBucketCORS action. By default, the bucket owner has this permission\n and can grant it to others.

\n\n

For more information about CORS, see Enabling Cross-Origin Resource\n Sharing.

\n\n

The following operations are related to GetBucketCors:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?cors", @@ -3896,7 +4159,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -3944,7 +4207,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4051,7 +4314,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4104,7 +4367,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4156,7 +4419,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4204,7 +4467,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4261,7 +4524,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4298,7 +4561,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4347,7 +4610,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4396,7 +4659,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4445,7 +4708,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4493,7 +4756,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4544,7 +4807,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4559,7 +4822,7 @@ "target": "com.amazonaws.s3#GetBucketTaggingOutput" }, "traits": { - "smithy.api#documentation": "

Returns the tag set associated with the bucket.

\n

To use this operation, you must have permission to perform the\n s3:GetBucketTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n\n

\n GetBucketTagging has the following special error:

\n \n\n

The following operations are related to GetBucketTagging:

\n ", + "smithy.api#documentation": "

Returns the tag set associated with the bucket.

\n

To use this operation, you must have permission to perform the\n s3:GetBucketTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n\n

\n GetBucketTagging has the following special error:

\n \n\n

The following operations are related to GetBucketTagging:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?tagging", @@ -4596,7 +4859,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4654,7 +4917,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4723,7 +4986,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4746,7 +5009,16 @@ } ], "traits": { - "smithy.api#documentation": "

Retrieves objects from Amazon S3. To use GET, you must have READ\n access to the object. If you grant READ access to the anonymous user, you can\n return the object without using an authorization header.

\n\n

An Amazon S3 bucket has no directory hierarchy such as you would find in a typical computer\n file system. You can, however, create a logical hierarchy by using object key names that\n imply a folder structure. For example, instead of naming an object sample.jpg,\n you can name it photos/2006/February/sample.jpg.

\n\n

To get an object from such a logical hierarchy, specify the full key name for the object\n in the GET operation. For a virtual hosted-style request example, if you have\n the object photos/2006/February/sample.jpg, specify the resource as\n /photos/2006/February/sample.jpg. For a path-style request example, if you\n have the object photos/2006/February/sample.jpg in the bucket named\n examplebucket, specify the resource as\n /examplebucket/photos/2006/February/sample.jpg. For more information about\n request types, see HTTP Host Header Bucket Specification.

\n\n

To distribute large files to many people, you can save bandwidth costs by using\n BitTorrent. For more information, see Amazon S3\n Torrent. For more information about returning the ACL of an object, see GetObjectAcl.

\n\n

If the object you are retrieving is stored in the S3 Glacier or\n S3 Glacier Deep Archive storage class, or S3 Intelligent-Tiering Archive or\n S3 Intelligent-Tiering Deep Archive tiers, before you can retrieve the object you must first restore a\n copy using RestoreObject. Otherwise, this action returns an\n InvalidObjectStateError error. For information about restoring archived\n objects, see Restoring Archived\n Objects.

\n\n

Encryption request headers, like x-amz-server-side-encryption, should not\n be sent for GET requests if your object uses server-side encryption with KMS keys (SSE-KMS) \n or server-side encryption with Amazon S3–managed encryption keys (SSE-S3). If your\n object does use these types of keys, you’ll get an HTTP 400 BadRequest error.

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object,\n you must use the following headers:

\n \n

For more information about SSE-C, see Server-Side Encryption (Using\n Customer-Provided Encryption Keys).

\n\n

Assuming you have the relevant permission to read object tags, the response also returns the\n x-amz-tagging-count header that provides the count of number of tags\n associated with the object. You can use GetObjectTagging to retrieve\n the tag set associated with an object.

\n\n

\n Permissions\n

\n

You need the relevant read object (or version) permission for this operation. For more\n information, see Specifying Permissions\n in a Policy. If the object you request does not exist, the error Amazon S3 returns\n depends on whether you also have the s3:ListBucket permission.

\n \n\n\n

\n Versioning\n

\n

By default, the GET action returns the current version of an object. To return a\n different version, use the versionId subresource.

\n\n \n \n \n\n\n

For more information about versioning, see PutBucketVersioning.

\n\n

\n Overriding Response Header Values\n

\n

There are times when you want to override certain response header values in a GET\n response. For example, you might override the Content-Disposition response header value in\n your GET request.

\n\n

You can override values for a set of response headers using the following query\n parameters. These response header values are sent only on a successful request, that is,\n when status code 200 OK is returned. The set of headers you can override using these\n parameters is a subset of the headers that Amazon S3 accepts when you create an object. The\n response headers that you can override for the GET response are Content-Type,\n Content-Language, Expires, Cache-Control,\n Content-Disposition, and Content-Encoding. To override these\n header values in the GET response, you use the following request parameters.

\n\n \n

You must sign the request, either using an Authorization header or a presigned URL,\n when using these parameters. They cannot be used with an unsigned (anonymous)\n request.

\n
\n \n\n

\n Additional Considerations about Request Headers\n

\n\n

If both of the If-Match and If-Unmodified-Since headers are\n present in the request as follows: If-Match condition evaluates to\n true, and; If-Unmodified-Since condition evaluates to\n false; then, S3 returns 200 OK and the data requested.

\n\n

If both of the If-None-Match and If-Modified-Since headers are\n present in the request as follows: If-None-Match condition evaluates to\n false, and; If-Modified-Since condition evaluates to\n true; then, S3 returns 304 Not Modified response code.

\n\n

For more information about conditional requests, see RFC 7232.

\n\n

The following operations are related to GetObject:

\n ", + "aws.protocols#httpChecksum": { + "requestValidationModeMember": "ChecksumMode", + "responseAlgorithms": [ + "CRC32", + "CRC32C", + "SHA256", + "SHA1" + ] + }, + "smithy.api#documentation": "

Retrieves objects from Amazon S3. To use GET, you must have READ\n access to the object. If you grant READ access to the anonymous user, you can\n return the object without using an authorization header.

\n\n

An Amazon S3 bucket has no directory hierarchy such as you would find in a typical computer\n file system. You can, however, create a logical hierarchy by using object key names that\n imply a folder structure. For example, instead of naming an object sample.jpg,\n you can name it photos/2006/February/sample.jpg.

\n\n

To get an object from such a logical hierarchy, specify the full key name for the object\n in the GET operation. For a virtual hosted-style request example, if you have\n the object photos/2006/February/sample.jpg, specify the resource as\n /photos/2006/February/sample.jpg. For a path-style request example, if you\n have the object photos/2006/February/sample.jpg in the bucket named\n examplebucket, specify the resource as\n /examplebucket/photos/2006/February/sample.jpg. For more information about\n request types, see HTTP Host Header Bucket Specification.

\n\n

For more information about returning the ACL of an object, see GetObjectAcl.

\n\n

If the object you are retrieving is stored in the S3 Glacier or\n S3 Glacier Deep Archive storage class, or S3 Intelligent-Tiering Archive or\n S3 Intelligent-Tiering Deep Archive tiers, before you can retrieve the object you must first restore a\n copy using RestoreObject. Otherwise, this action returns an\n InvalidObjectStateError error. For information about restoring archived\n objects, see Restoring Archived\n Objects.

\n\n

Encryption request headers, like x-amz-server-side-encryption, should not\n be sent for GET requests if your object uses server-side encryption with KMS keys (SSE-KMS) \n or server-side encryption with Amazon S3–managed encryption keys (SSE-S3). If your\n object does use these types of keys, you’ll get an HTTP 400 BadRequest error.

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object,\n you must use the following headers:

\n \n

For more information about SSE-C, see Server-Side Encryption (Using\n Customer-Provided Encryption Keys).

\n\n

Assuming you have the relevant permission to read object tags, the response also returns the\n x-amz-tagging-count header that provides the count of number of tags\n associated with the object. You can use GetObjectTagging to retrieve\n the tag set associated with an object.

\n\n

\n Permissions\n

\n

You need the relevant read object (or version) permission for this operation. For more\n information, see Specifying Permissions\n in a Policy. If the object you request does not exist, the error Amazon S3 returns\n depends on whether you also have the s3:ListBucket permission.

\n \n\n\n

\n Versioning\n

\n

By default, the GET action returns the current version of an object. To return a\n different version, use the versionId subresource.

\n\n \n \n \n\n\n

For more information about versioning, see PutBucketVersioning.

\n\n

\n Overriding Response Header Values\n

\n

There are times when you want to override certain response header values in a GET\n response. For example, you might override the Content-Disposition response\n header value in your GET request.

\n\n

You can override values for a set of response headers using the following query\n parameters. These response header values are sent only on a successful request, that is,\n when status code 200 OK is returned. The set of headers you can override using these\n parameters is a subset of the headers that Amazon S3 accepts when you create an object. The\n response headers that you can override for the GET response are Content-Type,\n Content-Language, Expires, Cache-Control,\n Content-Disposition, and Content-Encoding. To override these\n header values in the GET response, you use the following request parameters.

\n\n \n

You must sign the request, either using an Authorization header or a presigned URL,\n when using these parameters. They cannot be used with an unsigned (anonymous)\n request.

\n
\n \n\n

\n Additional Considerations about Request Headers\n

\n\n

If both of the If-Match and If-Unmodified-Since headers are\n present in the request as follows: If-Match condition evaluates to\n true, and; If-Unmodified-Since condition evaluates to\n false; then, S3 returns 200 OK and the data requested.

\n\n

If both of the If-None-Match and If-Modified-Since headers are\n present in the request as follows: If-None-Match condition evaluates to\n false, and; If-Modified-Since condition evaluates to\n true; then, S3 returns 304 Not Modified response code.

\n\n

For more information about conditional requests, see RFC 7232.

\n\n

The following operations are related to GetObject:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?x-id=GetObject", @@ -4768,7 +5040,7 @@ } ], "traits": { - "smithy.api#documentation": "

Returns the access control list (ACL) of an object. To use this operation, you must have\n READ_ACP access to the object.

\n

This action is not supported by Amazon S3 on Outposts.

\n

\n Versioning\n

\n

By default, GET returns ACL information about the current version of an object. To\n return ACL information about a different version, use the versionId subresource.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, \n requests to read ACLs are still supported and return the bucket-owner-full-control \n ACL with the owner being the account that created the bucket. For more information, see \n \n Controlling object ownership and disabling ACLs in the Amazon S3 User Guide.

\n
\n

The following operations are related to GetObjectAcl:

\n ", + "smithy.api#documentation": "

Returns the access control list (ACL) of an object. To use this operation, you must have\n s3:GetObjectAcl permissions or READ_ACP access to the object.\n For more information, see Mapping of ACL permissions and access policy permissions in the Amazon S3\n User Guide\n

\n

This action is not supported by Amazon S3 on Outposts.

\n

\n Versioning\n

\n

By default, GET returns ACL information about the current version of an object. To\n return ACL information about a different version, use the versionId subresource.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, \n requests to read ACLs are still supported and return the bucket-owner-full-control \n ACL with the owner being the account that created the bucket. For more information, see \n \n Controlling object ownership and disabling ACLs in the Amazon S3 User Guide.

\n
\n

The following operations are related to GetObjectAcl:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?acl", @@ -4838,12 +5110,227 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } } }, + "com.amazonaws.s3#GetObjectAttributes": { + "type": "operation", + "input": { + "target": "com.amazonaws.s3#GetObjectAttributesRequest" + }, + "output": { + "target": "com.amazonaws.s3#GetObjectAttributesOutput" + }, + "errors": [ + { + "target": "com.amazonaws.s3#NoSuchKey" + } + ], + "traits": { + "smithy.api#documentation": "

Retrieves all the metadata from an object without returning the object itself. This\n action is useful if you're interested only in an object's metadata. To use\n GetObjectAttributes, you must have READ access to the object.

\n\n

\n GetObjectAttributes combines the functionality of\n GetObjectAcl, GetObjectLegalHold,\n GetObjectLockConfiguration, GetObjectRetention,\n GetObjectTagging, HeadObject, and ListParts. All\n of the data returned with each of those individual calls can be returned with a single call\n to GetObjectAttributes.

\n\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the\n metadata from the object, you must use the following headers:

\n \n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys) in the\n Amazon S3 User Guide.

\n \n \n \n\n

Consider the following when using request headers:

\n \n\n

For more information about conditional requests, see RFC 7232.

\n\n

\n Permissions\n

\n

The permissions that you need to use this operation depend on whether the bucket is\n versioned. If the bucket is versioned, you need both the s3:GetObjectVersion\n and s3:GetObjectVersionAttributes permissions for this operation. If the\n bucket is not versioned, you need the s3:GetObject and\n s3:GetObjectAttributes permissions. For more information, see Specifying\n Permissions in a Policy in the Amazon S3 User Guide. If the\n object that you request does not exist, the error Amazon S3 returns depends on whether you also\n have the s3:ListBucket permission.

\n \n\n

The following actions are related to GetObjectAttributes:

\n ", + "smithy.api#http": { + "method": "GET", + "uri": "/{Bucket}/{Key+}?attributes", + "code": 200 + } + } + }, + "com.amazonaws.s3#GetObjectAttributesOutput": { + "type": "structure", + "members": { + "DeleteMarker": { + "target": "com.amazonaws.s3#DeleteMarker", + "traits": { + "smithy.api#documentation": "

Specifies whether the object retrieved was (true) or was not\n (false) a delete marker. If false, this response header does\n not appear in the response.

", + "smithy.api#httpHeader": "x-amz-delete-marker" + } + }, + "LastModified": { + "target": "com.amazonaws.s3#LastModified", + "traits": { + "smithy.api#documentation": "

The creation date of the object.

", + "smithy.api#httpHeader": "Last-Modified" + } + }, + "VersionId": { + "target": "com.amazonaws.s3#ObjectVersionId", + "traits": { + "smithy.api#documentation": "

The version ID of the object.

", + "smithy.api#httpHeader": "x-amz-version-id" + } + }, + "RequestCharged": { + "target": "com.amazonaws.s3#RequestCharged", + "traits": { + "smithy.api#httpHeader": "x-amz-request-charged" + } + }, + "ETag": { + "target": "com.amazonaws.s3#ETag", + "traits": { + "smithy.api#documentation": "

An ETag is an opaque identifier assigned by a web server to a specific version of a\n resource found at a URL.

" + } + }, + "Checksum": { + "target": "com.amazonaws.s3#Checksum", + "traits": { + "smithy.api#documentation": "

The checksum or digest of the object.

" + } + }, + "ObjectParts": { + "target": "com.amazonaws.s3#GetObjectAttributesParts", + "traits": { + "smithy.api#documentation": "

A collection of parts associated with a multipart upload.

" + } + }, + "StorageClass": { + "target": "com.amazonaws.s3#StorageClass", + "traits": { + "smithy.api#documentation": "

Provides the storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

\n\n

For more information, see Storage\n Classes.

" + } + }, + "ObjectSize": { + "target": "com.amazonaws.s3#ObjectSize", + "traits": { + "smithy.api#documentation": "

The size of the object in bytes.

" + } + } + } + }, + "com.amazonaws.s3#GetObjectAttributesParts": { + "type": "structure", + "members": { + "TotalPartsCount": { + "target": "com.amazonaws.s3#PartsCount", + "traits": { + "smithy.api#documentation": "

The total number of parts.

", + "smithy.api#xmlName": "PartsCount" + } + }, + "PartNumberMarker": { + "target": "com.amazonaws.s3#PartNumberMarker", + "traits": { + "smithy.api#documentation": "

The marker for the current part.

" + } + }, + "NextPartNumberMarker": { + "target": "com.amazonaws.s3#NextPartNumberMarker", + "traits": { + "smithy.api#documentation": "

When a list is truncated, this element specifies the last part in the list, as well as\n the value to use for the PartNumberMarker request parameter in a subsequent\n request.

" + } + }, + "MaxParts": { + "target": "com.amazonaws.s3#MaxParts", + "traits": { + "smithy.api#documentation": "

The maximum number of parts allowed in the response.

" + } + }, + "IsTruncated": { + "target": "com.amazonaws.s3#IsTruncated", + "traits": { + "smithy.api#documentation": "

Indicates whether the returned list of parts is truncated. A value of\n true indicates that the list was truncated. A list can be truncated if the\n number of parts exceeds the limit returned in the MaxParts element.

" + } + }, + "Parts": { + "target": "com.amazonaws.s3#PartsList", + "traits": { + "smithy.api#documentation": "

A container for elements related to a particular part. A response can contain zero or\n more Parts elements.

", + "smithy.api#xmlFlattened": {}, + "smithy.api#xmlName": "Part" + } + } + }, + "traits": { + "smithy.api#documentation": "

A collection of parts associated with a multipart upload.

" + } + }, + "com.amazonaws.s3#GetObjectAttributesRequest": { + "type": "structure", + "members": { + "Bucket": { + "target": "com.amazonaws.s3#BucketName", + "traits": { + "smithy.api#documentation": "

The name of the bucket that contains the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "Key": { + "target": "com.amazonaws.s3#ObjectKey", + "traits": { + "smithy.api#documentation": "

The object key.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {} + } + }, + "VersionId": { + "target": "com.amazonaws.s3#ObjectVersionId", + "traits": { + "smithy.api#documentation": "

The version ID used to reference a specific version of the object.

", + "smithy.api#httpQuery": "versionId" + } + }, + "MaxParts": { + "target": "com.amazonaws.s3#MaxParts", + "traits": { + "smithy.api#documentation": "

Sets the maximum number of parts to return.

", + "smithy.api#httpHeader": "x-amz-max-parts" + } + }, + "PartNumberMarker": { + "target": "com.amazonaws.s3#PartNumberMarker", + "traits": { + "smithy.api#documentation": "

Specifies the part after which listing should begin. Only parts with higher part numbers\n will be listed.

", + "smithy.api#httpHeader": "x-amz-part-number-marker" + } + }, + "SSECustomerAlgorithm": { + "target": "com.amazonaws.s3#SSECustomerAlgorithm", + "traits": { + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example,\n AES256).

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" + } + }, + "SSECustomerKey": { + "target": "com.amazonaws.s3#SSECustomerKey", + "traits": { + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" + } + }, + "SSECustomerKeyMD5": { + "target": "com.amazonaws.s3#SSECustomerKeyMD5", + "traits": { + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" + } + }, + "RequestPayer": { + "target": "com.amazonaws.s3#RequestPayer", + "traits": { + "smithy.api#httpHeader": "x-amz-request-payer" + } + }, + "ExpectedBucketOwner": { + "target": "com.amazonaws.s3#AccountId", + "traits": { + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#httpHeader": "x-amz-expected-bucket-owner" + } + }, + "ObjectAttributes": { + "target": "com.amazonaws.s3#ObjectAttributesList", + "traits": { + "smithy.api#documentation": "

An XML header that specifies the fields at the root level that you want returned in\n the response. Fields that you do not specify are not returned.

", + "smithy.api#httpHeader": "x-amz-object-attributes", + "smithy.api#required": {} + } + } + } + }, "com.amazonaws.s3#GetObjectLegalHold": { "type": "operation", "input": { @@ -4853,7 +5340,7 @@ "target": "com.amazonaws.s3#GetObjectLegalHoldOutput" }, "traits": { - "smithy.api#documentation": "

Gets an object's current Legal Hold status. For more information, see Locking Objects.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Gets an object's current legal hold status. For more information, see Locking\n Objects.

\n

This action is not supported by Amazon S3 on Outposts.

\n\n

The following action is related to GetObjectLegalHold:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?legal-hold", @@ -4867,7 +5354,7 @@ "LegalHold": { "target": "com.amazonaws.s3#ObjectLockLegalHold", "traits": { - "smithy.api#documentation": "

The current Legal Hold status for the specified object.

", + "smithy.api#documentation": "

The current legal hold status for the specified object.

", "smithy.api#httpPayload": {} } } @@ -4879,7 +5366,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object whose Legal Hold status you want to retrieve.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object whose legal hold status you want to retrieve.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -4887,7 +5374,7 @@ "Key": { "target": "com.amazonaws.s3#ObjectKey", "traits": { - "smithy.api#documentation": "

The key name for the object whose Legal Hold status you want to retrieve.

", + "smithy.api#documentation": "

The key name for the object whose legal hold status you want to retrieve.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -4895,7 +5382,7 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

The version ID of the object whose Legal Hold status you want to retrieve.

", + "smithy.api#documentation": "

The version ID of the object whose legal hold status you want to retrieve.

", "smithy.api#httpQuery": "versionId" } }, @@ -4908,7 +5395,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4923,7 +5410,7 @@ "target": "com.amazonaws.s3#GetObjectLockConfigurationOutput" }, "traits": { - "smithy.api#documentation": "

Gets the Object Lock configuration for a bucket. The rule specified in the Object Lock\n configuration will be applied by default to every new object placed in the specified\n bucket. For more information, see Locking\n Objects.

", + "smithy.api#documentation": "

Gets the Object Lock configuration for a bucket. The rule specified in the Object Lock\n configuration will be applied by default to every new object placed in the specified\n bucket. For more information, see Locking\n Objects.

\n\n

The following action is related to GetObjectLockConfiguration:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?object-lock", @@ -4957,7 +5444,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -4990,7 +5477,7 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the object expiration is configured (see PUT Bucket lifecycle), the response includes\n this header. It includes the expiry-date and rule-id key-value pairs providing object\n expiration information. The value of the rule-id is URL encoded.

", + "smithy.api#documentation": "

If the object expiration is configured (see PUT Bucket lifecycle), the response includes\n this header. It includes the expiry-date and rule-id key-value\n pairs providing object expiration information. The value of the rule-id is\n URL-encoded.

", "smithy.api#httpHeader": "x-amz-expiration" } }, @@ -5018,10 +5505,38 @@ "ETag": { "target": "com.amazonaws.s3#ETag", "traits": { - "smithy.api#documentation": "

An ETag is an opaque identifier assigned by a web server to a specific version of a\n resource found at a URL.

", + "smithy.api#documentation": "

An entity tag (ETag) is an opaque identifier assigned by a web server to a specific\n version of a resource found at a URL.

", "smithy.api#httpHeader": "ETag" } }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha256" + } + }, "MissingMeta": { "target": "com.amazonaws.s3#MissingMeta", "traits": { @@ -5157,7 +5672,7 @@ "PartsCount": { "target": "com.amazonaws.s3#PartsCount", "traits": { - "smithy.api#documentation": "

The count of parts this object has.

", + "smithy.api#documentation": "

The count of parts this object has. This value is only returned if you specify partNumber\n in your request and the object was uploaded as a multipart upload.

", "smithy.api#httpHeader": "x-amz-mp-parts-count" } }, @@ -5197,7 +5712,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using an Object Lambda access point the hostname takes the form AccessPointName-AccountId.s3-object-lambda.Region.amazonaws.com.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using an Object Lambda access point the hostname takes the form AccessPointName-AccountId.s3-object-lambda.Region.amazonaws.com.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -5205,28 +5720,28 @@ "IfMatch": { "target": "com.amazonaws.s3#IfMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified,\n otherwise return a 412 (precondition failed).

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified;\n otherwise, return a 412 (precondition failed) error.

", "smithy.api#httpHeader": "If-Match" } }, "IfModifiedSince": { "target": "com.amazonaws.s3#IfModifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has been modified since the specified time, otherwise\n return a 304 (not modified).

", + "smithy.api#documentation": "

Return the object only if it has been modified since the specified time; otherwise,\n return a 304 (not modified) error.

", "smithy.api#httpHeader": "If-Modified-Since" } }, "IfNoneMatch": { "target": "com.amazonaws.s3#IfNoneMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified,\n otherwise return a 304 (not modified).

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified;\n otherwise, return a 304 (not modified) error.

", "smithy.api#httpHeader": "If-None-Match" } }, "IfUnmodifiedSince": { "target": "com.amazonaws.s3#IfUnmodifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time, otherwise\n return a 412 (precondition failed).

", + "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time; otherwise,\n return a 412 (precondition failed) error.

", "smithy.api#httpHeader": "If-Unmodified-Since" } }, @@ -5331,9 +5846,16 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } + }, + "ChecksumMode": { + "target": "com.amazonaws.s3#ChecksumMode", + "traits": { + "smithy.api#documentation": "

To retrieve the checksum, this mode must be enabled.

", + "smithy.api#httpHeader": "x-amz-checksum-mode" + } } } }, @@ -5349,7 +5871,7 @@ "target": "com.amazonaws.s3#GetObjectRetentionOutput" }, "traits": { - "smithy.api#documentation": "

Retrieves an object's retention settings. For more information, see Locking Objects.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Retrieves an object's retention settings. For more information, see Locking Objects.

\n

This action is not supported by Amazon S3 on Outposts.

\n\n

The following action is related to GetObjectRetention:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?retention", @@ -5404,7 +5926,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -5419,7 +5941,7 @@ "target": "com.amazonaws.s3#GetObjectTaggingOutput" }, "traits": { - "smithy.api#documentation": "

Returns the tag-set of an object. You send the GET request against the tagging\n subresource associated with the object.

\n\n

To use this operation, you must have permission to perform the\n s3:GetObjectTagging action. By default, the GET action returns\n information about current version of an object. For a versioned bucket, you can have\n multiple versions of an object in your bucket. To retrieve tags of any other version, use\n the versionId query parameter. You also need permission for the\n s3:GetObjectVersionTagging action.

\n\n

By default, the bucket owner has this permission and can grant this permission to\n others.

\n\n

For information about the Amazon S3 object tagging feature, see Object Tagging.

\n\n

The following action is related to GetObjectTagging:

\n ", + "smithy.api#documentation": "

Returns the tag-set of an object. You send the GET request against the tagging\n subresource associated with the object.

\n\n

To use this operation, you must have permission to perform the\n s3:GetObjectTagging action. By default, the GET action returns\n information about current version of an object. For a versioned bucket, you can have\n multiple versions of an object in your bucket. To retrieve tags of any other version, use\n the versionId query parameter. You also need permission for the\n s3:GetObjectVersionTagging action.

\n\n

By default, the bucket owner has this permission and can grant this permission to\n others.

\n\n

For information about the Amazon S3 object tagging feature, see Object Tagging.

\n\n

The following actions are related to GetObjectTagging:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?tagging", @@ -5455,7 +5977,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object for which to get the tagging information.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object for which to get the tagging information.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -5478,7 +6000,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -5553,7 +6075,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -5602,7 +6124,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -5767,7 +6289,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -5775,7 +6297,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -5795,7 +6317,7 @@ } ], "traits": { - "smithy.api#documentation": "

The HEAD action retrieves metadata from an object without returning the object\n itself. This action is useful if you're only interested in an object's metadata. To use\n HEAD, you must have READ access to the object.

\n\n

A HEAD request has the same options as a GET action on an\n object. The response is identical to the GET response except that there is no\n response body. Because of this, if the HEAD request generates an error, it\n returns a generic 404 Not Found or 403 Forbidden code. It is not \n possible to retrieve the exact exception beyond these error codes.

\n\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the\n metadata from the object, you must use the following headers:

\n \n

For more information about SSE-C, see Server-Side Encryption (Using\n Customer-Provided Encryption Keys).

\n \n \n \n\n\n

Request headers are limited to 8 KB in size. For more information, see Common Request\n Headers.

\n

Consider the following when using request headers:

\n \n\n

For more information about conditional requests, see RFC 7232.

\n\n

\n Permissions\n

\n

You need the relevant read object (or version) permission for this operation. For more\n information, see Specifying Permissions\n in a Policy. If the object you request does not exist, the error Amazon S3 returns\n depends on whether you also have the s3:ListBucket permission.

\n \n\n

The following action is related to HeadObject:

\n ", + "smithy.api#documentation": "

The HEAD action retrieves metadata from an object without returning the object\n itself. This action is useful if you're only interested in an object's metadata. To use\n HEAD, you must have READ access to the object.

\n\n

A HEAD request has the same options as a GET action on an\n object. The response is identical to the GET response except that there is no\n response body. Because of this, if the HEAD request generates an error, it\n returns a generic 404 Not Found or 403 Forbidden code. It is not \n possible to retrieve the exact exception beyond these error codes.

\n\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the\n metadata from the object, you must use the following headers:

\n \n

For more information about SSE-C, see Server-Side Encryption (Using\n Customer-Provided Encryption Keys).

\n \n \n \n\n\n

Request headers are limited to 8 KB in size. For more information, see Common Request\n Headers.

\n

Consider the following when using request headers:

\n \n\n

For more information about conditional requests, see RFC 7232.

\n\n

\n Permissions\n

\n

You need the relevant read object (or version) permission for this operation. For more\n information, see Specifying Permissions\n in a Policy. If the object you request does not exist, the error Amazon S3 returns\n depends on whether you also have the s3:ListBucket permission.

\n \n\n

The following actions are related to HeadObject:

\n ", "smithy.api#http": { "method": "HEAD", "uri": "/{Bucket}/{Key+}", @@ -5853,7 +6375,7 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the object expiration is configured (see PUT Bucket lifecycle), the response includes\n this header. It includes the expiry-date and rule-id key-value pairs providing object\n expiration information. The value of the rule-id is URL encoded.

", + "smithy.api#documentation": "

If the object expiration is configured (see PUT Bucket lifecycle), the response includes\n this header. It includes the expiry-date and rule-id key-value\n pairs providing object expiration information. The value of the rule-id is\n URL-encoded.

", "smithy.api#httpHeader": "x-amz-expiration" } }, @@ -5885,10 +6407,38 @@ "smithy.api#httpHeader": "Content-Length" } }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha256" + } + }, "ETag": { "target": "com.amazonaws.s3#ETag", "traits": { - "smithy.api#documentation": "

An ETag is an opaque identifier assigned by a web server to a specific version of a\n resource found at a URL.

", + "smithy.api#documentation": "

An entity tag (ETag) is an opaque identifier assigned by a web server to a specific\n version of a resource found at a URL.

", "smithy.api#httpHeader": "ETag" } }, @@ -6013,14 +6563,14 @@ "ReplicationStatus": { "target": "com.amazonaws.s3#ReplicationStatus", "traits": { - "smithy.api#documentation": "

Amazon S3 can return this header if your request involves a bucket that is either a source or\n a destination in a replication rule.

\n\n

In replication, you have a source bucket on which you configure replication and\n destination bucket or buckets where Amazon S3 stores object replicas. When you request an object\n (GetObject) or object metadata (HeadObject) from these\n buckets, Amazon S3 will return the x-amz-replication-status header in the response\n as follows:

\n \n\n

For more information, see Replication.

", + "smithy.api#documentation": "

Amazon S3 can return this header if your request involves a bucket that is either a source or\n a destination in a replication rule.

\n\n

In replication, you have a source bucket on which you configure replication and\n destination bucket or buckets where Amazon S3 stores object replicas. When you request an object\n (GetObject) or object metadata (HeadObject) from these\n buckets, Amazon S3 will return the x-amz-replication-status header in the response\n as follows:

\n \n\n

For more information, see Replication.

", "smithy.api#httpHeader": "x-amz-replication-status" } }, "PartsCount": { "target": "com.amazonaws.s3#PartsCount", "traits": { - "smithy.api#documentation": "

The count of parts this object has.

", + "smithy.api#documentation": "

The count of parts this object has. This value is only returned if you specify partNumber\n in your request and the object was uploaded as a multipart upload.

", "smithy.api#httpHeader": "x-amz-mp-parts-count" } }, @@ -6053,7 +6603,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -6061,28 +6611,28 @@ "IfMatch": { "target": "com.amazonaws.s3#IfMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified,\n otherwise return a 412 (precondition failed).

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified;\n otherwise, return a 412 (precondition failed) error.

", "smithy.api#httpHeader": "If-Match" } }, "IfModifiedSince": { "target": "com.amazonaws.s3#IfModifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has been modified since the specified time, otherwise\n return a 304 (not modified).

", + "smithy.api#documentation": "

Return the object only if it has been modified since the specified time; otherwise,\n return a 304 (not modified) error.

", "smithy.api#httpHeader": "If-Modified-Since" } }, "IfNoneMatch": { "target": "com.amazonaws.s3#IfNoneMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified,\n otherwise return a 304 (not modified).

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified;\n otherwise, return a 304 (not modified) error.

", "smithy.api#httpHeader": "If-None-Match" } }, "IfUnmodifiedSince": { "target": "com.amazonaws.s3#IfUnmodifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time, otherwise\n return a 412 (precondition failed).

", + "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time; otherwise,\n return a 412 (precondition failed) error.

", "smithy.api#httpHeader": "If-Unmodified-Since" } }, @@ -6145,9 +6695,16 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } + }, + "ChecksumMode": { + "target": "com.amazonaws.s3#ChecksumMode", + "traits": { + "smithy.api#documentation": "

To retrieve the checksum, this parameter must be enabled.

\n

In addition, if you enable ChecksumMode and the object is encrypted with\n Amazon Web Services Key Management Service (Amazon Web Services KMS), you must have permission to use the\n kms:Decrypt action for the request to succeed.

", + "smithy.api#httpHeader": "x-amz-checksum-mode" + } } } }, @@ -6600,6 +7157,10 @@ { "value": "BucketKeyStatus", "name": "BucketKeyStatus" + }, + { + "value": "ChecksumAlgorithm", + "name": "ChecksumAlgorithm" } ] } @@ -6829,7 +7390,7 @@ "Filter": { "target": "com.amazonaws.s3#LifecycleRuleFilter", "traits": { - "smithy.api#documentation": "

The Filter is used to identify objects that a Lifecycle Rule applies to. A\n Filter must have exactly one of Prefix, Tag, or\n And specified. Filter is required if the LifecycleRule\n does not containt a Prefix element.

" + "smithy.api#documentation": "

The Filter is used to identify objects that a Lifecycle Rule applies to. A\n Filter must have exactly one of Prefix, Tag, or\n And specified. Filter is required if the\n LifecycleRule does not contain a Prefix element.

" } }, "Status": { @@ -7013,7 +7574,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -7042,13 +7603,13 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#documentation": "

Indicates whether the returned list of analytics configurations is complete. A value of\n true indicates that the list is not complete and the NextContinuationToken will be provided\n for a subsequent request.

" + "smithy.api#documentation": "

Indicates whether the returned list of analytics configurations is complete. A value of\n true indicates that the list is not complete and the\n NextContinuationToken will be provided for a subsequent request.

" } }, "ContinuationToken": { "target": "com.amazonaws.s3#Token", "traits": { - "smithy.api#documentation": "

The ContinuationToken that represents a placeholder from where this request should\n begin.

" + "smithy.api#documentation": "

The ContinuationToken that represents a placeholder from where this request\n should begin.

" } }, "NextContinuationToken": { @@ -7081,7 +7642,7 @@ "ContinuationToken": { "target": "com.amazonaws.s3#Token", "traits": { - "smithy.api#documentation": "

The ContinuationToken that represents a placeholder from where this request should\n begin.

", + "smithy.api#documentation": "

The ContinuationToken that represents a placeholder from where this request\n should begin.

", "smithy.api#httpQuery": "continuation-token" } } @@ -7159,7 +7720,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -7237,7 +7798,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -7249,7 +7810,7 @@ "target": "com.amazonaws.s3#ListBucketsOutput" }, "traits": { - "smithy.api#documentation": "

Returns a list of all buckets owned by the authenticated sender of the request.

", + "smithy.api#documentation": "

Returns a list of all buckets owned by the authenticated sender of the request. To use\n this operation, you must have the s3:ListAllMyBuckets permission.

", "smithy.api#http": { "method": "GET", "uri": "/", @@ -7263,7 +7824,7 @@ "Buckets": { "target": "com.amazonaws.s3#Buckets", "traits": { - "smithy.api#documentation": "

The list of buckets owned by the requestor.

" + "smithy.api#documentation": "

The list of buckets owned by the requester.

" } }, "Owner": { @@ -7383,7 +7944,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -7432,7 +7993,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -7601,7 +8162,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -7705,7 +8266,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket containing the objects.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket containing the objects.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -7754,7 +8315,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -7806,7 +8367,7 @@ "Name": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

" } }, "Prefix": { @@ -7875,7 +8436,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

Bucket name to list.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Bucket name to list.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -7939,7 +8500,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -7954,7 +8515,7 @@ "target": "com.amazonaws.s3#ListPartsOutput" }, "traits": { - "smithy.api#documentation": "

Lists the parts that have been uploaded for a specific multipart upload. This operation\n must include the upload ID, which you obtain by sending the initiate multipart upload\n request (see CreateMultipartUpload).\n This request returns a maximum of 1,000 uploaded parts. The default number of parts\n returned is 1,000 parts. You can restrict the number of parts returned by specifying the\n max-parts request parameter. If your multipart upload consists of more than\n 1,000 parts, the response returns an IsTruncated field with the value of true,\n and a NextPartNumberMarker element. In subsequent ListParts\n requests you can include the part-number-marker query string parameter and set its value to\n the NextPartNumberMarker field value from the previous response.

\n\n

For more information on multipart uploads, see Uploading Objects Using Multipart\n Upload.

\n\n

For information on permissions required to use the multipart upload API, see Multipart Upload and\n Permissions.

\n\n

The following operations are related to ListParts:

\n ", + "smithy.api#documentation": "

Lists the parts that have been uploaded for a specific multipart upload. This operation\n must include the upload ID, which you obtain by sending the initiate multipart upload\n request (see CreateMultipartUpload).\n This request returns a maximum of 1,000 uploaded parts. The default number of parts\n returned is 1,000 parts. You can restrict the number of parts returned by specifying the\n max-parts request parameter. If your multipart upload consists of more than\n 1,000 parts, the response returns an IsTruncated field with the value of true,\n and a NextPartNumberMarker element. In subsequent ListParts\n requests you can include the part-number-marker query string parameter and set its value to\n the NextPartNumberMarker field value from the previous response.

\n

If the upload was created using a checksum algorithm, you will need to have permission\n to the kms:Decrypt action for the request to succeed.\n

\n\n

For more information on multipart uploads, see Uploading Objects Using Multipart\n Upload.

\n\n

For information on permissions required to use the multipart upload API, see Multipart Upload and\n Permissions.

\n\n

The following operations are related to ListParts:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?x-id=ListParts", @@ -8058,6 +8619,12 @@ "traits": { "smithy.api#httpHeader": "x-amz-request-charged" } + }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

The algorithm that was used to create a checksum of the object.

" + } } }, "traits": { @@ -8070,7 +8637,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the parts are being uploaded.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the parts are being uploaded.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -8114,9 +8681,30 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } + }, + "SSECustomerAlgorithm": { + "target": "com.amazonaws.s3#SSECustomerAlgorithm", + "traits": { + "smithy.api#documentation": "

The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object was created \n using a checksum algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" + } + }, + "SSECustomerKey": { + "target": "com.amazonaws.s3#SSECustomerKey", + "traits": { + "smithy.api#documentation": "

The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm. \n For more information, see\n Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" + } + }, + "SSECustomerKeyMD5": { + "target": "com.amazonaws.s3#SSECustomerKeyMD5", + "traits": { + "smithy.api#documentation": "

The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum \n algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" + } } } }, @@ -8296,7 +8884,7 @@ "AccessPointArn": { "target": "com.amazonaws.s3#AccessPointArn", "traits": { - "smithy.api#documentation": "

The access point ARN used when evaluating an AND predicate.

" + "smithy.api#documentation": "

The access point ARN used when evaluating an AND predicate.

" } } }, @@ -8425,6 +9013,12 @@ "traits": { "smithy.api#documentation": "

Identifies who initiated the multipart upload.

" } + }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

The algorithm that was used to create a checksum of the object.

" + } } }, "traits": { @@ -8618,7 +9212,14 @@ "ETag": { "target": "com.amazonaws.s3#ETag", "traits": { - "smithy.api#documentation": "

The entity tag is a hash of the object. The ETag reflects changes only to the contents\n of an object, not its metadata. The ETag may or may not be an MD5 digest of the object\n data. Whether or not it is depends on how the object was created and how it is encrypted as\n described below:

\n " + "smithy.api#documentation": "

The entity tag is a hash of the object. The ETag reflects changes only to the contents\n of an object, not its metadata. The ETag may or may not be an MD5 digest of the object\n data. Whether or not it is depends on how the object was created and how it is encrypted as\n described below:

\n " + } + }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithmList", + "traits": { + "smithy.api#documentation": "

The algorithm that was used to create a checksum of the object.

", + "smithy.api#xmlFlattened": {} } }, "Size": { @@ -8652,6 +9253,39 @@ "smithy.api#error": "client" } }, + "com.amazonaws.s3#ObjectAttributes": { + "type": "string", + "traits": { + "smithy.api#enum": [ + { + "value": "ETag", + "name": "ETAG" + }, + { + "value": "Checksum", + "name": "CHECKSUM" + }, + { + "value": "ObjectParts", + "name": "OBJECT_PARTS" + }, + { + "value": "StorageClass", + "name": "STORAGE_CLASS" + }, + { + "value": "ObjectSize", + "name": "OBJECT_SIZE" + } + ] + } + }, + "com.amazonaws.s3#ObjectAttributesList": { + "type": "list", + "member": { + "target": "com.amazonaws.s3#ObjectAttributes" + } + }, "com.amazonaws.s3#ObjectCannedACL": { "type": "string", "traits": { @@ -8768,12 +9402,12 @@ "Status": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Indicates whether the specified object has a Legal Hold in place.

" + "smithy.api#documentation": "

Indicates whether the specified object has a legal hold in place.

" } } }, "traits": { - "smithy.api#documentation": "

A Legal Hold configuration for an object.

" + "smithy.api#documentation": "

A legal hold configuration for an object.

" } }, "com.amazonaws.s3#ObjectLockLegalHoldStatus": { @@ -8892,6 +9526,53 @@ ] } }, + "com.amazonaws.s3#ObjectPart": { + "type": "structure", + "members": { + "PartNumber": { + "target": "com.amazonaws.s3#PartNumber", + "traits": { + "smithy.api#documentation": "

The part number identifying the part. This value is a positive integer between 1 and\n 10,000.

" + } + }, + "Size": { + "target": "com.amazonaws.s3#Size", + "traits": { + "smithy.api#documentation": "

The size of the uploaded part in bytes.

" + } + }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

A container for elements related to an individual part.

" + } + }, + "com.amazonaws.s3#ObjectSize": { + "type": "long" + }, "com.amazonaws.s3#ObjectSizeGreaterThanBytes": { "type": "long" }, @@ -8950,6 +9631,13 @@ "smithy.api#documentation": "

The entity tag is an MD5 hash of that version of the object.

" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithmList", + "traits": { + "smithy.api#documentation": "

The algorithm that was used to create a checksum of the object.

", + "smithy.api#xmlFlattened": {} + } + }, "Size": { "target": "com.amazonaws.s3#Size", "traits": { @@ -9152,6 +9840,30 @@ "traits": { "smithy.api#documentation": "

Size in bytes of the uploaded part data.

" } + }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

" + } } }, "traits": { @@ -9173,6 +9885,12 @@ "com.amazonaws.s3#PartsCount": { "type": "integer" }, + "com.amazonaws.s3#PartsList": { + "type": "list", + "member": { + "target": "com.amazonaws.s3#ObjectPart" + } + }, "com.amazonaws.s3#Payer": { "type": "string", "traits": { @@ -9301,7 +10019,7 @@ "BlockPublicAcls": { "target": "com.amazonaws.s3#Setting", "traits": { - "smithy.api#documentation": "

Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket\n and objects in this bucket. Setting this element to TRUE causes the following\n behavior:

\n \n

Enabling this setting doesn't affect existing policies or ACLs.

", + "smithy.api#documentation": "

Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket\n and objects in this bucket. Setting this element to TRUE causes the following\n behavior:

\n \n

Enabling this setting doesn't affect existing policies or ACLs.

", "smithy.api#xmlName": "BlockPublicAcls" } }, @@ -9337,7 +10055,10 @@ "target": "com.amazonaws.s3#PutBucketAccelerateConfigurationRequest" }, "traits": { - "smithy.api#documentation": "

Sets the accelerate configuration of an existing bucket. Amazon S3 Transfer Acceleration is a\n bucket-level feature that enables you to perform faster data transfers to Amazon S3.

\n\n

To use this operation, you must have permission to perform the\n s3:PutAccelerateConfiguration action. The bucket owner has this permission by default. The\n bucket owner can grant this permission to others. For more information about permissions,\n see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3\n Resources.

\n\n

The Transfer Acceleration state of a bucket can be set to one of the following two\n values:

\n \n\n\n

The GetBucketAccelerateConfiguration action returns the transfer acceleration\n state of a bucket.

\n\n

After setting the Transfer Acceleration state of a bucket to Enabled, it might take up\n to thirty minutes before the data transfer rates to the bucket increase.

\n\n

The name of the bucket used for Transfer Acceleration must be DNS-compliant and must\n not contain periods (\".\").

\n\n

For more information about transfer acceleration, see Transfer Acceleration.

\n\n

The following operations are related to\n PutBucketAccelerateConfiguration:

\n ", + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm" + }, + "smithy.api#documentation": "

Sets the accelerate configuration of an existing bucket. Amazon S3 Transfer Acceleration is a\n bucket-level feature that enables you to perform faster data transfers to Amazon S3.

\n\n

To use this operation, you must have permission to perform the\n s3:PutAccelerateConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n\n

The Transfer Acceleration state of a bucket can be set to one of the following two\n values:

\n \n\n\n

The GetBucketAccelerateConfiguration action returns the transfer acceleration\n state of a bucket.

\n\n

After setting the Transfer Acceleration state of a bucket to Enabled, it might take up\n to thirty minutes before the data transfer rates to the bucket increase.

\n\n

The name of the bucket used for Transfer Acceleration must be DNS-compliant and must\n not contain periods (\".\").

\n\n

For more information about transfer acceleration, see Transfer Acceleration.

\n\n

The following operations are related to\n PutBucketAccelerateConfiguration:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?accelerate", @@ -9368,9 +10089,16 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } + }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } } } }, @@ -9380,13 +10108,16 @@ "target": "com.amazonaws.s3#PutBucketAclRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Sets the permissions on an existing bucket using access control lists (ACL). For more\n information, see Using ACLs. To set\n the ACL of a bucket, you must have WRITE_ACP permission.

\n\n

You can use one of the following two ways to set a bucket's permissions:

\n \n\n \n

You cannot specify access permission using both the body and the request\n headers.

\n
\n\n

Depending on your application needs, you may choose to set the ACL on a bucket using\n either the request body or the headers. For example, if you have an existing application\n that updates a bucket ACL using the request body, then you can continue to use that\n approach.

\n\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, ACLs are disabled and no longer affect permissions. \n You must use policies to grant access to your bucket and the objects in it. Requests to set ACLs or update ACLs fail and \n return the AccessControlListNotSupported error code. Requests to read ACLs are still supported.\n For more information, see Controlling object ownership\n in the Amazon S3 User Guide.

\n
\n

\n Access Permissions\n

\n

You can set access permissions using one of the following methods:

\n \n

You can use either a canned ACL or specify access permissions explicitly. You cannot do\n both.

\n

\n Grantee Values\n

\n

You can specify the person (grantee) to whom you're assigning access rights (using\n request elements) in the following ways:

\n \n\n\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?acl", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketAclRequest": { @@ -9422,6 +10153,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "GrantFullControl": { "target": "com.amazonaws.s3#GrantFullControl", "traits": { @@ -9460,7 +10198,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9511,7 +10249,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9523,13 +10261,16 @@ "target": "com.amazonaws.s3#PutBucketCorsRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Sets the cors configuration for your bucket. If the configuration exists,\n Amazon S3 replaces it.

\n

To use this operation, you must be allowed to perform the s3:PutBucketCORS\n action. By default, the bucket owner has this permission and can grant it to others.

\n

You set this configuration on a bucket so that the bucket can service cross-origin\n requests. For example, you might want to enable a request whose origin is\n http://www.example.com to access your Amazon S3 bucket at\n my.example.bucket.com by using the browser's XMLHttpRequest\n capability.

\n

To enable cross-origin resource sharing (CORS) on a bucket, you add the\n cors subresource to the bucket. The cors subresource is an XML\n document in which you configure rules that identify origins and the HTTP methods that can\n be executed on your bucket. The document is limited to 64 KB in size.

\n

When Amazon S3 receives a cross-origin request (or a pre-flight OPTIONS request) against a\n bucket, it evaluates the cors configuration on the bucket and uses the first\n CORSRule rule that matches the incoming browser request to enable a\n cross-origin request. For a rule to match, the following conditions must be met:

\n \n

For more information about CORS, go to Enabling\n Cross-Origin Resource Sharing in the Amazon S3 User Guide.

\n \n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?cors", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketCorsRequest": { @@ -9559,10 +10300,17 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9574,13 +10322,16 @@ "target": "com.amazonaws.s3#PutBucketEncryptionRequest" }, "traits": { - "smithy.api#documentation": "

This action uses the encryption subresource to configure default\n encryption and Amazon S3 Bucket Key for an existing bucket.

\n

Default encryption for a bucket can use server-side encryption with Amazon S3-managed keys\n (SSE-S3) or customer managed keys (SSE-KMS). If you specify default encryption\n using SSE-KMS, you can also configure Amazon S3 Bucket Key. For information about default\n encryption, see Amazon S3 default bucket encryption\n in the Amazon S3 User Guide. For more information about S3 Bucket Keys,\n see Amazon S3 Bucket Keys in the Amazon S3 User Guide.

\n \n

This action requires Amazon Web Services Signature Version 4. For more information, see Authenticating Requests (Amazon Web Services Signature\n Version 4).

\n
\n

To use this operation, you must have permissions to perform the\n s3:PutEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3\n Resources in the Amazon S3 User Guide.

\n \n

\n Related Resources\n

\n ", + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, + "smithy.api#documentation": "

This action uses the encryption subresource to configure default\n encryption and Amazon S3 Bucket Key for an existing bucket.

\n

Default encryption for a bucket can use server-side encryption with Amazon S3-managed keys\n (SSE-S3) or customer managed keys (SSE-KMS). If you specify default encryption\n using SSE-KMS, you can also configure Amazon S3 Bucket Key. When the default encryption is SSE-KMS, if\n you upload an object to the bucket and do not specify the KMS key to use for encryption, Amazon S3\n uses the default Amazon Web Services managed KMS key for your account. For information about default\n encryption, see Amazon S3 default bucket encryption\n in the Amazon S3 User Guide. For more information about S3 Bucket Keys,\n see Amazon S3 Bucket Keys in the Amazon S3 User Guide.

\n \n

This action requires Amazon Web Services Signature Version 4. For more information, see Authenticating Requests (Amazon Web Services Signature\n Version 4).

\n
\n

To use this operation, you must have permissions to perform the\n s3:PutEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3\n Resources in the Amazon S3 User Guide.

\n \n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?encryption", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketEncryptionRequest": { @@ -9601,6 +10352,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ServerSideEncryptionConfiguration": { "target": "com.amazonaws.s3#ServerSideEncryptionConfiguration", "traits": { @@ -9612,7 +10370,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9707,7 +10465,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9719,13 +10477,16 @@ "target": "com.amazonaws.s3#PutBucketLifecycleConfigurationRequest" }, "traits": { - "smithy.api#documentation": "

Creates a new lifecycle configuration for the bucket or replaces an existing lifecycle\n configuration. For information about lifecycle configuration, see Managing your storage\n lifecycle.

\n\n \n

Bucket lifecycle configuration now supports specifying a lifecycle rule using an\n object key name prefix, one or more object tags, or a combination of both. Accordingly,\n this section describes the latest API. The previous version of the API supported\n filtering based only on an object key name prefix, which is supported for backward\n compatibility. For the related API description, see PutBucketLifecycle.

\n
\n\n \n\n

\n Rules\n

\n

You specify the lifecycle configuration in your request body. The lifecycle\n configuration is specified as XML consisting of one or more rules. Each rule consists of\n the following:

\n\n \n\n

For more information, see Object\n Lifecycle Management and Lifecycle Configuration Elements.

\n\n\n

\n Permissions\n

\n\n\n

By default, all Amazon S3 resources are private, including buckets, objects, and related\n subresources (for example, lifecycle configuration and website configuration). Only the\n resource owner (that is, the Amazon Web Services account that created it) can access the resource. The\n resource owner can optionally grant access permissions to others by writing an access\n policy. For this operation, a user must get the s3:PutLifecycleConfiguration\n permission.

\n\n

You can also explicitly deny permissions. Explicit deny also supersedes any other\n permissions. If you want to block users or accounts from removing or deleting objects from\n your bucket, you must deny them permissions for the following actions:

\n\n \n\n\n

For more information about permissions, see Managing Access Permissions to Your Amazon S3\n Resources.

\n\n

The following are related to PutBucketLifecycleConfiguration:

\n ", + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, + "smithy.api#documentation": "

Creates a new lifecycle configuration for the bucket or replaces an existing lifecycle\n configuration. Keep in mind that this will overwrite an existing lifecycle configuration, so if\n you want to retain any configuration details, they must be included in the new lifecycle\n configuration. For information about lifecycle configuration, see Managing your storage\n lifecycle.

\n\n \n

Bucket lifecycle configuration now supports specifying a lifecycle rule using an\n object key name prefix, one or more object tags, or a combination of both. Accordingly,\n this section describes the latest API. The previous version of the API supported\n filtering based only on an object key name prefix, which is supported for backward\n compatibility. For the related API description, see PutBucketLifecycle.

\n
\n\n \n\n

\n Rules\n

\n

You specify the lifecycle configuration in your request body. The lifecycle\n configuration is specified as XML consisting of one or more rules. Each rule consists of\n the following:

\n\n \n\n

For more information, see Object\n Lifecycle Management and Lifecycle Configuration Elements.

\n\n\n

\n Permissions\n

\n\n\n

By default, all Amazon S3 resources are private, including buckets, objects, and related\n subresources (for example, lifecycle configuration and website configuration). Only the\n resource owner (that is, the Amazon Web Services account that created it) can access the resource. The\n resource owner can optionally grant access permissions to others by writing an access\n policy. For this operation, a user must get the s3:PutLifecycleConfiguration\n permission.

\n\n

You can also explicitly deny permissions. Explicit deny also supersedes any other\n permissions. If you want to block users or accounts from removing or deleting objects from\n your bucket, you must deny them permissions for the following actions:

\n\n \n\n\n

For more information about permissions, see Managing Access Permissions to Your Amazon S3\n Resources.

\n\n

The following are related to PutBucketLifecycleConfiguration:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?lifecycle", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketLifecycleConfigurationRequest": { @@ -9739,6 +10500,13 @@ "smithy.api#required": {} } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "LifecycleConfiguration": { "target": "com.amazonaws.s3#BucketLifecycleConfiguration", "traits": { @@ -9750,7 +10518,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9762,13 +10530,16 @@ "target": "com.amazonaws.s3#PutBucketLoggingRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Set the logging parameters for a bucket and to specify permissions for who can view and\n modify the logging parameters. All logs are saved to buckets in the same Amazon Web Services Region as the\n source bucket. To set the logging status of a bucket, you must be the bucket owner.

\n\n

The bucket owner is automatically granted FULL_CONTROL to all logs. You use the Grantee request element to grant access to other people. The\n Permissions request element specifies the kind of access the grantee has to\n the logs.

\n \n

If the target bucket for log delivery uses the bucket owner enforced\n setting for S3 Object Ownership, you can't use the Grantee request element\n to grant access to others. Permissions can only be granted using policies. For more information, see Permissions for server access log delivery in the\n Amazon S3 User Guide.

\n
\n\n

\n Grantee Values\n

\n

You can specify the person (grantee) to whom you're assigning access rights (using\n request elements) in the following ways:

\n\n \n\n\n

To enable logging, you use LoggingEnabled and its children request elements. To disable\n logging, you use an empty BucketLoggingStatus request element:

\n\n

\n \n

\n\n

For more information about server access logging, see Server Access Logging in the Amazon S3 User Guide.

\n\n

For more information about creating a bucket, see CreateBucket. For more\n information about returning the logging status of a bucket, see GetBucketLogging.

\n\n

The following operations are related to PutBucketLogging:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?logging", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketLoggingRequest": { @@ -9798,10 +10569,17 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9852,7 +10630,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -9864,7 +10642,7 @@ "target": "com.amazonaws.s3#PutBucketNotificationConfigurationRequest" }, "traits": { - "smithy.api#documentation": "

Enables notifications of specified events for a bucket. For more information about event\n notifications, see Configuring Event\n Notifications.

\n\n

Using this API, you can replace an existing notification configuration. The\n configuration is an XML file that defines the event types that you want Amazon S3 to publish and\n the destination where you want Amazon S3 to publish an event notification when it detects an\n event of the specified type.

\n\n

By default, your bucket has no event notifications configured. That is, the notification\n configuration will be an empty NotificationConfiguration.

\n\n

\n \n

\n

\n \n

\n

This action replaces the existing notification configuration with the configuration\n you include in the request body.

\n\n

After Amazon S3 receives this request, it first verifies that any Amazon Simple Notification\n Service (Amazon SNS) or Amazon Simple Queue Service (Amazon SQS) destination exists, and\n that the bucket owner has permission to publish to it by sending a test notification. In\n the case of Lambda destinations, Amazon S3 verifies that the Lambda function permissions\n grant Amazon S3 permission to invoke the function from the Amazon S3 bucket. For more information,\n see Configuring Notifications for Amazon S3\n Events.

\n\n

You can disable notifications by adding the empty NotificationConfiguration\n element.

\n\n

By default, only the bucket owner can configure notifications on a bucket. However,\n bucket owners can use a bucket policy to grant permission to other users to set this\n configuration with s3:PutBucketNotification permission.

\n\n \n

The PUT notification is an atomic operation. For example, suppose your notification\n configuration includes SNS topic, SQS queue, and Lambda function configurations. When\n you send a PUT request with this configuration, Amazon S3 sends test messages to your SNS\n topic. If the message fails, the entire PUT action will fail, and Amazon S3 will not add\n the configuration to your bucket.

\n
\n\n

\n Responses\n

\n

If the configuration in the request body includes only one\n TopicConfiguration specifying only the\n s3:ReducedRedundancyLostObject event type, the response will also include\n the x-amz-sns-test-message-id header containing the message ID of the test\n notification sent to the topic.

\n\n

The following action is related to\n PutBucketNotificationConfiguration:

\n ", + "smithy.api#documentation": "

Enables notifications of specified events for a bucket. For more information about event\n notifications, see Configuring Event\n Notifications.

\n\n

Using this API, you can replace an existing notification configuration. The\n configuration is an XML file that defines the event types that you want Amazon S3 to publish and\n the destination where you want Amazon S3 to publish an event notification when it detects an\n event of the specified type.

\n\n

By default, your bucket has no event notifications configured. That is, the notification\n configuration will be an empty NotificationConfiguration.

\n\n

\n \n

\n

\n \n

\n

This action replaces the existing notification configuration with the configuration\n you include in the request body.

\n\n

After Amazon S3 receives this request, it first verifies that any Amazon Simple Notification\n Service (Amazon SNS) or Amazon Simple Queue Service (Amazon SQS) destination exists, and\n that the bucket owner has permission to publish to it by sending a test notification. In\n the case of Lambda destinations, Amazon S3 verifies that the Lambda function permissions\n grant Amazon S3 permission to invoke the function from the Amazon S3 bucket. For more information,\n see Configuring Notifications for Amazon S3\n Events.

\n\n

You can disable notifications by adding the empty NotificationConfiguration\n element.

\n

For more information about the number of event notification configurations that you can create per bucket, see\n Amazon S3 service quotas in Amazon Web Services General Reference.

\n

By default, only the bucket owner can configure notifications on a bucket. However,\n bucket owners can use a bucket policy to grant permission to other users to set this\n configuration with s3:PutBucketNotification permission.

\n\n \n

The PUT notification is an atomic operation. For example, suppose your notification\n configuration includes SNS topic, SQS queue, and Lambda function configurations. When\n you send a PUT request with this configuration, Amazon S3 sends test messages to your SNS\n topic. If the message fails, the entire PUT action will fail, and Amazon S3 will not add\n the configuration to your bucket.

\n
\n\n

\n Responses\n

\n

If the configuration in the request body includes only one\n TopicConfiguration specifying only the\n s3:ReducedRedundancyLostObject event type, the response will also include\n the x-amz-sns-test-message-id header containing the message ID of the test\n notification sent to the topic.

\n\n

The following action is related to\n PutBucketNotificationConfiguration:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?notification", @@ -9894,7 +10672,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -9913,13 +10691,15 @@ "target": "com.amazonaws.s3#PutBucketOwnershipControlsRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Creates or modifies OwnershipControls for an Amazon S3 bucket. To use this\n operation, you must have the s3:PutBucketOwnershipControls permission. For\n more information about Amazon S3 permissions, see Specifying permissions in a policy.

\n

For information about Amazon S3 Object Ownership, see Using object ownership.

\n

The following operations are related to PutBucketOwnershipControls:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?ownershipControls", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketOwnershipControlsRequest": { @@ -9943,7 +10723,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -9964,13 +10744,16 @@ "target": "com.amazonaws.s3#PutBucketPolicyRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Applies an Amazon S3 bucket policy to an Amazon S3 bucket. If you are using an identity other than\n the root user of the Amazon Web Services account that owns the bucket, the calling identity must have the\n PutBucketPolicy permissions on the specified bucket and belong to the\n bucket owner's account in order to use this operation.

\n\n

If you don't have PutBucketPolicy permissions, Amazon S3 returns a 403\n Access Denied error. If you have the correct permissions, but you're not using an\n identity that belongs to the bucket owner's account, Amazon S3 returns a 405 Method Not\n Allowed error.

\n\n \n

As a security precaution, the root user of the Amazon Web Services account that owns a bucket can\n always use this operation, even if the policy explicitly denies the root user the\n ability to perform this action.

\n
\n

For more information, see Bucket policy examples.

\n\n

The following operations are related to PutBucketPolicy:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?policy", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketPolicyRequest": { @@ -9991,6 +10774,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ConfirmRemoveSelfBucketAccess": { "target": "com.amazonaws.s3#ConfirmRemoveSelfBucketAccess", "traits": { @@ -10009,7 +10799,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10021,13 +10811,16 @@ "target": "com.amazonaws.s3#PutBucketReplicationRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Creates a replication configuration or replaces an existing one. For more information,\n see Replication in the Amazon S3 User Guide.

\n \n

Specify the replication configuration in the request body. In the replication\n configuration, you provide the name of the destination bucket or buckets where you want\n Amazon S3 to replicate objects, the IAM role that Amazon S3 can assume to replicate objects on your\n behalf, and other relevant information.

\n\n\n

A replication configuration must include at least one rule, and can contain a maximum of\n 1,000. Each rule identifies a subset of objects to replicate by filtering the objects in\n the source bucket. To choose additional subsets of objects to replicate, add a rule for\n each subset.

\n\n

To specify a subset of the objects in the source bucket to apply a replication rule to,\n add the Filter element as a child of the Rule element. You can filter objects based on an\n object key prefix, one or more object tags, or both. When you add the Filter element in the\n configuration, you must also add the following elements:\n DeleteMarkerReplication, Status, and\n Priority.

\n \n

If you are using an earlier version of the replication configuration, Amazon S3 handles\n replication of delete markers differently. For more information, see Backward Compatibility.

\n
\n

For information about enabling versioning on a bucket, see Using Versioning.

\n\n

\n Handling Replication of Encrypted Objects\n

\n

By default, Amazon S3 doesn't replicate objects that are stored at rest using server-side\n encryption with KMS keys. To replicate Amazon Web Services KMS-encrypted objects, add the\n following: SourceSelectionCriteria, SseKmsEncryptedObjects,\n Status, EncryptionConfiguration, and\n ReplicaKmsKeyID. For information about replication configuration, see\n Replicating Objects\n Created with SSE Using KMS keys.

\n\n

For information on PutBucketReplication errors, see List of\n replication-related error codes\n

\n\n

\n Permissions\n

\n

To create a PutBucketReplication request, you must have s3:PutReplicationConfiguration \n permissions for the bucket. \n

\n

By default, a resource owner, in this case the Amazon Web Services account that created the bucket, can\n perform this operation. The resource owner can also grant others permissions to perform the\n operation. For more information about permissions, see Specifying Permissions in a Policy\n and Managing Access Permissions to Your\n Amazon S3 Resources.

\n \n

To perform this operation, the user or role performing the action must have the\n iam:PassRole permission.

\n
\n\n

The following operations are related to PutBucketReplication:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?replication", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketReplicationRequest": { @@ -10048,6 +10841,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ReplicationConfiguration": { "target": "com.amazonaws.s3#ReplicationConfiguration", "traits": { @@ -10066,7 +10866,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10078,13 +10878,16 @@ "target": "com.amazonaws.s3#PutBucketRequestPaymentRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Sets the request payment configuration for a bucket. By default, the bucket owner pays\n for downloads from the bucket. This configuration parameter enables the bucket owner (only)\n to specify that the person requesting the download will be charged for the download. For\n more information, see Requester Pays\n Buckets.

\n\n

The following operations are related to PutBucketRequestPayment:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?requestPayment", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketRequestPaymentRequest": { @@ -10105,6 +10908,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "RequestPaymentConfiguration": { "target": "com.amazonaws.s3#RequestPaymentConfiguration", "traits": { @@ -10117,7 +10927,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10129,13 +10939,16 @@ "target": "com.amazonaws.s3#PutBucketTaggingRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Sets the tags for a bucket.

\n

Use tags to organize your Amazon Web Services bill to reflect your own cost structure. To do this, sign\n up to get your Amazon Web Services account bill with tag key values included. Then, to see the cost of\n combined resources, organize your billing information according to resources with the same\n tag key values. For example, you can tag several resources with a specific application\n name, and then organize your billing information to see the total cost of that application\n across several services. For more information, see Cost Allocation\n and Tagging and Using Cost Allocation in Amazon S3 Bucket\n Tags.

\n\n \n

\n When this operation sets the tags for a bucket, it will overwrite any current tags the \n bucket already has. You cannot use this operation to add tags to an existing list of tags.

\n
\n

To use this operation, you must have permissions to perform the\n s3:PutBucketTagging action. The bucket owner has this permission by default\n and can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3\n Resources.

\n\n

\n PutBucketTagging has the following special errors:

\n \n\n\n

The following operations are related to PutBucketTagging:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?tagging", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketTaggingRequest": { @@ -10156,6 +10969,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "Tagging": { "target": "com.amazonaws.s3#Tagging", "traits": { @@ -10168,7 +10988,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10180,13 +11000,16 @@ "target": "com.amazonaws.s3#PutBucketVersioningRequest" }, "traits": { - "smithy.api#documentation": "

Sets the versioning state of an existing bucket. To set the versioning state, you must\n be the bucket owner.

\n

You can set the versioning state with one of the following values:

\n\n

\n Enabled—Enables versioning for the objects in the\n bucket. All objects added to the bucket receive a unique version ID.

\n\n

\n Suspended—Disables versioning for the objects in the\n bucket. All objects added to the bucket receive the version ID null.

\n\n

If the versioning state has never been set on a bucket, it has no versioning state; a\n GetBucketVersioning request does not return a versioning state value.

\n\n

If the bucket owner enables MFA Delete in the bucket versioning configuration, the\n bucket owner must include the x-amz-mfa request header and the\n Status and the MfaDelete request elements in a request to set\n the versioning state of the bucket.

\n\n \n

If you have an object expiration lifecycle policy in your non-versioned bucket and\n you want to maintain the same permanent delete behavior when you enable versioning, you\n must add a noncurrent expiration policy. The noncurrent expiration lifecycle policy will\n manage the deletes of the noncurrent object versions in the version-enabled bucket. (A\n version-enabled bucket maintains one current and zero or more noncurrent object\n versions.) For more information, see Lifecycle and Versioning.

\n
\n\n

\n Related Resources\n

\n ", + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, + "smithy.api#documentation": "

Sets the versioning state of an existing bucket.

\n

You can set the versioning state with one of the following values:

\n\n

\n Enabled—Enables versioning for the objects in the\n bucket. All objects added to the bucket receive a unique version ID.

\n\n

\n Suspended—Disables versioning for the objects in the\n bucket. All objects added to the bucket receive the version ID null.

\n\n

If the versioning state has never been set on a bucket, it has no versioning state; a\n GetBucketVersioning request does not return a versioning state value.

\n\n

In order to enable MFA Delete, you must be the bucket owner. If you are the bucket owner\n and want to enable MFA Delete in the bucket versioning configuration, you must\n include the x-amz-mfa request header and the\n Status and the MfaDelete request elements in a request to set\n the versioning state of the bucket.

\n\n \n

If you have an object expiration lifecycle policy in your non-versioned bucket and\n you want to maintain the same permanent delete behavior when you enable versioning, you\n must add a noncurrent expiration policy. The noncurrent expiration lifecycle policy will\n manage the deletes of the noncurrent object versions in the version-enabled bucket. (A\n version-enabled bucket maintains one current and zero or more noncurrent object\n versions.) For more information, see Lifecycle and Versioning.

\n
\n\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?versioning", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketVersioningRequest": { @@ -10207,6 +11030,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "MFA": { "target": "com.amazonaws.s3#MFA", "traits": { @@ -10226,7 +11056,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10238,13 +11068,16 @@ "target": "com.amazonaws.s3#PutBucketWebsiteRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Sets the configuration of the website that is specified in the website\n subresource. To configure a bucket as a website, you can add this subresource on the bucket\n with website configuration information such as the file name of the index document and any\n redirect rules. For more information, see Hosting Websites on Amazon S3.

\n\n

This PUT action requires the S3:PutBucketWebsite permission. By default,\n only the bucket owner can configure the website attached to a bucket; however, bucket\n owners can allow other users to set the website configuration by writing a bucket policy\n that grants them the S3:PutBucketWebsite permission.

\n\n

To redirect all website requests sent to the bucket's website endpoint, you add a\n website configuration with the following elements. Because all requests are sent to another\n website, you don't need to provide index document name for the bucket.

\n \n\n

If you want granular control over redirects, you can use the following elements to add\n routing rules that describe conditions for redirecting requests and information about the\n redirect destination. In this case, the website configuration must provide an index\n document for the bucket, because some requests might not be redirected.

\n \n\n

Amazon S3 has a limitation of 50 routing rules per website configuration. If you require more\n than 50 routing rules, you can use object redirect. For more information, see Configuring an\n Object Redirect in the Amazon S3 User Guide.

", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?website", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutBucketWebsiteRequest": { @@ -10265,6 +11098,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "WebsiteConfiguration": { "target": "com.amazonaws.s3#WebsiteConfiguration", "traits": { @@ -10277,7 +11117,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10292,6 +11132,9 @@ "target": "com.amazonaws.s3#PutObjectOutput" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm" + }, "smithy.api#documentation": "

Adds an object to a bucket. You must have WRITE permissions on a bucket to add an object\n to it.

\n\n\n

Amazon S3 never adds partial objects; if you receive a success response, Amazon S3 added the\n entire object to the bucket.

\n\n

Amazon S3 is a distributed system. If it receives multiple write requests for the same object\n simultaneously, it overwrites all but the last object written. Amazon S3 does not provide object\n locking; if you need this, make sure to build it into your application layer or use\n versioning instead.

\n\n

To ensure that data is not corrupted traversing the network, use the\n Content-MD5 header. When you use this header, Amazon S3 checks the object\n against the provided MD5 value and, if they do not match, returns an error. Additionally,\n you can calculate the MD5 while putting an object to Amazon S3 and compare the returned ETag to\n the calculated MD5 value.

\n \n \n \n

\n Server-side Encryption\n

\n

You can optionally request server-side encryption. With server-side encryption, Amazon S3 encrypts \n your data as it writes it to disks in its data centers and decrypts the data\n when you access it. You have the option to provide your own encryption key or use Amazon Web Services\n managed encryption keys (SSE-S3 or SSE-KMS). For more information, see Using Server-Side\n Encryption.

\n

If you request server-side encryption using Amazon Web Services Key Management Service (SSE-KMS), you can enable \n an S3 Bucket Key at the object-level. For more information, see Amazon S3 Bucket Keys in the \n Amazon S3 User Guide.

\n

\n Access Control List (ACL)-Specific Request\n Headers\n

\n

You can use headers to grant ACL- based permissions. By default, all objects are\n private. Only the owner has full access control. When adding a new object, you can grant\n permissions to individual Amazon Web Services accounts or to predefined groups defined by Amazon S3. These\n permissions are then added to the ACL on the object. For more information, see Access Control List\n (ACL) Overview and Managing ACLs Using the REST\n API.

\n

If the bucket that you're uploading objects to uses the bucket owner enforced setting\n for S3 Object Ownership, ACLs are disabled and no longer affect permissions. Buckets that\n use this setting only accept PUT requests that don't specify an ACL or PUT requests that\n specify bucket owner full control ACLs, such as the bucket-owner-full-control canned\n ACL or an equivalent form of this ACL expressed in the XML format. PUT requests that contain other\n ACLs (for example, custom grants to certain Amazon Web Services accounts) fail and return a\n 400 error with the error code\n AccessControlListNotSupported.

\n

For more information, see Controlling ownership of\n objects and disabling ACLs in the Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for Object Ownership, \n all objects written to the bucket by any account will be owned by the bucket owner.

\n
\n

\n Storage Class Options\n

\n

By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The\n STANDARD storage class provides high durability and high availability. Depending on\n performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses\n the OUTPOSTS Storage Class. For more information, see Storage Classes in the\n Amazon S3 User Guide.

\n\n\n

\n Versioning\n

\n

If you enable versioning for a bucket, Amazon S3 automatically generates a unique version ID\n for the object being stored. Amazon S3 returns this ID in the response. When you enable\n versioning for a bucket, if Amazon S3 receives multiple write requests for the same object\n simultaneously, it stores all of the objects.

\n

For more information about versioning, see Adding Objects to\n Versioning Enabled Buckets. For information about returning the versioning state\n of a bucket, see GetBucketVersioning.

\n\n\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", @@ -10314,13 +11157,16 @@ } ], "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Uses the acl subresource to set the access control list (ACL) permissions\n for a new or existing object in an S3 bucket. You must have WRITE_ACP\n permission to set the ACL of an object. For more information, see What\n permissions can I grant? in the Amazon S3 User Guide.

\n

This action is not supported by Amazon S3 on Outposts.

\n

Depending on your application needs, you can choose to set\n the ACL on an object using either the request body or the headers. For example, if you have\n an existing application that updates a bucket ACL using the request body, you can continue\n to use that approach. For more information, see Access Control List (ACL) Overview in the Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, ACLs are disabled and no longer affect permissions. \n You must use policies to grant access to your bucket and the objects in it. Requests to set ACLs or update ACLs fail and \n return the AccessControlListNotSupported error code. Requests to read ACLs are still supported.\n For more information, see Controlling object ownership\n in the Amazon S3 User Guide.

\n
\n\n

\n Access Permissions\n

\n

You can set access permissions using one of the following methods:

\n \n

You can use either a canned ACL or specify access permissions explicitly. You cannot do\n both.

\n

\n Grantee Values\n

\n

You can specify the person (grantee) to whom you're assigning access rights (using\n request elements) in the following ways:

\n \n

\n Versioning\n

\n

The ACL of an object is set at the object version level. By default, PUT sets the ACL of\n the current version of an object. To set the ACL of a different version, use the\n versionId subresource.

\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?acl", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutObjectAclOutput": { @@ -10367,6 +11213,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "GrantFullControl": { "target": "com.amazonaws.s3#GrantFullControl", "traits": { @@ -10405,7 +11258,7 @@ "Key": { "target": "com.amazonaws.s3#ObjectKey", "traits": { - "smithy.api#documentation": "

Key for which the PUT action was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Key for which the PUT action was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -10426,7 +11279,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10441,13 +11294,16 @@ "target": "com.amazonaws.s3#PutObjectLegalHoldOutput" }, "traits": { - "smithy.api#documentation": "

Applies a Legal Hold configuration to the specified object. For more information, see\n Locking\n Objects.

\n

This action is not supported by Amazon S3 on Outposts.

", + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, + "smithy.api#documentation": "

Applies a legal hold configuration to the specified object. For more information, see\n Locking\n Objects.

\n

This action is not supported by Amazon S3 on Outposts.

", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?legal-hold", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutObjectLegalHoldOutput": { @@ -10467,7 +11323,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object that you want to place a Legal Hold on.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object that you want to place a legal hold on.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -10475,7 +11331,7 @@ "Key": { "target": "com.amazonaws.s3#ObjectKey", "traits": { - "smithy.api#documentation": "

The key name for the object that you want to place a Legal Hold on.

", + "smithy.api#documentation": "

The key name for the object that you want to place a legal hold on.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -10483,7 +11339,7 @@ "LegalHold": { "target": "com.amazonaws.s3#ObjectLockLegalHold", "traits": { - "smithy.api#documentation": "

Container element for the Legal Hold configuration you want to apply to the specified\n object.

", + "smithy.api#documentation": "

Container element for the legal hold configuration you want to apply to the specified\n object.

", "smithy.api#httpPayload": {}, "smithy.api#xmlName": "LegalHold" } @@ -10497,7 +11353,7 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

The version ID of the object that you want to place a Legal Hold on.

", + "smithy.api#documentation": "

The version ID of the object that you want to place a legal hold on.

", "smithy.api#httpQuery": "versionId" } }, @@ -10508,10 +11364,17 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10526,13 +11389,16 @@ "target": "com.amazonaws.s3#PutObjectLockConfigurationOutput" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Places an Object Lock configuration on the specified bucket. The rule specified in the\n Object Lock configuration will be applied by default to every new object placed in the\n specified bucket. For more information, see Locking Objects.\n

\n \n \n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?object-lock", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutObjectLockConfigurationOutput": { @@ -10585,10 +11451,17 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10600,7 +11473,7 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the expiration is configured for the object (see PutBucketLifecycleConfiguration), the response includes this header. It\n includes the expiry-date and rule-id key-value pairs that provide information about object\n expiration. The value of the rule-id is URL encoded.

", + "smithy.api#documentation": "

If the expiration is configured for the object (see PutBucketLifecycleConfiguration), the response includes this header. It\n includes the expiry-date and rule-id key-value pairs that provide\n information about object expiration. The value of the rule-id is\n URL-encoded.

", "smithy.api#httpHeader": "x-amz-expiration" } }, @@ -10611,6 +11484,34 @@ "smithy.api#httpHeader": "ETag" } }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha256" + } + }, "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { @@ -10688,7 +11589,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name to which the PUT action was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name to which the PUT action was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -10742,6 +11643,41 @@ "smithy.api#httpHeader": "Content-Type" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32C checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 160-bit SHA-1 digest of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha256" + } + }, "Expires": { "target": "com.amazonaws.s3#Expires", "traits": { @@ -10892,7 +11828,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10907,13 +11843,16 @@ "target": "com.amazonaws.s3#PutObjectRetentionOutput" }, "traits": { - "smithy.api#documentation": "

Places an Object Retention configuration on an object. For more information, see Locking Objects.\n Users or accounts require the s3:PutObjectRetention permission in order to place\n an Object Retention configuration on objects. Bypassing a Governance Retention configuration\n requires the s3:BypassGovernanceRetention permission.\n

\n

This action is not supported by Amazon S3 on Outposts.

\n\n

\n Permissions\n

\n

When the Object Lock retention mode is set to compliance, you need s3:PutObjectRetention and \n s3:BypassGovernanceRetention permissions. For other requests to PutObjectRetention, \n only s3:PutObjectRetention permissions are required.

", + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, + "smithy.api#documentation": "

Places an Object Retention configuration on an object. For more information, see Locking Objects.\n Users or accounts require the s3:PutObjectRetention permission in order to place\n an Object Retention configuration on objects. Bypassing a Governance Retention configuration\n requires the s3:BypassGovernanceRetention permission.\n

\n

This action is not supported by Amazon S3 on Outposts.

", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?retention", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutObjectRetentionOutput": { @@ -10981,10 +11920,17 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -10999,13 +11945,16 @@ "target": "com.amazonaws.s3#PutObjectTaggingOutput" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Sets the supplied tag-set to an object that already exists in a bucket.

\n

A tag is a key-value pair. You can associate tags with an object by sending a PUT\n request against the tagging subresource that is associated with the object. You can\n retrieve tags by sending a GET request. For more information, see GetObjectTagging.

\n\n

For tagging-related restrictions related to characters and encodings, see Tag\n Restrictions. Note that Amazon S3 limits the maximum number of tags to 10 tags per\n object.

\n\n

To use this operation, you must have permission to perform the\n s3:PutObjectTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n\n

To put tags of any other version, use the versionId query parameter. You\n also need permission for the s3:PutObjectVersionTagging action.

\n\n

For information about the Amazon S3 object tagging feature, see Object Tagging.

\n\n\n

\n Special Errors\n

\n \n\n \n\n\n\n\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?tagging", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutObjectTaggingOutput": { @@ -11026,7 +11975,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -11053,6 +12002,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "Tagging": { "target": "com.amazonaws.s3#Tagging", "traits": { @@ -11065,7 +12021,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -11083,13 +12039,16 @@ "target": "com.amazonaws.s3#PutPublicAccessBlockRequest" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm", + "requestChecksumRequired": true + }, "smithy.api#documentation": "

Creates or modifies the PublicAccessBlock configuration for an Amazon S3 bucket.\n To use this operation, you must have the s3:PutBucketPublicAccessBlock\n permission. For more information about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n\n \n

When Amazon S3 evaluates the PublicAccessBlock configuration for a bucket or\n an object, it checks the PublicAccessBlock configuration for both the\n bucket (or the bucket that contains the object) and the bucket owner's account. If the\n PublicAccessBlock configurations are different between the bucket and\n the account, Amazon S3 uses the most restrictive combination of the bucket-level and\n account-level settings.

\n
\n\n\n

For more information about when Amazon S3 considers a bucket or an object public, see The Meaning of \"Public\".

\n\n\n\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?publicAccessBlock", "code": 200 - }, - "smithy.api#httpChecksumRequired": {} + } } }, "com.amazonaws.s3#PutPublicAccessBlockRequest": { @@ -11110,6 +12069,13 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "PublicAccessBlockConfiguration": { "target": "com.amazonaws.s3#PublicAccessBlockConfiguration", "traits": { @@ -11122,7 +12088,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -11552,7 +12518,7 @@ "com.amazonaws.s3#RequestPayer": { "type": "string", "traits": { - "smithy.api#documentation": "

Confirms that the requester knows that they will be charged for the request. Bucket\n owners need not specify this parameter in their requests. For information about downloading\n objects from requester pays buckets, see Downloading Objects in\n Requestor Pays Buckets in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Confirms that the requester knows that they will be charged for the request. Bucket\n owners need not specify this parameter in their requests. For information about downloading\n objects from Requester Pays buckets, see Downloading Objects in\n Requester Pays Buckets in the Amazon S3 User Guide.

", "smithy.api#enum": [ { "value": "requester", @@ -11634,7 +12600,10 @@ } ], "traits": { - "smithy.api#documentation": "

Restores an archived copy of an object back into Amazon S3

\n

This action is not supported by Amazon S3 on Outposts.

\n

This action performs the following types of requests:

\n \n

To use this operation, you must have permissions to perform the\n s3:RestoreObject action. The bucket owner has this permission by default\n and can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3\n Resources in the Amazon S3 User Guide.

\n

\n Querying Archives with Select Requests\n

\n

You use a select type of request to perform SQL queries on archived objects. The\n archived objects that are being queried by the select request must be formatted as\n uncompressed comma-separated values (CSV) files. You can run queries and custom analytics\n on your archived data without having to restore your data to a hotter Amazon S3 tier. For an\n overview about select requests, see Querying Archived Objects in the Amazon S3 User Guide.

\n

When making a select request, do the following:

\n \n

For more information about using SQL with S3 Glacier Select restore, see SQL Reference for Amazon S3 Select and\n S3 Glacier Select in the Amazon S3 User Guide.

\n

When making a select request, you can also do the following:

\n \n

The following are additional important facts about the select feature:

\n \n

\n Restoring objects\n

\n

Objects that you archive to the S3 Glacier or\n S3 Glacier Deep Archive storage class, and S3 Intelligent-Tiering Archive or\n S3 Intelligent-Tiering Deep Archive tiers are not accessible in real time. For objects in\n Archive Access or Deep Archive Access tiers you must first initiate a restore request, and\n then wait until the object is moved into the Frequent Access tier. For objects in\n S3 Glacier or S3 Glacier Deep Archive storage classes you must\n first initiate a restore request, and then wait until a temporary copy of the object is\n available. To access an archived object, you must restore the object for the duration\n (number of days) that you specify.

\n

To restore a specific object version, you can provide a version ID. If you don't provide\n a version ID, Amazon S3 restores the current version.

\n

When restoring an archived object (or using a select request), you can specify one of\n the following data access tier options in the Tier element of the request\n body:

\n \n

For more information about archive retrieval options and provisioned capacity for\n Expedited data access, see Restoring Archived Objects in the Amazon S3 User Guide.

\n

You can use Amazon S3 restore speed upgrade to change the restore speed to a faster speed\n while it is in progress. For more information, see \n Upgrading the speed of an in-progress restore in the\n Amazon S3 User Guide.

\n

To get the status of object restoration, you can send a HEAD request.\n Operations return the x-amz-restore header, which provides information about\n the restoration status, in the response. You can use Amazon S3 event notifications to notify you\n when a restore is initiated or completed. For more information, see Configuring Amazon S3 Event Notifications in\n the Amazon S3 User Guide.

\n

After restoring an archived object, you can update the restoration period by reissuing\n the request with a new period. Amazon S3 updates the restoration period relative to the current\n time and charges only for the request-there are no data transfer charges. You cannot\n update the restoration period when Amazon S3 is actively processing your current restore request\n for the object.

\n

If your bucket has a lifecycle configuration with a rule that includes an expiration\n action, the object expiration overrides the life span that you specify in a restore\n request. For example, if you restore an object copy for 10 days, but the object is\n scheduled to expire in 3 days, Amazon S3 deletes the object in 3 days. For more information\n about lifecycle configuration, see PutBucketLifecycleConfiguration and Object Lifecycle Management in\n Amazon S3 User Guide.

\n

\n Responses\n

\n

A successful action returns either the 200 OK or 202\n Accepted status code.

\n \n

\n Special Errors\n

\n \n \n

\n Related Resources\n

\n ", + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm" + }, + "smithy.api#documentation": "

Restores an archived copy of an object back into Amazon S3

\n

This action is not supported by Amazon S3 on Outposts.

\n

This action performs the following types of requests:

\n \n

To use this operation, you must have permissions to perform the\n s3:RestoreObject action. The bucket owner has this permission by default\n and can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3\n Resources in the Amazon S3 User Guide.

\n

\n Querying Archives with Select Requests\n

\n

You use a select type of request to perform SQL queries on archived objects. The\n archived objects that are being queried by the select request must be formatted as\n uncompressed comma-separated values (CSV) files. You can run queries and custom analytics\n on your archived data without having to restore your data to a hotter Amazon S3 tier. For an\n overview about select requests, see Querying Archived Objects in the Amazon S3 User Guide.

\n

When making a select request, do the following:

\n \n

For more information about using SQL with S3 Glacier Select restore, see SQL Reference for Amazon S3 Select and\n S3 Glacier Select in the Amazon S3 User Guide.

\n

When making a select request, you can also do the following:

\n \n

The following are additional important facts about the select feature:

\n \n

\n Restoring objects\n

\n

Objects that you archive to the S3 Glacier or\n S3 Glacier Deep Archive storage class, and S3 Intelligent-Tiering Archive or\n S3 Intelligent-Tiering Deep Archive tiers are not accessible in real time. For objects in\n Archive Access or Deep Archive Access tiers you must first initiate a restore request, and\n then wait until the object is moved into the Frequent Access tier. For objects in\n S3 Glacier or S3 Glacier Deep Archive storage classes you must\n first initiate a restore request, and then wait until a temporary copy of the object is\n available. To access an archived object, you must restore the object for the duration\n (number of days) that you specify.

\n

To restore a specific object version, you can provide a version ID. If you don't provide\n a version ID, Amazon S3 restores the current version.

\n

When restoring an archived object (or using a select request), you can specify one of\n the following data access tier options in the Tier element of the request\n body:

\n \n

For more information about archive retrieval options and provisioned capacity for\n Expedited data access, see Restoring Archived Objects in the Amazon S3 User Guide.

\n

You can use Amazon S3 restore speed upgrade to change the restore speed to a faster speed\n while it is in progress. For more information, see \n Upgrading the speed of an in-progress restore in the\n Amazon S3 User Guide.

\n

To get the status of object restoration, you can send a HEAD request.\n Operations return the x-amz-restore header, which provides information about\n the restoration status, in the response. You can use Amazon S3 event notifications to notify you\n when a restore is initiated or completed. For more information, see Configuring Amazon S3 Event Notifications in\n the Amazon S3 User Guide.

\n

After restoring an archived object, you can update the restoration period by reissuing\n the request with a new period. Amazon S3 updates the restoration period relative to the current\n time and charges only for the request-there are no data transfer charges. You cannot\n update the restoration period when Amazon S3 is actively processing your current restore request\n for the object.

\n

If your bucket has a lifecycle configuration with a rule that includes an expiration\n action, the object expiration overrides the life span that you specify in a restore\n request. For example, if you restore an object copy for 10 days, but the object is\n scheduled to expire in 3 days, Amazon S3 deletes the object in 3 days. For more information\n about lifecycle configuration, see PutBucketLifecycleConfiguration and Object Lifecycle Management in\n Amazon S3 User Guide.

\n

\n Responses\n

\n

A successful action returns either the 200 OK or 202\n Accepted status code.

\n \n

\n Special Errors\n

\n \n \n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "POST", "uri": "/{Bucket}/{Key+}?restore&x-id=RestoreObject", @@ -11666,7 +12635,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object to restore.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object to restore.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -11699,10 +12668,17 @@ "smithy.api#httpHeader": "x-amz-request-payer" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -11929,7 +12905,7 @@ "Start": { "target": "com.amazonaws.s3#Start", "traits": { - "smithy.api#documentation": "

Specifies the start of the byte range. This parameter is optional. Valid values:\n non-negative integers. The default value is 0. If only start is supplied, it means scan\n from that point to the end of the file.For example;\n 50 means scan\n from byte 50 until the end of the file.

" + "smithy.api#documentation": "

Specifies the start of the byte range. This parameter is optional. Valid values:\n non-negative integers. The default value is 0. If only start is supplied, it\n means scan from that point to the end of the file. For example,\n 50 means scan\n from byte 50 until the end of the file.

" } }, "End": { @@ -12033,21 +13009,21 @@ "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

The SSE Algorithm used to encrypt the object. For more information, see Server-Side Encryption (Using Customer-Provided Encryption Keys.

", + "smithy.api#documentation": "

The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object was created \n using a checksum algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

The SSE Customer Key. For more information, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys.

", + "smithy.api#documentation": "

The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm. \n For more information, see\n Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

The SSE Customer Key MD5. For more information, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys.

", + "smithy.api#documentation": "

The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum \n algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, @@ -12094,7 +13070,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -12716,6 +13692,9 @@ "target": "com.amazonaws.s3#UploadPartOutput" }, "traits": { + "aws.protocols#httpChecksum": { + "requestAlgorithmMember": "ChecksumAlgorithm" + }, "smithy.api#documentation": "

Uploads a part in a multipart upload.

\n \n

In this operation, you provide part data in your request. However, you have an option\n to specify your existing Amazon S3 object as a data source for the part you are uploading. To\n upload a part from an existing object, you use the UploadPartCopy operation.\n

\n
\n\n

You must initiate a multipart upload (see CreateMultipartUpload)\n before you can upload any part. In response to your initiate request, Amazon S3 returns an\n upload ID, a unique identifier, that you must include in your upload part request.

\n

Part numbers can be any number from 1 to 10,000, inclusive. A part number uniquely\n identifies a part and also defines its position within the object being created. If you\n upload a new part using the same part number that was used with a previous part, the\n previously uploaded part is overwritten. Each part must be at least 5 MB in size, except\n the last part. There is no size limit on the last part of your multipart upload.

\n

To ensure that data is not corrupted when traversing the network, specify the\n Content-MD5 header in the upload part request. Amazon S3 checks the part data\n against the provided MD5 value. If they do not match, Amazon S3 returns an error.

\n\n

If the upload request is signed with Signature Version 4, then Amazon Web Services S3 uses the\n x-amz-content-sha256 header as a checksum instead of\n Content-MD5. For more information see Authenticating Requests: Using the Authorization Header (Amazon Web Services Signature Version\n 4).

\n\n\n\n

\n Note: After you initiate multipart upload and upload\n one or more parts, you must either complete or abort multipart upload in order to stop\n getting charged for storage of the uploaded parts. Only after you either complete or abort\n multipart upload, Amazon S3 frees up the parts storage and stops charging you for the parts\n storage.

\n\n

For more information on multipart uploads, go to Multipart Upload Overview in the\n Amazon S3 User Guide .

\n

For information on the permissions required to use the multipart upload API, go to\n Multipart Upload and\n Permissions in the Amazon S3 User Guide.

\n\n

You can optionally request server-side encryption where Amazon S3 encrypts your data as it\n writes it to disks in its data centers and decrypts it for you when you access it. You have\n the option of providing your own encryption key, or you can use the Amazon Web Services managed encryption\n keys. If you choose to provide your own encryption key, the request headers you provide in\n the request must match the headers you used in the request to initiate the upload by using\n CreateMultipartUpload. For more information, go to Using Server-Side Encryption in\n the Amazon S3 User Guide.

\n\n

Server-side encryption is supported by the S3 Multipart Upload actions. Unless you are\n using a customer-provided encryption key, you don't need to specify the encryption\n parameters in each UploadPart request. Instead, you only need to specify the server-side\n encryption parameters in the initial Initiate Multipart request. For more information, see\n CreateMultipartUpload.

\n\n

If you requested server-side encryption using a customer-provided encryption key in your\n initiate multipart upload request, you must provide identical encryption information in\n each part upload using the following headers.

\n\n\n \n\n

\n Special Errors\n

\n \n\n \n\n\n\n\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", @@ -12733,7 +13712,7 @@ "target": "com.amazonaws.s3#UploadPartCopyOutput" }, "traits": { - "smithy.api#documentation": "

Uploads a part by copying data from an existing object as data source. You specify the\n data source by adding the request header x-amz-copy-source in your request and\n a byte range by adding the request header x-amz-copy-source-range in your\n request.

\n

The minimum allowable part size for a multipart upload is 5 MB. For more information\n about multipart upload limits, go to Quick\n Facts in the Amazon S3 User Guide.

\n \n

Instead of using an existing object as part data, you might use the UploadPart\n action and provide data in your request.

\n
\n\n

You must initiate a multipart upload before you can upload any part. In response to your\n initiate request. Amazon S3 returns a unique identifier, the upload ID, that you must include in\n your upload part request.

\n

For more information about using the UploadPartCopy operation, see the\n following:

\n\n \n

Note the following additional considerations about the request headers\n x-amz-copy-source-if-match, x-amz-copy-source-if-none-match,\n x-amz-copy-source-if-unmodified-since, and\n x-amz-copy-source-if-modified-since:

\n

\n \n

\n Versioning\n

\n

If your bucket has versioning enabled, you could have multiple versions of the same\n object. By default, x-amz-copy-source identifies the current version of the\n object to copy. If the current version is a delete marker and you don't specify a versionId\n in the x-amz-copy-source, Amazon S3 returns a 404 error, because the object does\n not exist. If you specify versionId in the x-amz-copy-source and the versionId\n is a delete marker, Amazon S3 returns an HTTP 400 error, because you are not allowed to specify\n a delete marker as a version for the x-amz-copy-source.

\n

You can optionally specify a specific version of the source object to copy by adding the\n versionId subresource as shown in the following example:

\n

\n x-amz-copy-source: /bucket/object?versionId=version id\n

\n\n

\n Special Errors\n

\n \n\n \n\n\n\n\n

\n Related Resources\n

\n ", + "smithy.api#documentation": "

Uploads a part by copying data from an existing object as data source. You specify the\n data source by adding the request header x-amz-copy-source in your request and\n a byte range by adding the request header x-amz-copy-source-range in your\n request.

\n

The minimum allowable part size for a multipart upload is 5 MB. For more information\n about multipart upload limits, go to Quick\n Facts in the Amazon S3 User Guide.

\n \n

Instead of using an existing object as part data, you might use the UploadPart\n action and provide data in your request.

\n
\n\n

You must initiate a multipart upload before you can upload any part. In response to your\n initiate request. Amazon S3 returns a unique identifier, the upload ID, that you must include in\n your upload part request.

\n

For more information about using the UploadPartCopy operation, see the\n following:

\n\n \n

Note the following additional considerations about the request headers\n x-amz-copy-source-if-match, x-amz-copy-source-if-none-match,\n x-amz-copy-source-if-unmodified-since, and\n x-amz-copy-source-if-modified-since:

\n

\n \n

\n Versioning\n

\n

If your bucket has versioning enabled, you could have multiple versions of the same\n object. By default, x-amz-copy-source identifies the current version of the\n object to copy. If the current version is a delete marker and you don't specify a versionId\n in the x-amz-copy-source, Amazon S3 returns a 404 error, because the object does\n not exist. If you specify versionId in the x-amz-copy-source and the versionId\n is a delete marker, Amazon S3 returns an HTTP 400 error, because you are not allowed to specify\n a delete marker as a version for the x-amz-copy-source.

\n

You can optionally specify a specific version of the source object to copy by adding the\n versionId subresource as shown in the following example:

\n

\n x-amz-copy-source: /bucket/object?versionId=version id\n

\n\n

\n Special Errors\n

\n \n\n \n\n\n\n\n

\n Related Resources\n

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?x-id=UploadPartCopy", @@ -12807,7 +13786,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -12815,7 +13794,7 @@ "CopySource": { "target": "com.amazonaws.s3#CopySource", "traits": { - "smithy.api#documentation": "

Specifies the source object for the copy operation. You specify the value in one of two\n formats, depending on whether you want to access the source object through an access point:

\n \n

To copy a specific version of an object, append ?versionId=\n to the value (for example,\n awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n If you don't specify a version ID, Amazon S3 copies the latest version of the source\n object.

", + "smithy.api#documentation": "

Specifies the source object for the copy operation. You specify the value in one of two\n formats, depending on whether you want to access the source object through an access point:

\n \n

To copy a specific version of an object, append ?versionId=\n to the value (for example,\n awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n If you don't specify a version ID, Amazon S3 copies the latest version of the source\n object.

", "smithy.api#httpHeader": "x-amz-copy-source", "smithy.api#required": {} } @@ -12930,14 +13909,14 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "ExpectedSourceBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-source-expected-bucket-owner" } } @@ -12960,6 +13939,34 @@ "smithy.api#httpHeader": "ETag" } }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha256" + } + }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { @@ -13009,7 +14016,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action using S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using S3 on Outposts in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {} } @@ -13028,6 +14035,41 @@ "smithy.api#httpHeader": "Content-MD5" } }, + "ChecksumAlgorithm": { + "target": "com.amazonaws.s3#ChecksumAlgorithm", + "traits": { + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

\n

This checksum algorithm must be the same for all parts and it match the checksum\n value supplied in the CreateMultipartUpload request.

", + "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" + } + }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 32-bit CRC32C checksum of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 160-bit SHA-1 digest of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the same data that was originally sent.\n This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more information, see\n Checking object integrity in the\n Amazon S3 User Guide.

", + "smithy.api#httpHeader": "x-amz-checksum-sha256" + } + }, "Key": { "target": "com.amazonaws.s3#ObjectKey", "traits": { @@ -13082,7 +14124,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP 403 (Access Denied) error.

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -13213,14 +14255,14 @@ "StatusCode": { "target": "com.amazonaws.s3#GetObjectResponseStatusCode", "traits": { - "smithy.api#documentation": "

The integer status code for an HTTP response of a corresponding GetObject\n request.

\n

\n Status Codes\n

\n ", + "smithy.api#documentation": "

The integer status code for an HTTP response of a corresponding GetObject\n request.

\n

\n Status Codes\n

\n ", "smithy.api#httpHeader": "x-amz-fwd-status" } }, "ErrorCode": { "target": "com.amazonaws.s3#ErrorCode", "traits": { - "smithy.api#documentation": "

A string that uniquely identifies an error condition. Returned in the tag\n of the error XML response for a corresponding GetObject call. Cannot be used\n with a successful StatusCode header or when the transformed object is provided\n in the body. All error codes from S3 are sentence-cased. Regex value is \"^[A-Z][a-zA-Z]+$\".

", + "smithy.api#documentation": "

A string that uniquely identifies an error condition. Returned in the tag\n of the error XML response for a corresponding GetObject call. Cannot be used\n with a successful StatusCode header or when the transformed object is provided\n in the body. All error codes from S3 are sentence-cased. The regular expression (regex)\n value is \"^[A-Z][a-zA-Z]+$\".

", "smithy.api#httpHeader": "x-amz-fwd-error-code" } }, @@ -13287,6 +14329,34 @@ "smithy.api#httpHeader": "x-amz-fwd-header-Content-Type" } }, + "ChecksumCRC32": { + "target": "com.amazonaws.s3#ChecksumCRC32", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the\n same data that was originally sent. This specifies the base64-encoded, 32-bit CRC32 checksum\n of the object returned by the Object Lambda function. This may not match the checksum for the\n object stored in Amazon S3. Amazon S3 will perform validation of the checksum values only when the original\n GetObject request required checksum validation. For more information about checksums, see\n Checking\n object integrity in the Amazon S3 User Guide.

\n

Only one checksum header can be specified at a time. If you supply multiple\n checksum headers, this request will fail.

\n

", + "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-checksum-crc32" + } + }, + "ChecksumCRC32C": { + "target": "com.amazonaws.s3#ChecksumCRC32C", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the\n same data that was originally sent. This specifies the base64-encoded, 32-bit CRC32C checksum\n of the object returned by the Object Lambda function. This may not match the checksum for the\n object stored in Amazon S3. Amazon S3 will perform validation of the checksum values only when the original\n GetObject request required checksum validation. For more information about checksums, see\n Checking\n object integrity in the Amazon S3 User Guide.

\n

Only one checksum header can be specified at a time. If you supply multiple\n checksum headers, this request will fail.

", + "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-checksum-crc32c" + } + }, + "ChecksumSHA1": { + "target": "com.amazonaws.s3#ChecksumSHA1", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the\n same data that was originally sent. This specifies the base64-encoded, 160-bit SHA-1 digest\n of the object returned by the Object Lambda function. This may not match the checksum for the\n object stored in Amazon S3. Amazon S3 will perform validation of the checksum values only when the original\n GetObject request required checksum validation. For more information about checksums, see\n Checking\n object integrity in the Amazon S3 User Guide.

\n

Only one checksum header can be specified at a time. If you supply multiple\n checksum headers, this request will fail.

", + "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-checksum-sha1" + } + }, + "ChecksumSHA256": { + "target": "com.amazonaws.s3#ChecksumSHA256", + "traits": { + "smithy.api#documentation": "

This header can be used as a data integrity check to verify that the data received is the\n same data that was originally sent. This specifies the base64-encoded, 256-bit SHA-256 digest\n of the object returned by the Object Lambda function. This may not match the checksum for the\n object stored in Amazon S3. Amazon S3 will perform validation of the checksum values only when the original\n GetObject request required checksum validation. For more information about checksums, see\n Checking\n object integrity in the Amazon S3 User Guide.

\n

Only one checksum header can be specified at a time. If you supply multiple\n checksum headers, this request will fail.

", + "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-checksum-sha256" + } + }, "DeleteMarker": { "target": "com.amazonaws.s3#DeleteMarker", "traits": { @@ -13311,7 +14381,7 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If object stored in Amazon S3 expiration is configured (see PUT Bucket lifecycle) it includes expiry-date and rule-id key-value pairs providing object expiration information. The value of the rule-id is URL encoded.

", + "smithy.api#documentation": "

If the object expiration is configured (see PUT Bucket lifecycle), the response\n includes this header. It includes the expiry-date and rule-id\n key-value pairs that provide the object expiration information. The value of the\n rule-id is URL-encoded.

", "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-expiration" } }, @@ -13415,7 +14485,7 @@ "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

The class of storage used to store object in Amazon S3.

", + "smithy.api#documentation": "

Provides storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

\n \n

For more information, see Storage\n Classes.

", "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-storage-class" } }, diff --git a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsGoDependency.java b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsGoDependency.java index 66ace99bfd9..1fcacc3196b 100644 --- a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsGoDependency.java +++ b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsGoDependency.java @@ -47,6 +47,8 @@ public class AwsGoDependency { public static final GoDependency SERVICE_INTERNAL_ENDPOINT_DISCOVERY = awsModuleDep("service/internal/endpoint-discovery", null, Versions.SERVICE_INTERNAL_ENDPOINT_DISCOVERY, "internalEndpointDiscovery"); public static final GoDependency AWS_DEFAULTS = aws("aws/defaults"); + public static final GoDependency SERVICE_INTERNAL_CHECKSUM = awsModuleDep("service/internal/checksum", + null, Versions.SERVICE_INTERNAL_CHECKSUM, "internalChecksum"); public static final GoDependency REGEXP = SmithyGoDependency.stdlib("regexp"); @@ -99,5 +101,6 @@ private static final class Versions { private static final String SERVICE_INTERNAL_ENDPOINT_DISCOVERY = "v0.0.0-00010101000000-000000000000"; private static final String INTERNAL_ENDPOINTS_V2 = "v2.0.0-00010101000000-000000000000"; private static final String AWS_PROTOCOL_EVENTSTREAM = "v0.0.0-00010101000000-000000000000"; + private static final String SERVICE_INTERNAL_CHECKSUM = "v0.0.0-00010101000000-000000000000"; } } diff --git a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsHttpChecksumGenerator.java b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsHttpChecksumGenerator.java new file mode 100644 index 00000000000..a23b71cdbc6 --- /dev/null +++ b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsHttpChecksumGenerator.java @@ -0,0 +1,482 @@ +package software.amazon.smithy.aws.go.codegen; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import software.amazon.smithy.aws.traits.ServiceTrait; +import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait; +import software.amazon.smithy.codegen.core.CodegenException; +import software.amazon.smithy.codegen.core.Symbol; +import software.amazon.smithy.codegen.core.SymbolProvider; +import software.amazon.smithy.go.codegen.GoCodegenPlugin; +import software.amazon.smithy.go.codegen.GoDelegator; +import software.amazon.smithy.go.codegen.GoSettings; +import software.amazon.smithy.go.codegen.GoWriter; +import software.amazon.smithy.go.codegen.SmithyGoDependency; +import software.amazon.smithy.go.codegen.SymbolUtils; +import software.amazon.smithy.go.codegen.integration.GoIntegration; +import software.amazon.smithy.go.codegen.integration.MiddlewareRegistrar; +import software.amazon.smithy.go.codegen.integration.RuntimeClientPlugin; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.MemberShape; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ServiceShape; +import software.amazon.smithy.aws.traits.HttpChecksumTrait; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.shapes.StructureShape; +import software.amazon.smithy.model.traits.StreamingTrait; +import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.SetUtils; + +public class AwsHttpChecksumGenerator implements GoIntegration { + // constant map with service to list of operation for which we should ignore multipart checksum validation. + private static final Map> ignoreMultipartChecksumValidationMap = MapUtils.of( + ShapeId.from("com.amazonaws.s3#AmazonS3"), SetUtils.of( + ShapeId.from("com.amazonaws.s3#GetObject") + ) + ); + // list of runtime-client plugins + private final List runtimeClientPlugins = new ArrayList<>(); + + private static String getRequestAlgorithmAccessorFuncName(String operationName) { + return String.format("get%s%s", operationName, "RequestAlgorithmMember"); + } + + private static String getRequestValidationModeAccessorFuncName(String operationName) { + return String.format("get%s%s", operationName, "RequestValidationModeMember"); + } + + private static String getAddInputMiddlewareFuncName(String operationName) { + return String.format("add%sInputChecksumMiddlewares", operationName); + } + + private static String getAddOutputMiddlewareFuncName(String operationName) { + return String.format("add%sOutputChecksumMiddlewares", operationName); + } + + @Override + public byte getOrder() { + return 127; + } + + /** + * Builds the set of runtime plugs. + * + * @param settings codegen settings + * @param model api model + */ + @Override + public void processFinalizedModel(GoSettings settings, Model model) { + ServiceShape service = settings.getService(model); + for (ShapeId operationId : service.getAllOperations()) { + final OperationShape operation = model.expectShape(operationId, OperationShape.class); + + // Create a symbol provider because one is not available in this call. + SymbolProvider symbolProvider = GoCodegenPlugin.createSymbolProvider(model, settings); + + // Input helper + String inputHelperFuncName = getAddInputMiddlewareFuncName( + symbolProvider.toSymbol(operation).getName() + ); + runtimeClientPlugins.add(RuntimeClientPlugin.builder() + .operationPredicate((m, s, o) -> { + if (!hasInputChecksumTrait(m, s, o)) { + return false; + } + return o.equals(operation); + }) + .registerMiddleware(MiddlewareRegistrar.builder() + .resolvedFunction(SymbolUtils.createValueSymbolBuilder(inputHelperFuncName) + .build()) + .useClientOptions() + .build()) + .build()); + + // Output helper + String outputHelperFuncName = getAddOutputMiddlewareFuncName( + symbolProvider.toSymbol(operation).getName() + ); + runtimeClientPlugins.add(RuntimeClientPlugin.builder() + .operationPredicate((m, s, o) -> { + if (!hasOutputChecksumTrait(m, s, o)) { + return false; + } + return o.equals(operation); + }) + .registerMiddleware(MiddlewareRegistrar.builder() + .resolvedFunction(SymbolUtils.createValueSymbolBuilder(outputHelperFuncName) + .build()) + .useClientOptions() + .build()) + .build()); + } + } + + @Override + public void writeAdditionalFiles( + GoSettings settings, + Model model, + SymbolProvider symbolProvider, + GoDelegator goDelegator + ) { + ServiceShape service = settings.getService(model); + boolean supportsComputeInputChecksumsWorkflow = false; + boolean supportsChecksumValidationWorkflow = false; + + for (ShapeId operationID : service.getAllOperations()) { + OperationShape operation = model.expectShape(operationID, OperationShape.class); + if (!hasChecksumTrait(model, service, operation)) { + continue; + } + + final boolean generateComputeInputChecksums = hasInputChecksumTrait(model, service, operation); + if (generateComputeInputChecksums) { + supportsComputeInputChecksumsWorkflow = true; + } + + final boolean generateOutputChecksumValidation = hasOutputChecksumTrait(model, service, operation); + if (generateOutputChecksumValidation) { + supportsChecksumValidationWorkflow = true; + } + + goDelegator.useShapeWriter(operation, writer -> { + // generate getter helper function to access input member value + writeGetInputMemberAccessorHelper(writer, model, symbolProvider, operation); + + // generate middleware helper function + if (generateComputeInputChecksums) { + writeInputMiddlewareHelper(writer, model, symbolProvider, service, operation); + } + + if (generateOutputChecksumValidation) { + writeOutputMiddlewareHelper(writer, model, symbolProvider, service, operation); + } + }); + } + + if (supportsComputeInputChecksumsWorkflow) { + goDelegator.useShapeWriter(service, writer -> { + generateInputComputedChecksumMetadataHelpers(writer, model, symbolProvider, service); + }); + } + + if (supportsChecksumValidationWorkflow) { + goDelegator.useShapeWriter(service, writer -> { + generateOutputChecksumValidationMetadataHelpers(writer, model, symbolProvider, service); + }); + } + } + + @Override + public List getClientPlugins() { + return runtimeClientPlugins; + } + + // return true if operation shape is decorated with `httpChecksum` trait. + private boolean hasChecksumTrait(Model model, ServiceShape service, OperationShape operation) { + return operation.hasTrait(HttpChecksumTrait.class); + } + + private boolean hasInputChecksumTrait(Model model, ServiceShape service, OperationShape operation) { + if (!hasChecksumTrait(model, service, operation)) { + return false; + } + HttpChecksumTrait trait = operation.expectTrait(HttpChecksumTrait.class); + return trait.isRequestChecksumRequired() || trait.getRequestAlgorithmMember().isPresent(); + } + + private boolean hasOutputChecksumTrait(Model model, ServiceShape service, OperationShape operation) { + if (!hasChecksumTrait(model, service, operation)) { + return false; + } + HttpChecksumTrait trait = operation.expectTrait(HttpChecksumTrait.class); + return trait.getRequestValidationModeMember().isPresent() && !trait.getResponseAlgorithms().isEmpty(); + } + + private boolean isS3ServiceShape(Model model, ServiceShape service) { + String serviceId = service.expectTrait(ServiceTrait.class).getSdkId(); + return serviceId.equalsIgnoreCase("S3"); + } + + private void writeInputMiddlewareHelper( + GoWriter writer, + Model model, + SymbolProvider symbolProvider, + ServiceShape service, + OperationShape operation + ) { + Symbol operationSymbol = symbolProvider.toSymbol(operation); + String operationName = operationSymbol.getName(); + StructureShape input = model.expectShape(operation.getInput().get(), StructureShape.class); + + HttpChecksumTrait trait = operation.expectTrait(HttpChecksumTrait.class); + boolean isRequestChecksumRequired = trait.isRequestChecksumRequired(); + boolean hasRequestAlgorithmMember = trait.getRequestAlgorithmMember().isPresent(); + + boolean supportsTrailingChecksum = false; + for (MemberShape memberShape : input.getAllMembers().values()) { + Shape targetShape = model.expectShape(memberShape.getTarget()); + if (targetShape.hasTrait(StreamingTrait.class) && + !StreamingTrait.isEventStream(model, memberShape) + ) { + if (isS3ServiceShape(model, service) || ( + AwsSignatureVersion4.hasSigV4AuthScheme(model, service, operation) + && !operation.hasTrait(UnsignedPayloadTrait.class))) { + supportsTrailingChecksum = true; + } + } + } + + boolean supportsRequestTrailingChecksum = supportsTrailingChecksum; + boolean supportsDecodedContentLengthHeader = isS3ServiceShape(model, service); + + // imports + writer.addUseImports(SmithyGoDependency.SMITHY_MIDDLEWARE); + + writer.openBlock("func $L(stack *middleware.Stack, options Options) error {", "}", + getAddInputMiddlewareFuncName(operationName), () -> { + writer.write(""" + return $T(stack, $T{ + GetAlgorithm: $L, + RequireChecksum: $L, + EnableTrailingChecksum: $L, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: $L, + })""", + SymbolUtils.createValueSymbolBuilder("AddInputMiddleware", + AwsGoDependency.SERVICE_INTERNAL_CHECKSUM).build(), + SymbolUtils.createValueSymbolBuilder("InputMiddlewareOptions", + AwsGoDependency.SERVICE_INTERNAL_CHECKSUM).build(), + hasRequestAlgorithmMember ? + getRequestAlgorithmAccessorFuncName(operationName) : "nil", + isRequestChecksumRequired, + supportsRequestTrailingChecksum, + supportsDecodedContentLengthHeader); + } + ); + writer.insertTrailingNewline(); + } + + private void writeOutputMiddlewareHelper( + GoWriter writer, + Model model, + SymbolProvider symbolProvider, + ServiceShape service, + OperationShape operation + ) { + Symbol operationSymbol = symbolProvider.toSymbol(operation); + String operationName = operationSymbol.getName(); + StructureShape input = model.expectShape(operation.getInput().get(), StructureShape.class); + + HttpChecksumTrait trait = operation.expectTrait(HttpChecksumTrait.class); + List responseAlgorithms = trait.getResponseAlgorithms(); + + // imports + writer.addUseImports(SmithyGoDependency.SMITHY_MIDDLEWARE); + + writer.openBlock("func $L(stack *middleware.Stack, options Options) error {", "}", + getAddOutputMiddlewareFuncName(operationName), () -> { + writer.write(""" + return $T(stack, $T{ + GetValidationMode: $L, + ValidationAlgorithms: $L, + IgnoreMultipartValidation: $L, + LogValidationSkipped: true, + LogMultipartValidationSkipped: true, + })""", + SymbolUtils.createValueSymbolBuilder("AddOutputMiddleware", + AwsGoDependency.SERVICE_INTERNAL_CHECKSUM).build(), + SymbolUtils.createValueSymbolBuilder("OutputMiddlewareOptions", + AwsGoDependency.SERVICE_INTERNAL_CHECKSUM).build(), + + getRequestValidationModeAccessorFuncName(operationName), + convertToGoStringList(responseAlgorithms), + ignoreMultipartChecksumValidationMap.getOrDefault( + service.toShapeId(), new HashSet<>()).contains(operation.toShapeId()) + ); + }); + writer.insertTrailingNewline(); + } + + private String convertToGoStringList(List list) { + StringBuilder sb = new StringBuilder(); + sb.append("[]string{"); + for (String item : list) { + sb.append("\"").append(item).append("\""); + sb.append(","); + } + if (!list.isEmpty()) { + sb.deleteCharAt(sb.length() - 1); + } + sb.append("}"); + return sb.toString(); + } + + private void writeGetInputMemberAccessorHelper( + GoWriter writer, + Model model, + SymbolProvider symbolProvider, + OperationShape operation + ) { + Symbol operationSymbol = symbolProvider.toSymbol(operation); + StructureShape input = model.expectShape(operation.getInput().get(), StructureShape.class); + + HttpChecksumTrait trait = operation.expectTrait(HttpChecksumTrait.class); + + // Input parameter for computing request payload's checksum. + if (trait.getRequestAlgorithmMember().isPresent()) { + Optional memberShape = input.getAllMembers().values().stream() + .filter(m -> m.getMemberName().toLowerCase(Locale.ENGLISH) + .equals(trait.getRequestAlgorithmMember().get().toLowerCase(Locale.ENGLISH))) + .findFirst(); + if (!memberShape.isPresent()) { + throw new CodegenException(String.format( + "Found no matching input member named %s modeled with HttpChecksum trait", + trait.getRequestAlgorithmMember().get())); + } + + String memberName = memberShape.get().getMemberName(); + String funcName = getRequestAlgorithmAccessorFuncName(operationSymbol.getName()); + writer.writeDocs( + String.format("%s gets the request checksum algorithm value provided as input.", funcName)); + getInputTemplate(writer, symbolProvider, input, funcName, memberName); + writer.insertTrailingNewline(); + } + + // Output parameter for validating response payload's checksum + if (trait.getRequestValidationModeMember().isPresent()) { + Optional memberShape = input.getAllMembers().values().stream() + .filter(m -> m.getMemberName().toLowerCase(Locale.ENGLISH) + .equals(trait.getRequestValidationModeMember().get().toLowerCase(Locale.ENGLISH))) + .findFirst(); + if (!memberShape.isPresent()) { + throw new CodegenException(String.format( + "Found no matching input member named %s modeled with HttpChecksum trait", + trait.getRequestValidationModeMember().get())); + } + + String memberName = memberShape.get().getMemberName(); + String funcName = getRequestValidationModeAccessorFuncName(operationSymbol.getName()); + writer.writeDocs( + String.format("%s gets the request checksum validation mode provided as input.", funcName)); + getInputTemplate(writer, symbolProvider, input, funcName, memberName); + writer.insertTrailingNewline(); + } + } + + private void getInputTemplate( + GoWriter writer, + SymbolProvider symbolProvider, + StructureShape input, + String funcName, + String memberName + ) { + writer.openBlock("func $L(input interface{}) (string, bool) {", "}", funcName, + () -> { + writer.write("in := input.($P)", symbolProvider.toSymbol(input)); + writer.openBlock("if len(in.$L) == 0 {", "}", memberName, () -> { + writer.write("return \"\", false"); + }); + writer.write("return string(in.$L), true", memberName); + }); + writer.write(""); + } + + private void generateInputComputedChecksumMetadataHelpers( + GoWriter writer, + Model model, + SymbolProvider symbolProvider, + ServiceShape service + ) { + String metadataStructName = "ComputedInputChecksumsMetadata"; + + writer.writeDocs(String.format(""" + %s provides information about the algorithms used to compute the checksum(s) of the + input payload. + """, metadataStructName)); + writer.openBlock("type $L struct {", "}", metadataStructName, () -> { + writer.writeDocs(""" + ComputedChecksums is a map of algorithm name to checksum value of the computed + input payload's checksums. + """); + writer.write("ComputedChecksums map[string]string"); + }); + + Symbol metadataStructSymbol = + SymbolUtils.createValueSymbolBuilder(metadataStructName).build(); + String metadataGetterFuncName = "Get" + metadataStructName; + Symbol getAlgorithmUsed = SymbolUtils.createValueSymbolBuilder( + "GetComputedInputChecksums", AwsGoDependency.SERVICE_INTERNAL_CHECKSUM).build(); + + writer.writeDocs(String.format(""" + %s retrieves from the result metadata the map of algorithms and input payload checksums values. + """, metadataGetterFuncName)); + writer.openBlock("func $L(m $T) ($T, bool) {", "}", + metadataGetterFuncName, + SymbolUtils.createValueSymbolBuilder("Metadata", SmithyGoDependency.SMITHY_MIDDLEWARE).build(), + metadataStructSymbol, + () -> { + writer.write("values, ok := $T(m)", getAlgorithmUsed); + writer.write("if !ok { return $T{}, false }", metadataStructSymbol); + writer.write(""" + return $T{ + ComputedChecksums: values, + }, true + """, metadataStructSymbol); + }); + writer.write(""); + } + + private void generateOutputChecksumValidationMetadataHelpers( + GoWriter writer, + Model model, + SymbolProvider symbolProvider, + ServiceShape service + ) { + String metadataStructName = "ChecksumValidationMetadata"; + + writer.writeDocs(String.format( + "%s contains metadata such as the checksum algorithm used for data integrity validation.", + metadataStructName)); + writer.openBlock("type $L struct {", "}", metadataStructName, () -> { + writer.writeDocs(""" + AlgorithmsUsed is the set of the checksum algorithms used to validate the response payload. + The response payload must be completely read in order for the checksum validation to be + performed. An error is returned by the operation output's response io.ReadCloser + if the computed checksums are invalid. + """); + writer.write("AlgorithmsUsed []string"); + }); + + Symbol metadataStructSymbol = + SymbolUtils.createValueSymbolBuilder(metadataStructName).build(); + String metadataGetterFuncName = "Get" + metadataStructName; + Symbol getAlgorithmUsed = SymbolUtils.createValueSymbolBuilder( + "GetOutputValidationAlgorithmsUsed", AwsGoDependency.SERVICE_INTERNAL_CHECKSUM).build(); + + writer.writeDocs(String.format(""" + %s returns the set of algorithms that will be used to validate the response payload with. The + response payload must be completely read in order for the checksum validation to be performed. + An error is returned by the operation output's response io.ReadCloser if the computed checksums + are invalid. Returns false if no checksum algorithm used metadata was found. + """, metadataGetterFuncName)); + writer.openBlock("func $L(m $T) ($T, bool) {", "}", metadataGetterFuncName, + SymbolUtils.createValueSymbolBuilder("Metadata", SmithyGoDependency.SMITHY_MIDDLEWARE).build(), + metadataStructSymbol, + () -> { + writer.write("values, ok := $T(m)", getAlgorithmUsed); + writer.write("if !ok { return $T{}, false }", metadataStructSymbol); + writer.write(""" + return $T{ + AlgorithmsUsed: append(make([]string, 0, len(values)), values...), + }, true + """, metadataStructSymbol); + }); + writer.write(""); + } +} diff --git a/codegen/smithy-aws-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration b/codegen/smithy-aws-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration index e51cb422b7d..7588c64aa80 100644 --- a/codegen/smithy-aws-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration +++ b/codegen/smithy-aws-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration @@ -1,6 +1,7 @@ software.amazon.smithy.aws.go.codegen.AddProtocols software.amazon.smithy.aws.go.codegen.ClientResolvedDefaultsMode software.amazon.smithy.aws.go.codegen.AddAwsConfigFields +software.amazon.smithy.aws.go.codegen.AwsHttpChecksumGenerator software.amazon.smithy.aws.go.codegen.RegisterServiceMetadataMiddleware software.amazon.smithy.aws.go.codegen.AwsEventStreamIntegration software.amazon.smithy.aws.go.codegen.AssembleMiddlewareStack diff --git a/example/service/s3/listObjects/go.mod b/example/service/s3/listObjects/go.mod index 4766c309169..68e8f6ad8bb 100644 --- a/example/service/s3/listObjects/go.mod +++ b/example/service/s3/listObjects/go.mod @@ -25,6 +25,8 @@ replace github.com/aws/aws-sdk-go-v2/internal/ini => ../../../../internal/ini/ replace github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding => ../../../../service/internal/accept-encoding/ +replace github.com/aws/aws-sdk-go-v2/service/internal/checksum => ../../../../service/internal/checksum/ + replace github.com/aws/aws-sdk-go-v2/service/internal/presigned-url => ../../../../service/internal/presigned-url/ replace github.com/aws/aws-sdk-go-v2/service/internal/s3shared => ../../../../service/internal/s3shared/ diff --git a/example/service/s3/usingPrivateLink/go.mod b/example/service/s3/usingPrivateLink/go.mod index 5822a7bfe39..b441298f922 100644 --- a/example/service/s3/usingPrivateLink/go.mod +++ b/example/service/s3/usingPrivateLink/go.mod @@ -27,6 +27,8 @@ replace github.com/aws/aws-sdk-go-v2/internal/ini => ../../../../internal/ini/ replace github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding => ../../../../service/internal/accept-encoding/ +replace github.com/aws/aws-sdk-go-v2/service/internal/checksum => ../../../../service/internal/checksum/ + replace github.com/aws/aws-sdk-go-v2/service/internal/presigned-url => ../../../../service/internal/presigned-url/ replace github.com/aws/aws-sdk-go-v2/service/internal/s3shared => ../../../../service/internal/s3shared/ diff --git a/feature/s3/manager/download.go b/feature/s3/manager/download.go index a1f3ceb11f5..c3fbe021982 100644 --- a/feature/s3/manager/download.go +++ b/feature/s3/manager/download.go @@ -348,16 +348,16 @@ func (d *downloader) downloadRange(rng string) { // downloadChunk downloads the chunk from s3 func (d *downloader) downloadChunk(chunk dlchunk) error { - in := &s3.GetObjectInput{} - awsutil.Copy(in, d.in) + var params s3.GetObjectInput + awsutil.Copy(¶ms, d.in) // Get the next byte range of data - in.Range = aws.String(chunk.ByteRange()) + params.Range = aws.String(chunk.ByteRange()) var n int64 var err error for retry := 0; retry <= d.partBodyMaxRetries; retry++ { - n, err = d.tryDownloadChunk(in, &chunk) + n, err = d.tryDownloadChunk(¶ms, &chunk) if err == nil { break } @@ -374,8 +374,9 @@ func (d *downloader) downloadChunk(chunk dlchunk) error { chunk.cur = 0 - d.cfg.Logger.Logf(logging.Debug, "object part body download interrupted %s, err, %v, retrying attempt %d", - aws.ToString(in.Key), err, retry) + d.cfg.Logger.Logf(logging.Debug, + "object part body download interrupted %s, err, %v, retrying attempt %d", + aws.ToString(params.Key), err, retry) } d.incrWritten(n) @@ -383,14 +384,14 @@ func (d *downloader) downloadChunk(chunk dlchunk) error { return err } -func (d *downloader) tryDownloadChunk(in *s3.GetObjectInput, w io.Writer) (int64, error) { +func (d *downloader) tryDownloadChunk(params *s3.GetObjectInput, w io.Writer) (int64, error) { cleanup := func() {} if d.cfg.BufferProvider != nil { w, cleanup = d.cfg.BufferProvider.GetReadFrom(w) } defer cleanup() - resp, err := d.cfg.S3.GetObject(d.ctx, in, d.cfg.ClientOptions...) + resp, err := d.cfg.S3.GetObject(d.ctx, params, d.cfg.ClientOptions...) if err != nil { return 0, err } diff --git a/feature/s3/manager/go.mod b/feature/s3/manager/go.mod index 12493700dec..71233fa4bd7 100644 --- a/feature/s3/manager/go.mod +++ b/feature/s3/manager/go.mod @@ -28,6 +28,8 @@ replace github.com/aws/aws-sdk-go-v2/internal/ini => ../../../internal/ini/ replace github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding => ../../../service/internal/accept-encoding/ +replace github.com/aws/aws-sdk-go-v2/service/internal/checksum => ../../../service/internal/checksum/ + replace github.com/aws/aws-sdk-go-v2/service/internal/presigned-url => ../../../service/internal/presigned-url/ replace github.com/aws/aws-sdk-go-v2/service/internal/s3shared => ../../../service/internal/s3shared/ diff --git a/feature/s3/manager/integ_shared_test.go b/feature/s3/manager/integ_shared_test.go index e63239dbe73..121b5669476 100644 --- a/feature/s3/manager/integ_shared_test.go +++ b/feature/s3/manager/integ_shared_test.go @@ -17,6 +17,7 @@ import ( "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/feature/s3/manager/internal/integration" "github.com/aws/aws-sdk-go-v2/service/s3" + s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" ) var integConfig aws.Config @@ -92,7 +93,11 @@ func (d dlwriter) WriteAt(p []byte, pos int64) (n int, err error) { func validate(t *testing.T, key string, md5value string) { mgr := manager.NewDownloader(client) - params := &s3.GetObjectInput{Bucket: bucketName, Key: &key} + params := &s3.GetObjectInput{ + Bucket: bucketName, + Key: &key, + ChecksumMode: s3types.ChecksumModeEnabled, + } w := newDLWriter(1024 * 1024 * 20) n, err := mgr.Download(context.Background(), w, params) diff --git a/feature/s3/manager/integ_upload_test.go b/feature/s3/manager/integ_upload_test.go index 4c2a0c9e054..2555cf5ed54 100644 --- a/feature/s3/manager/integ_upload_test.go +++ b/feature/s3/manager/integ_upload_test.go @@ -7,27 +7,92 @@ import ( "bytes" "context" "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "encoding/base64" + "encoding/hex" "errors" "fmt" + "hash" + "hash/crc32" + "io" + "log" "regexp" + "strconv" "testing" + "github.com/aws/aws-sdk-go-v2/aws" v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" ) var integBuf12MB = make([]byte, 1024*1024*12) var integMD512MB = fmt.Sprintf("%x", md5.Sum(integBuf12MB)) +func hexEncodeSum(sum []byte) string { + sumHex := make([]byte, hex.EncodedLen(len(sum))) + hex.Encode(sumHex, sum) + return string(sumHex) +} + +func base64EncodeSum(sum []byte) string { + sum64 := make([]byte, base64.StdEncoding.EncodedLen(len(sum))) + base64.StdEncoding.Encode(sum64, sum) + return string(sum64) +} + +func base64Sum(h hash.Hash, b []byte) string { + h.Write(b) + return base64EncodeSum(h.Sum(nil)) +} +func hexSum(h hash.Hash, b []byte) string { + h.Write(b) + return hexEncodeSum(h.Sum(nil)) +} + +func base64StringDecode(v string) []byte { + vv, err := base64.StdEncoding.DecodeString(v) + if err != nil { + panic(err.Error()) + } + return vv +} +func hexStringDecode(v string) []byte { + vv, err := base64.StdEncoding.DecodeString(v) + if err != nil { + panic(err.Error()) + } + return vv +} + +func base64SumOfSums(h hash.Hash, sums []string) string { + for _, v := range sums { + h.Write(base64StringDecode(v)) + } + return base64EncodeSum(h.Sum(nil)) + "-" + strconv.Itoa(len(sums)) +} + +func hexSumOfSums(h hash.Hash, sums []string) string { + for _, v := range sums { + h.Write(hexStringDecode(unquote(v))) + } + return hexEncodeSum(h.Sum(nil)) + "-" + strconv.Itoa(len(sums)) +} + func TestInteg_UploadConcurrently(t *testing.T) { key := "12mb-1" mgr := manager.NewUploader(client) out, err := mgr.Upload(context.Background(), &s3.PutObjectInput{ - Bucket: bucketName, - Key: &key, - Body: bytes.NewReader(integBuf12MB), + Bucket: bucketName, + Key: &key, + Body: bytes.NewReader(integBuf12MB), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, }) if err != nil { @@ -45,6 +110,382 @@ func TestInteg_UploadConcurrently(t *testing.T) { validate(t, key, integMD512MB) } +func unquote(v string) string { + log.Printf("unquote: %v", v) + vv, err := strconv.Unquote(v) + if err != nil { + // Unquote returns error if string doesn't contain quotes + if err == strconv.ErrSyntax { + return v + } + panic(err.Error()) + } + return vv +} + +func TestInteg_UploadPresetChecksum(t *testing.T) { + singlePartBytes := integBuf12MB[0:manager.DefaultUploadPartSize] + singlePartCRC32 := base64Sum(crc32.NewIEEE(), singlePartBytes) + singlePartCRC32C := base64Sum(crc32.New(crc32.MakeTable(crc32.Castagnoli)), singlePartBytes) + singlePartSHA1 := base64Sum(sha1.New(), singlePartBytes) + singlePartSHA256 := base64Sum(sha256.New(), singlePartBytes) + singlePartMD5 := base64Sum(md5.New(), singlePartBytes) + singlePartETag := fmt.Sprintf("%q", hexSum(md5.New(), singlePartBytes)) + + multiPartTailBytes := integBuf12MB[manager.DefaultUploadPartSize*2:] + multiPartTailCRC32 := base64Sum(crc32.NewIEEE(), multiPartTailBytes) + multiPartTailCRC32C := base64Sum(crc32.New(crc32.MakeTable(crc32.Castagnoli)), multiPartTailBytes) + multiPartTailSHA1 := base64Sum(sha1.New(), multiPartTailBytes) + multiPartTailSHA256 := base64Sum(sha256.New(), multiPartTailBytes) + multiPartTailETag := fmt.Sprintf("%q", hexSum(md5.New(), multiPartTailBytes)) + + multiPartBytes := integBuf12MB + multiPartCRC32 := base64SumOfSums(crc32.NewIEEE(), []string{singlePartCRC32, singlePartCRC32, multiPartTailCRC32}) + multiPartCRC32C := base64SumOfSums(crc32.New(crc32.MakeTable(crc32.Castagnoli)), []string{singlePartCRC32C, singlePartCRC32C, multiPartTailCRC32C}) + multiPartSHA1 := base64SumOfSums(sha1.New(), []string{singlePartSHA1, singlePartSHA1, multiPartTailSHA1}) + multiPartSHA256 := base64SumOfSums(sha256.New(), []string{singlePartSHA256, singlePartSHA256, multiPartTailSHA256}) + multiPartETag := `"4e982d58b6c2ce178ae042c23f9bca6e-3"` // Not obvious how this is computed + + cases := map[string]map[string]struct { + algorithm s3types.ChecksumAlgorithm + payload io.Reader + checksumCRC32 string + checksumCRC32C string + checksumSHA1 string + checksumSHA256 string + contentMD5 string + expectParts []s3types.CompletedPart + expectChecksumCRC32 string + expectChecksumCRC32C string + expectChecksumSHA1 string + expectChecksumSHA256 string + expectETag string + }{ + "auto single part": { + "no checksum": { + payload: bytes.NewReader(singlePartBytes), + expectETag: singlePartETag, + }, + "CRC32": { + algorithm: s3types.ChecksumAlgorithmCrc32, + payload: bytes.NewReader(singlePartBytes), + expectChecksumCRC32: singlePartCRC32, + expectETag: singlePartETag, + }, + "CRC32C": { + algorithm: s3types.ChecksumAlgorithmCrc32c, + payload: bytes.NewReader(singlePartBytes), + expectChecksumCRC32C: singlePartCRC32C, + expectETag: singlePartETag, + }, + "SHA1": { + algorithm: s3types.ChecksumAlgorithmSha1, + payload: bytes.NewReader(singlePartBytes), + expectChecksumSHA1: singlePartSHA1, + expectETag: singlePartETag, + }, + "SHA256": { + algorithm: s3types.ChecksumAlgorithmSha256, + payload: bytes.NewReader(singlePartBytes), + expectChecksumSHA256: singlePartSHA256, + expectETag: singlePartETag, + }, + }, + "preset single part": { + "CRC32": { + payload: bytes.NewReader(singlePartBytes), + checksumCRC32: singlePartCRC32, + expectChecksumCRC32: singlePartCRC32, + expectETag: singlePartETag, + }, + "CRC32C": { + payload: bytes.NewReader(singlePartBytes), + checksumCRC32C: singlePartCRC32C, + expectChecksumCRC32C: singlePartCRC32C, + expectETag: singlePartETag, + }, + "SHA1": { + payload: bytes.NewReader(singlePartBytes), + checksumSHA1: singlePartSHA1, + expectChecksumSHA1: singlePartSHA1, + expectETag: singlePartETag, + }, + "SHA256": { + payload: bytes.NewReader(singlePartBytes), + checksumSHA256: singlePartSHA256, + expectChecksumSHA256: singlePartSHA256, + expectETag: singlePartETag, + }, + "MD5": { + payload: bytes.NewReader(singlePartBytes), + contentMD5: singlePartMD5, + expectETag: singlePartETag, + }, + }, + "auto multipart part": { + "no checksum": { + payload: bytes.NewReader(multiPartBytes), + expectParts: []s3types.CompletedPart{ + { + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectETag: multiPartETag, + }, + "CRC32": { + algorithm: s3types.ChecksumAlgorithmCrc32, + payload: bytes.NewReader(multiPartBytes), + expectParts: []s3types.CompletedPart{ + { + ChecksumCRC32: aws.String(singlePartCRC32), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumCRC32: aws.String(singlePartCRC32), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumCRC32: aws.String(multiPartTailCRC32), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumCRC32: multiPartCRC32, + expectETag: multiPartETag, + }, + "CRC32C": { + algorithm: s3types.ChecksumAlgorithmCrc32c, + payload: bytes.NewReader(multiPartBytes), + expectParts: []s3types.CompletedPart{ + { + ChecksumCRC32C: aws.String(singlePartCRC32C), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumCRC32C: aws.String(singlePartCRC32C), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumCRC32C: aws.String(multiPartTailCRC32C), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumCRC32C: multiPartCRC32C, + expectETag: multiPartETag, + }, + "SHA1": { + algorithm: s3types.ChecksumAlgorithmSha1, + payload: bytes.NewReader(multiPartBytes), + expectParts: []s3types.CompletedPart{ + { + ChecksumSHA1: aws.String(singlePartSHA1), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumSHA1: aws.String(singlePartSHA1), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumSHA1: aws.String(multiPartTailSHA1), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumSHA1: multiPartSHA1, + expectETag: multiPartETag, + }, + "SHA256": { + algorithm: s3types.ChecksumAlgorithmSha256, + payload: bytes.NewReader(multiPartBytes), + expectParts: []s3types.CompletedPart{ + { + ChecksumSHA256: aws.String(singlePartSHA256), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumSHA256: aws.String(singlePartSHA256), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumSHA256: aws.String(multiPartTailSHA256), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumSHA256: multiPartSHA256, + expectETag: multiPartETag, + }, + }, + "preset multipart part": { + "CRC32": { + algorithm: s3types.ChecksumAlgorithmCrc32, + payload: bytes.NewReader(multiPartBytes), + checksumCRC32: multiPartCRC32, + expectParts: []s3types.CompletedPart{ + { + ChecksumCRC32: aws.String(singlePartCRC32), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumCRC32: aws.String(singlePartCRC32), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumCRC32: aws.String(multiPartTailCRC32), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumCRC32: multiPartCRC32, + expectETag: multiPartETag, + }, + "CRC32C": { + algorithm: s3types.ChecksumAlgorithmCrc32c, + payload: bytes.NewReader(multiPartBytes), + checksumCRC32C: multiPartCRC32C, + expectParts: []s3types.CompletedPart{ + { + ChecksumCRC32C: aws.String(singlePartCRC32C), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumCRC32C: aws.String(singlePartCRC32C), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumCRC32C: aws.String(multiPartTailCRC32C), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumCRC32C: multiPartCRC32C, + expectETag: multiPartETag, + }, + "SHA1": { + algorithm: s3types.ChecksumAlgorithmSha1, + payload: bytes.NewReader(multiPartBytes), + checksumSHA1: multiPartSHA1, + expectParts: []s3types.CompletedPart{ + { + ChecksumSHA1: aws.String(singlePartSHA1), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumSHA1: aws.String(singlePartSHA1), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumSHA1: aws.String(multiPartTailSHA1), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumSHA1: multiPartSHA1, + expectETag: multiPartETag, + }, + "SHA256": { + algorithm: s3types.ChecksumAlgorithmSha256, + payload: bytes.NewReader(multiPartBytes), + checksumSHA256: multiPartSHA256, + expectParts: []s3types.CompletedPart{ + { + ChecksumSHA256: aws.String(singlePartSHA256), + ETag: aws.String(singlePartETag), + PartNumber: 1, + }, + { + ChecksumSHA256: aws.String(singlePartSHA256), + ETag: aws.String(singlePartETag), + PartNumber: 2, + }, + { + ChecksumSHA256: aws.String(multiPartTailSHA256), + ETag: aws.String(multiPartTailETag), + PartNumber: 3, + }, + }, + expectChecksumSHA256: multiPartSHA256, + expectETag: multiPartETag, + }, + }, + } + + for group, cs := range cases { + t.Run(group, func(t *testing.T) { + for name, c := range cs { + t.Run(name, func(t *testing.T) { + mgr := manager.NewUploader(client) + out, err := mgr.Upload(context.Background(), &s3.PutObjectInput{ + Bucket: bucketName, + Key: aws.String(t.Name()), + Body: c.payload, + ChecksumAlgorithm: c.algorithm, + ChecksumCRC32: toStringPtr(c.checksumCRC32), + ChecksumCRC32C: toStringPtr(c.checksumCRC32C), + ChecksumSHA1: toStringPtr(c.checksumSHA1), + ChecksumSHA256: toStringPtr(c.checksumSHA256), + ContentMD5: toStringPtr(c.contentMD5), + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if diff := cmp.Diff(c.expectParts, out.CompletedParts, cmpopts.IgnoreUnexported(types.CompletedPart{})); diff != "" { + t.Errorf("expect parts match\n%s", diff) + } + + if e, a := c.expectChecksumCRC32, aws.ToString(out.ChecksumCRC32); e != a { + t.Errorf("expect %v CRC32 checksum, got %v", e, a) + } + if e, a := c.expectChecksumCRC32C, aws.ToString(out.ChecksumCRC32C); e != a { + t.Errorf("expect %v CRC32C checksum, got %v", e, a) + } + if e, a := c.expectChecksumSHA1, aws.ToString(out.ChecksumSHA1); e != a { + t.Errorf("expect %v SHA1 checksum, got %v", e, a) + } + if e, a := c.expectChecksumSHA256, aws.ToString(out.ChecksumSHA256); e != a { + t.Errorf("expect %v SHA256 checksum, got %v", e, a) + } + if e, a := c.expectETag, aws.ToString(out.ETag); e != a { + t.Errorf("expect %v ETag, got %v", e, a) + } + }) + } + }) + } +} + +func toStringPtr(v string) *string { + if v == "" { + return nil + } + return &v +} + type invalidateHash struct{} func (b *invalidateHash) ID() string { diff --git a/feature/s3/manager/upload.go b/feature/s3/manager/upload.go index 089109f1ad9..3e80df4111f 100644 --- a/feature/s3/manager/upload.go +++ b/feature/s3/manager/upload.go @@ -4,12 +4,13 @@ import ( "bytes" "context" "fmt" - "github.com/aws/aws-sdk-go-v2/aws" "io" "net/http" "sort" "sync" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/internal/awsutil" "github.com/aws/aws-sdk-go-v2/service/s3" @@ -97,14 +98,62 @@ type UploadOutput struct { // The URL where the object was uploaded to. Location string + // The ID for a multipart upload to S3. In the case of an error the error + // can be cast to the MultiUploadFailure interface to extract the upload ID. + // Will be empty string if multipart upload was not used, and the object + // was uploaded as a single PutObject call. + UploadID string + + // The list of parts that were uploaded and their checksums. Will be empty + // if multipart upload was not used, and the object was uploaded as a + // single PutObject call. + CompletedParts []types.CompletedPart + + // Indicates whether the uploaded object uses an S3 Bucket Key for server-side + // encryption with Amazon Web Services KMS (SSE-KMS). + BucketKeyEnabled bool + + // The base64-encoded, 32-bit CRC32 checksum of the object. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. + ChecksumSHA256 *string + + // Entity tag for the uploaded object. + ETag *string + + // If the object expiration is configured, this will contain the expiration date + // (expiry-date) and rule ID (rule-id). The value of rule-id is URL encoded. + Expiration *string + + // The object key of the newly created object. + Key *string + + // If present, indicates that the requester was successfully charged for the + // request. + RequestCharged types.RequestCharged + + // If present, specifies the ID of the Amazon Web Services Key Management Service + // (Amazon Web Services KMS) symmetric customer managed customer master key (CMK) + // that was used for the object. + SSEKMSKeyId *string + + // If you specified server-side encryption either with an Amazon S3-managed + // encryption key or an Amazon Web Services KMS customer master key (CMK) in your + // initiate multipart upload request, the response includes this header. It + // confirms the encryption algorithm that Amazon S3 used to encrypt the object. + ServerSideEncryption types.ServerSideEncryption + // The version of the object that was uploaded. Will only be populated if // the S3 Bucket is versioned. If the bucket is not versioned this field // will not be set. VersionID *string - - // The ID for a multipart upload to S3. In the case of an error the error - // can be cast to the MultiUploadFailure interface to extract the upload ID. - UploadID string } // WithUploaderRequestOptions appends to the Uploader's API client options. @@ -117,6 +166,35 @@ func WithUploaderRequestOptions(opts ...func(*s3.Options)) func(*Uploader) { // The Uploader structure that calls Upload(). It is safe to call Upload() // on this structure for multiple objects and across concurrent goroutines. // Mutating the Uploader's properties is not safe to be done concurrently. +// +// Pre-computed Checksums +// +// Care must be taken when using pre-computed checksums the transfer upload +// manager. The format and value of the checksum differs based on if the upload +// will preformed as a single or multipart upload. +// +// Uploads that are smaller than the Uploader's PartSize will be uploaded using +// the PutObject API operation. Pre-computed checksum of the uploaded object's +// content are valid for these single part uploads. If the checksum provided +// does not match the uploaded content the upload will fail. +// +// Uploads that are larger than the Uploader's PartSize will be uploaded using +// multi-part upload. The Pre-computed checksums for these uploads are a +// checksum of checksums of each part. Not a checksum of the full uploaded +// bytes. With the format of "-", (e.g. +// "DUoRhQ==-3"). If a pre-computed checksum is provided that does not match +// this format, as matches the content uploaded, the upload will fail. +// +// ContentMD5 for multipart upload is explicitly ignored for multipart upload, +// and its value is suppressed. +// +// Automatically Computed Checksums +// +// When the ChecksumAlgorithm member of Upload's input parameter PutObjectInput +// is set to a valid value, the SDK will automatically compute the checksum of +// the individual uploaded parts. The UploadOutput result from Upload will +// include the checksum of part checksums provided by S3 +// CompleteMultipartUpload API call. type Uploader struct { // The buffer size (in bytes) to use when buffering data into chunks and // sending them as parts to S3. The minimum allowed part size is 5MB, and @@ -220,13 +298,17 @@ func NewUploader(client UploadAPIClient, options ...func(*Uploader)) *Uploader { // options that will be applied to all API operations made with this uploader. // // It is safe to call this method concurrently across goroutines. -func (u Uploader) Upload(ctx context.Context, input *s3.PutObjectInput, opts ...func(*Uploader)) (*UploadOutput, error) { +func (u Uploader) Upload(ctx context.Context, input *s3.PutObjectInput, opts ...func(*Uploader)) ( + *UploadOutput, error, +) { i := uploader{in: input, cfg: u, ctx: ctx} // Copy ClientOptions clientOptions := make([]func(*s3.Options), 0, len(i.cfg.ClientOptions)+1) clientOptions = append(clientOptions, func(o *s3.Options) { - o.APIOptions = append(o.APIOptions, middleware.AddSDKAgentKey(middleware.FeatureMetadata, userAgentKey)) + o.APIOptions = append(o.APIOptions, + middleware.AddSDKAgentKey(middleware.FeatureMetadata, userAgentKey), + ) }) clientOptions = append(clientOptions, i.cfg.ClientOptions...) i.cfg.ClientOptions = clientOptions @@ -402,22 +484,35 @@ func readFillBuf(r io.Reader, b []byte) (offset int, err error) { func (u *uploader) singlePart(r io.ReadSeeker, cleanup func()) (*UploadOutput, error) { defer cleanup() - params := &s3.PutObjectInput{} - awsutil.Copy(params, u.in) + var params s3.PutObjectInput + awsutil.Copy(¶ms, u.in) params.Body = r // Need to use request form because URL generated in request is // used in return. var locationRecorder recordLocationClient - out, err := u.cfg.S3.PutObject(u.ctx, params, append(u.cfg.ClientOptions, locationRecorder.WrapClient())...) + out, err := u.cfg.S3.PutObject(u.ctx, ¶ms, + append(u.cfg.ClientOptions, locationRecorder.WrapClient())...) if err != nil { return nil, err } return &UploadOutput{ - Location: locationRecorder.location, - VersionID: out.VersionId, + Location: locationRecorder.location, + + BucketKeyEnabled: out.BucketKeyEnabled, + ChecksumCRC32: out.ChecksumCRC32, + ChecksumCRC32C: out.ChecksumCRC32C, + ChecksumSHA1: out.ChecksumSHA1, + ChecksumSHA256: out.ChecksumSHA256, + ETag: out.ETag, + Expiration: out.Expiration, + Key: params.Key, + RequestCharged: out.RequestCharged, + SSEKMSKeyId: out.SSEKMSKeyId, + ServerSideEncryption: out.ServerSideEncryption, + VersionID: out.VersionId, }, nil } @@ -480,12 +575,13 @@ func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].Part // upload will perform a multipart upload using the firstBuf buffer containing // the first chunk of data. func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadOutput, error) { - params := &s3.CreateMultipartUploadInput{} - awsutil.Copy(params, u.in) + var params s3.CreateMultipartUploadInput + awsutil.Copy(¶ms, u.in) // Create the multipart var locationRecorder recordLocationClient - resp, err := u.cfg.S3.CreateMultipartUpload(u.ctx, params, append(u.cfg.ClientOptions, locationRecorder.WrapClient())...) + resp, err := u.cfg.S3.CreateMultipartUpload(u.ctx, ¶ms, + append(u.cfg.ClientOptions, locationRecorder.WrapClient())...) if err != nil { cleanup() return nil, err @@ -529,7 +625,7 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadO // Close the channel, wait for workers, and complete upload close(ch) u.wg.Wait() - complete := u.complete() + completeOut := u.complete() if err := u.geterr(); err != nil { return nil, &multiUploadError{ @@ -539,9 +635,22 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadO } return &UploadOutput{ - Location: locationRecorder.location, - VersionID: complete.VersionId, - UploadID: u.uploadID, + Location: locationRecorder.location, + UploadID: u.uploadID, + CompletedParts: u.parts, + + BucketKeyEnabled: completeOut.BucketKeyEnabled, + ChecksumCRC32: completeOut.ChecksumCRC32, + ChecksumCRC32C: completeOut.ChecksumCRC32C, + ChecksumSHA1: completeOut.ChecksumSHA1, + ChecksumSHA256: completeOut.ChecksumSHA256, + ETag: completeOut.ETag, + Expiration: completeOut.Expiration, + Key: completeOut.Key, + RequestCharged: completeOut.RequestCharged, + SSEKMSKeyId: completeOut.SSEKMSKeyId, + ServerSideEncryption: completeOut.ServerSideEncryption, + VersionID: completeOut.VersionId, }, nil } @@ -602,19 +711,30 @@ func (u *multiuploader) send(c chunk) error { Bucket: u.in.Bucket, Key: u.in.Key, Body: c.buf, - UploadId: &u.uploadID, SSECustomerAlgorithm: u.in.SSECustomerAlgorithm, SSECustomerKey: u.in.SSECustomerKey, - PartNumber: c.num, + SSECustomerKeyMD5: u.in.SSECustomerKeyMD5, + ExpectedBucketOwner: u.in.ExpectedBucketOwner, + RequestPayer: u.in.RequestPayer, + + ChecksumAlgorithm: u.in.ChecksumAlgorithm, + // Invalid to set any of the individual ChecksumXXX members from + // PutObject as they are never valid for individual parts of a + // multipart upload. + + PartNumber: c.num, + UploadId: &u.uploadID, } + // TODO should do copy then clear? resp, err := u.cfg.S3.UploadPart(u.ctx, params, u.cfg.ClientOptions...) if err != nil { return err } - n := c.num - completed := types.CompletedPart{ETag: resp.ETag, PartNumber: n} + var completed types.CompletedPart + awsutil.Copy(&completed, resp) + completed.PartNumber = c.num u.m.Lock() u.parts = append(u.parts, completed) @@ -668,13 +788,12 @@ func (u *multiuploader) complete() *s3.CompleteMultipartUploadOutput { // Parts must be sorted in PartNumber order. sort.Sort(u.parts) - params := &s3.CompleteMultipartUploadInput{ - Bucket: u.in.Bucket, - Key: u.in.Key, - UploadId: &u.uploadID, - MultipartUpload: &types.CompletedMultipartUpload{Parts: u.parts}, - } - resp, err := u.cfg.S3.CompleteMultipartUpload(u.ctx, params, u.cfg.ClientOptions...) + var params s3.CompleteMultipartUploadInput + awsutil.Copy(¶ms, u.in) + params.UploadId = &u.uploadID + params.MultipartUpload = &types.CompletedMultipartUpload{Parts: u.parts} + + resp, err := u.cfg.S3.CompleteMultipartUpload(u.ctx, ¶ms, u.cfg.ClientOptions...) if err != nil { u.seterr(err) u.fail() diff --git a/service/internal/benchmark/go.mod b/service/internal/benchmark/go.mod index 433cada100a..a4eef2bdb62 100644 --- a/service/internal/benchmark/go.mod +++ b/service/internal/benchmark/go.mod @@ -24,6 +24,8 @@ replace github.com/aws/aws-sdk-go-v2/service/dynamodb => ../../../service/dynamo replace github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding => ../../../service/internal/accept-encoding/ +replace github.com/aws/aws-sdk-go-v2/service/internal/checksum => ../../../service/internal/checksum/ + replace github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery => ../../../service/internal/endpoint-discovery/ replace github.com/aws/aws-sdk-go-v2/service/internal/presigned-url => ../../../service/internal/presigned-url/ diff --git a/service/internal/checksum/LICENSE.txt b/service/internal/checksum/LICENSE.txt new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/service/internal/checksum/LICENSE.txt @@ -0,0 +1,202 @@ + + 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 [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/service/internal/checksum/algorithms.go b/service/internal/checksum/algorithms.go new file mode 100644 index 00000000000..a17041c35d0 --- /dev/null +++ b/service/internal/checksum/algorithms.go @@ -0,0 +1,323 @@ +package checksum + +import ( + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "fmt" + "hash" + "hash/crc32" + "io" + "strings" + "sync" +) + +// Algorithm represents the checksum algorithms supported +type Algorithm string + +// Enumeration values for supported checksum Algorithms. +const ( + // AlgorithmCRC32C represents CRC32C hash algorithm + AlgorithmCRC32C Algorithm = "CRC32C" + + // AlgorithmCRC32 represents CRC32 hash algorithm + AlgorithmCRC32 Algorithm = "CRC32" + + // AlgorithmSHA1 represents SHA1 hash algorithm + AlgorithmSHA1 Algorithm = "SHA1" + + // AlgorithmSHA256 represents SHA256 hash algorithm + AlgorithmSHA256 Algorithm = "SHA256" +) + +var supportedAlgorithms = []Algorithm{ + AlgorithmCRC32C, + AlgorithmCRC32, + AlgorithmSHA1, + AlgorithmSHA256, +} + +func (a Algorithm) String() string { return string(a) } + +// ParseAlgorithm attempts to parse the provided value into a checksum +// algorithm, matching without case. Returns the algorithm matched, or an error +// if the algorithm wasn't matched. +func ParseAlgorithm(v string) (Algorithm, error) { + for _, a := range supportedAlgorithms { + if strings.EqualFold(string(a), v) { + return a, nil + } + } + return "", fmt.Errorf("unknown checksum algorithm, %v", v) +} + +// FilterSupportedAlgorithms filters the set of algorithms, returning a slice +// of algorithms that are supported. +func FilterSupportedAlgorithms(vs []string) []Algorithm { + found := map[Algorithm]struct{}{} + + supported := make([]Algorithm, 0, len(supportedAlgorithms)) + for _, v := range vs { + for _, a := range supportedAlgorithms { + // Only consider algorithms that are supported + if !strings.EqualFold(v, string(a)) { + continue + } + // Ignore duplicate algorithms in list. + if _, ok := found[a]; ok { + continue + } + + supported = append(supported, a) + found[a] = struct{}{} + } + } + return supported +} + +// NewAlgorithmHash returns a hash.Hash for the checksum algorithm. Error is +// returned if the algorithm is unknown. +func NewAlgorithmHash(v Algorithm) (hash.Hash, error) { + switch v { + case AlgorithmSHA1: + return sha1.New(), nil + case AlgorithmSHA256: + return sha256.New(), nil + case AlgorithmCRC32: + return crc32.NewIEEE(), nil + case AlgorithmCRC32C: + return crc32.New(crc32.MakeTable(crc32.Castagnoli)), nil + default: + return nil, fmt.Errorf("unknown checksum algorithm, %v", v) + } +} + +// AlgorithmChecksumLength returns the length of the algorithm's checksum in +// bytes. If the algorithm is not known, an error is returned. +func AlgorithmChecksumLength(v Algorithm) (int, error) { + switch v { + case AlgorithmSHA1: + return sha1.Size, nil + case AlgorithmSHA256: + return sha256.Size, nil + case AlgorithmCRC32: + return crc32.Size, nil + case AlgorithmCRC32C: + return crc32.Size, nil + default: + return 0, fmt.Errorf("unknown checksum algorithm, %v", v) + } +} + +const awsChecksumHeaderPrefix = "x-amz-checksum-" + +// AlgorithmHTTPHeader returns the HTTP header for the algorithm's hash. +func AlgorithmHTTPHeader(v Algorithm) string { + return awsChecksumHeaderPrefix + strings.ToLower(string(v)) +} + +// base64EncodeHashSum computes base64 encoded checksum of a given running +// hash. The running hash must already have content written to it. Returns the +// byte slice of checksum and an error +func base64EncodeHashSum(h hash.Hash) []byte { + sum := h.Sum(nil) + sum64 := make([]byte, base64.StdEncoding.EncodedLen(len(sum))) + base64.StdEncoding.Encode(sum64, sum) + return sum64 +} + +// hexEncodeHashSum computes hex encoded checksum of a given running hash. The +// running hash must already have content written to it. Returns the byte slice +// of checksum and an error +func hexEncodeHashSum(h hash.Hash) []byte { + sum := h.Sum(nil) + sumHex := make([]byte, hex.EncodedLen(len(sum))) + hex.Encode(sumHex, sum) + return sumHex +} + +// computeMD5Checksum computes base64 MD5 checksum of an io.Reader's contents. +// Returns the byte slice of MD5 checksum and an error. +func computeMD5Checksum(r io.Reader) ([]byte, error) { + h := md5.New() + + // Copy errors may be assumed to be from the body. + if _, err := io.Copy(h, r); err != nil { + return nil, fmt.Errorf("failed compute MD5 hash of reader, %w", err) + } + + // Encode the MD5 checksum in base64. + return base64EncodeHashSum(h), nil +} + +// computeChecksumReader provides a reader wrapping an underlying io.Reader to +// compute the checksum of the stream's bytes. +type computeChecksumReader struct { + stream io.Reader + algorithm Algorithm + hasher hash.Hash + base64ChecksumLen int + + mux sync.RWMutex + lockedChecksum string + lockedErr error +} + +// newComputeChecksumReader returns a computeChecksumReader for the stream and +// algorithm specified. Returns error if unable to create the reader, or +// algorithm is unknown. +func newComputeChecksumReader(stream io.Reader, algorithm Algorithm) (*computeChecksumReader, error) { + hasher, err := NewAlgorithmHash(algorithm) + if err != nil { + return nil, err + } + + checksumLength, err := AlgorithmChecksumLength(algorithm) + if err != nil { + return nil, err + } + + return &computeChecksumReader{ + stream: io.TeeReader(stream, hasher), + algorithm: algorithm, + hasher: hasher, + base64ChecksumLen: base64.StdEncoding.EncodedLen(checksumLength), + }, nil +} + +// Read wraps the underlying reader. When the underlying reader returns EOF, +// the checksum of the reader will be computed, and can be retrieved with +// ChecksumBase64String. +func (r *computeChecksumReader) Read(p []byte) (int, error) { + n, err := r.stream.Read(p) + if err == nil { + return n, nil + } else if err != io.EOF { + r.mux.Lock() + defer r.mux.Unlock() + + r.lockedErr = err + return n, err + } + + b := base64EncodeHashSum(r.hasher) + + r.mux.Lock() + defer r.mux.Unlock() + + r.lockedChecksum = string(b) + + return n, err +} + +func (r *computeChecksumReader) Algorithm() Algorithm { + return r.algorithm +} + +// Base64ChecksumLength returns the base64 encoded length of the checksum for +// algorithm. +func (r *computeChecksumReader) Base64ChecksumLength() int { + return r.base64ChecksumLen +} + +// Base64Checksum returns the base64 checksum for the algorithm, or error if +// the underlying reader returned a non-EOF error. +// +// Safe to be called concurrently, but will return an error until after the +// underlying reader is returns EOF. +func (r *computeChecksumReader) Base64Checksum() (string, error) { + r.mux.RLock() + defer r.mux.RUnlock() + + if r.lockedErr != nil { + return "", r.lockedErr + } + + if r.lockedChecksum == "" { + return "", fmt.Errorf( + "checksum not available yet, called before reader returns EOF", + ) + } + + return r.lockedChecksum, nil +} + +// validateChecksumReader implements io.ReadCloser interface. The wrapper +// performs checksum validation when the underlying reader has been fully read. +type validateChecksumReader struct { + originalBody io.ReadCloser + body io.Reader + hasher hash.Hash + algorithm Algorithm + expectChecksum string +} + +// newValidateChecksumReader returns a configured io.ReadCloser that performs +// checksum validation when the underlying reader has been fully read. +func newValidateChecksumReader( + body io.ReadCloser, + algorithm Algorithm, + expectChecksum string, +) (*validateChecksumReader, error) { + hasher, err := NewAlgorithmHash(algorithm) + if err != nil { + return nil, err + } + + return &validateChecksumReader{ + originalBody: body, + body: io.TeeReader(body, hasher), + hasher: hasher, + algorithm: algorithm, + expectChecksum: expectChecksum, + }, nil +} + +// Read attempts to read from the underlying stream while also updating the +// running hash. If the underlying stream returns with an EOF error, the +// checksum of the stream will be collected, and compared against the expected +// checksum. If the checksums do not match, an error will be returned. +// +// If a non-EOF error occurs when reading the underlying stream, that error +// will be returned and the checksum for the stream will be discarded. +func (c *validateChecksumReader) Read(p []byte) (n int, err error) { + n, err = c.body.Read(p) + if err == io.EOF { + if checksumErr := c.validateChecksum(); checksumErr != nil { + return n, checksumErr + } + } + + return n, err +} + +// Close closes the underlying reader, returning any error that occurred in the +// underlying reader. +func (c *validateChecksumReader) Close() (err error) { + return c.originalBody.Close() +} + +func (c *validateChecksumReader) validateChecksum() error { + // Compute base64 encoded checksum hash of the payload's read bytes. + v := base64EncodeHashSum(c.hasher) + if e, a := c.expectChecksum, string(v); !strings.EqualFold(e, a) { + return validationError{ + Algorithm: c.algorithm, Expect: e, Actual: a, + } + } + + return nil +} + +type validationError struct { + Algorithm Algorithm + Expect string + Actual string +} + +func (v validationError) Error() string { + return fmt.Sprintf("checksum did not match: algorithm %v, expect %v, actual %v", + v.Algorithm, v.Expect, v.Actual) +} diff --git a/service/internal/checksum/algorithms_test.go b/service/internal/checksum/algorithms_test.go new file mode 100644 index 00000000000..3f8b27018a7 --- /dev/null +++ b/service/internal/checksum/algorithms_test.go @@ -0,0 +1,470 @@ +//go:build go1.16 +// +build go1.16 + +package checksum + +import ( + "bytes" + "crypto/sha1" + "crypto/sha256" + "encoding/base64" + "fmt" + "hash/crc32" + "io" + "io/ioutil" + "strings" + "testing" + "testing/iotest" + + "github.com/google/go-cmp/cmp" +) + +func TestComputeChecksumReader(t *testing.T) { + cases := map[string]struct { + Input io.Reader + Algorithm Algorithm + ExpectErr string + ExpectChecksumLen int + + ExpectRead string + ExpectReadErr string + ExpectComputeErr string + ExpectChecksum string + }{ + "unknown algorithm": { + Input: bytes.NewBuffer(nil), + Algorithm: Algorithm("something"), + ExpectErr: "unknown checksum algorithm", + }, + "read error": { + Input: iotest.ErrReader(fmt.Errorf("some error")), + Algorithm: AlgorithmSHA256, + ExpectChecksumLen: base64.StdEncoding.EncodedLen(sha256.Size), + ExpectReadErr: "some error", + ExpectComputeErr: "some error", + }, + "crc32c": { + Input: strings.NewReader("hello world"), + Algorithm: AlgorithmCRC32C, + ExpectChecksumLen: base64.StdEncoding.EncodedLen(crc32.Size), + ExpectRead: "hello world", + ExpectChecksum: "yZRlqg==", + }, + "crc32": { + Input: strings.NewReader("hello world"), + Algorithm: AlgorithmCRC32, + ExpectChecksumLen: base64.StdEncoding.EncodedLen(crc32.Size), + ExpectRead: "hello world", + ExpectChecksum: "DUoRhQ==", + }, + "sha1": { + Input: strings.NewReader("hello world"), + Algorithm: AlgorithmSHA1, + ExpectChecksumLen: base64.StdEncoding.EncodedLen(sha1.Size), + ExpectRead: "hello world", + ExpectChecksum: "Kq5sNclPz7QV2+lfQIuc6R7oRu0=", + }, + "sha256": { + Input: strings.NewReader("hello world"), + Algorithm: AlgorithmSHA256, + ExpectChecksumLen: base64.StdEncoding.EncodedLen(sha256.Size), + ExpectRead: "hello world", + ExpectChecksum: "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + // Validate reader can be created as expected. + r, err := newComputeChecksumReader(c.Input, c.Algorithm) + if err == nil && len(c.ExpectErr) != 0 { + t.Fatalf("expect error %v, got none", c.ExpectErr) + } + if err != nil && len(c.ExpectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.ExpectErr) { + t.Fatalf("expect error to contain %v, got %v", c.ExpectErr, err) + } + if c.ExpectErr != "" { + return + } + + if e, a := c.Algorithm, r.Algorithm(); e != a { + t.Errorf("expect %v algorithm, got %v", e, a) + } + + // Validate expected checksum length. + if e, a := c.ExpectChecksumLen, r.Base64ChecksumLength(); e != a { + t.Errorf("expect %v checksum length, got %v", e, a) + } + + // Validate read reads underlying stream's bytes as expected. + b, err := ioutil.ReadAll(r) + if err == nil && len(c.ExpectReadErr) != 0 { + t.Fatalf("expect error %v, got none", c.ExpectReadErr) + } + if err != nil && len(c.ExpectReadErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.ExpectReadErr) { + t.Fatalf("expect error to contain %v, got %v", c.ExpectReadErr, err) + } + if len(c.ExpectReadErr) != 0 { + return + } + + if diff := cmp.Diff(string(c.ExpectRead), string(b)); diff != "" { + t.Errorf("expect read match, got\n%v", diff) + } + + // validate computed base64 + v, err := r.Base64Checksum() + if err == nil && len(c.ExpectComputeErr) != 0 { + t.Fatalf("expect error %v, got none", c.ExpectComputeErr) + } + if err != nil && len(c.ExpectComputeErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.ExpectComputeErr) { + t.Fatalf("expect error to contain %v, got %v", c.ExpectComputeErr, err) + } + if diff := cmp.Diff(c.ExpectChecksum, v); diff != "" { + t.Errorf("expect checksum match, got\n%v", diff) + } + if c.ExpectComputeErr != "" { + return + } + + if e, a := c.ExpectChecksumLen, len(v); e != a { + t.Errorf("expect computed checksum length %v, got %v", e, a) + } + }) + } +} + +func TestComputeChecksumReader_earlyGetChecksum(t *testing.T) { + r, err := newComputeChecksumReader(strings.NewReader("hello world"), AlgorithmCRC32C) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + v, err := r.Base64Checksum() + if err == nil { + t.Fatalf("expect error, got none") + } + if err != nil && !strings.Contains(err.Error(), "not available") { + t.Fatalf("expect error to match, got %v", err) + } + if v != "" { + t.Errorf("expect no checksum, got %v", err) + } +} + +// TODO race condition case with many reads, and get checksum + +func TestValidateChecksumReader(t *testing.T) { + cases := map[string]struct { + payload io.ReadCloser + algorithm Algorithm + checksum string + expectErr string + expectChecksumErr string + expectedBody []byte + }{ + "unknown algorithm": { + payload: ioutil.NopCloser(bytes.NewBuffer(nil)), + algorithm: Algorithm("something"), + expectErr: "unknown checksum algorithm", + }, + "empty body": { + payload: ioutil.NopCloser(bytes.NewReader([]byte(""))), + algorithm: AlgorithmCRC32, + checksum: "AAAAAA==", + expectedBody: []byte(""), + }, + "standard body": { + payload: ioutil.NopCloser(bytes.NewReader([]byte("Hello world"))), + algorithm: AlgorithmCRC32, + checksum: "i9aeUg==", + expectedBody: []byte("Hello world"), + }, + "checksum mismatch": { + payload: ioutil.NopCloser(bytes.NewReader([]byte("Hello world"))), + algorithm: AlgorithmCRC32, + checksum: "AAAAAA==", + expectedBody: []byte("Hello world"), + expectChecksumErr: "checksum did not match", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + response, err := newValidateChecksumReader(c.payload, c.algorithm, c.checksum) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if response == nil { + if c.expectedBody == nil { + return + } + t.Fatalf("expected non nil response, got nil") + } + + actualResponse, err := ioutil.ReadAll(response) + if err == nil && len(c.expectChecksumErr) != 0 { + t.Fatalf("expected error %v, got none", c.expectChecksumErr) + } + if err != nil && !strings.Contains(err.Error(), c.expectChecksumErr) { + t.Fatalf("expected error %v to contain %v", err.Error(), c.expectChecksumErr) + } + + if diff := cmp.Diff(c.expectedBody, actualResponse); len(diff) != 0 { + t.Fatalf("found diff comparing response body %v", diff) + } + + err = response.Close() + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + }) + } +} + +func TestComputeMD5Checksum(t *testing.T) { + cases := map[string]struct { + payload io.Reader + expectErr string + expectChecksum string + }{ + "empty payload": { + payload: strings.NewReader(""), + expectChecksum: "1B2M2Y8AsgTpgAmY7PhCfg==", + }, + "payload": { + payload: strings.NewReader("hello world"), + expectChecksum: "XrY7u+Ae7tCTyyK7j1rNww==", + }, + "error payload": { + payload: iotest.ErrReader(fmt.Errorf("some error")), + expectErr: "some error", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + actualChecksum, err := computeMD5Checksum(c.payload) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if e, a := c.expectChecksum, string(actualChecksum); !strings.EqualFold(e, a) { + t.Errorf("expect %v checksum, got %v", e, a) + } + }) + } +} + +func TestParseAlgorithm(t *testing.T) { + cases := map[string]struct { + Value string + expectAlgorithm Algorithm + expectErr string + }{ + "crc32c": { + Value: "crc32c", + expectAlgorithm: AlgorithmCRC32C, + }, + "CRC32C": { + Value: "CRC32C", + expectAlgorithm: AlgorithmCRC32C, + }, + "crc32": { + Value: "crc32", + expectAlgorithm: AlgorithmCRC32, + }, + "CRC32": { + Value: "CRC32", + expectAlgorithm: AlgorithmCRC32, + }, + "sha1": { + Value: "sha1", + expectAlgorithm: AlgorithmSHA1, + }, + "SHA1": { + Value: "SHA1", + expectAlgorithm: AlgorithmSHA1, + }, + "sha256": { + Value: "sha256", + expectAlgorithm: AlgorithmSHA256, + }, + "SHA256": { + Value: "SHA256", + expectAlgorithm: AlgorithmSHA256, + }, + "empty": { + Value: "", + expectErr: "unknown checksum algorithm", + }, + "unknown": { + Value: "unknown", + expectErr: "unknown checksum algorithm", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + // Asserts + algorithm, err := ParseAlgorithm(c.Value) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if e, a := c.expectAlgorithm, algorithm; e != a { + t.Errorf("expect %v algorithm, got %v", e, a) + } + }) + } +} + +func TestFilterSupportedAlgorithms(t *testing.T) { + cases := map[string]struct { + values []string + expectAlgorithms []Algorithm + }{ + "no algorithms": { + expectAlgorithms: []Algorithm{}, + }, + "no supported algorithms": { + values: []string{"abc", "123"}, + expectAlgorithms: []Algorithm{}, + }, + "duplicate algorithms": { + values: []string{"crc32", "crc32c", "crc32c"}, + expectAlgorithms: []Algorithm{ + AlgorithmCRC32, + AlgorithmCRC32C, + }, + }, + "preserve order": { + values: []string{"crc32", "crc32c", "sha1", "sha256"}, + expectAlgorithms: []Algorithm{ + AlgorithmCRC32, + AlgorithmCRC32C, + AlgorithmSHA1, + AlgorithmSHA256, + }, + }, + "preserve order 2": { + values: []string{"sha256", "crc32", "sha1", "crc32c"}, + expectAlgorithms: []Algorithm{ + AlgorithmSHA256, + AlgorithmCRC32, + AlgorithmSHA1, + AlgorithmCRC32C, + }, + }, + "mixed case": { + values: []string{"Crc32", "cRc32c", "shA1", "sHA256"}, + expectAlgorithms: []Algorithm{ + AlgorithmCRC32, + AlgorithmCRC32C, + AlgorithmSHA1, + AlgorithmSHA256, + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + algorithms := FilterSupportedAlgorithms(c.values) + if diff := cmp.Diff(c.expectAlgorithms, algorithms); diff != "" { + t.Errorf("expect algorithms match\n%s", diff) + } + }) + } +} + +func TestAlgorithmChecksumLength(t *testing.T) { + cases := map[string]struct { + algorithm Algorithm + expectErr string + expectLength int + }{ + "empty": { + algorithm: "", + expectErr: "unknown checksum algorithm", + }, + "unknown": { + algorithm: "", + expectErr: "unknown checksum algorithm", + }, + "crc32": { + algorithm: AlgorithmCRC32, + expectLength: crc32.Size, + }, + "crc32c": { + algorithm: AlgorithmCRC32C, + expectLength: crc32.Size, + }, + "sha1": { + algorithm: AlgorithmSHA1, + expectLength: sha1.Size, + }, + "sha256": { + algorithm: AlgorithmSHA256, + expectLength: sha256.Size, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + l, err := AlgorithmChecksumLength(c.algorithm) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if e, a := c.expectLength, l; e != a { + t.Errorf("expect %v checksum length, got %v", e, a) + } + }) + } +} diff --git a/service/internal/checksum/aws_chunked_encoding.go b/service/internal/checksum/aws_chunked_encoding.go new file mode 100644 index 00000000000..e8b5c3f5a2c --- /dev/null +++ b/service/internal/checksum/aws_chunked_encoding.go @@ -0,0 +1,389 @@ +package checksum + +import ( + "bytes" + "fmt" + "io" + "strconv" + "strings" +) + +const ( + crlf = "\r\n" + + // https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html + defaultChunkLength = 1024 * 64 + + awsTrailerHeaderName = "x-amz-trailer" + decodedContentLengthHeaderName = "x-amz-decoded-content-length" + + contentEncodingHeaderName = "content-encoding" + awsChunkedContentEncodingHeaderValue = "aws-chunked" + + trailerKeyValueSeparator = ":" +) + +var ( + crlfBytes = []byte(crlf) + finalChunkBytes = []byte("0" + crlf) +) + +type awsChunkedEncodingOptions struct { + // The total size of the stream. For unsigned encoding this implies that + // there will only be a single chunk containing the underlying payload, + // unless ChunkLength is also specified. + StreamLength int64 + + // Set of trailer key:value pairs that will be appended to the end of the + // payload after the end chunk has been written. + Trailers map[string]awsChunkedTrailerValue + + // The maximum size of each chunk to be sent. Default value of -1, signals + // that optimal chunk length will be used automatically. ChunkSize must be + // at least 8KB. + // + // If ChunkLength and StreamLength are both specified, the stream will be + // broken up into ChunkLength chunks. The encoded length of the aws-chunked + // encoding can still be determined as long as all trailers, if any, have a + // fixed length. + ChunkLength int +} + +type awsChunkedTrailerValue struct { + // Function to retrieve the value of the trailer. Will only be called after + // the underlying stream returns EOF error. + Get func() (string, error) + + // If the length of the value can be pre-determined, and is constant + // specify the length. A value of -1 means the length is unknown, or + // cannot be pre-determined. + Length int +} + +// awsChunkedEncoding provides a reader that wraps the payload such that +// payload is read as a single aws-chunk payload. This reader can only be used +// if the content length of payload is known. Content-Length is used as size of +// the single payload chunk. The final chunk and trailing checksum is appended +// at the end. +// +// https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html#sigv4-chunked-body-definition +// +// Here is the aws-chunked payload stream as read from the awsChunkedEncoding +// if original request stream is "Hello world", and checksum hash used is SHA256 +// +// \r\n +// Hello world\r\n +// 0\r\n +// x-amz-checksum-sha256:ZOyIygCyaOW6GjVnihtTFtIS9PNmskdyMlNKiuyjfzw=\r\n +// \r\n +type awsChunkedEncoding struct { + options awsChunkedEncodingOptions + + encodedStream io.Reader + trailerEncodedLength int +} + +// newUnsignedAWSChunkedEncoding returns a new awsChunkedEncoding configured +// for unsigned aws-chunked content encoding. Any additional trailers that need +// to be appended after the end chunk must be included as via Trailer +// callbacks. +func newUnsignedAWSChunkedEncoding( + stream io.Reader, + optFns ...func(*awsChunkedEncodingOptions), +) *awsChunkedEncoding { + options := awsChunkedEncodingOptions{ + Trailers: map[string]awsChunkedTrailerValue{}, + StreamLength: -1, + ChunkLength: -1, + } + for _, fn := range optFns { + fn(&options) + } + + var chunkReader io.Reader + if options.ChunkLength != -1 || options.StreamLength == -1 { + if options.ChunkLength == -1 { + options.ChunkLength = defaultChunkLength + } + chunkReader = newBufferedAWSChunkReader(stream, options.ChunkLength) + } else { + chunkReader = newUnsignedChunkReader(stream, options.StreamLength) + } + + trailerReader := newAWSChunkedTrailerReader(options.Trailers) + + return &awsChunkedEncoding{ + options: options, + encodedStream: io.MultiReader(chunkReader, + trailerReader, + bytes.NewBuffer(crlfBytes), + ), + trailerEncodedLength: trailerReader.EncodedLength(), + } +} + +// EncodedLength returns the final length of the aws-chunked content encoded +// stream if it can be determined without reading the underlying stream or lazy +// header values, otherwise -1 is returned. +func (e *awsChunkedEncoding) EncodedLength() int64 { + var length int64 + if e.options.StreamLength == -1 || e.trailerEncodedLength == -1 { + return -1 + } + + if e.options.StreamLength != 0 { + // If the stream length is known, and there is no chunk length specified, + // only a single chunk will be used. Otherwise the stream length needs to + // include the multiple chunk padding content. + if e.options.ChunkLength == -1 { + length += getUnsignedChunkBytesLength(e.options.StreamLength) + + } else { + // Compute chunk header and payload length + numChunks := e.options.StreamLength / int64(e.options.ChunkLength) + length += numChunks * getUnsignedChunkBytesLength(int64(e.options.ChunkLength)) + if remainder := e.options.StreamLength % int64(e.options.ChunkLength); remainder != 0 { + length += getUnsignedChunkBytesLength(remainder) + } + } + } + + // End chunk + length += int64(len(finalChunkBytes)) + + // Trailers + length += int64(e.trailerEncodedLength) + + // Encoding terminator + length += int64(len(crlf)) + + return length +} + +func getUnsignedChunkBytesLength(payloadLength int64) int64 { + payloadLengthStr := strconv.FormatInt(payloadLength, 16) + return int64(len(payloadLengthStr)) + int64(len(crlf)) + payloadLength + int64(len(crlf)) +} + +// HTTPHeaders returns the set of headers that must be included the request for +// aws-chunked to work. This includes the content-encoding: aws-chunked header. +// +// If there are multiple layered content encoding, the aws-chunked encoding +// must be appended to the previous layers the stream's encoding. The best way +// to do this is to append all header values returned to the HTTP request's set +// of headers. +func (e *awsChunkedEncoding) HTTPHeaders() map[string][]string { + headers := map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + } + + if len(e.options.Trailers) != 0 { + trailers := make([]string, 0, len(e.options.Trailers)) + for name := range e.options.Trailers { + trailers = append(trailers, strings.ToLower(name)) + } + headers[awsTrailerHeaderName] = trailers + } + + return headers +} + +func (e *awsChunkedEncoding) Read(b []byte) (n int, err error) { + return e.encodedStream.Read(b) +} + +// awsChunkedTrailerReader provides a lazy reader for reading of aws-chunked +// content encoded trailers. The trailer values will not be retrieved until the +// reader is read from. +type awsChunkedTrailerReader struct { + reader *bytes.Buffer + trailers map[string]awsChunkedTrailerValue + trailerEncodedLength int +} + +// newAWSChunkedTrailerReader returns an initialized awsChunkedTrailerReader to +// lazy reading aws-chunk content encoded trailers. +func newAWSChunkedTrailerReader(trailers map[string]awsChunkedTrailerValue) *awsChunkedTrailerReader { + return &awsChunkedTrailerReader{ + trailers: trailers, + trailerEncodedLength: trailerEncodedLength(trailers), + } +} + +func trailerEncodedLength(trailers map[string]awsChunkedTrailerValue) (length int) { + for name, trailer := range trailers { + length += len(name) + len(trailerKeyValueSeparator) + l := trailer.Length + if l == -1 { + return -1 + } + length += l + len(crlf) + } + + return length +} + +// EncodedLength returns the length of the encoded trailers if the length could +// be determined without retrieving the header values. Returns -1 if length is +// unknown. +func (r *awsChunkedTrailerReader) EncodedLength() (length int) { + return r.trailerEncodedLength +} + +// Read populates the passed in byte slice with bytes from the encoded +// trailers. Will lazy read header values first time Read is called. +func (r *awsChunkedTrailerReader) Read(p []byte) (int, error) { + if r.trailerEncodedLength == 0 { + return 0, io.EOF + } + + if r.reader == nil { + trailerLen := r.trailerEncodedLength + if r.trailerEncodedLength == -1 { + trailerLen = 0 + } + r.reader = bytes.NewBuffer(make([]byte, 0, trailerLen)) + for name, trailer := range r.trailers { + r.reader.WriteString(name) + r.reader.WriteString(trailerKeyValueSeparator) + v, err := trailer.Get() + if err != nil { + return 0, fmt.Errorf("failed to get trailer value, %w", err) + } + r.reader.WriteString(v) + r.reader.WriteString(crlf) + } + } + + return r.reader.Read(p) +} + +// newUnsignedChunkReader returns an io.Reader encoding the underlying reader +// as unsigned aws-chunked chunks. The returned reader will also include the +// end chunk, but not the aws-chunked final `crlf` segment so trailers can be +// added. +// +// If the payload size is -1 for unknown length the content will be buffered in +// defaultChunkLength chunks before wrapped in aws-chunked chunk encoding. +func newUnsignedChunkReader(reader io.Reader, payloadSize int64) io.Reader { + if payloadSize == -1 { + return newBufferedAWSChunkReader(reader, defaultChunkLength) + } + + var endChunk bytes.Buffer + if payloadSize == 0 { + endChunk.Write(finalChunkBytes) + return &endChunk + } + + endChunk.WriteString(crlf) + endChunk.Write(finalChunkBytes) + + var header bytes.Buffer + header.WriteString(strconv.FormatInt(payloadSize, 16)) + header.WriteString(crlf) + return io.MultiReader( + &header, + reader, + &endChunk, + ) +} + +// Provides a buffered aws-chunked chunk encoder of an underlying io.Reader. +// Will include end chunk, but not the aws-chunked final `crlf` segment so +// trailers can be added. +// +// Note does not implement support for chunk extensions, e.g. chunk signing. +type bufferedAWSChunkReader struct { + reader io.Reader + chunkSize int + chunkSizeStr string + + headerBuffer *bytes.Buffer + chunkBuffer *bytes.Buffer + + multiReader io.Reader + multiReaderLen int + endChunkDone bool +} + +// newBufferedAWSChunkReader returns an bufferedAWSChunkReader for reading +// aws-chunked encoded chunks. +func newBufferedAWSChunkReader(reader io.Reader, chunkSize int) *bufferedAWSChunkReader { + return &bufferedAWSChunkReader{ + reader: reader, + chunkSize: chunkSize, + chunkSizeStr: strconv.FormatInt(int64(chunkSize), 16), + + headerBuffer: bytes.NewBuffer(make([]byte, 0, 64)), + chunkBuffer: bytes.NewBuffer(make([]byte, 0, chunkSize+len(crlf))), + } +} + +// Read attempts to read from the underlying io.Reader writing aws-chunked +// chunk encoded bytes to p. When the underlying io.Reader has been completed +// read the end chunk will be available. Once the end chunk is read, the reader +// will return EOF. +func (r *bufferedAWSChunkReader) Read(p []byte) (n int, err error) { + if r.multiReaderLen == 0 && r.endChunkDone { + return 0, io.EOF + } + if r.multiReader == nil || r.multiReaderLen == 0 { + r.multiReader, r.multiReaderLen, err = r.newMultiReader() + if err != nil { + return 0, err + } + } + + n, err = r.multiReader.Read(p) + r.multiReaderLen -= n + + if err == io.EOF && !r.endChunkDone { + // Edge case handling when the multi-reader has been completely read, + // and returned an EOF, make sure that EOF only gets returned if the + // end chunk was included in the multi-reader. Otherwise, the next call + // to read will initialize the next chunk's multi-reader. + err = nil + } + return n, err +} + +// newMultiReader returns a new io.Reader for wrapping the next chunk. Will +// return an error if the underlying reader can not be read from. Will never +// return io.EOF. +func (r *bufferedAWSChunkReader) newMultiReader() (io.Reader, int, error) { + // io.Copy eats the io.EOF returned by io.LimitReader. Any error that + // occurs here is due to an actual read error. + n, err := io.Copy(r.chunkBuffer, io.LimitReader(r.reader, int64(r.chunkSize))) + if err != nil { + return nil, 0, err + } + if n == 0 { + // Early exit writing out only the end chunk. This does not include + // aws-chunk's final `crlf` so that trailers can still be added by + // upstream reader. + r.headerBuffer.Reset() + r.headerBuffer.WriteString("0") + r.headerBuffer.WriteString(crlf) + r.endChunkDone = true + + return r.headerBuffer, r.headerBuffer.Len(), nil + } + r.chunkBuffer.WriteString(crlf) + + chunkSizeStr := r.chunkSizeStr + if int(n) != r.chunkSize { + chunkSizeStr = strconv.FormatInt(n, 16) + } + + r.headerBuffer.Reset() + r.headerBuffer.WriteString(chunkSizeStr) + r.headerBuffer.WriteString(crlf) + + return io.MultiReader( + r.headerBuffer, + r.chunkBuffer, + ), r.headerBuffer.Len() + r.chunkBuffer.Len(), nil +} diff --git a/service/internal/checksum/aws_chunked_encoding_test.go b/service/internal/checksum/aws_chunked_encoding_test.go new file mode 100644 index 00000000000..8e9ce3c8a9d --- /dev/null +++ b/service/internal/checksum/aws_chunked_encoding_test.go @@ -0,0 +1,507 @@ +//go:build go1.16 +// +build go1.16 + +package checksum + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "strings" + "testing" + "testing/iotest" + + "github.com/google/go-cmp/cmp" +) + +func TestAWSChunkedEncoding(t *testing.T) { + cases := map[string]struct { + reader *awsChunkedEncoding + expectErr string + expectEncodedLength int64 + expectHTTPHeaders map[string][]string + expectPayload []byte + }{ + "empty payload fixed stream length": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader(""), + func(o *awsChunkedEncodingOptions) { + o.StreamLength = 0 + }), + expectEncodedLength: 5, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + }, + expectPayload: []byte("0\r\n\r\n"), + }, + "empty payload unknown stream length": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader("")), + expectEncodedLength: -1, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + }, + expectPayload: []byte("0\r\n\r\n"), + }, + "payload fixed stream length": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader("hello world"), + func(o *awsChunkedEncodingOptions) { + o.StreamLength = 11 + }), + expectEncodedLength: 21, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + }, + expectPayload: []byte("b\r\nhello world\r\n0\r\n\r\n"), + }, + "payload unknown stream length": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader("hello world")), + expectEncodedLength: -1, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + }, + expectPayload: []byte("b\r\nhello world\r\n0\r\n\r\n"), + }, + "payload unknown stream length with chunk size": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader("hello world"), + func(o *awsChunkedEncodingOptions) { + o.ChunkLength = 8 + }), + expectEncodedLength: -1, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + }, + expectPayload: []byte("8\r\nhello wo\r\n3\r\nrld\r\n0\r\n\r\n"), + }, + "payload fixed stream length with chunk size": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader("hello world"), + func(o *awsChunkedEncodingOptions) { + o.StreamLength = 11 + o.ChunkLength = 8 + }), + expectEncodedLength: 26, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + }, + expectPayload: []byte("8\r\nhello wo\r\n3\r\nrld\r\n0\r\n\r\n"), + }, + "payload fixed stream length with fixed length trailer": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader("hello world"), + func(o *awsChunkedEncodingOptions) { + o.StreamLength = 11 + o.Trailers = map[string]awsChunkedTrailerValue{ + "foo": { + Get: func() (string, error) { + return "abc123", nil + }, + Length: 6, + }, + } + }), + expectEncodedLength: 33, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + awsTrailerHeaderName: {"foo"}, + }, + expectPayload: []byte("b\r\nhello world\r\n0\r\nfoo:abc123\r\n\r\n"), + }, + "payload fixed stream length with unknown length trailer": { + reader: newUnsignedAWSChunkedEncoding(strings.NewReader("hello world"), + func(o *awsChunkedEncodingOptions) { + o.StreamLength = 11 + o.Trailers = map[string]awsChunkedTrailerValue{ + "foo": { + Get: func() (string, error) { + return "abc123", nil + }, + Length: -1, + }, + } + }), + expectEncodedLength: -1, + expectHTTPHeaders: map[string][]string{ + contentEncodingHeaderName: { + awsChunkedContentEncodingHeaderValue, + }, + awsTrailerHeaderName: {"foo"}, + }, + expectPayload: []byte("b\r\nhello world\r\n0\r\nfoo:abc123\r\n\r\n"), + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if e, a := c.expectEncodedLength, c.reader.EncodedLength(); e != a { + t.Errorf("expect %v encoded length, got %v", e, a) + } + if diff := cmp.Diff(c.expectHTTPHeaders, c.reader.HTTPHeaders()); diff != "" { + t.Errorf("expect HTTP headers match\n%v", diff) + } + + actualPayload, err := ioutil.ReadAll(c.reader) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if diff := cmp.Diff(string(c.expectPayload), string(actualPayload)); diff != "" { + t.Errorf("expect payload match\n%v", diff) + } + }) + } +} + +func TestUnsignedAWSChunkReader(t *testing.T) { + cases := map[string]struct { + payload interface { + io.Reader + Len() int + } + + expectPayload []byte + expectErr string + }{ + "empty body": { + payload: bytes.NewReader([]byte{}), + expectPayload: []byte("0\r\n"), + }, + "with body": { + payload: strings.NewReader("Hello world"), + expectPayload: []byte("b\r\nHello world\r\n0\r\n"), + }, + "large body": { + payload: bytes.NewBufferString("Hello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello world"), + expectPayload: []byte("205\r\nHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello world\r\n0\r\n"), + }, + "reader error": { + payload: newLimitReadLener(iotest.ErrReader(fmt.Errorf("some read error")), 128), + expectErr: "some read error", + }, + "unknown length reader": { + payload: newUnknownLenReader(io.LimitReader(byteReader('a'), defaultChunkLength*2)), + expectPayload: func() []byte { + reader := newBufferedAWSChunkReader( + io.LimitReader(byteReader('a'), defaultChunkLength*2), + defaultChunkLength, + ) + actualPayload, err := ioutil.ReadAll(reader) + if err != nil { + t.Fatalf("failed to create unknown length reader test data, %v", err) + } + return actualPayload + }(), + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + reader := newUnsignedChunkReader(c.payload, int64(c.payload.Len())) + + actualPayload, err := ioutil.ReadAll(reader) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if diff := cmp.Diff(string(c.expectPayload), string(actualPayload)); diff != "" { + t.Errorf("expect payload match\n%v", diff) + } + }) + } +} + +func TestBufferedAWSChunkReader(t *testing.T) { + cases := map[string]struct { + payload io.Reader + readSize int + chunkSize int + + expectPayload []byte + expectErr string + }{ + "empty body": { + payload: bytes.NewReader([]byte{}), + chunkSize: 4, + expectPayload: []byte("0\r\n"), + }, + "with one chunk body": { + payload: strings.NewReader("Hello world"), + chunkSize: 20, + expectPayload: []byte("b\r\nHello world\r\n0\r\n"), + }, + "single byte read": { + payload: strings.NewReader("Hello world"), + chunkSize: 8, + readSize: 1, + expectPayload: []byte("8\r\nHello wo\r\n3\r\nrld\r\n0\r\n"), + }, + "single chunk and byte read": { + payload: strings.NewReader("Hello world"), + chunkSize: 1, + readSize: 1, + expectPayload: []byte("1\r\nH\r\n1\r\ne\r\n1\r\nl\r\n1\r\nl\r\n1\r\no\r\n1\r\n \r\n1\r\nw\r\n1\r\no\r\n1\r\nr\r\n1\r\nl\r\n1\r\nd\r\n0\r\n"), + }, + "with two chunk body": { + payload: strings.NewReader("Hello world"), + chunkSize: 8, + expectPayload: []byte("8\r\nHello wo\r\n3\r\nrld\r\n0\r\n"), + }, + "chunk size equal to read size": { + payload: strings.NewReader("Hello world"), + chunkSize: 512, + expectPayload: []byte("b\r\nHello world\r\n0\r\n"), + }, + "chunk size greater than read size": { + payload: strings.NewReader("Hello world"), + chunkSize: 1024, + expectPayload: []byte("b\r\nHello world\r\n0\r\n"), + }, + "payload size more than default read size, chunk size less than read size": { + payload: bytes.NewBufferString("Hello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello world"), + chunkSize: 500, + expectPayload: []byte("1f4\r\nHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello\r\n11\r\n worldHello world\r\n0\r\n"), + }, + "payload size more than default read size, chunk size equal to read size": { + payload: bytes.NewBufferString("Hello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello world"), + chunkSize: 512, + expectPayload: []byte("200\r\nHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello \r\n5\r\nworld\r\n0\r\n"), + }, + "payload size more than default read size, chunk size more than read size": { + payload: bytes.NewBufferString("Hello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello world"), + chunkSize: 1024, + expectPayload: []byte("205\r\nHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello worldHello " + + "worldHello worldHello worldHello worldHello worldHello world\r\n0\r\n"), + }, + "reader error": { + payload: iotest.ErrReader(fmt.Errorf("some read error")), + chunkSize: 128, + expectErr: "some read error", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + reader := newBufferedAWSChunkReader(c.payload, c.chunkSize) + + var actualPayload []byte + var err error + + if c.readSize != 0 { + for err == nil { + var n int + p := make([]byte, c.readSize) + n, err = reader.Read(p) + if n != 0 { + actualPayload = append(actualPayload, p[:n]...) + } + } + if err == io.EOF { + err = nil + } + } else { + actualPayload, err = ioutil.ReadAll(reader) + } + + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if diff := cmp.Diff(string(c.expectPayload), string(actualPayload)); diff != "" { + t.Errorf("expect payload match\n%v", diff) + } + }) + } +} + +func TestAwsChunkedTrailerReader(t *testing.T) { + cases := map[string]struct { + reader *awsChunkedTrailerReader + + expectErr string + expectEncodedLength int + expectPayload []byte + }{ + "no trailers": { + reader: newAWSChunkedTrailerReader(nil), + expectPayload: []byte{}, + }, + "unknown length trailers": { + reader: newAWSChunkedTrailerReader(map[string]awsChunkedTrailerValue{ + "foo": { + Get: func() (string, error) { + return "abc123", nil + }, + Length: -1, + }, + }), + expectEncodedLength: -1, + expectPayload: []byte("foo:abc123\r\n"), + }, + "known length trailers": { + reader: newAWSChunkedTrailerReader(map[string]awsChunkedTrailerValue{ + "foo": { + Get: func() (string, error) { + return "abc123", nil + }, + Length: 6, + }, + }), + expectEncodedLength: 12, + expectPayload: []byte("foo:abc123\r\n"), + }, + "trailer error": { + reader: newAWSChunkedTrailerReader(map[string]awsChunkedTrailerValue{ + "foo": { + Get: func() (string, error) { + return "", fmt.Errorf("some error") + }, + Length: 6, + }, + }), + expectEncodedLength: 12, + expectErr: "failed to get trailer", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if e, a := c.expectEncodedLength, c.reader.EncodedLength(); e != a { + t.Errorf("expect %v encoded length, got %v", e, a) + } + + actualPayload, err := ioutil.ReadAll(c.reader) + + // Asserts + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + if diff := cmp.Diff(string(c.expectPayload), string(actualPayload)); diff != "" { + t.Errorf("expect payload match\n%v", diff) + } + }) + } +} + +type limitReadLener struct { + io.Reader + length int +} + +func newLimitReadLener(r io.Reader, l int) *limitReadLener { + return &limitReadLener{ + Reader: io.LimitReader(r, int64(l)), + length: l, + } +} +func (r *limitReadLener) Len() int { + return r.length +} + +type unknownLenReader struct { + io.Reader +} + +func newUnknownLenReader(r io.Reader) *unknownLenReader { + return &unknownLenReader{ + Reader: r, + } +} +func (r *unknownLenReader) Len() int { + return -1 +} + +type byteReader byte + +func (r byteReader) Read(p []byte) (int, error) { + for i := 0; i < len(p); i++ { + p[i] = byte(r) + } + return len(p), nil +} diff --git a/service/internal/checksum/go.mod b/service/internal/checksum/go.mod new file mode 100644 index 00000000000..2f9a9293192 --- /dev/null +++ b/service/internal/checksum/go.mod @@ -0,0 +1,11 @@ +module github.com/aws/aws-sdk-go-v2/service/internal/checksum + +go 1.15 + +require ( + github.com/aws/aws-sdk-go-v2 v1.13.0 + github.com/aws/smithy-go v1.10.1-0.20220223172659-66863935410f + github.com/google/go-cmp v0.5.7 +) + +replace github.com/aws/aws-sdk-go-v2 => ../../../ diff --git a/service/internal/checksum/go.sum b/service/internal/checksum/go.sum new file mode 100644 index 00000000000..71b0f3f6c2d --- /dev/null +++ b/service/internal/checksum/go.sum @@ -0,0 +1,13 @@ +github.com/aws/smithy-go v1.10.1-0.20220223172659-66863935410f h1:NbdOxyeISnwVF6VFxWz2TJ84x8TH+tPUixCqQI01s9s= +github.com/aws/smithy-go v1.10.1-0.20220223172659-66863935410f/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/service/internal/checksum/go_module_metadata.go b/service/internal/checksum/go_module_metadata.go new file mode 100644 index 00000000000..085d94bd1b0 --- /dev/null +++ b/service/internal/checksum/go_module_metadata.go @@ -0,0 +1,6 @@ +// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT. + +package checksum + +// goModuleVersion is the tagged release for this module +const goModuleVersion = "tip" diff --git a/service/internal/checksum/middleware_add.go b/service/internal/checksum/middleware_add.go new file mode 100644 index 00000000000..3e17d2216b7 --- /dev/null +++ b/service/internal/checksum/middleware_add.go @@ -0,0 +1,185 @@ +package checksum + +import ( + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// InputMiddlewareOptions provides the options for the request +// checksum middleware setup. +type InputMiddlewareOptions struct { + // GetAlgorithm is a function to get the checksum algorithm of the + // input payload from the input parameters. + // + // Given the input parameter value, the function must return the algorithm + // and true, or false if no algorithm is specified. + GetAlgorithm func(interface{}) (string, bool) + + // Forces the middleware to compute the input payload's checksum. The + // request will fail if the algorithm is not specified or unable to compute + // the checksum. + RequireChecksum bool + + // Enables support for wrapping the serialized input payload with a + // content-encoding: aws-check wrapper, and including a trailer for the + // algorithm's checksum value. + // + // The checksum will not be computed, nor added as trailing checksum, if + // the Algorithm's header is already set on the request. + EnableTrailingChecksum bool + + // Enables support for computing the SHA256 checksum of input payloads + // along with the algorithm specified checksum. Prevents downstream + // middleware handlers (computePayloadSHA256) re-reading the payload. + // + // The SHA256 payload checksum will only be used for computed for requests + // that are not TLS, or do not enable trailing checksums. + // + // The SHA256 payload hash will not be computed, if the Algorithm's header + // is already set on the request. + EnableComputeSHA256PayloadHash bool + + // Enables support for setting the aws-chunked decoded content length + // header for the decoded length of the underlying stream. Will only be set + // when used with trailing checksums, and aws-chunked content-encoding. + EnableDecodedContentLengthHeader bool +} + +// AddInputMiddleware adds the middleware for performing checksum computing +// of request payloads, and checksum validation of response payloads. +func AddInputMiddleware(stack *middleware.Stack, options InputMiddlewareOptions) (err error) { + // TODO ensure this works correctly with presigned URLs + + // Middleware stack: + // * (OK)(Initialize) --none-- + // * (OK)(Serialize) EndpointResolver + // * (OK)(Build) ComputeContentLength + // * (AD)(Build) Header ComputeInputPayloadChecksum + // * SIGNED Payload - If HTTP && not support trailing checksum + // * UNSIGNED Payload - If HTTPS && not support trailing checksum + // * (RM)(Build) ContentChecksum - OK to remove + // * (OK)(Build) ComputePayloadHash + // * v4.dynamicPayloadSigningMiddleware + // * v4.computePayloadSHA256 + // * v4.unsignedPayload + // (OK)(Build) Set computedPayloadHash header + // * (OK)(Finalize) Retry + // * (AD)(Finalize) Trailer ComputeInputPayloadChecksum, + // * Requires HTTPS && support trailing checksum + // * UNSIGNED Payload + // * Finalize run if HTTPS && support trailing checksum + // * (OK)(Finalize) Signing + // * (OK)(Deserialize) --none-- + + // Initial checksum configuration look up middleware + err = stack.Initialize.Add(&setupInputContext{ + GetAlgorithm: options.GetAlgorithm, + }, middleware.Before) + if err != nil { + return err + } + + stack.Build.Remove("ContentChecksum") + + // Create the compute checksum middleware that will be added as both a + // build and finalize handler. + inputChecksum := &computeInputPayloadChecksum{ + RequireChecksum: options.RequireChecksum, + EnableTrailingChecksum: options.EnableTrailingChecksum, + EnableComputePayloadHash: options.EnableComputeSHA256PayloadHash, + EnableDecodedContentLengthHeader: options.EnableDecodedContentLengthHeader, + } + + // Insert header checksum after ComputeContentLength middleware, must also + // be before the computePayloadHash middleware handlers. + err = stack.Build.Insert(inputChecksum, + (*smithyhttp.ComputeContentLength)(nil).ID(), + middleware.After) + if err != nil { + return err + } + + // If trailing checksum is not supported no need for finalize handler to be added. + if options.EnableTrailingChecksum { + err = stack.Finalize.Insert(inputChecksum, "Retry", middleware.After) + if err != nil { + return err + } + } + + return nil +} + +// RemoveInputMiddleware Removes the compute input payload checksum middleware +// handlers from the stack. +func RemoveInputMiddleware(stack *middleware.Stack) { + id := (*setupInputContext)(nil).ID() + stack.Initialize.Remove(id) + + id = (*computeInputPayloadChecksum)(nil).ID() + stack.Build.Remove(id) + stack.Finalize.Remove(id) +} + +// OutputMiddlewareOptions provides options for configuring output checksum +// validation middleware. +type OutputMiddlewareOptions struct { + // GetValidationMode is a function to get the checksum validation + // mode of the output payload from the input parameters. + // + // Given the input parameter value, the function must return the validation + // mode and true, or false if no mode is specified. + GetValidationMode func(interface{}) (string, bool) + + // The set of checksum algorithms that should be used for response payload + // checksum validation. The algorithm(s) used will be a union of the + // output's returned algorithms and this set. + // + // Only the first algorithm in the union is currently used. + ValidationAlgorithms []string + + // If set the middleware will ignore output multipart checksums. Otherwise + // an checksum format error will be returned by the middleware. + IgnoreMultipartValidation bool + + // When set the middleware will log when output does not have checksum or + // algorithm to validate. + LogValidationSkipped bool + + // When set the middleware will log when the output contains a multipart + // checksum that was, skipped and not validated. + LogMultipartValidationSkipped bool +} + +// AddOutputMiddleware adds the middleware for validating response payload's +// checksum. +func AddOutputMiddleware(stack *middleware.Stack, options OutputMiddlewareOptions) error { + err := stack.Initialize.Add(&setupOutputContext{ + GetValidationMode: options.GetValidationMode, + }, middleware.Before) + if err != nil { + return err + } + + // Resolve a supported priority order list of algorithms to validate. + algorithms := FilterSupportedAlgorithms(options.ValidationAlgorithms) + + m := &validateOutputPayloadChecksum{ + Algorithms: algorithms, + IgnoreMultipartValidation: options.IgnoreMultipartValidation, + LogMultipartValidationSkipped: options.LogMultipartValidationSkipped, + LogValidationSkipped: options.LogValidationSkipped, + } + + return stack.Deserialize.Add(m, middleware.After) +} + +// RemoveOutputMiddleware Removes the compute input payload checksum middleware +// handlers from the stack. +func RemoveOutputMiddleware(stack *middleware.Stack) { + id := (*setupOutputContext)(nil).ID() + stack.Initialize.Remove(id) + + id = (*validateOutputPayloadChecksum)(nil).ID() + stack.Deserialize.Remove(id) +} diff --git a/service/internal/checksum/middleware_add_test.go b/service/internal/checksum/middleware_add_test.go new file mode 100644 index 00000000000..33f952ebe93 --- /dev/null +++ b/service/internal/checksum/middleware_add_test.go @@ -0,0 +1,412 @@ +//go:build go1.16 +// +build go1.16 + +package checksum + +import ( + "context" + "testing" + + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/google/go-cmp/cmp" +) + +func TestAddInputMiddleware(t *testing.T) { + cases := map[string]struct { + options InputMiddlewareOptions + expectErr string + expectMiddleware []string + expectInitialize *setupInputContext + expectBuild *computeInputPayloadChecksum + expectFinalize *computeInputPayloadChecksum + }{ + "with trailing checksum": { + options: InputMiddlewareOptions{ + GetAlgorithm: func(interface{}) (string, bool) { + return string(AlgorithmCRC32), true + }, + EnableTrailingChecksum: true, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }, + expectMiddleware: []string{ + "test", + "Initialize stack step", + "AWSChecksum:SetupInputContext", + "Serialize stack step", + "Build stack step", + "ComputeContentLength", + "AWSChecksum:ComputeInputPayloadChecksum", + "ComputePayloadHash", + "Finalize stack step", + "Retry", + "AWSChecksum:ComputeInputPayloadChecksum", + "Signing", + "Deserialize stack step", + }, + expectInitialize: &setupInputContext{ + GetAlgorithm: func(interface{}) (string, bool) { + return string(AlgorithmCRC32), true + }, + }, + expectBuild: &computeInputPayloadChecksum{ + EnableTrailingChecksum: true, + EnableComputePayloadHash: true, + EnableDecodedContentLengthHeader: true, + }, + }, + "with checksum required": { + options: InputMiddlewareOptions{ + GetAlgorithm: func(interface{}) (string, bool) { + return string(AlgorithmCRC32), true + }, + EnableTrailingChecksum: true, + RequireChecksum: true, + }, + expectMiddleware: []string{ + "test", + "Initialize stack step", + "AWSChecksum:SetupInputContext", + "Serialize stack step", + "Build stack step", + "ComputeContentLength", + "AWSChecksum:ComputeInputPayloadChecksum", + "ComputePayloadHash", + "Finalize stack step", + "Retry", + "AWSChecksum:ComputeInputPayloadChecksum", + "Signing", + "Deserialize stack step", + }, + expectInitialize: &setupInputContext{ + GetAlgorithm: func(interface{}) (string, bool) { + return string(AlgorithmCRC32), true + }, + }, + expectBuild: &computeInputPayloadChecksum{ + RequireChecksum: true, + EnableTrailingChecksum: true, + }, + }, + "no trailing checksum": { + options: InputMiddlewareOptions{ + GetAlgorithm: func(interface{}) (string, bool) { + return string(AlgorithmCRC32), true + }, + }, + expectMiddleware: []string{ + "test", + "Initialize stack step", + "AWSChecksum:SetupInputContext", + "Serialize stack step", + "Build stack step", + "ComputeContentLength", + "AWSChecksum:ComputeInputPayloadChecksum", + "ComputePayloadHash", + "Finalize stack step", + "Retry", + "Signing", + "Deserialize stack step", + }, + expectInitialize: &setupInputContext{ + GetAlgorithm: func(interface{}) (string, bool) { + return string(AlgorithmCRC32), true + }, + }, + expectBuild: &computeInputPayloadChecksum{}, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + stack := middleware.NewStack("test", smithyhttp.NewStackRequest) + + stack.Build.Add(nopBuildMiddleware("ComputeContentLength"), middleware.After) + stack.Build.Add(nopBuildMiddleware("ContentChecksum"), middleware.After) + stack.Build.Add(nopBuildMiddleware("ComputePayloadHash"), middleware.After) + stack.Finalize.Add(nopFinalizeMiddleware("Retry"), middleware.After) + stack.Finalize.Add(nopFinalizeMiddleware("Signing"), middleware.After) + + err := AddInputMiddleware(stack, c.options) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if diff := cmp.Diff(c.expectMiddleware, stack.List()); diff != "" { + t.Fatalf("expect stack list match:\n%s", diff) + } + + initializeMiddleware, ok := stack.Initialize.Get((*setupInputContext)(nil).ID()) + if e, a := (c.expectInitialize != nil), ok; e != a { + t.Errorf("expect initialize middleware %t, got %t", e, a) + } + if c.expectInitialize != nil && ok { + setupInput := initializeMiddleware.(*setupInputContext) + if e, a := c.options.GetAlgorithm != nil, setupInput.GetAlgorithm != nil; e != a { + t.Fatalf("expect GetAlgorithm %t, got %t", e, a) + } + expectAlgo, expectOK := c.options.GetAlgorithm(nil) + actualAlgo, actualOK := setupInput.GetAlgorithm(nil) + if e, a := expectAlgo, actualAlgo; e != a { + t.Errorf("expect %v algorithm, got %v", e, a) + } + if e, a := expectOK, actualOK; e != a { + t.Errorf("expect %v algorithm present, got %v", e, a) + } + } + + buildMiddleware, ok := stack.Build.Get((*computeInputPayloadChecksum)(nil).ID()) + if e, a := (c.expectBuild != nil), ok; e != a { + t.Errorf("expect build middleware %t, got %t", e, a) + } + var computeInput *computeInputPayloadChecksum + if c.expectBuild != nil && ok { + computeInput = buildMiddleware.(*computeInputPayloadChecksum) + if e, a := c.expectBuild.RequireChecksum, computeInput.RequireChecksum; e != a { + t.Errorf("expect %v require checksum, got %v", e, a) + } + if e, a := c.expectBuild.EnableTrailingChecksum, computeInput.EnableTrailingChecksum; e != a { + t.Errorf("expect %v enable trailing checksum, got %v", e, a) + } + if e, a := c.expectBuild.EnableComputePayloadHash, computeInput.EnableComputePayloadHash; e != a { + t.Errorf("expect %v enable compute payload hash, got %v", e, a) + } + if e, a := c.expectBuild.EnableDecodedContentLengthHeader, computeInput.EnableDecodedContentLengthHeader; e != a { + t.Errorf("expect %v enable decoded length header, got %v", e, a) + } + } + + if c.expectFinalize != nil && ok { + finalizeMiddleware, ok := stack.Build.Get((*computeInputPayloadChecksum)(nil).ID()) + if !ok { + t.Errorf("expect finalize middleware") + } + finalizeComputeInput := finalizeMiddleware.(*computeInputPayloadChecksum) + + if e, a := computeInput, finalizeComputeInput; e != a { + t.Errorf("expect build and finalize to be same value") + } + } + }) + } +} + +func TestRemoveInputMiddleware(t *testing.T) { + stack := middleware.NewStack("test", smithyhttp.NewStackRequest) + + stack.Build.Add(nopBuildMiddleware("ComputeContentLength"), middleware.After) + stack.Build.Add(nopBuildMiddleware("ContentChecksum"), middleware.After) + stack.Build.Add(nopBuildMiddleware("ComputePayloadHash"), middleware.After) + stack.Finalize.Add(nopFinalizeMiddleware("Retry"), middleware.After) + stack.Finalize.Add(nopFinalizeMiddleware("Signing"), middleware.After) + + err := AddInputMiddleware(stack, InputMiddlewareOptions{ + EnableTrailingChecksum: true, + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + RemoveInputMiddleware(stack) + + expectStack := []string{ + "test", + "Initialize stack step", + "Serialize stack step", + "Build stack step", + "ComputeContentLength", + "ComputePayloadHash", + "Finalize stack step", + "Retry", + "Signing", + "Deserialize stack step", + } + + if diff := cmp.Diff(expectStack, stack.List()); diff != "" { + t.Fatalf("expect stack list match:\n%s", diff) + } +} + +func TestAddOutputMiddleware(t *testing.T) { + cases := map[string]struct { + options OutputMiddlewareOptions + expectErr string + expectMiddleware []string + expectInitialize *setupOutputContext + expectDeserialize *validateOutputPayloadChecksum + }{ + "validate output": { + options: OutputMiddlewareOptions{ + GetValidationMode: func(interface{}) (string, bool) { + return "ENABLED", true + }, + ValidationAlgorithms: []string{ + "crc32", "sha1", "abc123", "crc32c", + }, + IgnoreMultipartValidation: true, + LogMultipartValidationSkipped: true, + LogValidationSkipped: true, + }, + expectMiddleware: []string{ + "test", + "Initialize stack step", + "AWSChecksum:SetupOutputContext", + "Serialize stack step", + "Build stack step", + "Finalize stack step", + "Deserialize stack step", + "AWSChecksum:ValidateOutputPayloadChecksum", + }, + expectInitialize: &setupOutputContext{ + GetValidationMode: func(interface{}) (string, bool) { + return "ENABLED", true + }, + }, + expectDeserialize: &validateOutputPayloadChecksum{ + Algorithms: []Algorithm{ + AlgorithmCRC32, AlgorithmSHA1, AlgorithmCRC32C, + }, + IgnoreMultipartValidation: true, + LogMultipartValidationSkipped: true, + LogValidationSkipped: true, + }, + }, + "validate options off": { + options: OutputMiddlewareOptions{ + GetValidationMode: func(interface{}) (string, bool) { + return "ENABLED", true + }, + ValidationAlgorithms: []string{ + "crc32", "sha1", "abc123", "crc32c", + }, + }, + expectMiddleware: []string{ + "test", + "Initialize stack step", + "AWSChecksum:SetupOutputContext", + "Serialize stack step", + "Build stack step", + "Finalize stack step", + "Deserialize stack step", + "AWSChecksum:ValidateOutputPayloadChecksum", + }, + expectInitialize: &setupOutputContext{ + GetValidationMode: func(interface{}) (string, bool) { + return "ENABLED", true + }, + }, + expectDeserialize: &validateOutputPayloadChecksum{ + Algorithms: []Algorithm{ + AlgorithmCRC32, AlgorithmSHA1, AlgorithmCRC32C, + }, + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + stack := middleware.NewStack("test", smithyhttp.NewStackRequest) + + err := AddOutputMiddleware(stack, c.options) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if diff := cmp.Diff(c.expectMiddleware, stack.List()); diff != "" { + t.Fatalf("expect stack list match:\n%s", diff) + } + + initializeMiddleware, ok := stack.Initialize.Get((*setupOutputContext)(nil).ID()) + if e, a := (c.expectInitialize != nil), ok; e != a { + t.Errorf("expect initialize middleware %t, got %t", e, a) + } + if c.expectInitialize != nil && ok { + setupOutput := initializeMiddleware.(*setupOutputContext) + if e, a := c.options.GetValidationMode != nil, setupOutput.GetValidationMode != nil; e != a { + t.Fatalf("expect GetValidationMode %t, got %t", e, a) + } + expectMode, expectOK := c.options.GetValidationMode(nil) + actualMode, actualOK := setupOutput.GetValidationMode(nil) + if e, a := expectMode, actualMode; e != a { + t.Errorf("expect %v mode, got %v", e, a) + } + if e, a := expectOK, actualOK; e != a { + t.Errorf("expect %v mode present, got %v", e, a) + } + } + + deserializeMiddleware, ok := stack.Deserialize.Get((*validateOutputPayloadChecksum)(nil).ID()) + if e, a := (c.expectDeserialize != nil), ok; e != a { + t.Errorf("expect deserialize middleware %t, got %t", e, a) + } + if c.expectDeserialize != nil && ok { + validateOutput := deserializeMiddleware.(*validateOutputPayloadChecksum) + if diff := cmp.Diff(c.expectDeserialize.Algorithms, validateOutput.Algorithms); diff != "" { + t.Errorf("expect algorithms match:\n%s", diff) + } + if e, a := c.expectDeserialize.IgnoreMultipartValidation, validateOutput.IgnoreMultipartValidation; e != a { + t.Errorf("expect %v ignore multipart checksum, got %v", e, a) + } + if e, a := c.expectDeserialize.LogMultipartValidationSkipped, validateOutput.LogMultipartValidationSkipped; e != a { + t.Errorf("expect %v log multipart skipped, got %v", e, a) + } + if e, a := c.expectDeserialize.LogValidationSkipped, validateOutput.LogValidationSkipped; e != a { + t.Errorf("expect %v log validation skipped, got %v", e, a) + } + } + }) + } +} + +func TestRemoveOutputMiddleware(t *testing.T) { + stack := middleware.NewStack("test", smithyhttp.NewStackRequest) + + err := AddOutputMiddleware(stack, OutputMiddlewareOptions{}) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + RemoveOutputMiddleware(stack) + + expectStack := []string{ + "test", + "Initialize stack step", + "Serialize stack step", + "Build stack step", + "Finalize stack step", + "Deserialize stack step", + } + + if diff := cmp.Diff(expectStack, stack.List()); diff != "" { + t.Fatalf("expect stack list match:\n%s", diff) + } +} + +func setSerializedRequest(req *smithyhttp.Request) middleware.SerializeMiddleware { + return middleware.SerializeMiddlewareFunc("OperationSerializer", + func(ctx context.Context, input middleware.SerializeInput, next middleware.SerializeHandler) ( + middleware.SerializeOutput, middleware.Metadata, error, + ) { + input.Request = req + return next.HandleSerialize(ctx, input) + }) +} + +func nopBuildMiddleware(id string) middleware.BuildMiddleware { + return middleware.BuildMiddlewareFunc(id, + func(ctx context.Context, input middleware.BuildInput, next middleware.BuildHandler) ( + middleware.BuildOutput, middleware.Metadata, error, + ) { + return next.HandleBuild(ctx, input) + }) +} + +func nopFinalizeMiddleware(id string) middleware.FinalizeMiddleware { + return middleware.FinalizeMiddlewareFunc(id, + func(ctx context.Context, input middleware.FinalizeInput, next middleware.FinalizeHandler) ( + middleware.FinalizeOutput, middleware.Metadata, error, + ) { + return next.HandleFinalize(ctx, input) + }) +} diff --git a/service/internal/checksum/middleware_compute_input_checksum.go b/service/internal/checksum/middleware_compute_input_checksum.go new file mode 100644 index 00000000000..675d0928ced --- /dev/null +++ b/service/internal/checksum/middleware_compute_input_checksum.go @@ -0,0 +1,474 @@ +package checksum + +import ( + "context" + "crypto/sha256" + "fmt" + "hash" + "io" + "strconv" + "strings" + + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +const ( + contentMD5Header = "Content-Md5" + streamingUnsignedPayloadTrailerPayloadHash = "STREAMING-UNSIGNED-PAYLOAD-TRAILER" +) + +// computedInputChecksumsKey is the metadata key for recording the algorithm the +// checksum was computed for and the checksum value. +type computedInputChecksumsKey struct{} + +// GetComputedInputChecksums returns the map of checksum algorithm to their +// computed value stored in the middleware Metadata. Returns false if no values +// were stored in the Metadata. +func GetComputedInputChecksums(m middleware.Metadata) (map[string]string, bool) { + vs, ok := m.Get(computedInputChecksumsKey{}).(map[string]string) + return vs, ok +} + +// SetComputedInputChecksums stores the map of checksum algorithm to their +// computed value in the middleware Metadata. Overwrites any values that +// currently exist in the metadata. +func SetComputedInputChecksums(m *middleware.Metadata, vs map[string]string) { + m.Set(computedInputChecksumsKey{}, vs) +} + +// computeInputPayloadChecksum middleware computes payload checksum +type computeInputPayloadChecksum struct { + // Enables support for wrapping the serialized input payload with a + // content-encoding: aws-check wrapper, and including a trailer for the + // algorithm's checksum value. + // + // The checksum will not be computed, nor added as trailing checksum, if + // the Algorithm's header is already set on the request. + EnableTrailingChecksum bool + + // States that a checksum is required to be included for the operation. If + // Input does not specify a checksum, fallback to built in MD5 checksum is + // used. + // + // Replaces smithy-go's ContentChecksum middleware. + RequireChecksum bool + + // Enables support for computing the SHA256 checksum of input payloads + // along with the algorithm specified checksum. Prevents downstream + // middleware handlers (computePayloadSHA256) re-reading the payload. + // + // The SHA256 payload hash will only be used for computed for requests + // that are not TLS, or do not enable trailing checksums. + // + // The SHA256 payload hash will not be computed, if the Algorithm's header + // is already set on the request. + EnableComputePayloadHash bool + + // Enables support for setting the aws-chunked decoded content length + // header for the decoded length of the underlying stream. Will only be set + // when used with trailing checksums, and aws-chunked content-encoding. + EnableDecodedContentLengthHeader bool + + buildHandlerRun bool + deferToFinalizeHandler bool +} + +// ID provides the middleware's identifier. +func (m *computeInputPayloadChecksum) ID() string { + return "AWSChecksum:ComputeInputPayloadChecksum" +} + +type computeInputHeaderChecksumError struct { + Msg string + Err error +} + +func (e computeInputHeaderChecksumError) Error() string { + const intro = "compute input header checksum failed" + + if e.Err != nil { + return fmt.Sprintf("%s, %s, %v", intro, e.Msg, e.Err) + } + + return fmt.Sprintf("%s, %s", intro, e.Msg) +} +func (e computeInputHeaderChecksumError) Unwrap() error { return e.Err } + +// HandleBuild handles computing the payload's checksum, in the following cases: +// * Is HTTP, not HTTPS +// * RequireChecksum is true, and no checksums were specified via the Input +// * Trailing checksums are not supported +// +// The build handler must be inserted in the stack before ContentPayloadHash +// and after ComputeContentLength. +func (m *computeInputPayloadChecksum) HandleBuild( + ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler, +) ( + out middleware.BuildOutput, metadata middleware.Metadata, err error, +) { + m.buildHandlerRun = true + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, computeInputHeaderChecksumError{ + Msg: fmt.Sprintf("unknown request type %T", req), + } + } + + var algorithm Algorithm + var checksum string + defer func() { + if algorithm == "" || checksum == "" || err != nil { + return + } + + // Record the checksum and algorithm that was computed + SetComputedInputChecksums(&metadata, map[string]string{ + string(algorithm): checksum, + }) + }() + + // If no algorithm was specified, and the operation requires a checksum, + // fallback to the legacy content MD5 checksum. + algorithm, ok, err = getInputAlgorithm(ctx) + if err != nil { + return out, metadata, err + } else if !ok { + if m.RequireChecksum { + checksum, err = setMD5Checksum(ctx, req) + if err != nil { + return out, metadata, computeInputHeaderChecksumError{ + Msg: "failed to compute stream's MD5 checksum", + Err: err, + } + } + algorithm = Algorithm("MD5") + } + return next.HandleBuild(ctx, in) + } + + // If the checksum header is already set nothing to do. + checksumHeader := AlgorithmHTTPHeader(algorithm) + if checksum = req.Header.Get(checksumHeader); checksum != "" { + return next.HandleBuild(ctx, in) + } + + computePayloadHash := m.EnableComputePayloadHash + if v := v4.GetPayloadHash(ctx); v != "" { + computePayloadHash = false + } + + stream := req.GetStream() + streamLength, err := getRequestStreamLength(req) + if err != nil { + return out, metadata, computeInputHeaderChecksumError{ + Msg: "failed to determine stream length", + Err: err, + } + } + + // If trailing checksums are supported, the request is HTTPS, and the + // stream is not nil or empty, there is nothing to do in the build stage. + // The checksum will be added to the request as a trailing checksum in the + // finalize handler. + // + // Nil and empty streams will always be handled as a request header, + // regardless if the operation supports trailing checksums or not. + if strings.EqualFold(req.URL.Scheme, "https") { + if stream != nil && streamLength != 0 && m.EnableTrailingChecksum { + if m.EnableComputePayloadHash { + // payload hash is set as header in Build middleware handler, + // ContentSHA256Header. + ctx = v4.SetPayloadHash(ctx, streamingUnsignedPayloadTrailerPayloadHash) + } + + m.deferToFinalizeHandler = true + return next.HandleBuild(ctx, in) + } + + // If trailing checksums are not enabled but protocol is still HTTPS + // disabling computing the payload hash. Downstream middleware handler + // (ComputetPayloadHash) will set the payload hash to unsigned payload, + // if signing was used. + computePayloadHash = false + } + + // Only seekable streams are supported for non-trailing checksums, because + // the stream needs to be rewound before the handler can continue. + if stream != nil && !req.IsStreamSeekable() { + return out, metadata, computeInputHeaderChecksumError{ + Msg: "unseekable stream is not supported without TLS and trailing checksum", + } + } + + var sha256Checksum string + checksum, sha256Checksum, err = computeStreamChecksum( + algorithm, stream, computePayloadHash) + if err != nil { + return out, metadata, computeInputHeaderChecksumError{ + Msg: "failed to compute stream checksum", + Err: err, + } + } + + if err := req.RewindStream(); err != nil { + return out, metadata, computeInputHeaderChecksumError{ + Msg: "failed to rewind stream", + Err: err, + } + } + + req.Header.Set(checksumHeader, checksum) + + if computePayloadHash { + ctx = v4.SetPayloadHash(ctx, sha256Checksum) + } + + return next.HandleBuild(ctx, in) +} + +type computeInputTrailingChecksumError struct { + Msg string + Err error +} + +func (e computeInputTrailingChecksumError) Error() string { + const intro = "compute input trailing checksum failed" + + if e.Err != nil { + return fmt.Sprintf("%s, %s, %v", intro, e.Msg, e.Err) + } + + return fmt.Sprintf("%s, %s", intro, e.Msg) +} +func (e computeInputTrailingChecksumError) Unwrap() error { return e.Err } + +// HandleFinalize handles computing the payload's checksum, in the following cases: +// * Is HTTPS, not HTTP +// * A checksum was specified via the Input +// * Trailing checksums are supported. +// +// The finalize handler must be inserted in the stack before Signing, and after Retry. +func (m *computeInputPayloadChecksum) HandleFinalize( + ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, +) ( + out middleware.FinalizeOutput, metadata middleware.Metadata, err error, +) { + if !m.deferToFinalizeHandler { + if !m.buildHandlerRun { + return out, metadata, computeInputTrailingChecksumError{ + Msg: "build handler was removed without also removing finalize handler", + } + } + return next.HandleFinalize(ctx, in) + } + + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, computeInputTrailingChecksumError{ + Msg: fmt.Sprintf("unknown request type %T", req), + } + } + + // Trailing checksums are only supported when TLS is enabled. + if !strings.EqualFold(req.URL.Scheme, "https") { + return out, metadata, computeInputTrailingChecksumError{ + Msg: "HTTPS required", + } + } + + // If no algorithm was specified, there is nothing to do. + algorithm, ok, err := getInputAlgorithm(ctx) + if err != nil { + return out, metadata, computeInputTrailingChecksumError{ + Msg: "failed to get algorithm", + Err: err, + } + } else if !ok { + return out, metadata, computeInputTrailingChecksumError{ + Msg: "no algorithm specified", + } + } + + // If the checksum header is already set before finalize could run, there + // is nothing to do. + checksumHeader := AlgorithmHTTPHeader(algorithm) + if req.Header.Get(checksumHeader) != "" { + return next.HandleFinalize(ctx, in) + } + + stream := req.GetStream() + streamLength, err := getRequestStreamLength(req) + if err != nil { + return out, metadata, computeInputTrailingChecksumError{ + Msg: "failed to determine stream length", + Err: err, + } + } + + if stream == nil || streamLength == 0 { + // Nil and empty streams are handled by the Build handler. They are not + // supported by the trailing checksums finalize handler. There is no + // benefit to sending them as trailers compared to headers. + return out, metadata, computeInputTrailingChecksumError{ + Msg: "nil or empty streams are not supported", + } + } + + checksumReader, err := newComputeChecksumReader(stream, algorithm) + if err != nil { + return out, metadata, computeInputTrailingChecksumError{ + Msg: "failed to created checksum reader", + Err: err, + } + } + + awsChunkedReader := newUnsignedAWSChunkedEncoding(checksumReader, + func(o *awsChunkedEncodingOptions) { + o.Trailers[AlgorithmHTTPHeader(checksumReader.Algorithm())] = awsChunkedTrailerValue{ + Get: checksumReader.Base64Checksum, + Length: checksumReader.Base64ChecksumLength(), + } + o.StreamLength = streamLength + }) + + for key, values := range awsChunkedReader.HTTPHeaders() { + for _, value := range values { + req.Header.Add(key, value) + } + } + + // Setting the stream on the request will create a copy. The content length + // is not updated until after the request is copied to prevent impacting + // upstream middleware. + req, err = req.SetStream(awsChunkedReader) + if err != nil { + return out, metadata, computeInputTrailingChecksumError{ + Msg: "failed updating request to trailing checksum wrapped stream", + Err: err, + } + } + req.ContentLength = awsChunkedReader.EncodedLength() + in.Request = req + + // Add decoded content length header if original stream's content length is known. + if streamLength != -1 && m.EnableDecodedContentLengthHeader { + req.Header.Set(decodedContentLengthHeaderName, strconv.FormatInt(streamLength, 10)) + } + + out, metadata, err = next.HandleFinalize(ctx, in) + if err == nil { + checksum, err := checksumReader.Base64Checksum() + if err != nil { + return out, metadata, fmt.Errorf("failed to get computed checksum, %w", err) + } + + // Record the checksum and algorithm that was computed + SetComputedInputChecksums(&metadata, map[string]string{ + string(algorithm): checksum, + }) + } + + return out, metadata, err +} + +func getInputAlgorithm(ctx context.Context) (Algorithm, bool, error) { + ctxAlgorithm := getContextInputAlgorithm(ctx) + if ctxAlgorithm == "" { + return "", false, nil + } + + algorithm, err := ParseAlgorithm(ctxAlgorithm) + if err != nil { + return "", false, fmt.Errorf( + "failed to parse algorithm, %w", err) + } + + return algorithm, true, nil +} + +func computeStreamChecksum(algorithm Algorithm, stream io.Reader, computePayloadHash bool) ( + checksum string, sha256Checksum string, err error, +) { + hasher, err := NewAlgorithmHash(algorithm) + if err != nil { + return "", "", fmt.Errorf( + "failed to get hasher for checksum algorithm, %w", err) + } + + var sha256Hasher hash.Hash + var batchHasher io.Writer = hasher + + // Compute payload hash for the protocol. To prevent another handler + // (computePayloadSHA256) re-reading body also compute the SHA256 for + // request signing. If configured checksum algorithm is SHA256, don't + // double wrap stream with another SHA256 hasher. + if computePayloadHash && algorithm != AlgorithmSHA256 { + sha256Hasher = sha256.New() + batchHasher = io.MultiWriter(hasher, sha256Hasher) + } + + if stream != nil { + if _, err = io.Copy(batchHasher, stream); err != nil { + return "", "", fmt.Errorf( + "failed to read stream to compute hash, %w", err) + } + } + + checksum = string(base64EncodeHashSum(hasher)) + if computePayloadHash { + if algorithm != AlgorithmSHA256 { + sha256Checksum = string(hexEncodeHashSum(sha256Hasher)) + } else { + sha256Checksum = checksum + } + } + + return checksum, sha256Checksum, nil +} + +func getRequestStreamLength(req *smithyhttp.Request) (int64, error) { + if v := req.ContentLength; v > 0 { + return v, nil + } + + if length, ok, err := req.StreamLength(); err != nil { + return 0, fmt.Errorf("failed getting request stream's length, %w", err) + } else if ok { + return length, nil + } + + return -1, nil +} + +// setMD5Checksum computes the MD5 of the request payload and sets it to the +// Content-MD5 header. Returning the MD5 base64 encoded string or error. +// +// If the MD5 is already set as the Content-MD5 header, that value will be +// returned, and nothing else will be done. +// +// If the payload is empty, no MD5 will be computed. No error will be returned. +// Empty payloads do not have an MD5 value. +// +// Replaces the smithy-go middleware for httpChecksum trait. +func setMD5Checksum(ctx context.Context, req *smithyhttp.Request) (string, error) { + if v := req.Header.Get(contentMD5Header); len(v) != 0 { + return v, nil + } + stream := req.GetStream() + if stream == nil { + return "", nil + } + v, err := computeMD5Checksum(stream) + if err != nil { + return "", err + } + if err := req.RewindStream(); err != nil { + return "", fmt.Errorf("failed to rewind stream after computing MD5 checksum, %w", err) + } + // set the 'Content-MD5' header + req.Header.Set(contentMD5Header, string(v)) + return string(v), nil +} diff --git a/service/internal/checksum/middleware_compute_input_checksum_test.go b/service/internal/checksum/middleware_compute_input_checksum_test.go new file mode 100644 index 00000000000..f8c0e6e4912 --- /dev/null +++ b/service/internal/checksum/middleware_compute_input_checksum_test.go @@ -0,0 +1,889 @@ +//go:build go1.16 +// +build go1.16 + +package checksum + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strings" + "testing" + "testing/iotest" + + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/google/go-cmp/cmp" +) + +// TODO test cases: +// * Retry re-wrapping payload + +func TestComputeInputPayloadChecksum(t *testing.T) { + cases := map[string]map[string]struct { + optionsFn func(*computeInputPayloadChecksum) + initContext func(context.Context) context.Context + buildInput middleware.BuildInput + + expectErr string + expectBuildErr bool + expectFinalizeErr bool + expectReadErr bool + + expectHeader http.Header + expectContentLength int64 + expectPayload []byte + expectPayloadHash string + + expectChecksumMetadata map[string]string + + expectDeferToFinalize bool + expectLogged string + }{ + "no op": { + "checksum header set known length": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.Header.Set(AlgorithmHTTPHeader(AlgorithmCRC32), "AAAAAA==") + r = requestMust(r.SetStream(strings.NewReader("hello world"))) + r.ContentLength = 11 + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"AAAAAA=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "CRC32": "AAAAAA==", + }, + }, + "checksum header set unknown length": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.Header.Set(AlgorithmHTTPHeader(AlgorithmCRC32), "AAAAAA==") + r = requestMust(r.SetStream(strings.NewReader("hello world"))) + r.ContentLength = -1 + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"AAAAAA=="}, + }, + expectContentLength: -1, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "CRC32": "AAAAAA==", + }, + }, + "no algorithm": { + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r = requestMust(r.SetStream(strings.NewReader("hello world"))) + r.ContentLength = 11 + return r + }(), + }, + expectHeader: http.Header{}, + expectContentLength: 11, + expectPayload: []byte("hello world"), + }, + "nil stream no algorithm require checksum": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.RequireChecksum = true + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + return r + }(), + }, + expectContentLength: -1, + expectHeader: http.Header{}, + }, + }, + + "build handled": { + "http nil stream": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"AAAAAA=="}, + }, + expectContentLength: -1, + expectPayloadHash: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + expectChecksumMetadata: map[string]string{ + "CRC32": "AAAAAA==", + }, + }, + "http empty stream": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 0 + r = requestMust(r.SetStream(strings.NewReader(""))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"AAAAAA=="}, + }, + expectContentLength: 0, + expectPayload: []byte{}, + expectPayloadHash: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + expectChecksumMetadata: map[string]string{ + "CRC32": "AAAAAA==", + }, + }, + "https nil stream": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"AAAAAA=="}, + }, + expectContentLength: -1, + expectChecksumMetadata: map[string]string{ + "CRC32": "AAAAAA==", + }, + }, + "https empty stream": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 0 + r = requestMust(r.SetStream(strings.NewReader(""))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"AAAAAA=="}, + }, + expectContentLength: 0, + expectPayload: []byte{}, + expectChecksumMetadata: map[string]string{ + "CRC32": "AAAAAA==", + }, + }, + "http no algorithm require checksum": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.RequireChecksum = true + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Md5": []string{"XrY7u+Ae7tCTyyK7j1rNww=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "MD5": "XrY7u+Ae7tCTyyK7j1rNww==", + }, + }, + "http no algorithm require checksum header preset": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.RequireChecksum = true + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 11 + r.Header.Set("Content-MD5", "XrY7u+Ae7tCTyyK7j1rNww==") + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Md5": []string{"XrY7u+Ae7tCTyyK7j1rNww=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "MD5": "XrY7u+Ae7tCTyyK7j1rNww==", + }, + }, + "https no algorithm require checksum": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.RequireChecksum = true + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Md5": []string{"XrY7u+Ae7tCTyyK7j1rNww=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "MD5": "XrY7u+Ae7tCTyyK7j1rNww==", + }, + }, + "http seekable": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"DUoRhQ=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectPayloadHash: "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "http payload hash already set": { + initContext: func(ctx context.Context) context.Context { + ctx = setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + ctx = v4.SetPayloadHash(ctx, "somehash") + return ctx + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"DUoRhQ=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectPayloadHash: "somehash", + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "http payload hash disabled": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + optionsFn: func(o *computeInputPayloadChecksum) { + o.EnableComputePayloadHash = false + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"DUoRhQ=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "https no trailing checksum": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.EnableTrailingChecksum = false + }, + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"DUoRhQ=="}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "with content encoding set": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.EnableTrailingChecksum = false + }, + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r.Header.Set("Content-Encoding", "gzip") + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Checksum-Crc32": []string{"DUoRhQ=="}, + "Content-Encoding": []string{"gzip"}, + }, + expectContentLength: 11, + expectPayload: []byte("hello world"), + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + }, + + "build error": { + "unknown algorithm": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string("unknown")) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r = requestMust(r.SetStream(bytes.NewBuffer([]byte("hello world")))) + return r + }(), + }, + expectErr: "failed to parse algorithm", + expectBuildErr: true, + }, + "no algorithm require checksum unseekable stream": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.RequireChecksum = true + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r = requestMust(r.SetStream(bytes.NewBuffer([]byte("hello world")))) + return r + }(), + }, + expectErr: "failed to rewind stream", + expectBuildErr: true, + }, + "http unseekable stream": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r = requestMust(r.SetStream(bytes.NewBuffer([]byte("hello world")))) + return r + }(), + }, + expectErr: "unseekable stream is not supported", + expectBuildErr: true, + }, + "http stream read error": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 128 + r = requestMust(r.SetStream(&mockReadSeeker{ + Reader: iotest.ErrReader(fmt.Errorf("read error")), + })) + return r + }(), + }, + expectErr: "failed to read stream to compute hash", + expectBuildErr: true, + }, + "http stream rewind error": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("http://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(&errSeekReader{ + Reader: strings.NewReader("hello world"), + })) + return r + }(), + }, + expectErr: "failed to rewind stream", + expectBuildErr: true, + }, + "https no trailing unseekable stream": { + optionsFn: func(o *computeInputPayloadChecksum) { + o.EnableTrailingChecksum = false + }, + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r = requestMust(r.SetStream(bytes.NewBuffer([]byte("hello world")))) + return r + }(), + }, + expectErr: "unseekable stream is not supported", + expectBuildErr: true, + }, + }, + + "finalize handled": { + "https unseekable": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewBuffer([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Encoding": []string{"aws-chunked"}, + "X-Amz-Decoded-Content-Length": []string{"11"}, + "X-Amz-Trailer": []string{"x-amz-checksum-crc32"}, + }, + expectContentLength: 52, + expectPayload: []byte("b\r\nhello world\r\n0\r\nx-amz-checksum-crc32:DUoRhQ==\r\n\r\n"), + expectPayloadHash: "STREAMING-UNSIGNED-PAYLOAD-TRAILER", + expectDeferToFinalize: true, + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "https unseekable unknown length": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = -1 + r = requestMust(r.SetStream(ioutil.NopCloser(bytes.NewBuffer([]byte("hello world"))))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Encoding": []string{"aws-chunked"}, + "X-Amz-Trailer": []string{"x-amz-checksum-crc32"}, + }, + expectContentLength: -1, + expectPayload: []byte("b\r\nhello world\r\n0\r\nx-amz-checksum-crc32:DUoRhQ==\r\n\r\n"), + expectPayloadHash: "STREAMING-UNSIGNED-PAYLOAD-TRAILER", + expectDeferToFinalize: true, + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "https seekable": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Encoding": []string{"aws-chunked"}, + "X-Amz-Decoded-Content-Length": []string{"11"}, + "X-Amz-Trailer": []string{"x-amz-checksum-crc32"}, + }, + expectContentLength: 52, + expectPayload: []byte("b\r\nhello world\r\n0\r\nx-amz-checksum-crc32:DUoRhQ==\r\n\r\n"), + expectPayloadHash: "STREAMING-UNSIGNED-PAYLOAD-TRAILER", + expectDeferToFinalize: true, + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "https seekable unknown length": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = -1 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Encoding": []string{"aws-chunked"}, + "X-Amz-Decoded-Content-Length": []string{"11"}, + "X-Amz-Trailer": []string{"x-amz-checksum-crc32"}, + }, + expectContentLength: 52, + expectPayload: []byte("b\r\nhello world\r\n0\r\nx-amz-checksum-crc32:DUoRhQ==\r\n\r\n"), + expectPayloadHash: "STREAMING-UNSIGNED-PAYLOAD-TRAILER", + expectDeferToFinalize: true, + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "https no compute payload hash": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + optionsFn: func(o *computeInputPayloadChecksum) { + o.EnableComputePayloadHash = false + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Encoding": []string{"aws-chunked"}, + "X-Amz-Decoded-Content-Length": []string{"11"}, + "X-Amz-Trailer": []string{"x-amz-checksum-crc32"}, + }, + expectContentLength: 52, + expectPayload: []byte("b\r\nhello world\r\n0\r\nx-amz-checksum-crc32:DUoRhQ==\r\n\r\n"), + expectDeferToFinalize: true, + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "https no decode content length": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + optionsFn: func(o *computeInputPayloadChecksum) { + o.EnableDecodedContentLengthHeader = false + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "Content-Encoding": []string{"aws-chunked"}, + "X-Amz-Trailer": []string{"x-amz-checksum-crc32"}, + }, + expectContentLength: 52, + expectPayloadHash: "STREAMING-UNSIGNED-PAYLOAD-TRAILER", + expectPayload: []byte("b\r\nhello world\r\n0\r\nx-amz-checksum-crc32:DUoRhQ==\r\n\r\n"), + expectDeferToFinalize: true, + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + "with content encoding set": { + initContext: func(ctx context.Context) context.Context { + return setContextInputAlgorithm(ctx, string(AlgorithmCRC32)) + }, + buildInput: middleware.BuildInput{ + Request: func() *smithyhttp.Request { + r := smithyhttp.NewStackRequest().(*smithyhttp.Request) + r.URL, _ = url.Parse("https://example.aws") + r.ContentLength = 11 + r.Header.Set("Content-Encoding", "gzip") + r = requestMust(r.SetStream(bytes.NewReader([]byte("hello world")))) + return r + }(), + }, + expectHeader: http.Header{ + "X-Amz-Trailer": []string{"x-amz-checksum-crc32"}, + "X-Amz-Decoded-Content-Length": []string{"11"}, + "Content-Encoding": []string{"gzip", "aws-chunked"}, + }, + expectContentLength: 52, + expectPayloadHash: "STREAMING-UNSIGNED-PAYLOAD-TRAILER", + expectPayload: []byte("b\r\nhello world\r\n0\r\nx-amz-checksum-crc32:DUoRhQ==\r\n\r\n"), + expectDeferToFinalize: true, + expectChecksumMetadata: map[string]string{ + "CRC32": "DUoRhQ==", + }, + }, + }, + } + + for name, cs := range cases { + t.Run(name, func(t *testing.T) { + for name, c := range cs { + t.Run(name, func(t *testing.T) { + m := &computeInputPayloadChecksum{ + EnableTrailingChecksum: true, + EnableComputePayloadHash: true, + EnableDecodedContentLengthHeader: true, + } + if c.optionsFn != nil { + c.optionsFn(m) + } + + ctx := context.Background() + var logged bytes.Buffer + logger := logging.LoggerFunc( + func(classification logging.Classification, format string, v ...interface{}) { + fmt.Fprintf(&logged, format, v...) + }, + ) + + stack := middleware.NewStack("test", smithyhttp.NewStackRequest) + middleware.AddSetLoggerMiddleware(stack, logger) + + //------------------------------ + // Build handler + //------------------------------ + // On return path validate any errors were expected. + stack.Build.Add(middleware.BuildMiddlewareFunc( + "build-assert", + func(ctx context.Context, input middleware.BuildInput, next middleware.BuildHandler) ( + out middleware.BuildOutput, metadata middleware.Metadata, err error, + ) { + // ignore initial build input for the test case's build input. + out, metadata, err = next.HandleBuild(ctx, c.buildInput) + if err == nil && c.expectBuildErr { + t.Fatalf("expect build error, got none") + } + + if !m.buildHandlerRun { + t.Fatalf("expect build handler run") + } + return out, metadata, err + }, + ), middleware.After) + + // Build middleware + stack.Build.Add(m, middleware.After) + + // Validate defer to finalize was performed as expected + stack.Build.Add(middleware.BuildMiddlewareFunc( + "assert-defer-to-finalize", + func(ctx context.Context, input middleware.BuildInput, next middleware.BuildHandler) ( + out middleware.BuildOutput, metadata middleware.Metadata, err error, + ) { + if e, a := c.expectDeferToFinalize, m.deferToFinalizeHandler; e != a { + t.Fatalf("expect %v defer to finalize, got %v", e, a) + } + return next.HandleBuild(ctx, input) + }, + ), middleware.After) + + //------------------------------ + // Finalize handler + //------------------------------ + if m.EnableTrailingChecksum { + // On return path assert any errors are expected. + stack.Finalize.Add(middleware.FinalizeMiddlewareFunc( + "build-assert", + func(ctx context.Context, input middleware.FinalizeInput, next middleware.FinalizeHandler) ( + out middleware.FinalizeOutput, metadata middleware.Metadata, err error, + ) { + out, metadata, err = next.HandleFinalize(ctx, input) + if err == nil && c.expectFinalizeErr { + t.Fatalf("expect finalize error, got none") + } + + return out, metadata, err + }, + ), middleware.After) + + // Add finalize middleware + stack.Finalize.Add(m, middleware.After) + } + + //------------------------------ + // Request validation + //------------------------------ + validateRequestHandler := middleware.HandlerFunc( + func(ctx context.Context, input interface{}) ( + output interface{}, metadata middleware.Metadata, err error, + ) { + request := input.(*smithyhttp.Request) + + if diff := cmp.Diff(c.expectHeader, request.Header); diff != "" { + t.Errorf("expect header to match:\n%s", diff) + } + if e, a := c.expectContentLength, request.ContentLength; e != a { + t.Errorf("expect %v content length, got %v", e, a) + } + + stream := request.GetStream() + if e, a := stream != nil, c.expectPayload != nil; e != a { + t.Fatalf("expect nil payload %t, got %t", e, a) + } + if stream == nil { + return + } + + actualPayload, err := ioutil.ReadAll(stream) + if err == nil && c.expectReadErr { + t.Fatalf("expected read error, got none") + } + + if diff := cmp.Diff(string(c.expectPayload), string(actualPayload)); diff != "" { + t.Errorf("expect payload match:\n%s", diff) + } + + payloadHash := v4.GetPayloadHash(ctx) + if e, a := c.expectPayloadHash, payloadHash; e != a { + t.Errorf("expect %v payload hash, got %v", e, a) + } + + return &smithyhttp.Response{}, metadata, nil + }, + ) + + if c.initContext != nil { + ctx = c.initContext(ctx) + } + _, metadata, err := stack.HandleMiddleware(ctx, struct{}{}, validateRequestHandler) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expected error: %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expected error %v to contain %v", err, c.expectErr) + } + if c.expectErr != "" { + return + } + + if c.expectLogged != "" { + if e, a := c.expectLogged, logged.String(); !strings.Contains(a, e) { + t.Errorf("expected %q logged in:\n%s", e, a) + } + } + + // assert computed input checksums metadata + computedMetadata, ok := GetComputedInputChecksums(metadata) + if e, a := ok, (c.expectChecksumMetadata != nil); e != a { + t.Fatalf("expect checksum metadata %t, got %t, %v", e, a, computedMetadata) + } + if c.expectChecksumMetadata != nil { + if diff := cmp.Diff(c.expectChecksumMetadata, computedMetadata); diff != "" { + t.Errorf("expect checksum metadata match\n%s", diff) + } + } + }) + } + }) + } +} + +type mockReadSeeker struct { + io.Reader +} + +func (r *mockReadSeeker) Seek(int64, int) (int64, error) { + return 0, nil +} + +type errSeekReader struct { + io.Reader +} + +func (r *errSeekReader) Seek(offset int64, whence int) (int64, error) { + if whence == io.SeekCurrent { + return 0, nil + } + + return 0, fmt.Errorf("seek failed") +} + +func requestMust(r *smithyhttp.Request, err error) *smithyhttp.Request { + if err != nil { + panic(err.Error()) + } + + return r +} diff --git a/service/internal/checksum/middleware_setup_context.go b/service/internal/checksum/middleware_setup_context.go new file mode 100644 index 00000000000..f7295254976 --- /dev/null +++ b/service/internal/checksum/middleware_setup_context.go @@ -0,0 +1,117 @@ +package checksum + +import ( + "context" + + "github.com/aws/smithy-go/middleware" +) + +// setupChecksumContext is the initial middleware that looks up the input +// used to configure checksum behavior. This middleware must be executed before +// input validation step or any other checksum middleware. +type setupInputContext struct { + // GetAlgorithm is a function to get the checksum algorithm of the + // input payload from the input parameters. + // + // Given the input parameter value, the function must return the algorithm + // and true, or false if no algorithm is specified. + GetAlgorithm func(interface{}) (string, bool) +} + +// ID for the middleware +func (m *setupInputContext) ID() string { + return "AWSChecksum:SetupInputContext" +} + +// HandleInitialize initialization middleware that setups up the checksum +// context based on the input parameters provided in the stack. +func (m *setupInputContext) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + // Check if validation algorithm is specified. + if m.GetAlgorithm != nil { + // check is input resource has a checksum algorithm + algorithm, ok := m.GetAlgorithm(in.Parameters) + if ok && len(algorithm) != 0 { + ctx = setContextInputAlgorithm(ctx, algorithm) + } + } + + return next.HandleInitialize(ctx, in) +} + +// inputAlgorithmKey is the key set on context used to identify, retrieves the +// request checksum algorithm if present on the context. +type inputAlgorithmKey struct{} + +// setContextInputAlgorithm sets the request checksum algorithm on the context. +// +// Scoped to stack values. +func setContextInputAlgorithm(ctx context.Context, value string) context.Context { + return middleware.WithStackValue(ctx, inputAlgorithmKey{}, value) +} + +// getContextInputAlgorithm returns the checksum algorithm from the context if +// one was specified. Empty string is returned if one is not specified. +// +// Scoped to stack values. +func getContextInputAlgorithm(ctx context.Context) (v string) { + v, _ = middleware.GetStackValue(ctx, inputAlgorithmKey{}).(string) + return v +} + +type setupOutputContext struct { + // GetValidationMode is a function to get the checksum validation + // mode of the output payload from the input parameters. + // + // Given the input parameter value, the function must return the validation + // mode and true, or false if no mode is specified. + GetValidationMode func(interface{}) (string, bool) +} + +// ID for the middleware +func (m *setupOutputContext) ID() string { + return "AWSChecksum:SetupOutputContext" +} + +// HandleInitialize initialization middleware that setups up the checksum +// context based on the input parameters provided in the stack. +func (m *setupOutputContext) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + // Check if validation mode is specified. + if m.GetValidationMode != nil { + // check is input resource has a checksum algorithm + mode, ok := m.GetValidationMode(in.Parameters) + if ok && len(mode) != 0 { + ctx = setContextOutputValidationMode(ctx, mode) + } + } + + return next.HandleInitialize(ctx, in) +} + +// outputValidationModeKey is the key set on context used to identify if +// output checksum validation is enabled. +type outputValidationModeKey struct{} + +// setContextOutputValidationMode sets the request checksum +// algorithm on the context. +// +// Scoped to stack values. +func setContextOutputValidationMode(ctx context.Context, value string) context.Context { + return middleware.WithStackValue(ctx, outputValidationModeKey{}, value) +} + +// getContextOutputValidationMode returns response checksum validation state, +// if one was specified. Empty string is returned if one is not specified. +// +// Scoped to stack values. +func getContextOutputValidationMode(ctx context.Context) (v string) { + v, _ = middleware.GetStackValue(ctx, outputValidationModeKey{}).(string) + return v +} diff --git a/service/internal/checksum/middleware_setup_context_test.go b/service/internal/checksum/middleware_setup_context_test.go new file mode 100644 index 00000000000..3235983bad4 --- /dev/null +++ b/service/internal/checksum/middleware_setup_context_test.go @@ -0,0 +1,143 @@ +//go:build go1.16 +// +build go1.16 + +package checksum + +import ( + "context" + "testing" + + "github.com/aws/smithy-go/middleware" +) + +func TestSetupInput(t *testing.T) { + type Params struct { + Value string + } + + cases := map[string]struct { + inputParams interface{} + getAlgorithm func(interface{}) (string, bool) + expectValue string + }{ + "nil accessor": { + expectValue: "", + }, + "found empty": { + inputParams: Params{Value: ""}, + getAlgorithm: func(v interface{}) (string, bool) { + vv := v.(Params) + return vv.Value, true + }, + expectValue: "", + }, + "found not set": { + inputParams: Params{Value: ""}, + getAlgorithm: func(v interface{}) (string, bool) { + return "", false + }, + expectValue: "", + }, + "found": { + inputParams: Params{Value: "abc123"}, + getAlgorithm: func(v interface{}) (string, bool) { + vv := v.(Params) + return vv.Value, true + }, + expectValue: "abc123", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + m := setupInputContext{ + GetAlgorithm: c.getAlgorithm, + } + + _, _, err := m.HandleInitialize(context.Background(), + middleware.InitializeInput{Parameters: c.inputParams}, + middleware.InitializeHandlerFunc( + func(ctx context.Context, input middleware.InitializeInput) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, + ) { + v := getContextInputAlgorithm(ctx) + if e, a := c.expectValue, v; e != a { + t.Errorf("expect value %v, got %v", e, a) + } + + return out, metadata, nil + }, + )) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + }) + } +} + +func TestSetupOutput(t *testing.T) { + type Params struct { + Value string + } + + cases := map[string]struct { + inputParams interface{} + getValidationMode func(interface{}) (string, bool) + expectValue string + }{ + "nil accessor": { + expectValue: "", + }, + "found empty": { + inputParams: Params{Value: ""}, + getValidationMode: func(v interface{}) (string, bool) { + vv := v.(Params) + return vv.Value, true + }, + expectValue: "", + }, + "found not set": { + inputParams: Params{Value: ""}, + getValidationMode: func(v interface{}) (string, bool) { + return "", false + }, + expectValue: "", + }, + "found": { + inputParams: Params{Value: "abc123"}, + getValidationMode: func(v interface{}) (string, bool) { + vv := v.(Params) + return vv.Value, true + }, + expectValue: "abc123", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + m := setupOutputContext{ + GetValidationMode: c.getValidationMode, + } + + _, _, err := m.HandleInitialize(context.Background(), + middleware.InitializeInput{Parameters: c.inputParams}, + middleware.InitializeHandlerFunc( + func(ctx context.Context, input middleware.InitializeInput) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, + ) { + v := getContextOutputValidationMode(ctx) + if e, a := c.expectValue, v; e != a { + t.Errorf("expect value %v, got %v", e, a) + } + + return out, metadata, nil + }, + )) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + }) + } +} diff --git a/service/internal/checksum/middleware_validate_output.go b/service/internal/checksum/middleware_validate_output.go new file mode 100644 index 00000000000..5ca5d49880f --- /dev/null +++ b/service/internal/checksum/middleware_validate_output.go @@ -0,0 +1,126 @@ +package checksum + +import ( + "context" + "fmt" + "strings" + + "github.com/aws/smithy-go" + "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// outputValidationAlgorithmsUsedKey is the metadata key for indexing the algorithms +// that were used, by the middleware's validation. +type outputValidationAlgorithmsUsedKey struct{} + +// GetOutputValidationAlgorithmsUsed returns the checksum algorithms used +// stored in the middleware Metadata. Returns false if no algorithms were +// stored in the Metadata. +func GetOutputValidationAlgorithmsUsed(m middleware.Metadata) ([]string, bool) { + vs, ok := m.Get(outputValidationAlgorithmsUsedKey{}).([]string) + return vs, ok +} + +// SetOutputValidationAlgorithmsUsed stores the checksum algorithms used in the +// middleware Metadata. +func SetOutputValidationAlgorithmsUsed(m *middleware.Metadata, vs []string) { + m.Set(outputValidationAlgorithmsUsedKey{}, vs) +} + +// validateOutputPayloadChecksum middleware computes payload checksum of the +// received response and validates with checksum returned by the service. +type validateOutputPayloadChecksum struct { + // Algorithms represents a priority-ordered list of valid checksum + // algorithm that should be validated when present in HTTP response + // headers. + Algorithms []Algorithm + + // IgnoreMultipartValidation indicates multipart checksums ending with "-#" + // will be ignored. + IgnoreMultipartValidation bool + + // When set the middleware will log when output does not have checksum or + // algorithm to validate. + LogValidationSkipped bool + + // When set the middleware will log when the output contains a multipart + // checksum that was, skipped and not validated. + LogMultipartValidationSkipped bool +} + +func (m *validateOutputPayloadChecksum) ID() string { + return "AWSChecksum:ValidateOutputPayloadChecksum" +} + +// HandleDeserialize is a Deserialize middleware that wraps the HTTP response +// body with an io.ReadCloser that will validate the its checksum. +func (m *validateOutputPayloadChecksum) HandleDeserialize( + ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler, +) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("unknown transport type %T", out.RawResponse), + } + } + + var expectedChecksum string + var algorithmToUse Algorithm + for _, algorithm := range m.Algorithms { + value := response.Header.Get(AlgorithmHTTPHeader(algorithm)) + if len(value) == 0 { + continue + } + + expectedChecksum = value + algorithmToUse = algorithm + } + + // TODO this must validate the validation mode is set to enabled. + + logger := middleware.GetLogger(ctx) + + // Skip validation if no checksum algorithm or checksum is available. + if len(expectedChecksum) == 0 || len(algorithmToUse) == 0 { + if m.LogValidationSkipped { + // TODO this probably should have more information about the + // operation output that won't be validated. + logger.Logf(logging.Warn, + "Response has no supported checksum. Not validating response payload.") + } + return out, metadata, nil + } + + // Ignore multipart validation + if m.IgnoreMultipartValidation && strings.Contains(expectedChecksum, "-") { + if m.LogMultipartValidationSkipped { + // TODO this probably should have more information about the + // operation output that won't be validated. + logger.Logf(logging.Warn, "Skipped validation of multipart checksum.") + } + return out, metadata, nil + } + + body, err := newValidateChecksumReader(response.Body, algorithmToUse, expectedChecksum) + if err != nil { + return out, metadata, fmt.Errorf("failed to create checksum validation reader, %w", err) + } + response.Body = body + + // Update the metadata to include the set of the checksum algorithms that + // will be validated. + SetOutputValidationAlgorithmsUsed(&metadata, []string{ + string(algorithmToUse), + }) + + return out, metadata, nil +} diff --git a/service/internal/checksum/middleware_validate_output_test.go b/service/internal/checksum/middleware_validate_output_test.go new file mode 100644 index 00000000000..7f286b75615 --- /dev/null +++ b/service/internal/checksum/middleware_validate_output_test.go @@ -0,0 +1,213 @@ +//go:build go1.16 +// +build go1.16 + +package checksum + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" + "testing/iotest" + + "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/google/go-cmp/cmp" +) + +func TestValidateOutputPayloadChecksum(t *testing.T) { + cases := map[string]struct { + response *smithyhttp.Response + validateOptions func(*validateOutputPayloadChecksum) + expectHaveAlgorithmsUsed bool + expectAlgorithmsUsed []string + expectErr string + expectReadErr string + expectLogged string + expectPayload []byte + }{ + "success": { + response: &smithyhttp.Response{ + Response: &http.Response{ + StatusCode: 200, + Header: func() http.Header { + h := http.Header{} + h.Set(AlgorithmHTTPHeader(AlgorithmCRC32), "DUoRhQ==") + return h + }(), + Body: ioutil.NopCloser(strings.NewReader("hello world")), + }, + }, + expectHaveAlgorithmsUsed: true, + expectAlgorithmsUsed: []string{"CRC32"}, + expectPayload: []byte("hello world"), + }, + "failure": { + response: &smithyhttp.Response{ + Response: &http.Response{ + StatusCode: 200, + Header: func() http.Header { + h := http.Header{} + h.Set(AlgorithmHTTPHeader(AlgorithmCRC32), "AAAAAA==") + return h + }(), + Body: ioutil.NopCloser(strings.NewReader("hello world")), + }, + }, + expectReadErr: "checksum did not match", + }, + "read error": { + response: &smithyhttp.Response{ + Response: &http.Response{ + StatusCode: 200, + Header: func() http.Header { + h := http.Header{} + h.Set(AlgorithmHTTPHeader(AlgorithmCRC32), "AAAAAA==") + return h + }(), + Body: ioutil.NopCloser(iotest.ErrReader(fmt.Errorf("some read error"))), + }, + }, + expectReadErr: "some read error", + }, + "unsupported algorithm": { + response: &smithyhttp.Response{ + Response: &http.Response{ + StatusCode: 200, + Header: func() http.Header { + h := http.Header{} + h.Set(AlgorithmHTTPHeader("unsupported"), "AAAAAA==") + return h + }(), + Body: ioutil.NopCloser(strings.NewReader("hello world")), + }, + }, + expectLogged: "no supported checksum", + expectPayload: []byte("hello world"), + }, + "success ignore multipart checksum": { + response: &smithyhttp.Response{ + Response: &http.Response{ + StatusCode: 200, + Header: func() http.Header { + h := http.Header{} + h.Set(AlgorithmHTTPHeader(AlgorithmCRC32), "DUoRhQ==") + return h + }(), + Body: ioutil.NopCloser(strings.NewReader("hello world")), + }, + }, + validateOptions: func(o *validateOutputPayloadChecksum) { + o.IgnoreMultipartValidation = true + }, + expectHaveAlgorithmsUsed: true, + expectAlgorithmsUsed: []string{"CRC32"}, + expectPayload: []byte("hello world"), + }, + "success skip ignore multipart checksum": { + response: &smithyhttp.Response{ + Response: &http.Response{ + StatusCode: 200, + Header: func() http.Header { + h := http.Header{} + h.Set(AlgorithmHTTPHeader(AlgorithmCRC32), "DUoRhQ==-12") + return h + }(), + Body: ioutil.NopCloser(strings.NewReader("hello world")), + }, + }, + validateOptions: func(o *validateOutputPayloadChecksum) { + o.IgnoreMultipartValidation = true + }, + expectLogged: "Skipped validation of multipart checksum", + expectPayload: []byte("hello world"), + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + var logged bytes.Buffer + ctx := middleware.SetLogger(context.Background(), logging.LoggerFunc( + func(classification logging.Classification, format string, v ...interface{}) { + fmt.Fprintf(&logged, format, v...) + })) + + validateOutput := validateOutputPayloadChecksum{ + Algorithms: []Algorithm{ + AlgorithmSHA1, AlgorithmCRC32, AlgorithmCRC32C, + }, + LogValidationSkipped: true, + LogMultipartValidationSkipped: true, + } + if c.validateOptions != nil { + c.validateOptions(&validateOutput) + } + + out, meta, err := validateOutput.HandleDeserialize(ctx, + middleware.DeserializeInput{}, + middleware.DeserializeHandlerFunc( + func(ctx context.Context, input middleware.DeserializeInput) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, + ) { + out.RawResponse = c.response + return out, metadata, nil + }, + ), + ) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + + response := out.RawResponse.(*smithyhttp.Response) + + actualPayload, err := ioutil.ReadAll(response.Body) + if err == nil && len(c.expectReadErr) != 0 { + t.Fatalf("expected read error: %v, got none", c.expectReadErr) + } + if err != nil && len(c.expectReadErr) == 0 { + t.Fatalf("expect no read error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectReadErr) { + t.Fatalf("expected read error %v to contain %v", err, c.expectReadErr) + } + if c.expectReadErr != "" { + return + } + + if c.expectLogged != "" { + if e, a := c.expectLogged, logged.String(); !strings.Contains(a, e) { + t.Errorf("expected %q logged in:\n%s", e, a) + } + } + + if diff := cmp.Diff(string(c.expectPayload), string(actualPayload)); diff != "" { + t.Errorf("expect payload match:\n%s", diff) + } + + if err = response.Body.Close(); err != nil { + t.Errorf("expect no close error, got %v", err) + } + + values, ok := GetOutputValidationAlgorithmsUsed(meta) + if ok != c.expectHaveAlgorithmsUsed { + t.Errorf("expect metadata to contain algorithms used, %t", c.expectHaveAlgorithmsUsed) + } + if diff := cmp.Diff(c.expectAlgorithmsUsed, values); diff != "" { + t.Errorf("expect algorithms used to match\n%s", diff) + } + }) + } +} diff --git a/service/internal/integrationtest/go.mod b/service/internal/integrationtest/go.mod index 0414744e98e..8ca5820ef57 100644 --- a/service/internal/integrationtest/go.mod +++ b/service/internal/integrationtest/go.mod @@ -204,6 +204,8 @@ replace github.com/aws/aws-sdk-go-v2/service/inspector => ../../../service/inspe replace github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding => ../../../service/internal/accept-encoding/ +replace github.com/aws/aws-sdk-go-v2/service/internal/checksum => ../../../service/internal/checksum/ + replace github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery => ../../../service/internal/endpoint-discovery/ replace github.com/aws/aws-sdk-go-v2/service/internal/presigned-url => ../../../service/internal/presigned-url/ diff --git a/service/internal/integrationtest/s3/checksum_test.go b/service/internal/integrationtest/s3/checksum_test.go new file mode 100644 index 00000000000..1a5f7f3a4f6 --- /dev/null +++ b/service/internal/integrationtest/s3/checksum_test.go @@ -0,0 +1,491 @@ +//go:build integration +// +build integration + +package s3 + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "strings" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/smithy-go/logging" + "github.com/google/go-cmp/cmp" +) + +func TestInteg_ObjectChecksums(t *testing.T) { + cases := map[string]map[string]struct { + disableHTTPS bool + params *s3.PutObjectInput + expectErr string + + getObjectChecksumMode s3types.ChecksumMode + expectReadErr string + expectLogged string + expectChecksumAlgorithms s3types.ChecksumAlgorithm + expectPayload []byte + expectComputedChecksums *s3.ComputedInputChecksumsMetadata + expectAlgorithmsUsed *s3.ChecksumValidationMetadata + }{ + "seekable": { + "no checksum": { + params: &s3.PutObjectInput{ + Body: strings.NewReader("abc123"), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("abc123"), + expectLogged: "Response has no supported checksum.", + }, + "preset checksum": { + params: &s3.PutObjectInput{ + Body: strings.NewReader("hello world"), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32C: aws.String("yZRlqg=="), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "wrong preset checksum": { + params: &s3.PutObjectInput{ + Body: strings.NewReader("hello world"), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32C: aws.String("RZRlqg=="), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectErr: "BadDigest", + }, + "without TLS autofill header checksum": { + disableHTTPS: true, + params: &s3.PutObjectInput{ + Body: strings.NewReader("hello world"), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "autofill trailing checksum": { + params: &s3.PutObjectInput{ + Body: strings.NewReader("hello world"), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "content length preset": { + params: &s3.PutObjectInput{ + Body: strings.NewReader("hello world"), + ContentLength: 11, + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "with content encoding set": { + params: &s3.PutObjectInput{ + Body: strings.NewReader("hello world"), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ContentEncoding: aws.String("gzip"), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + }, + "unseekable": { + "no checksum": { + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte("abc123")), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("abc123"), + expectLogged: "Response has no supported checksum.", + }, + "preset checksum": { + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte("hello world")), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32C: aws.String("yZRlqg=="), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "wrong preset checksum": { + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte("hello world")), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32C: aws.String("RZRlqg=="), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectErr: "BadDigest", + }, + "autofill trailing checksum": { + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte("hello world")), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "without TLS": { + disableHTTPS: true, + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte("hello world")), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + expectErr: "unseekable stream is not supported without TLS", + }, + "content length preset": { + params: &s3.PutObjectInput{ + Body: ioutil.NopCloser(strings.NewReader("hello world")), + ContentLength: 11, + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectPayload: []byte("hello world"), + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "yZRlqg==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "unknown content length": { + params: &s3.PutObjectInput{ + Body: ioutil.NopCloser(strings.NewReader("hello world")), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + expectErr: "MissingContentLength", + }, + }, + "nil body": { + "no checksum": { + params: &s3.PutObjectInput{}, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectLogged: "Response has no supported checksum.", + }, + "preset checksum": { + params: &s3.PutObjectInput{ + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32C: aws.String("AAAAAA=="), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "AAAAAA==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "autofill checksum": { + params: &s3.PutObjectInput{ + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "AAAAAA==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "without TLS autofill checksum": { + disableHTTPS: true, + params: &s3.PutObjectInput{ + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "AAAAAA==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + }, + "empty body": { + "no checksum": { + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte{}), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectLogged: "Response has no supported checksum.", + }, + "preset checksum": { + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte{}), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32C: aws.String("AAAAAA=="), + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "AAAAAA==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "autofill checksum": { + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte{}), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "AAAAAA==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + "without TLS autofill checksum": { + disableHTTPS: true, + params: &s3.PutObjectInput{ + Body: bytes.NewBuffer([]byte{}), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + }, + getObjectChecksumMode: s3types.ChecksumModeEnabled, + expectComputedChecksums: &s3.ComputedInputChecksumsMetadata{ + ComputedChecksums: map[string]string{ + "CRC32C": "AAAAAA==", + }, + }, + expectAlgorithmsUsed: &s3.ChecksumValidationMetadata{ + AlgorithmsUsed: []string{"CRC32C"}, + }, + }, + }, + } + + for groupName, cs := range cases { + t.Run(groupName, func(t *testing.T) { + for caseName, c := range cs { + t.Run(caseName, func(t *testing.T) { + c.params.Bucket = &setupMetadata.Buckets.Source.Name + c.params.Key = aws.String(t.Name()) + + ctx := context.Background() + logger, logged := bufferLogger(t) + s3Options := func(o *s3.Options) { + o.Logger = logger + o.EndpointOptions.DisableHTTPS = c.disableHTTPS + } + + t.Logf("putting bucket: %q, object: %q", *c.params.Bucket, *c.params.Key) + putResult, err := s3client.PutObject(ctx, c.params, s3Options) + if err == nil && len(c.expectErr) != 0 { + t.Fatalf("expect error %v, got none", c.expectErr) + } + if err != nil && len(c.expectErr) == 0 { + t.Fatalf("expect no error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectErr) { + t.Fatalf("expect error to contain %v, got %v", c.expectErr, err) + } + if c.expectErr != "" { + return + } + // assert computed input checksums metadata + computedChecksums, ok := s3.GetComputedInputChecksumsMetadata(putResult.ResultMetadata) + if e, a := ok, (c.expectComputedChecksums != nil); e != a { + t.Fatalf("expect computed checksum metadata %t, got %t, %v", e, a, computedChecksums) + } + if c.expectComputedChecksums != nil { + if diff := cmp.Diff(*c.expectComputedChecksums, computedChecksums); diff != "" { + t.Errorf("expect computed checksum metadata match\n%s", diff) + } + } + + getResult, err := s3client.GetObject(ctx, &s3.GetObjectInput{ + Bucket: c.params.Bucket, + Key: c.params.Key, + ChecksumMode: c.getObjectChecksumMode, + }, s3Options) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + actualPayload, err := ioutil.ReadAll(getResult.Body) + if err == nil && len(c.expectReadErr) != 0 { + t.Fatalf("expected read error: %v, got none", c.expectReadErr) + } + if err != nil && len(c.expectReadErr) == 0 { + t.Fatalf("expect no read error, got %v", err) + } + if err != nil && !strings.Contains(err.Error(), c.expectReadErr) { + t.Fatalf("expected read error %v to contain %v", err, c.expectReadErr) + } + if c.expectReadErr != "" { + return + } + + if diff := cmp.Diff(string(c.expectPayload), string(actualPayload)); diff != "" { + t.Errorf("expect payload match:\n%s", diff) + } + + if err = getResult.Body.Close(); err != nil { + t.Errorf("expect no close error, got %v", err) + } + + // Only compare string values, since S3 can respond with + // empty value Content-Encoding header. + if e, a := aws.ToString(c.params.ContentEncoding), aws.ToString(getResult.ContentEncoding); e != a { + t.Errorf("expect %v content encoding, got %v", e, a) + } + + // assert checksum validation metadata + algorithmsUsed, ok := s3.GetChecksumValidationMetadata(getResult.ResultMetadata) + if e, a := ok, (c.expectAlgorithmsUsed != nil); e != a { + t.Fatalf("expect algorithms used metadata %t, got %t, %v", e, a, algorithmsUsed) + } + if c.expectAlgorithmsUsed != nil { + if diff := cmp.Diff(*c.expectAlgorithmsUsed, algorithmsUsed); diff != "" { + t.Errorf("expect algorithms used to match\n%s", diff) + } + } + + if c.expectLogged != "" { + if e, a := c.expectLogged, logged.String(); !strings.Contains(a, e) { + t.Errorf("expected %q logged in:\n%s", e, a) + } + } + }) + } + }) + } +} + +func TestInteg_RequireChecksum(t *testing.T) { + cases := map[string]struct { + checksumAlgorithm types.ChecksumAlgorithm + expectComputedChecksums []string + }{ + "no algorithm": { + expectComputedChecksums: []string{"MD5"}, + }, + "with algorithm": { + checksumAlgorithm: types.ChecksumAlgorithmCrc32c, + expectComputedChecksums: []string{"CRC32C"}, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + result, err := s3client.DeleteObjects(context.Background(), &s3.DeleteObjectsInput{ + Bucket: &setupMetadata.Buckets.Source.Name, + Delete: &s3types.Delete{ + Objects: []s3types.ObjectIdentifier{ + {Key: aws.String(t.Name())}, + }, + Quiet: true, + }, + ChecksumAlgorithm: c.checksumAlgorithm, + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + // assert computed input checksums metadata + computedChecksums, ok := s3.GetComputedInputChecksumsMetadata(result.ResultMetadata) + if e, a := ok, (c.expectComputedChecksums != nil); e != a { + t.Fatalf("expect computed checksum metadata %t, got %t, %v", e, a, computedChecksums) + } + if e, a := len(c.expectComputedChecksums), len(computedChecksums.ComputedChecksums); e != a { + t.Errorf("expect %v computed checksums, got %v, %v", e, a, computedChecksums) + } + for _, e := range c.expectComputedChecksums { + v, ok := computedChecksums.ComputedChecksums[e] + if !ok { + t.Errorf("expect %v algorithm to be computed", e) + } + if v == "" { + t.Errorf("expect %v algorithm to have non-empty computed checksum", e) + } + } + }) + } +} + +func bufferLogger(t *testing.T) (logging.Logger, *bytes.Buffer) { + var logged bytes.Buffer + + logger := logging.LoggerFunc( + func(classification logging.Classification, format string, v ...interface{}) { + fmt.Fprintf(&logged, format, v...) + t.Logf(format, v...) + }) + + return logger, &logged +} diff --git a/service/internal/integrationtest/s3/presign_test.go b/service/internal/integrationtest/s3/presign_test.go index bd1280e0f2b..e74ca40147d 100644 --- a/service/internal/integrationtest/s3/presign_test.go +++ b/service/internal/integrationtest/s3/presign_test.go @@ -14,42 +14,54 @@ import ( "testing" "time" + "github.com/aws/aws-sdk-go-v2/aws" v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/service/internal/integrationtest" "github.com/aws/aws-sdk-go-v2/service/s3" + s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/google/go-cmp/cmp" ) func TestInteg_PresignURL(t *testing.T) { cases := map[string]struct { - key string - body io.Reader + params s3.PutObjectInput expires time.Duration sha256Header string expectedSignedHeader http.Header + expectErr string }{ "standard": { - body: bytes.NewReader([]byte("Hello-world")), + params: s3.PutObjectInput{ + Body: bytes.NewReader([]byte("Hello-world")), + }, expectedSignedHeader: http.Header{}, }, "special characters": { - key: "some_value_(1).foo", + params: s3.PutObjectInput{ + Key: aws.String("some_value_(1).foo"), + }, }, "nil-body": { expectedSignedHeader: http.Header{}, }, "empty-body": { - body: bytes.NewReader([]byte("")), + params: s3.PutObjectInput{ + Body: bytes.NewReader([]byte("")), + }, + expectedSignedHeader: http.Header{}, + }, + "preset checksum": { + params: s3.PutObjectInput{ + Body: bytes.NewReader([]byte("hello world")), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32, + ChecksumCRC32: aws.String("DUoRhQ=="), + }, expectedSignedHeader: http.Header{}, }, } for name, c := range cases { t.Run(name, func(t *testing.T) { - key := c.key - if len(key) == 0 { - key = integrationtest.UniqueID() - } ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second) defer cancelFn() @@ -62,17 +74,17 @@ func TestInteg_PresignURL(t *testing.T) { client := s3.NewFromConfig(cfg) // construct a put object - putObjectInput := &s3.PutObjectInput{ - Bucket: &setupMetadata.Buckets.Source.Name, - Key: &key, - Body: c.body, - } - presignerClient := s3.NewPresignClient(client, func(options *s3.PresignOptions) { options.Expires = 600 * time.Second }) - presignRequest, err := presignerClient.PresignPutObject(ctx, putObjectInput) + params := c.params + if params.Key == nil { + params.Key = aws.String(integrationtest.UniqueID()) + } + params.Bucket = &setupMetadata.Buckets.Source.Name + + presignRequest, err := presignerClient.PresignPutObject(ctx, ¶ms) if err != nil { t.Fatalf("expect no error, got %v", err) } @@ -88,7 +100,7 @@ func TestInteg_PresignURL(t *testing.T) { } } - resp, err := sendHTTPRequest(presignRequest, putObjectInput.Body) + resp, err := sendHTTPRequest(presignRequest, params.Body) if err != nil { t.Errorf("expect no error while sending HTTP request using presigned url, got %v", err) } @@ -101,8 +113,8 @@ func TestInteg_PresignURL(t *testing.T) { // construct a get object getObjectInput := &s3.GetObjectInput{ - Bucket: &setupMetadata.Buckets.Source.Name, - Key: &key, + Bucket: params.Bucket, + Key: params.Key, } presignRequest, err = presignerClient.PresignGetObject(ctx, getObjectInput) diff --git a/service/s3/api_client.go b/service/s3/api_client.go index dfb7f6ad5c1..b35b1276cee 100644 --- a/service/s3/api_client.go +++ b/service/s3/api_client.go @@ -13,6 +13,7 @@ import ( awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources" acceptencodingcust "github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" presignedurlcust "github.com/aws/aws-sdk-go-v2/service/internal/presigned-url" "github.com/aws/aws-sdk-go-v2/service/internal/s3shared" s3sharedconfig "github.com/aws/aws-sdk-go-v2/service/internal/s3shared/config" @@ -526,6 +527,53 @@ func addMetadataRetrieverMiddleware(stack *middleware.Stack) error { return s3shared.AddMetadataRetrieverMiddleware(stack) } +// ComputedInputChecksumsMetadata provides information about the algorithms used to +// compute the checksum(s) of the input payload. +type ComputedInputChecksumsMetadata struct { + // ComputedChecksums is a map of algorithm name to checksum value of the computed + // input payload's checksums. + ComputedChecksums map[string]string +} + +// GetComputedInputChecksumsMetadata retrieves from the result metadata the map of +// algorithms and input payload checksums values. +func GetComputedInputChecksumsMetadata(m middleware.Metadata) (ComputedInputChecksumsMetadata, bool) { + values, ok := internalChecksum.GetComputedInputChecksums(m) + if !ok { + return ComputedInputChecksumsMetadata{}, false + } + return ComputedInputChecksumsMetadata{ + ComputedChecksums: values, + }, true + +} + +// ChecksumValidationMetadata contains metadata such as the checksum algorithm used +// for data integrity validation. +type ChecksumValidationMetadata struct { + // AlgorithmsUsed is the set of the checksum algorithms used to validate the + // response payload. The response payload must be completely read in order for the + // checksum validation to be performed. An error is returned by the operation + // output's response io.ReadCloser if the computed checksums are invalid. + AlgorithmsUsed []string +} + +// GetChecksumValidationMetadata returns the set of algorithms that will be used to +// validate the response payload with. The response payload must be completely read +// in order for the checksum validation to be performed. An error is returned by +// the operation output's response io.ReadCloser if the computed checksums are +// invalid. Returns false if no checksum algorithm used metadata was found. +func GetChecksumValidationMetadata(m middleware.Metadata) (ChecksumValidationMetadata, bool) { + values, ok := internalChecksum.GetOutputValidationAlgorithmsUsed(m) + if !ok { + return ChecksumValidationMetadata{}, false + } + return ChecksumValidationMetadata{ + AlgorithmsUsed: append(make([]string, 0, len(values)), values...), + }, true + +} + // nopGetBucketAccessor is no-op accessor for operation that don't support bucket // member as input func nopGetBucketAccessor(input interface{}) (*string, bool) { diff --git a/service/s3/api_op_AbortMultipartUpload.go b/service/s3/api_op_AbortMultipartUpload.go index 25b0b762bf5..042e848a387 100644 --- a/service/s3/api_op_AbortMultipartUpload.go +++ b/service/s3/api_op_AbortMultipartUpload.go @@ -74,9 +74,9 @@ type AbortMultipartUploadInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -94,13 +94,14 @@ type AbortMultipartUploadInput struct { UploadId *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_CompleteMultipartUpload.go b/service/s3/api_op_CompleteMultipartUpload.go index 12f9a080fa1..95ff6496863 100644 --- a/service/s3/api_op_CompleteMultipartUpload.go +++ b/service/s3/api_op_CompleteMultipartUpload.go @@ -127,9 +127,9 @@ type CompleteMultipartUploadInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -146,8 +146,41 @@ type CompleteMultipartUploadInput struct { // This member is required. UploadId *string + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32 checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32C checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 160-bit SHA-1 digest of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 256-bit SHA-256 digest of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The container for the multipart upload request information. @@ -155,12 +188,33 @@ type CompleteMultipartUploadInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer + // The server-side encryption (SSE) algorithm used to encrypt the object. This + // parameter is needed only when the object was created using a checksum algorithm. + // For more information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. + SSECustomerAlgorithm *string + + // The server-side encryption (SSE) customer managed key. This parameter is needed + // only when the object was created using a checksum algorithm. For more + // information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. + SSECustomerKey *string + + // The MD5 server-side encryption (SSE) customer managed key. This parameter is + // needed only when the object was created using a checksum algorithm. For more + // information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. + SSECustomerKeyMD5 *string + noSmithyDocumentSerde } @@ -179,9 +233,9 @@ type CompleteMultipartUploadOutput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. Bucket *string @@ -190,16 +244,51 @@ type CompleteMultipartUploadOutput struct { // encryption with Amazon Web Services KMS (SSE-KMS). BucketKeyEnabled bool + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Entity tag that identifies the newly created object's data. Objects with // different object data will have different entity tags. The entity tag is an // opaque string. The entity tag may or may not be an MD5 digest of the object // data. If the entity tag is not an MD5 digest of the object data, it will contain // one or more nonhexadecimal characters and/or will consist of less than 32 or - // more than 32 hexadecimal digits. + // more than 32 hexadecimal digits. For more information about how the entity tag + // is calculated, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. ETag *string // If the object expiration is configured, this will contain the expiration date - // (expiry-date) and rule ID (rule-id). The value of rule-id is URL encoded. + // (expiry-date) and rule ID (rule-id). The value of rule-id is URL-encoded. Expiration *string // The object key of the newly created object. diff --git a/service/s3/api_op_CopyObject.go b/service/s3/api_op_CopyObject.go index cd5ea4208e9..477900778d7 100644 --- a/service/s3/api_op_CopyObject.go +++ b/service/s3/api_op_CopyObject.go @@ -17,7 +17,8 @@ import ( // individual objects of up to 5 TB in Amazon S3. You create a copy of your object // up to 5 GB in size in a single atomic action using this API. However, to copy an // object greater than 5 GB, you must use the multipart upload Upload Part - Copy -// API. For more information, see Copy Object Using the REST Multipart Upload API +// (UploadPartCopy) API. For more information, see Copy Object Using the REST +// Multipart Upload API // (https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjctsUsingRESTMPUapi.html). // All copy requests must be authenticated. Additionally, you must have read access // to the source object and write access to the destination bucket. For more @@ -124,10 +125,13 @@ import ( // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html) // in the Amazon S3 User Guide. If your bucket uses the bucket owner enforced // setting for Object Ownership, all objects written to the bucket by any account -// will be owned by the bucket owner. Storage Class Options You can use the -// CopyObject action to change the storage class of an object that is already -// stored in Amazon S3 using the StorageClass parameter. For more information, see -// Storage Classes +// will be owned by the bucket owner. Checksums When copying an object, if it has a +// checksum, that checksum will be copied to the new object by default. When you +// copy the object over, you may optionally specify a different checksum algorithm +// to use with the x-amz-checksum-algorithm header. Storage Class Options You can +// use the CopyObject action to change the storage class of an object that is +// already stored in Amazon S3 using the StorageClass parameter. For more +// information, see Storage Classes // (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) in // the Amazon S3 User Guide. Versioning By default, x-amz-copy-source identifies // the current version of an object to copy. If the current version is a delete @@ -182,9 +186,9 @@ type CopyObjectInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -200,7 +204,7 @@ type CopyObjectInput struct { // For objects not accessed through an access point, specify the name of the source // bucket and the key of the source object, separated by a slash (/). For example, // to copy the object reports/january.pdf from the bucket awsexamplebucket, use - // awsexamplebucket/reports/january.pdf. The value must be URL encoded. + // awsexamplebucket/reports/january.pdf. The value must be URL-encoded. // // * For // objects accessed through access points, specify the Amazon Resource Name (ARN) @@ -217,7 +221,7 @@ type CopyObjectInput struct { // reports/january.pdf through outpost my-outpost owned by account 123456789012 in // Region us-west-2, use the URL encoding of // arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf. - // The value must be URL encoded. + // The value must be URL-encoded. // // To copy a specific version of an object, append // ?versionId= to the value (for example, @@ -247,6 +251,12 @@ type CopyObjectInput struct { // Specifies caching behavior along the request/reply chain. CacheControl *string + // Indicates the algorithm you want Amazon S3 to use to create the checksum for the + // object. For more information, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumAlgorithm types.ChecksumAlgorithm + // Specifies presentational information for the object. ContentDisposition *string @@ -288,13 +298,13 @@ type CopyObjectInput struct { CopySourceSSECustomerKeyMD5 *string // The account ID of the expected destination bucket owner. If the destination - // bucket is owned by a different account, the request will fail with an HTTP 403 - // (Access Denied) error. + // bucket is owned by a different account, the request fails with the HTTP status + // code 403 Forbidden (access denied). ExpectedBucketOwner *string // The account ID of the expected source bucket owner. If the source bucket is - // owned by a different account, the request will fail with an HTTP 403 (Access - // Denied) error. + // owned by a different account, the request fails with the HTTP status code 403 + // Forbidden (access denied). ExpectedSourceBucketOwner *string // The date and time at which the object is no longer cacheable. @@ -323,7 +333,7 @@ type CopyObjectInput struct { // metadata provided in the request. MetadataDirective types.MetadataDirective - // Specifies whether you want to apply a Legal Hold to the copied object. + // Specifies whether you want to apply a legal hold to the copied object. ObjectLockLegalHoldStatus types.ObjectLockLegalHoldStatus // The Object Lock mode that you want to apply to the copied object. @@ -334,8 +344,8 @@ type CopyObjectInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_CreateBucket.go b/service/s3/api_op_CreateBucket.go index 62798d98692..27322a2c656 100644 --- a/service/s3/api_op_CreateBucket.go +++ b/service/s3/api_op_CreateBucket.go @@ -198,9 +198,7 @@ type CreateBucketInput struct { type CreateBucketOutput struct { - // Specifies the Region where the bucket will be created. If you are creating a - // bucket on the US East (N. Virginia) Region (us-east-1), you do not need to - // specify the location. + // A forward slash followed by the name of the bucket. Location *string // Metadata pertaining to the operation's result. diff --git a/service/s3/api_op_CreateMultipartUpload.go b/service/s3/api_op_CreateMultipartUpload.go index 9e3f7ed85b3..825feebd2c8 100644 --- a/service/s3/api_op_CreateMultipartUpload.go +++ b/service/s3/api_op_CreateMultipartUpload.go @@ -262,9 +262,9 @@ type CreateMultipartUploadInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -290,6 +290,12 @@ type CreateMultipartUploadInput struct { // Specifies caching behavior along the request/reply chain. CacheControl *string + // Indicates the algorithm you want Amazon S3 to use to create the checksum for the + // object. For more information, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumAlgorithm types.ChecksumAlgorithm + // Specifies presentational information for the object. ContentDisposition *string @@ -305,7 +311,8 @@ type CreateMultipartUploadInput struct { ContentType *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The date and time at which the object is no longer cacheable. @@ -330,7 +337,7 @@ type CreateMultipartUploadInput struct { // A map of metadata to store with the object in S3. Metadata map[string]string - // Specifies whether you want to apply a Legal Hold to the uploaded object. + // Specifies whether you want to apply a legal hold to the uploaded object. ObjectLockLegalHoldStatus types.ObjectLockLegalHoldStatus // Specifies the Object Lock mode that you want to apply to the uploaded object. @@ -341,8 +348,8 @@ type CreateMultipartUploadInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -433,9 +440,9 @@ type CreateMultipartUploadOutput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. Bucket *string @@ -444,6 +451,9 @@ type CreateMultipartUploadOutput struct { // encryption with Amazon Web Services KMS (SSE-KMS). BucketKeyEnabled bool + // The algorithm that was used to create a checksum of the object. + ChecksumAlgorithm types.ChecksumAlgorithm + // Object key for which the multipart upload was initiated. Key *string diff --git a/service/s3/api_op_DeleteBucket.go b/service/s3/api_op_DeleteBucket.go index bcbfc3590a7..44823c6a8fe 100644 --- a/service/s3/api_op_DeleteBucket.go +++ b/service/s3/api_op_DeleteBucket.go @@ -44,7 +44,8 @@ type DeleteBucketInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketAnalyticsConfiguration.go b/service/s3/api_op_DeleteBucketAnalyticsConfiguration.go index 6f7ab3ff799..e016d976302 100644 --- a/service/s3/api_op_DeleteBucketAnalyticsConfiguration.go +++ b/service/s3/api_op_DeleteBucketAnalyticsConfiguration.go @@ -64,7 +64,8 @@ type DeleteBucketAnalyticsConfigurationInput struct { Id *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketCors.go b/service/s3/api_op_DeleteBucketCors.go index 07fe6302ffa..79045abe2d0 100644 --- a/service/s3/api_op_DeleteBucketCors.go +++ b/service/s3/api_op_DeleteBucketCors.go @@ -47,7 +47,8 @@ type DeleteBucketCorsInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketEncryption.go b/service/s3/api_op_DeleteBucketEncryption.go index 79f70860b74..9c3201f6ded 100644 --- a/service/s3/api_op_DeleteBucketEncryption.go +++ b/service/s3/api_op_DeleteBucketEncryption.go @@ -55,7 +55,8 @@ type DeleteBucketEncryptionInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketInventoryConfiguration.go b/service/s3/api_op_DeleteBucketInventoryConfiguration.go index 9d0e6a8b861..32fe81f12e0 100644 --- a/service/s3/api_op_DeleteBucketInventoryConfiguration.go +++ b/service/s3/api_op_DeleteBucketInventoryConfiguration.go @@ -63,7 +63,8 @@ type DeleteBucketInventoryConfigurationInput struct { Id *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketLifecycle.go b/service/s3/api_op_DeleteBucketLifecycle.go index f1c59da4528..c110bfb440d 100644 --- a/service/s3/api_op_DeleteBucketLifecycle.go +++ b/service/s3/api_op_DeleteBucketLifecycle.go @@ -53,7 +53,8 @@ type DeleteBucketLifecycleInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketMetricsConfiguration.go b/service/s3/api_op_DeleteBucketMetricsConfiguration.go index c9d7e8c782b..cc08f04b787 100644 --- a/service/s3/api_op_DeleteBucketMetricsConfiguration.go +++ b/service/s3/api_op_DeleteBucketMetricsConfiguration.go @@ -69,7 +69,8 @@ type DeleteBucketMetricsConfigurationInput struct { Id *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketOwnershipControls.go b/service/s3/api_op_DeleteBucketOwnershipControls.go index 2f3dc331992..6186db5e194 100644 --- a/service/s3/api_op_DeleteBucketOwnershipControls.go +++ b/service/s3/api_op_DeleteBucketOwnershipControls.go @@ -46,7 +46,8 @@ type DeleteBucketOwnershipControlsInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketPolicy.go b/service/s3/api_op_DeleteBucketPolicy.go index 815b5baabdc..618d9bedebe 100644 --- a/service/s3/api_op_DeleteBucketPolicy.go +++ b/service/s3/api_op_DeleteBucketPolicy.go @@ -56,7 +56,8 @@ type DeleteBucketPolicyInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketReplication.go b/service/s3/api_op_DeleteBucketReplication.go index 3489765b58b..ad2d772d477 100644 --- a/service/s3/api_op_DeleteBucketReplication.go +++ b/service/s3/api_op_DeleteBucketReplication.go @@ -54,7 +54,8 @@ type DeleteBucketReplicationInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketTagging.go b/service/s3/api_op_DeleteBucketTagging.go index e05f3d44d9a..063f0bc5977 100644 --- a/service/s3/api_op_DeleteBucketTagging.go +++ b/service/s3/api_op_DeleteBucketTagging.go @@ -45,7 +45,8 @@ type DeleteBucketTaggingInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteBucketWebsite.go b/service/s3/api_op_DeleteBucketWebsite.go index a1d22e9e948..7eb72b86a22 100644 --- a/service/s3/api_op_DeleteBucketWebsite.go +++ b/service/s3/api_op_DeleteBucketWebsite.go @@ -54,7 +54,8 @@ type DeleteBucketWebsiteInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_DeleteObject.go b/service/s3/api_op_DeleteObject.go index 54468e90a75..82e6687f8af 100644 --- a/service/s3/api_op_DeleteObject.go +++ b/service/s3/api_op_DeleteObject.go @@ -65,9 +65,9 @@ type DeleteObjectInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -81,11 +81,12 @@ type DeleteObjectInput struct { // Indicates whether S3 Object Lock should bypass Governance-mode restrictions to // process this operation. To use this header, you must have the - // s3:PutBucketPublicAccessBlock permission. + // s3:BypassGovernanceRetention permission. BypassGovernanceRetention bool // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The concatenation of the authentication device's serial number, a space, and the @@ -95,8 +96,8 @@ type DeleteObjectInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_DeleteObjectTagging.go b/service/s3/api_op_DeleteObjectTagging.go index 81640f66fc0..0d1bb73994f 100644 --- a/service/s3/api_op_DeleteObjectTagging.go +++ b/service/s3/api_op_DeleteObjectTagging.go @@ -55,9 +55,9 @@ type DeleteObjectTaggingInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -70,7 +70,8 @@ type DeleteObjectTaggingInput struct { Key *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The versionId of the object that the tag-set will be removed from. diff --git a/service/s3/api_op_DeleteObjects.go b/service/s3/api_op_DeleteObjects.go index 7e439da48c9..50078da53bc 100644 --- a/service/s3/api_op_DeleteObjects.go +++ b/service/s3/api_op_DeleteObjects.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -86,9 +87,9 @@ type DeleteObjectsInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -102,11 +103,25 @@ type DeleteObjectsInput struct { // Specifies whether you want to delete this object even if it has a // Governance-type Object Lock in place. To use this header, you must have the - // s3:PutBucketPublicAccessBlock permission. + // s3:BypassGovernanceRetention permission. BypassGovernanceRetention bool + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. This checksum algorithm must + // be the same for all parts and it match the checksum value supplied in the + // CreateMultipartUpload request. + ChecksumAlgorithm types.ChecksumAlgorithm + // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The concatenation of the authentication device's serial number, a space, and the @@ -116,8 +131,8 @@ type DeleteObjectsInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -193,9 +208,6 @@ func (c *Client) addOperationDeleteObjectsMiddlewares(stack *middleware.Stack, o if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpDeleteObjectsValidationMiddleware(stack); err != nil { return err } @@ -205,6 +217,9 @@ func (c *Client) addOperationDeleteObjectsMiddlewares(stack *middleware.Stack, o if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addDeleteObjectsInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addDeleteObjectsUpdateEndpoint(stack, options); err != nil { return err } @@ -232,6 +247,26 @@ func newServiceMetadataMiddleware_opDeleteObjects(region string) *awsmiddleware. } } +// getDeleteObjectsRequestAlgorithmMember gets the request checksum algorithm value +// provided as input. +func getDeleteObjectsRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*DeleteObjectsInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addDeleteObjectsInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getDeleteObjectsRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getDeleteObjectsBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_DeletePublicAccessBlock.go b/service/s3/api_op_DeletePublicAccessBlock.go index 04df4643e42..3defd538c74 100644 --- a/service/s3/api_op_DeletePublicAccessBlock.go +++ b/service/s3/api_op_DeletePublicAccessBlock.go @@ -58,7 +58,8 @@ type DeletePublicAccessBlockInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketAccelerateConfiguration.go b/service/s3/api_op_GetBucketAccelerateConfiguration.go index d2dff759cd0..d1690f3ea4f 100644 --- a/service/s3/api_op_GetBucketAccelerateConfiguration.go +++ b/service/s3/api_op_GetBucketAccelerateConfiguration.go @@ -59,7 +59,8 @@ type GetBucketAccelerateConfigurationInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketAcl.go b/service/s3/api_op_GetBucketAcl.go index 7dcd976e21c..610762883aa 100644 --- a/service/s3/api_op_GetBucketAcl.go +++ b/service/s3/api_op_GetBucketAcl.go @@ -49,7 +49,8 @@ type GetBucketAclInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketAnalyticsConfiguration.go b/service/s3/api_op_GetBucketAnalyticsConfiguration.go index 3f87c9811f3..bf2c3be6726 100644 --- a/service/s3/api_op_GetBucketAnalyticsConfiguration.go +++ b/service/s3/api_op_GetBucketAnalyticsConfiguration.go @@ -65,7 +65,8 @@ type GetBucketAnalyticsConfigurationInput struct { Id *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketCors.go b/service/s3/api_op_GetBucketCors.go index 1f291ac0573..0ed61273a75 100644 --- a/service/s3/api_op_GetBucketCors.go +++ b/service/s3/api_op_GetBucketCors.go @@ -12,10 +12,11 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// Returns the cors configuration information set for the bucket. To use this -// operation, you must have permission to perform the s3:GetBucketCORS action. By -// default, the bucket owner has this permission and can grant it to others. For -// more information about cors, see Enabling Cross-Origin Resource Sharing +// Returns the Cross-Origin Resource Sharing (CORS) configuration information set +// for the bucket. To use this operation, you must have permission to perform the +// s3:GetBucketCORS action. By default, the bucket owner has this permission and +// can grant it to others. For more information about CORS, see Enabling +// Cross-Origin Resource Sharing // (https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html). The following // operations are related to GetBucketCors: // @@ -48,7 +49,8 @@ type GetBucketCorsInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketEncryption.go b/service/s3/api_op_GetBucketEncryption.go index 12507c17bf0..7fa92fc5fd2 100644 --- a/service/s3/api_op_GetBucketEncryption.go +++ b/service/s3/api_op_GetBucketEncryption.go @@ -59,7 +59,8 @@ type GetBucketEncryptionInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketInventoryConfiguration.go b/service/s3/api_op_GetBucketInventoryConfiguration.go index 64114720225..f35a4606c8f 100644 --- a/service/s3/api_op_GetBucketInventoryConfiguration.go +++ b/service/s3/api_op_GetBucketInventoryConfiguration.go @@ -63,7 +63,8 @@ type GetBucketInventoryConfigurationInput struct { Id *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketLifecycleConfiguration.go b/service/s3/api_op_GetBucketLifecycleConfiguration.go index f64f1486982..5d72d2ebc49 100644 --- a/service/s3/api_op_GetBucketLifecycleConfiguration.go +++ b/service/s3/api_op_GetBucketLifecycleConfiguration.go @@ -80,7 +80,8 @@ type GetBucketLifecycleConfigurationInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketLocation.go b/service/s3/api_op_GetBucketLocation.go index 7adda2097ae..fb8ff30fd41 100644 --- a/service/s3/api_op_GetBucketLocation.go +++ b/service/s3/api_op_GetBucketLocation.go @@ -57,7 +57,8 @@ type GetBucketLocationInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketLogging.go b/service/s3/api_op_GetBucketLogging.go index 2e43477b111..ca115886d50 100644 --- a/service/s3/api_op_GetBucketLogging.go +++ b/service/s3/api_op_GetBucketLogging.go @@ -45,7 +45,8 @@ type GetBucketLoggingInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketMetricsConfiguration.go b/service/s3/api_op_GetBucketMetricsConfiguration.go index 30025a6685b..22cf389cd88 100644 --- a/service/s3/api_op_GetBucketMetricsConfiguration.go +++ b/service/s3/api_op_GetBucketMetricsConfiguration.go @@ -70,7 +70,8 @@ type GetBucketMetricsConfigurationInput struct { Id *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketNotificationConfiguration.go b/service/s3/api_op_GetBucketNotificationConfiguration.go index a6bdeaa035b..cbf103a7fd1 100644 --- a/service/s3/api_op_GetBucketNotificationConfiguration.go +++ b/service/s3/api_op_GetBucketNotificationConfiguration.go @@ -50,7 +50,8 @@ type GetBucketNotificationConfigurationInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketOwnershipControls.go b/service/s3/api_op_GetBucketOwnershipControls.go index 88042750b48..571c9566cec 100644 --- a/service/s3/api_op_GetBucketOwnershipControls.go +++ b/service/s3/api_op_GetBucketOwnershipControls.go @@ -47,7 +47,8 @@ type GetBucketOwnershipControlsInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketPolicy.go b/service/s3/api_op_GetBucketPolicy.go index 4e0d1afa9e3..f16c84cddf1 100644 --- a/service/s3/api_op_GetBucketPolicy.go +++ b/service/s3/api_op_GetBucketPolicy.go @@ -51,7 +51,8 @@ type GetBucketPolicyInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketPolicyStatus.go b/service/s3/api_op_GetBucketPolicyStatus.go index 42b3b801226..570f60faa9a 100644 --- a/service/s3/api_op_GetBucketPolicyStatus.go +++ b/service/s3/api_op_GetBucketPolicyStatus.go @@ -60,7 +60,8 @@ type GetBucketPolicyStatusInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketReplication.go b/service/s3/api_op_GetBucketReplication.go index b03baf4d307..5d7f3115b8d 100644 --- a/service/s3/api_op_GetBucketReplication.go +++ b/service/s3/api_op_GetBucketReplication.go @@ -58,7 +58,8 @@ type GetBucketReplicationInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketRequestPayment.go b/service/s3/api_op_GetBucketRequestPayment.go index 18166d4797d..45f985b95a5 100644 --- a/service/s3/api_op_GetBucketRequestPayment.go +++ b/service/s3/api_op_GetBucketRequestPayment.go @@ -43,7 +43,8 @@ type GetBucketRequestPaymentInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketTagging.go b/service/s3/api_op_GetBucketTagging.go index 707284408d8..816d1b3e7b7 100644 --- a/service/s3/api_op_GetBucketTagging.go +++ b/service/s3/api_op_GetBucketTagging.go @@ -17,16 +17,15 @@ import ( // bucket owner has this permission and can grant this permission to others. // GetBucketTagging has the following special error: // -// * Error code: -// NoSuchTagSetError +// * Error code: NoSuchTagSet // -// * Description: There is no tag set associated with the -// bucket. +// * +// Description: There is no tag set associated with the bucket. // -// The following operations are related to GetBucketTagging: +// The following +// operations are related to GetBucketTagging: // -// * -// PutBucketTagging +// * PutBucketTagging // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html) // // * @@ -55,7 +54,8 @@ type GetBucketTaggingInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketVersioning.go b/service/s3/api_op_GetBucketVersioning.go index 7de1f13b2e8..3657bd1ca4d 100644 --- a/service/s3/api_op_GetBucketVersioning.go +++ b/service/s3/api_op_GetBucketVersioning.go @@ -52,7 +52,8 @@ type GetBucketVersioningInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetBucketWebsite.go b/service/s3/api_op_GetBucketWebsite.go index 5e994e391bd..aa866b30187 100644 --- a/service/s3/api_op_GetBucketWebsite.go +++ b/service/s3/api_op_GetBucketWebsite.go @@ -51,7 +51,8 @@ type GetBucketWebsiteInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetObject.go b/service/s3/api_op_GetObject.go index d3575b259a0..92c38bed815 100644 --- a/service/s3/api_op_GetObject.go +++ b/service/s3/api_op_GetObject.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -29,10 +30,7 @@ import ( // specify the resource as /examplebucket/photos/2006/February/sample.jpg. For more // information about request types, see HTTP Host Header Bucket Specification // (https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html#VirtualHostingSpecifyBucket). -// To distribute large files to many people, you can save bandwidth costs by using -// BitTorrent. For more information, see Amazon S3 Torrent -// (https://docs.aws.amazon.com/AmazonS3/latest/dev/S3Torrent.html). For more -// information about returning the ACL of an object, see GetObjectAcl +// For more information about returning the ACL of an object, see GetObjectAcl // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html). If the // object you are retrieving is stored in the S3 Glacier or S3 Glacier Deep Archive // storage class, or S3 Intelligent-Tiering Archive or S3 Intelligent-Tiering Deep @@ -173,9 +171,9 @@ type GetObjectInput struct { // action with Amazon S3 on Outposts, you must direct requests to the S3 on // Outposts hostname. The S3 on Outposts hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -187,24 +185,28 @@ type GetObjectInput struct { // This member is required. Key *string + // To retrieve the checksum, this mode must be enabled. + ChecksumMode types.ChecksumMode + // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Return the object only if its entity tag (ETag) is the same as the one - // specified, otherwise return a 412 (precondition failed). + // specified; otherwise, return a 412 (precondition failed) error. IfMatch *string - // Return the object only if it has been modified since the specified time, - // otherwise return a 304 (not modified). + // Return the object only if it has been modified since the specified time; + // otherwise, return a 304 (not modified) error. IfModifiedSince *time.Time // Return the object only if its entity tag (ETag) is different from the one - // specified, otherwise return a 304 (not modified). + // specified; otherwise, return a 304 (not modified) error. IfNoneMatch *string - // Return the object only if it has not been modified since the specified time, - // otherwise return a 412 (precondition failed). + // Return the object only if it has not been modified since the specified time; + // otherwise, return a 412 (precondition failed) error. IfUnmodifiedSince *time.Time // Part number of the object being read. This is a positive integer between 1 and @@ -221,8 +223,8 @@ type GetObjectInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -282,6 +284,38 @@ type GetObjectOutput struct { // Specifies caching behavior along the request/reply chain. CacheControl *string + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Specifies presentational information for the object. ContentDisposition *string @@ -306,14 +340,14 @@ type GetObjectOutput struct { // Marker. If false, this response header does not appear in the response. DeleteMarker bool - // An ETag is an opaque identifier assigned by a web server to a specific version - // of a resource found at a URL. + // An entity tag (ETag) is an opaque identifier assigned by a web server to a + // specific version of a resource found at a URL. ETag *string // If the object expiration is configured (see PUT Bucket lifecycle), the response // includes this header. It includes the expiry-date and rule-id key-value pairs - // providing object expiration information. The value of the rule-id is URL - // encoded. + // providing object expiration information. The value of the rule-id is + // URL-encoded. Expiration *string // The date and time at which the object is no longer cacheable. @@ -343,7 +377,8 @@ type GetObjectOutput struct { // The date and time when this object's Object Lock will expire. ObjectLockRetainUntilDate *time.Time - // The count of parts this object has. + // The count of parts this object has. This value is only returned if you specify + // partNumber in your request and the object was uploaded as a multipart upload. PartsCount int32 // Amazon S3 can return this if your request involves a bucket that is either a @@ -451,6 +486,9 @@ func (c *Client) addOperationGetObjectMiddlewares(stack *middleware.Stack, optio if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addGetObjectOutputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addGetObjectUpdateEndpoint(stack, options); err != nil { return err } @@ -478,6 +516,26 @@ func newServiceMetadataMiddleware_opGetObject(region string) *awsmiddleware.Regi } } +// getGetObjectRequestValidationModeMember gets the request checksum validation +// mode provided as input. +func getGetObjectRequestValidationModeMember(input interface{}) (string, bool) { + in := input.(*GetObjectInput) + if len(in.ChecksumMode) == 0 { + return "", false + } + return string(in.ChecksumMode), true +} + +func addGetObjectOutputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddOutputMiddleware(stack, internalChecksum.OutputMiddlewareOptions{ + GetValidationMode: getGetObjectRequestValidationModeMember, + ValidationAlgorithms: []string{"CRC32", "CRC32C", "SHA256", "SHA1"}, + IgnoreMultipartValidation: true, + LogValidationSkipped: true, + LogMultipartValidationSkipped: true, + }) +} + // getGetObjectBucketMember returns a pointer to string denoting a provided bucket // member valueand a boolean indicating if the input has a modeled bucket name, func getGetObjectBucketMember(input interface{}) (*string, bool) { diff --git a/service/s3/api_op_GetObjectAcl.go b/service/s3/api_op_GetObjectAcl.go index ed331c4b38f..709e62ff755 100644 --- a/service/s3/api_op_GetObjectAcl.go +++ b/service/s3/api_op_GetObjectAcl.go @@ -13,14 +13,17 @@ import ( ) // Returns the access control list (ACL) of an object. To use this operation, you -// must have READ_ACP access to the object. This action is not supported by Amazon -// S3 on Outposts. Versioning By default, GET returns ACL information about the -// current version of an object. To return ACL information about a different -// version, use the versionId subresource. If your bucket uses the bucket owner -// enforced setting for S3 Object Ownership, requests to read ACLs are still -// supported and return the bucket-owner-full-control ACL with the owner being the -// account that created the bucket. For more information, see Controlling object -// ownership and disabling ACLs +// must have s3:GetObjectAcl permissions or READ_ACP access to the object. For more +// information, see Mapping of ACL permissions and access policy permissions +// (https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#acl-access-policy-permission-mapping) +// in the Amazon S3 User Guide This action is not supported by Amazon S3 on +// Outposts. Versioning By default, GET returns ACL information about the current +// version of an object. To return ACL information about a different version, use +// the versionId subresource. If your bucket uses the bucket owner enforced setting +// for S3 Object Ownership, requests to read ACLs are still supported and return +// the bucket-owner-full-control ACL with the owner being the account that created +// the bucket. For more information, see Controlling object ownership and +// disabling ACLs // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html) // in the Amazon S3 User Guide. The following operations are related to // GetObjectAcl: @@ -29,6 +32,10 @@ import ( // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) // // * +// GetObjectAttributes +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) +// +// * // DeleteObject // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html) // @@ -70,13 +77,14 @@ type GetObjectAclInput struct { Key *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_GetObjectAttributes.go b/service/s3/api_op_GetObjectAttributes.go new file mode 100644 index 00000000000..fb1683e7d2d --- /dev/null +++ b/service/s3/api_op_GetObjectAttributes.go @@ -0,0 +1,363 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package s3 + +import ( + "context" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "time" +) + +// Retrieves all the metadata from an object without returning the object itself. +// This action is useful if you're interested only in an object's metadata. To use +// GetObjectAttributes, you must have READ access to the object. +// GetObjectAttributes combines the functionality of GetObjectAcl, +// GetObjectLegalHold, GetObjectLockConfiguration, GetObjectRetention, +// GetObjectTagging, HeadObject, and ListParts. All of the data returned with each +// of those individual calls can be returned with a single call to +// GetObjectAttributes. If you encrypt an object by using server-side encryption +// with customer-provided encryption keys (SSE-C) when you store the object in +// Amazon S3, then when you retrieve the metadata from the object, you must use the +// following headers: +// +// * x-amz-server-side-encryption-customer-algorithm +// +// * +// x-amz-server-side-encryption-customer-key +// +// * +// x-amz-server-side-encryption-customer-key-MD5 +// +// For more information about SSE-C, +// see Server-Side Encryption (Using Customer-Provided Encryption Keys) +// (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) +// in the Amazon S3 User Guide. +// +// * Encryption request headers, such as +// x-amz-server-side-encryption, should not be sent for GET requests if your object +// uses server-side encryption with Amazon Web Services KMS keys stored in Amazon +// Web Services Key Management Service (SSE-KMS) or server-side encryption with +// Amazon S3 managed encryption keys (SSE-S3). If your object does use these types +// of keys, you'll get an HTTP 400 Bad Request error. +// +// * The last modified property +// in this case is the creation date of the object. +// +// Consider the following when +// using request headers: +// +// * If both of the If-Match and If-Unmodified-Since +// headers are present in the request as follows, then Amazon S3 returns the HTTP +// status code 200 OK and the data requested: +// +// * If-Match condition evaluates to +// true. +// +// * If-Unmodified-Since condition evaluates to false. +// +// * If both of the +// If-None-Match and If-Modified-Since headers are present in the request as +// follows, then Amazon S3 returns the HTTP status code 304 Not Modified: +// +// * +// If-None-Match condition evaluates to false. +// +// * If-Modified-Since condition +// evaluates to true. +// +// For more information about conditional requests, see RFC +// 7232 (https://tools.ietf.org/html/rfc7232). Permissions The permissions that you +// need to use this operation depend on whether the bucket is versioned. If the +// bucket is versioned, you need both the s3:GetObjectVersion and +// s3:GetObjectVersionAttributes permissions for this operation. If the bucket is +// not versioned, you need the s3:GetObject and s3:GetObjectAttributes permissions. +// For more information, see Specifying Permissions in a Policy +// (https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html) in +// the Amazon S3 User Guide. If the object that you request does not exist, the +// error Amazon S3 returns depends on whether you also have the s3:ListBucket +// permission. +// +// * If you have the s3:ListBucket permission on the bucket, Amazon S3 +// returns an HTTP status code 404 Not Found ("no such key") error. +// +// * If you don't +// have the s3:ListBucket permission, Amazon S3 returns an HTTP status code 403 +// Forbidden ("access denied") error. +// +// The following actions are related to +// GetObjectAttributes: +// +// * GetObject +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) +// +// * +// GetObjectAcl +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html) +// +// * +// GetObjectLegalHold +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLegalHold.html) +// +// * +// GetObjectLockConfiguration +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLockConfiguration.html) +// +// * +// GetObjectRetention +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectRetention.html) +// +// * +// GetObjectTagging +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html) +// +// * +// HeadObject +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html) +// +// * +// ListParts (https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html) +func (c *Client) GetObjectAttributes(ctx context.Context, params *GetObjectAttributesInput, optFns ...func(*Options)) (*GetObjectAttributesOutput, error) { + if params == nil { + params = &GetObjectAttributesInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "GetObjectAttributes", params, optFns, c.addOperationGetObjectAttributesMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*GetObjectAttributesOutput) + out.ResultMetadata = metadata + return out, nil +} + +type GetObjectAttributesInput struct { + + // The name of the bucket that contains the object. When using this action with an + // access point, you must direct requests to the access point hostname. The access + // point hostname takes the form + // AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this + // action with an access point through the Amazon Web Services SDKs, you provide + // the access point ARN in place of the bucket name. For more information about + // access point ARNs, see Using access points + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html) + // in the Amazon S3 User Guide. When using this action with Amazon S3 on Outposts, + // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts + // hostname takes the form + // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using + // this action with S3 on Outposts through the Amazon Web Services SDKs, you + // provide the Outposts bucket ARN in place of the bucket name. For more + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the + // Amazon S3 User Guide. + // + // This member is required. + Bucket *string + + // The object key. + // + // This member is required. + Key *string + + // An XML header that specifies the fields at the root level that you want returned + // in the response. Fields that you do not specify are not returned. + // + // This member is required. + ObjectAttributes []types.ObjectAttributes + + // The account ID of the expected bucket owner. If the bucket is owned by a + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). + ExpectedBucketOwner *string + + // Sets the maximum number of parts to return. + MaxParts int32 + + // Specifies the part after which listing should begin. Only parts with higher part + // numbers will be listed. + PartNumberMarker *string + + // Confirms that the requester knows that they will be charged for the request. + // Bucket owners need not specify this parameter in their requests. For information + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) + // in the Amazon S3 User Guide. + RequestPayer types.RequestPayer + + // Specifies the algorithm to use when encrypting the object (for example, AES256). + SSECustomerAlgorithm *string + + // Specifies the customer-provided encryption key for Amazon S3 to use in + // encrypting data. This value is used to store the object and then it is + // discarded; Amazon S3 does not store the encryption key. The key must be + // appropriate for use with the algorithm specified in the + // x-amz-server-side-encryption-customer-algorithm header. + SSECustomerKey *string + + // Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. + // Amazon S3 uses this header for a message integrity check to ensure that the + // encryption key was transmitted without error. + SSECustomerKeyMD5 *string + + // The version ID used to reference a specific version of the object. + VersionId *string + + noSmithyDocumentSerde +} + +type GetObjectAttributesOutput struct { + + // The checksum or digest of the object. + Checksum *types.Checksum + + // Specifies whether the object retrieved was (true) or was not (false) a delete + // marker. If false, this response header does not appear in the response. + DeleteMarker bool + + // An ETag is an opaque identifier assigned by a web server to a specific version + // of a resource found at a URL. + ETag *string + + // The creation date of the object. + LastModified *time.Time + + // A collection of parts associated with a multipart upload. + ObjectParts *types.GetObjectAttributesParts + + // The size of the object in bytes. + ObjectSize int64 + + // If present, indicates that the requester was successfully charged for the + // request. + RequestCharged types.RequestCharged + + // Provides the storage class information of the object. Amazon S3 returns this + // header for all objects except for S3 Standard storage class objects. For more + // information, see Storage Classes + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html). + StorageClass types.StorageClass + + // The version ID of the object. + VersionId *string + + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata + + noSmithyDocumentSerde +} + +func (c *Client) addOperationGetObjectAttributesMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestxml_serializeOpGetObjectAttributes{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpGetObjectAttributes{}, middleware.After) + if err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = addHTTPSignerV4Middleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { + return err + } + if err = addOpGetObjectAttributesValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opGetObjectAttributes(options.Region), middleware.Before); err != nil { + return err + } + if err = addMetadataRetrieverMiddleware(stack); err != nil { + return err + } + if err = addGetObjectAttributesUpdateEndpoint(stack, options); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = v4.AddContentSHA256HeaderMiddleware(stack); err != nil { + return err + } + if err = disableAcceptEncodingGzip(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + return nil +} + +func newServiceMetadataMiddleware_opGetObjectAttributes(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + SigningName: "s3", + OperationName: "GetObjectAttributes", + } +} + +// getGetObjectAttributesBucketMember returns a pointer to string denoting a +// provided bucket member valueand a boolean indicating if the input has a modeled +// bucket name, +func getGetObjectAttributesBucketMember(input interface{}) (*string, bool) { + in := input.(*GetObjectAttributesInput) + if in.Bucket == nil { + return nil, false + } + return in.Bucket, true +} +func addGetObjectAttributesUpdateEndpoint(stack *middleware.Stack, options Options) error { + return s3cust.UpdateEndpoint(stack, s3cust.UpdateEndpointOptions{ + Accessor: s3cust.UpdateEndpointParameterAccessor{ + GetBucketFromInput: getGetObjectAttributesBucketMember, + }, + UsePathStyle: options.UsePathStyle, + UseAccelerate: options.UseAccelerate, + SupportsAccelerate: true, + TargetS3ObjectLambda: false, + EndpointResolver: options.EndpointResolver, + EndpointResolverOptions: options.EndpointOptions, + UseARNRegion: options.UseARNRegion, + DisableMultiRegionAccessPoints: options.DisableMultiRegionAccessPoints, + }) +} diff --git a/service/s3/api_op_GetObjectLegalHold.go b/service/s3/api_op_GetObjectLegalHold.go index 75a6cfb2953..a2446ac32c9 100644 --- a/service/s3/api_op_GetObjectLegalHold.go +++ b/service/s3/api_op_GetObjectLegalHold.go @@ -12,9 +12,13 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// Gets an object's current Legal Hold status. For more information, see Locking +// Gets an object's current legal hold status. For more information, see Locking // Objects (https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html). This -// action is not supported by Amazon S3 on Outposts. +// action is not supported by Amazon S3 on Outposts. The following action is +// related to GetObjectLegalHold: +// +// * GetObjectAttributes +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) func (c *Client) GetObjectLegalHold(ctx context.Context, params *GetObjectLegalHoldInput, optFns ...func(*Options)) (*GetObjectLegalHoldOutput, error) { if params == nil { params = &GetObjectLegalHoldInput{} @@ -32,7 +36,7 @@ func (c *Client) GetObjectLegalHold(ctx context.Context, params *GetObjectLegalH type GetObjectLegalHoldInput struct { - // The bucket name containing the object whose Legal Hold status you want to + // The bucket name containing the object whose legal hold status you want to // retrieve. When using this action with an access point, you must direct requests // to the access point hostname. The access point hostname takes the form // AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this @@ -45,24 +49,25 @@ type GetObjectLegalHoldInput struct { // This member is required. Bucket *string - // The key name for the object whose Legal Hold status you want to retrieve. + // The key name for the object whose legal hold status you want to retrieve. // // This member is required. Key *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer - // The version ID of the object whose Legal Hold status you want to retrieve. + // The version ID of the object whose legal hold status you want to retrieve. VersionId *string noSmithyDocumentSerde @@ -70,7 +75,7 @@ type GetObjectLegalHoldInput struct { type GetObjectLegalHoldOutput struct { - // The current Legal Hold status for the specified object. + // The current legal hold status for the specified object. LegalHold *types.ObjectLockLegalHold // Metadata pertaining to the operation's result. diff --git a/service/s3/api_op_GetObjectLockConfiguration.go b/service/s3/api_op_GetObjectLockConfiguration.go index 34f4a62a706..91793c13385 100644 --- a/service/s3/api_op_GetObjectLockConfiguration.go +++ b/service/s3/api_op_GetObjectLockConfiguration.go @@ -15,7 +15,12 @@ import ( // Gets the Object Lock configuration for a bucket. The rule specified in the // Object Lock configuration will be applied by default to every new object placed // in the specified bucket. For more information, see Locking Objects -// (https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html). +// (https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html). The +// following action is related to GetObjectLockConfiguration: +// +// * +// GetObjectAttributes +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) func (c *Client) GetObjectLockConfiguration(ctx context.Context, params *GetObjectLockConfigurationInput, optFns ...func(*Options)) (*GetObjectLockConfigurationOutput, error) { if params == nil { params = &GetObjectLockConfigurationInput{} @@ -47,7 +52,8 @@ type GetObjectLockConfigurationInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_GetObjectRetention.go b/service/s3/api_op_GetObjectRetention.go index 7c23c795edf..33fc04897a3 100644 --- a/service/s3/api_op_GetObjectRetention.go +++ b/service/s3/api_op_GetObjectRetention.go @@ -14,7 +14,11 @@ import ( // Retrieves an object's retention settings. For more information, see Locking // Objects (https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html). This -// action is not supported by Amazon S3 on Outposts. +// action is not supported by Amazon S3 on Outposts. The following action is +// related to GetObjectRetention: +// +// * GetObjectAttributes +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) func (c *Client) GetObjectRetention(ctx context.Context, params *GetObjectRetentionInput, optFns ...func(*Options)) (*GetObjectRetentionOutput, error) { if params == nil { params = &GetObjectRetentionInput{} @@ -51,13 +55,14 @@ type GetObjectRetentionInput struct { Key *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_GetObjectTagging.go b/service/s3/api_op_GetObjectTagging.go index bad76369356..cec5210c243 100644 --- a/service/s3/api_op_GetObjectTagging.go +++ b/service/s3/api_op_GetObjectTagging.go @@ -22,14 +22,18 @@ import ( // permission and can grant this permission to others. For information about the // Amazon S3 object tagging feature, see Object Tagging // (https://docs.aws.amazon.com/AmazonS3/latest/dev/object-tagging.html). The -// following action is related to GetObjectTagging: +// following actions are related to GetObjectTagging: // -// * PutObjectTagging -// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html) +// * DeleteObjectTagging +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html) // // * -// DeleteObjectTagging -// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html) +// GetObjectAttributes +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) +// +// * +// PutObjectTagging +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html) func (c *Client) GetObjectTagging(ctx context.Context, params *GetObjectTaggingInput, optFns ...func(*Options)) (*GetObjectTaggingOutput, error) { if params == nil { params = &GetObjectTaggingInput{} @@ -59,9 +63,9 @@ type GetObjectTaggingInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -74,13 +78,14 @@ type GetObjectTaggingInput struct { Key *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_GetObjectTorrent.go b/service/s3/api_op_GetObjectTorrent.go index a8c7cdd495e..fa71442c286 100644 --- a/service/s3/api_op_GetObjectTorrent.go +++ b/service/s3/api_op_GetObjectTorrent.go @@ -53,13 +53,14 @@ type GetObjectTorrentInput struct { Key *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_GetPublicAccessBlock.go b/service/s3/api_op_GetPublicAccessBlock.go index 16b957aa5ae..eb42c7d275a 100644 --- a/service/s3/api_op_GetPublicAccessBlock.go +++ b/service/s3/api_op_GetPublicAccessBlock.go @@ -66,7 +66,8 @@ type GetPublicAccessBlockInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_HeadBucket.go b/service/s3/api_op_HeadBucket.go index 1623e3452f4..7344f202e0b 100644 --- a/service/s3/api_op_HeadBucket.go +++ b/service/s3/api_op_HeadBucket.go @@ -66,9 +66,9 @@ type HeadBucketInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -76,7 +76,8 @@ type HeadBucketInput struct { Bucket *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_HeadObject.go b/service/s3/api_op_HeadObject.go index 76e81e240a4..1e745a7e5ce 100644 --- a/service/s3/api_op_HeadObject.go +++ b/service/s3/api_op_HeadObject.go @@ -97,10 +97,14 @@ import ( // Amazon S3 returns an HTTP status code 403 ("access denied") error. // // The -// following action is related to HeadObject: +// following actions are related to HeadObject: // // * GetObject // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) +// +// * +// GetObjectAttributes +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) func (c *Client) HeadObject(ctx context.Context, params *HeadObjectInput, optFns ...func(*Options)) (*HeadObjectOutput, error) { if params == nil { params = &HeadObjectInput{} @@ -130,9 +134,9 @@ type HeadObjectInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -144,24 +148,31 @@ type HeadObjectInput struct { // This member is required. Key *string + // To retrieve the checksum, this parameter must be enabled. In addition, if you + // enable ChecksumMode and the object is encrypted with Amazon Web Services Key + // Management Service (Amazon Web Services KMS), you must have permission to use + // the kms:Decrypt action for the request to succeed. + ChecksumMode types.ChecksumMode + // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Return the object only if its entity tag (ETag) is the same as the one - // specified, otherwise return a 412 (precondition failed). + // specified; otherwise, return a 412 (precondition failed) error. IfMatch *string - // Return the object only if it has been modified since the specified time, - // otherwise return a 304 (not modified). + // Return the object only if it has been modified since the specified time; + // otherwise, return a 304 (not modified) error. IfModifiedSince *time.Time // Return the object only if its entity tag (ETag) is different from the one - // specified, otherwise return a 304 (not modified). + // specified; otherwise, return a 304 (not modified) error. IfNoneMatch *string - // Return the object only if it has not been modified since the specified time, - // otherwise return a 412 (precondition failed). + // Return the object only if it has not been modified since the specified time; + // otherwise, return a 412 (precondition failed) error. IfUnmodifiedSince *time.Time // Part number of the object being read. This is a positive integer between 1 and @@ -176,8 +187,8 @@ type HeadObjectInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -219,6 +230,38 @@ type HeadObjectOutput struct { // Specifies caching behavior along the request/reply chain. CacheControl *string + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Specifies presentational information for the object. ContentDisposition *string @@ -240,14 +283,14 @@ type HeadObjectOutput struct { // Marker. If false, this response header does not appear in the response. DeleteMarker bool - // An ETag is an opaque identifier assigned by a web server to a specific version - // of a resource found at a URL. + // An entity tag (ETag) is an opaque identifier assigned by a web server to a + // specific version of a resource found at a URL. ETag *string // If the object expiration is configured (see PUT Bucket lifecycle), the response // includes this header. It includes the expiry-date and rule-id key-value pairs - // providing object expiration information. The value of the rule-id is URL - // encoded. + // providing object expiration information. The value of the rule-id is + // URL-encoded. Expiration *string // The date and time at which the object is no longer cacheable. @@ -284,7 +327,8 @@ type HeadObjectOutput struct { // only returned if the requester has the s3:GetObjectRetention permission. ObjectLockRetainUntilDate *time.Time - // The count of parts this object has. + // The count of parts this object has. This value is only returned if you specify + // partNumber in your request and the object was uploaded as a multipart upload. PartsCount int32 // Amazon S3 can return this header if your request involves a bucket that is @@ -295,7 +339,7 @@ type HeadObjectOutput struct { // return the x-amz-replication-status header in the response as follows: // // * If - // requesting an object from the source bucket — Amazon S3 will return the + // requesting an object from the source bucket, Amazon S3 will return the // x-amz-replication-status header if the object in your request is eligible for // replication. For example, suppose that in your replication configuration, you // specify object prefix TaxDocs requesting Amazon S3 to replicate objects with key @@ -305,13 +349,13 @@ type HeadObjectOutput struct { // with value PENDING, COMPLETED or FAILED indicating object replication status. // // * - // If requesting an object from a destination bucket — Amazon S3 will return the + // If requesting an object from a destination bucket, Amazon S3 will return the // x-amz-replication-status header with value REPLICA if the object in your request // is a replica that Amazon S3 created and there is no replica modification // replication in progress. // // * When replicating objects to multiple destination - // buckets the x-amz-replication-status header acts differently. The header of the + // buckets, the x-amz-replication-status header acts differently. The header of the // source object will only return a value of COMPLETED when replication is // successful to all destinations. The header will remain at value PENDING until // replication has completed for all destinations. If one or more destinations diff --git a/service/s3/api_op_ListBucketAnalyticsConfigurations.go b/service/s3/api_op_ListBucketAnalyticsConfigurations.go index e2b24a91d32..0a0373f2904 100644 --- a/service/s3/api_op_ListBucketAnalyticsConfigurations.go +++ b/service/s3/api_op_ListBucketAnalyticsConfigurations.go @@ -71,7 +71,8 @@ type ListBucketAnalyticsConfigurationsInput struct { ContinuationToken *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_ListBucketInventoryConfigurations.go b/service/s3/api_op_ListBucketInventoryConfigurations.go index 8dc32152f11..e6c8c79a84a 100644 --- a/service/s3/api_op_ListBucketInventoryConfigurations.go +++ b/service/s3/api_op_ListBucketInventoryConfigurations.go @@ -72,7 +72,8 @@ type ListBucketInventoryConfigurationsInput struct { ContinuationToken *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_ListBucketMetricsConfigurations.go b/service/s3/api_op_ListBucketMetricsConfigurations.go index fdd73096d3b..50b207af615 100644 --- a/service/s3/api_op_ListBucketMetricsConfigurations.go +++ b/service/s3/api_op_ListBucketMetricsConfigurations.go @@ -74,7 +74,8 @@ type ListBucketMetricsConfigurationsInput struct { ContinuationToken *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_ListBuckets.go b/service/s3/api_op_ListBuckets.go index 54abd9fddc9..7a3de38f428 100644 --- a/service/s3/api_op_ListBuckets.go +++ b/service/s3/api_op_ListBuckets.go @@ -13,6 +13,7 @@ import ( ) // Returns a list of all buckets owned by the authenticated sender of the request. +// To use this operation, you must have the s3:ListAllMyBuckets permission. func (c *Client) ListBuckets(ctx context.Context, params *ListBucketsInput, optFns ...func(*Options)) (*ListBucketsOutput, error) { if params == nil { params = &ListBucketsInput{} @@ -34,7 +35,7 @@ type ListBucketsInput struct { type ListBucketsOutput struct { - // The list of buckets owned by the requestor. + // The list of buckets owned by the requester. Buckets []types.Bucket // The owner of the buckets listed. diff --git a/service/s3/api_op_ListMultipartUploads.go b/service/s3/api_op_ListMultipartUploads.go index 9fff7280cd6..af281a25287 100644 --- a/service/s3/api_op_ListMultipartUploads.go +++ b/service/s3/api_op_ListMultipartUploads.go @@ -81,9 +81,9 @@ type ListMultipartUploadsInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -107,7 +107,8 @@ type ListMultipartUploadsInput struct { EncodingType types.EncodingType // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Together with upload-id-marker, this parameter specifies the multipart upload diff --git a/service/s3/api_op_ListObjectVersions.go b/service/s3/api_op_ListObjectVersions.go index 0013ad01bbe..f2d2b9fa951 100644 --- a/service/s3/api_op_ListObjectVersions.go +++ b/service/s3/api_op_ListObjectVersions.go @@ -74,7 +74,8 @@ type ListObjectVersionsInput struct { EncodingType types.EncodingType // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Specifies the key to start with when listing objects in a bucket. diff --git a/service/s3/api_op_ListObjects.go b/service/s3/api_op_ListObjects.go index 37a467ea838..b2d83ff7468 100644 --- a/service/s3/api_op_ListObjects.go +++ b/service/s3/api_op_ListObjects.go @@ -70,9 +70,9 @@ type ListObjectsInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -91,7 +91,8 @@ type ListObjectsInput struct { EncodingType types.EncodingType // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Marker is where you want Amazon S3 to start listing from. Amazon S3 starts diff --git a/service/s3/api_op_ListObjectsV2.go b/service/s3/api_op_ListObjectsV2.go index 6fcb7e35b0e..6214d24716f 100644 --- a/service/s3/api_op_ListObjectsV2.go +++ b/service/s3/api_op_ListObjectsV2.go @@ -76,9 +76,9 @@ type ListObjectsV2Input struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -96,7 +96,8 @@ type ListObjectsV2Input struct { EncodingType types.EncodingType // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The owner field is not present in listV2 by default, if you want to return owner @@ -181,9 +182,9 @@ type ListObjectsV2Output struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. Name *string diff --git a/service/s3/api_op_ListParts.go b/service/s3/api_op_ListParts.go index f907683acd3..36675dcd74c 100644 --- a/service/s3/api_op_ListParts.go +++ b/service/s3/api_op_ListParts.go @@ -24,8 +24,10 @@ import ( // more than 1,000 parts, the response returns an IsTruncated field with the value // of true, and a NextPartNumberMarker element. In subsequent ListParts requests // you can include the part-number-marker query string parameter and set its value -// to the NextPartNumberMarker field value from the previous response. For more -// information on multipart uploads, see Uploading Objects Using Multipart Upload +// to the NextPartNumberMarker field value from the previous response. If the +// upload was created using a checksum algorithm, you will need to have permission +// to the kms:Decrypt action for the request to succeed. For more information on +// multipart uploads, see Uploading Objects Using Multipart Upload // (https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html). For // information on permissions required to use the multipart upload API, see // Multipart Upload and Permissions @@ -48,6 +50,10 @@ import ( // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html) // // * +// GetObjectAttributes +// (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) +// +// * // ListMultipartUploads // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html) func (c *Client) ListParts(ctx context.Context, params *ListPartsInput, optFns ...func(*Options)) (*ListPartsOutput, error) { @@ -79,9 +85,9 @@ type ListPartsInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -99,7 +105,8 @@ type ListPartsInput struct { UploadId *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Sets the maximum number of parts to return. @@ -111,12 +118,33 @@ type ListPartsInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer + // The server-side encryption (SSE) algorithm used to encrypt the object. This + // parameter is needed only when the object was created using a checksum algorithm. + // For more information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. + SSECustomerAlgorithm *string + + // The server-side encryption (SSE) customer managed key. This parameter is needed + // only when the object was created using a checksum algorithm. For more + // information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. + SSECustomerKey *string + + // The MD5 server-side encryption (SSE) customer managed key. This parameter is + // needed only when the object was created using a checksum algorithm. For more + // information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. + SSECustomerKeyMD5 *string + noSmithyDocumentSerde } @@ -142,6 +170,9 @@ type ListPartsOutput struct { // return the access point ARN or access point alias if used. Bucket *string + // The algorithm that was used to create a checksum of the object. + ChecksumAlgorithm types.ChecksumAlgorithm + // Container element that identifies who initiated the multipart upload. If the // initiator is an Amazon Web Services account, this element provides the same // information as the Owner element. If the initiator is an IAM User, this element diff --git a/service/s3/api_op_PutBucketAccelerateConfiguration.go b/service/s3/api_op_PutBucketAccelerateConfiguration.go index d8da696598c..7875798f255 100644 --- a/service/s3/api_op_PutBucketAccelerateConfiguration.go +++ b/service/s3/api_op_PutBucketAccelerateConfiguration.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -76,8 +77,20 @@ type PutBucketAccelerateConfigurationInput struct { // This member is required. Bucket *string + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -147,6 +160,9 @@ func (c *Client) addOperationPutBucketAccelerateConfigurationMiddlewares(stack * if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketAccelerateConfigurationInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketAccelerateConfigurationUpdateEndpoint(stack, options); err != nil { return err } @@ -174,6 +190,26 @@ func newServiceMetadataMiddleware_opPutBucketAccelerateConfiguration(region stri } } +// getPutBucketAccelerateConfigurationRequestAlgorithmMember gets the request +// checksum algorithm value provided as input. +func getPutBucketAccelerateConfigurationRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketAccelerateConfigurationInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketAccelerateConfigurationInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketAccelerateConfigurationRequestAlgorithmMember, + RequireChecksum: false, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketAccelerateConfigurationBucketMember returns a pointer to string // denoting a provided bucket member valueand a boolean indicating if the input has // a modeled bucket name, diff --git a/service/s3/api_op_PutBucketAcl.go b/service/s3/api_op_PutBucketAcl.go index 9f80ccc4836..0f669d2acbb 100644 --- a/service/s3/api_op_PutBucketAcl.go +++ b/service/s3/api_op_PutBucketAcl.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -181,6 +182,17 @@ type PutBucketAclInput struct { // Contains the elements that set the ACL permissions for an object per grantee. AccessControlPolicy *types.AccessControlPolicy + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the data. This header must be used as a // message integrity check to verify that the request body was not corrupted in // transit. For more information, go to RFC 1864. @@ -190,7 +202,8 @@ type PutBucketAclInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Allows grantee the read, write, read ACP, and write ACP permissions on the @@ -269,9 +282,6 @@ func (c *Client) addOperationPutBucketAclMiddlewares(stack *middleware.Stack, op if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketAclValidationMiddleware(stack); err != nil { return err } @@ -281,6 +291,9 @@ func (c *Client) addOperationPutBucketAclMiddlewares(stack *middleware.Stack, op if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketAclInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketAclUpdateEndpoint(stack, options); err != nil { return err } @@ -308,6 +321,26 @@ func newServiceMetadataMiddleware_opPutBucketAcl(region string) *awsmiddleware.R } } +// getPutBucketAclRequestAlgorithmMember gets the request checksum algorithm value +// provided as input. +func getPutBucketAclRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketAclInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketAclInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketAclRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketAclBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutBucketAnalyticsConfiguration.go b/service/s3/api_op_PutBucketAnalyticsConfiguration.go index dc78a41ac06..45cec74ed1e 100644 --- a/service/s3/api_op_PutBucketAnalyticsConfiguration.go +++ b/service/s3/api_op_PutBucketAnalyticsConfiguration.go @@ -109,7 +109,8 @@ type PutBucketAnalyticsConfigurationInput struct { Id *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_PutBucketCors.go b/service/s3/api_op_PutBucketCors.go index 038d9799dc7..55a67f18826 100644 --- a/service/s3/api_op_PutBucketCors.go +++ b/service/s3/api_op_PutBucketCors.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -84,6 +85,17 @@ type PutBucketCorsInput struct { // This member is required. CORSConfiguration *types.CORSConfiguration + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the data. This header must be used as a // message integrity check to verify that the request body was not corrupted in // transit. For more information, go to RFC 1864. @@ -93,7 +105,8 @@ type PutBucketCorsInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -154,9 +167,6 @@ func (c *Client) addOperationPutBucketCorsMiddlewares(stack *middleware.Stack, o if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketCorsValidationMiddleware(stack); err != nil { return err } @@ -166,6 +176,9 @@ func (c *Client) addOperationPutBucketCorsMiddlewares(stack *middleware.Stack, o if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketCorsInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketCorsUpdateEndpoint(stack, options); err != nil { return err } @@ -193,6 +206,26 @@ func newServiceMetadataMiddleware_opPutBucketCors(region string) *awsmiddleware. } } +// getPutBucketCorsRequestAlgorithmMember gets the request checksum algorithm value +// provided as input. +func getPutBucketCorsRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketCorsInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketCorsInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketCorsRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketCorsBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutBucketEncryption.go b/service/s3/api_op_PutBucketEncryption.go index 7e6006b2e54..184f0cd3118 100644 --- a/service/s3/api_op_PutBucketEncryption.go +++ b/service/s3/api_op_PutBucketEncryption.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -16,8 +17,11 @@ import ( // Amazon S3 Bucket Key for an existing bucket. Default encryption for a bucket can // use server-side encryption with Amazon S3-managed keys (SSE-S3) or customer // managed keys (SSE-KMS). If you specify default encryption using SSE-KMS, you can -// also configure Amazon S3 Bucket Key. For information about default encryption, -// see Amazon S3 default bucket encryption +// also configure Amazon S3 Bucket Key. When the default encryption is SSE-KMS, if +// you upload an object to the bucket and do not specify the KMS key to use for +// encryption, Amazon S3 uses the default Amazon Web Services managed KMS key for +// your account. For information about default encryption, see Amazon S3 default +// bucket encryption // (https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html) in the // Amazon S3 User Guide. For more information about S3 Bucket Keys, see Amazon S3 // Bucket Keys (https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html) in @@ -73,6 +77,17 @@ type PutBucketEncryptionInput struct { // This member is required. ServerSideEncryptionConfiguration *types.ServerSideEncryptionConfiguration + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the server-side encryption // configuration. For requests made using the Amazon Web Services Command Line // Interface (CLI) or Amazon Web Services SDKs, this field is calculated @@ -80,7 +95,8 @@ type PutBucketEncryptionInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -141,9 +157,6 @@ func (c *Client) addOperationPutBucketEncryptionMiddlewares(stack *middleware.St if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketEncryptionValidationMiddleware(stack); err != nil { return err } @@ -153,6 +166,9 @@ func (c *Client) addOperationPutBucketEncryptionMiddlewares(stack *middleware.St if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketEncryptionInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketEncryptionUpdateEndpoint(stack, options); err != nil { return err } @@ -180,6 +196,26 @@ func newServiceMetadataMiddleware_opPutBucketEncryption(region string) *awsmiddl } } +// getPutBucketEncryptionRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutBucketEncryptionRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketEncryptionInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketEncryptionInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketEncryptionRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketEncryptionBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutBucketInventoryConfiguration.go b/service/s3/api_op_PutBucketInventoryConfiguration.go index 239235c4b5d..afca60b9d10 100644 --- a/service/s3/api_op_PutBucketInventoryConfiguration.go +++ b/service/s3/api_op_PutBucketInventoryConfiguration.go @@ -110,7 +110,8 @@ type PutBucketInventoryConfigurationInput struct { InventoryConfiguration *types.InventoryConfiguration // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_PutBucketLifecycleConfiguration.go b/service/s3/api_op_PutBucketLifecycleConfiguration.go index 13c5955f40a..414600dcdfe 100644 --- a/service/s3/api_op_PutBucketLifecycleConfiguration.go +++ b/service/s3/api_op_PutBucketLifecycleConfiguration.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -13,8 +14,10 @@ import ( ) // Creates a new lifecycle configuration for the bucket or replaces an existing -// lifecycle configuration. For information about lifecycle configuration, see -// Managing your storage lifecycle +// lifecycle configuration. Keep in mind that this will overwrite an existing +// lifecycle configuration, so if you want to retain any configuration details, +// they must be included in the new lifecycle configuration. For information about +// lifecycle configuration, see Managing your storage lifecycle // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html). // Bucket lifecycle configuration now supports specifying a lifecycle rule using an // object key name prefix, one or more object tags, or a combination of both. @@ -101,8 +104,20 @@ type PutBucketLifecycleConfigurationInput struct { // This member is required. Bucket *string + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Container for lifecycle rules. You can add as many as 1,000 rules. @@ -166,9 +181,6 @@ func (c *Client) addOperationPutBucketLifecycleConfigurationMiddlewares(stack *m if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketLifecycleConfigurationValidationMiddleware(stack); err != nil { return err } @@ -178,6 +190,9 @@ func (c *Client) addOperationPutBucketLifecycleConfigurationMiddlewares(stack *m if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketLifecycleConfigurationInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketLifecycleConfigurationUpdateEndpoint(stack, options); err != nil { return err } @@ -205,6 +220,26 @@ func newServiceMetadataMiddleware_opPutBucketLifecycleConfiguration(region strin } } +// getPutBucketLifecycleConfigurationRequestAlgorithmMember gets the request +// checksum algorithm value provided as input. +func getPutBucketLifecycleConfigurationRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketLifecycleConfigurationInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketLifecycleConfigurationInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketLifecycleConfigurationRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketLifecycleConfigurationBucketMember returns a pointer to string // denoting a provided bucket member valueand a boolean indicating if the input has // a modeled bucket name, diff --git a/service/s3/api_op_PutBucketLogging.go b/service/s3/api_op_PutBucketLogging.go index fab276d1f7a..0f3ea6d33c2 100644 --- a/service/s3/api_op_PutBucketLogging.go +++ b/service/s3/api_op_PutBucketLogging.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -92,13 +93,25 @@ type PutBucketLoggingInput struct { // This member is required. BucketLoggingStatus *types.BucketLoggingStatus + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The MD5 hash of the PutBucketLogging request body. For requests made using the // Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, // this field is calculated automatically. ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -159,9 +172,6 @@ func (c *Client) addOperationPutBucketLoggingMiddlewares(stack *middleware.Stack if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketLoggingValidationMiddleware(stack); err != nil { return err } @@ -171,6 +181,9 @@ func (c *Client) addOperationPutBucketLoggingMiddlewares(stack *middleware.Stack if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketLoggingInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketLoggingUpdateEndpoint(stack, options); err != nil { return err } @@ -198,6 +211,26 @@ func newServiceMetadataMiddleware_opPutBucketLogging(region string) *awsmiddlewa } } +// getPutBucketLoggingRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutBucketLoggingRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketLoggingInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketLoggingInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketLoggingRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketLoggingBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutBucketMetricsConfiguration.go b/service/s3/api_op_PutBucketMetricsConfiguration.go index d42a6dfdf5b..6f0c6facd5e 100644 --- a/service/s3/api_op_PutBucketMetricsConfiguration.go +++ b/service/s3/api_op_PutBucketMetricsConfiguration.go @@ -84,7 +84,8 @@ type PutBucketMetricsConfigurationInput struct { MetricsConfiguration *types.MetricsConfiguration // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde diff --git a/service/s3/api_op_PutBucketNotificationConfiguration.go b/service/s3/api_op_PutBucketNotificationConfiguration.go index bd9bc06f343..8e771d6bc95 100644 --- a/service/s3/api_op_PutBucketNotificationConfiguration.go +++ b/service/s3/api_op_PutBucketNotificationConfiguration.go @@ -31,18 +31,22 @@ import ( // more information, see Configuring Notifications for Amazon S3 Events // (https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html). You // can disable notifications by adding the empty NotificationConfiguration element. -// By default, only the bucket owner can configure notifications on a bucket. -// However, bucket owners can use a bucket policy to grant permission to other -// users to set this configuration with s3:PutBucketNotification permission. The -// PUT notification is an atomic operation. For example, suppose your notification -// configuration includes SNS topic, SQS queue, and Lambda function configurations. -// When you send a PUT request with this configuration, Amazon S3 sends test -// messages to your SNS topic. If the message fails, the entire PUT action will -// fail, and Amazon S3 will not add the configuration to your bucket. Responses If -// the configuration in the request body includes only one TopicConfiguration -// specifying only the s3:ReducedRedundancyLostObject event type, the response will -// also include the x-amz-sns-test-message-id header containing the message ID of -// the test notification sent to the topic. The following action is related to +// For more information about the number of event notification configurations that +// you can create per bucket, see Amazon S3 service quotas +// (https://docs.aws.amazon.com/general/latest/gr/s3.html#limits_s3) in Amazon Web +// Services General Reference. By default, only the bucket owner can configure +// notifications on a bucket. However, bucket owners can use a bucket policy to +// grant permission to other users to set this configuration with +// s3:PutBucketNotification permission. The PUT notification is an atomic +// operation. For example, suppose your notification configuration includes SNS +// topic, SQS queue, and Lambda function configurations. When you send a PUT +// request with this configuration, Amazon S3 sends test messages to your SNS +// topic. If the message fails, the entire PUT action will fail, and Amazon S3 will +// not add the configuration to your bucket. Responses If the configuration in the +// request body includes only one TopicConfiguration specifying only the +// s3:ReducedRedundancyLostObject event type, the response will also include the +// x-amz-sns-test-message-id header containing the message ID of the test +// notification sent to the topic. The following action is related to // PutBucketNotificationConfiguration: // // * GetBucketNotificationConfiguration @@ -76,7 +80,8 @@ type PutBucketNotificationConfigurationInput struct { NotificationConfiguration *types.NotificationConfiguration // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Skips validation of Amazon SQS, Amazon SNS, and Lambda destinations. True or diff --git a/service/s3/api_op_PutBucketOwnershipControls.go b/service/s3/api_op_PutBucketOwnershipControls.go index 3d3557d138f..83210cac46b 100644 --- a/service/s3/api_op_PutBucketOwnershipControls.go +++ b/service/s3/api_op_PutBucketOwnershipControls.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -58,7 +59,8 @@ type PutBucketOwnershipControlsInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -119,9 +121,6 @@ func (c *Client) addOperationPutBucketOwnershipControlsMiddlewares(stack *middle if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketOwnershipControlsValidationMiddleware(stack); err != nil { return err } @@ -131,6 +130,9 @@ func (c *Client) addOperationPutBucketOwnershipControlsMiddlewares(stack *middle if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketOwnershipControlsInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketOwnershipControlsUpdateEndpoint(stack, options); err != nil { return err } @@ -158,6 +160,16 @@ func newServiceMetadataMiddleware_opPutBucketOwnershipControls(region string) *a } } +func addPutBucketOwnershipControlsInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: nil, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketOwnershipControlsBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutBucketPolicy.go b/service/s3/api_op_PutBucketPolicy.go index 090459944fa..8860d3b560d 100644 --- a/service/s3/api_op_PutBucketPolicy.go +++ b/service/s3/api_op_PutBucketPolicy.go @@ -6,7 +6,9 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" + "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) @@ -58,6 +60,17 @@ type PutBucketPolicyInput struct { // This member is required. Policy *string + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // Set this parameter to true to confirm that you want to remove your permissions // to change this bucket policy in the future. ConfirmRemoveSelfBucketAccess bool @@ -68,7 +81,8 @@ type PutBucketPolicyInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -129,9 +143,6 @@ func (c *Client) addOperationPutBucketPolicyMiddlewares(stack *middleware.Stack, if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketPolicyValidationMiddleware(stack); err != nil { return err } @@ -141,6 +152,9 @@ func (c *Client) addOperationPutBucketPolicyMiddlewares(stack *middleware.Stack, if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketPolicyInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketPolicyUpdateEndpoint(stack, options); err != nil { return err } @@ -168,6 +182,26 @@ func newServiceMetadataMiddleware_opPutBucketPolicy(region string) *awsmiddlewar } } +// getPutBucketPolicyRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutBucketPolicyRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketPolicyInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketPolicyInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketPolicyRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketPolicyBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutBucketReplication.go b/service/s3/api_op_PutBucketReplication.go index 691c08aa3aa..2213373f30b 100644 --- a/service/s3/api_op_PutBucketReplication.go +++ b/service/s3/api_op_PutBucketReplication.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -92,6 +93,17 @@ type PutBucketReplicationInput struct { // This member is required. ReplicationConfiguration *types.ReplicationConfiguration + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the data. You must use this header as a // message integrity check to verify that the request body was not corrupted in // transit. For more information, see RFC 1864 @@ -101,7 +113,8 @@ type PutBucketReplicationInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // A token to allow Object Lock to be enabled for an existing bucket. @@ -165,9 +178,6 @@ func (c *Client) addOperationPutBucketReplicationMiddlewares(stack *middleware.S if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketReplicationValidationMiddleware(stack); err != nil { return err } @@ -177,6 +187,9 @@ func (c *Client) addOperationPutBucketReplicationMiddlewares(stack *middleware.S if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketReplicationInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketReplicationUpdateEndpoint(stack, options); err != nil { return err } @@ -204,6 +217,26 @@ func newServiceMetadataMiddleware_opPutBucketReplication(region string) *awsmidd } } +// getPutBucketReplicationRequestAlgorithmMember gets the request checksum +// algorithm value provided as input. +func getPutBucketReplicationRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketReplicationInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketReplicationInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketReplicationRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketReplicationBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutBucketRequestPayment.go b/service/s3/api_op_PutBucketRequestPayment.go index 36f4b5dd936..c89d97becee 100644 --- a/service/s3/api_op_PutBucketRequestPayment.go +++ b/service/s3/api_op_PutBucketRequestPayment.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -52,6 +53,17 @@ type PutBucketRequestPaymentInput struct { // This member is required. RequestPaymentConfiguration *types.RequestPaymentConfiguration + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the data. You must use this header as a // message integrity check to verify that the request body was not corrupted in // transit. For more information, see RFC 1864 @@ -61,7 +73,8 @@ type PutBucketRequestPaymentInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -122,9 +135,6 @@ func (c *Client) addOperationPutBucketRequestPaymentMiddlewares(stack *middlewar if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketRequestPaymentValidationMiddleware(stack); err != nil { return err } @@ -134,6 +144,9 @@ func (c *Client) addOperationPutBucketRequestPaymentMiddlewares(stack *middlewar if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketRequestPaymentInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketRequestPaymentUpdateEndpoint(stack, options); err != nil { return err } @@ -161,6 +174,26 @@ func newServiceMetadataMiddleware_opPutBucketRequestPayment(region string) *awsm } } +// getPutBucketRequestPaymentRequestAlgorithmMember gets the request checksum +// algorithm value provided as input. +func getPutBucketRequestPaymentRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketRequestPaymentInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketRequestPaymentInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketRequestPaymentRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketRequestPaymentBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutBucketTagging.go b/service/s3/api_op_PutBucketTagging.go index 0803795c711..f410107737c 100644 --- a/service/s3/api_op_PutBucketTagging.go +++ b/service/s3/api_op_PutBucketTagging.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -97,6 +98,17 @@ type PutBucketTaggingInput struct { // This member is required. Tagging *types.Tagging + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the data. You must use this header as a // message integrity check to verify that the request body was not corrupted in // transit. For more information, see RFC 1864 @@ -106,7 +118,8 @@ type PutBucketTaggingInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -167,9 +180,6 @@ func (c *Client) addOperationPutBucketTaggingMiddlewares(stack *middleware.Stack if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketTaggingValidationMiddleware(stack); err != nil { return err } @@ -179,6 +189,9 @@ func (c *Client) addOperationPutBucketTaggingMiddlewares(stack *middleware.Stack if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketTaggingInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketTaggingUpdateEndpoint(stack, options); err != nil { return err } @@ -206,6 +219,26 @@ func newServiceMetadataMiddleware_opPutBucketTagging(region string) *awsmiddlewa } } +// getPutBucketTaggingRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutBucketTaggingRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketTaggingInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketTaggingInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketTaggingRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketTaggingBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutBucketVersioning.go b/service/s3/api_op_PutBucketVersioning.go index 1f87c2db7f9..6d7943e6f66 100644 --- a/service/s3/api_op_PutBucketVersioning.go +++ b/service/s3/api_op_PutBucketVersioning.go @@ -6,30 +6,31 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) -// Sets the versioning state of an existing bucket. To set the versioning state, -// you must be the bucket owner. You can set the versioning state with one of the -// following values: Enabled—Enables versioning for the objects in the bucket. All -// objects added to the bucket receive a unique version ID. Suspended—Disables -// versioning for the objects in the bucket. All objects added to the bucket -// receive the version ID null. If the versioning state has never been set on a -// bucket, it has no versioning state; a GetBucketVersioning +// Sets the versioning state of an existing bucket. You can set the versioning +// state with one of the following values: Enabled—Enables versioning for the +// objects in the bucket. All objects added to the bucket receive a unique version +// ID. Suspended—Disables versioning for the objects in the bucket. All objects +// added to the bucket receive the version ID null. If the versioning state has +// never been set on a bucket, it has no versioning state; a GetBucketVersioning // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html) -// request does not return a versioning state value. If the bucket owner enables -// MFA Delete in the bucket versioning configuration, the bucket owner must include -// the x-amz-mfa request header and the Status and the MfaDelete request elements -// in a request to set the versioning state of the bucket. If you have an object -// expiration lifecycle policy in your non-versioned bucket and you want to -// maintain the same permanent delete behavior when you enable versioning, you must -// add a noncurrent expiration policy. The noncurrent expiration lifecycle policy -// will manage the deletes of the noncurrent object versions in the version-enabled -// bucket. (A version-enabled bucket maintains one current and zero or more -// noncurrent object versions.) For more information, see Lifecycle and Versioning +// request does not return a versioning state value. In order to enable MFA Delete, +// you must be the bucket owner. If you are the bucket owner and want to enable MFA +// Delete in the bucket versioning configuration, you must include the x-amz-mfa +// request header and the Status and the MfaDelete request elements in a request to +// set the versioning state of the bucket. If you have an object expiration +// lifecycle policy in your non-versioned bucket and you want to maintain the same +// permanent delete behavior when you enable versioning, you must add a noncurrent +// expiration policy. The noncurrent expiration lifecycle policy will manage the +// deletes of the noncurrent object versions in the version-enabled bucket. (A +// version-enabled bucket maintains one current and zero or more noncurrent object +// versions.) For more information, see Lifecycle and Versioning // (https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html#lifecycle-and-other-bucket-config). // Related Resources // @@ -70,6 +71,17 @@ type PutBucketVersioningInput struct { // This member is required. VersioningConfiguration *types.VersioningConfiguration + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // >The base64-encoded 128-bit MD5 digest of the data. You must use this header as // a message integrity check to verify that the request body was not corrupted in // transit. For more information, see RFC 1864 @@ -79,7 +91,8 @@ type PutBucketVersioningInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The concatenation of the authentication device's serial number, a space, and the @@ -144,9 +157,6 @@ func (c *Client) addOperationPutBucketVersioningMiddlewares(stack *middleware.St if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketVersioningValidationMiddleware(stack); err != nil { return err } @@ -156,6 +166,9 @@ func (c *Client) addOperationPutBucketVersioningMiddlewares(stack *middleware.St if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketVersioningInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketVersioningUpdateEndpoint(stack, options); err != nil { return err } @@ -183,6 +196,26 @@ func newServiceMetadataMiddleware_opPutBucketVersioning(region string) *awsmiddl } } +// getPutBucketVersioningRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutBucketVersioningRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketVersioningInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketVersioningInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketVersioningRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketVersioningBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutBucketWebsite.go b/service/s3/api_op_PutBucketWebsite.go index 0e1db51fb24..11cb4a35593 100644 --- a/service/s3/api_op_PutBucketWebsite.go +++ b/service/s3/api_op_PutBucketWebsite.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -110,6 +111,17 @@ type PutBucketWebsiteInput struct { // This member is required. WebsiteConfiguration *types.WebsiteConfiguration + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the data. You must use this header as a // message integrity check to verify that the request body was not corrupted in // transit. For more information, see RFC 1864 @@ -119,7 +131,8 @@ type PutBucketWebsiteInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -180,9 +193,6 @@ func (c *Client) addOperationPutBucketWebsiteMiddlewares(stack *middleware.Stack if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutBucketWebsiteValidationMiddleware(stack); err != nil { return err } @@ -192,6 +202,9 @@ func (c *Client) addOperationPutBucketWebsiteMiddlewares(stack *middleware.Stack if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutBucketWebsiteInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutBucketWebsiteUpdateEndpoint(stack, options); err != nil { return err } @@ -219,6 +232,26 @@ func newServiceMetadataMiddleware_opPutBucketWebsite(region string) *awsmiddlewa } } +// getPutBucketWebsiteRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutBucketWebsiteRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutBucketWebsiteInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutBucketWebsiteInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutBucketWebsiteRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutBucketWebsiteBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutObject.go b/service/s3/api_op_PutObject.go index a4340ca90a7..6433640616c 100644 --- a/service/s3/api_op_PutObject.go +++ b/service/s3/api_op_PutObject.go @@ -7,6 +7,7 @@ import ( awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -127,9 +128,9 @@ type PutObjectInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -161,6 +162,49 @@ type PutObjectInput struct { // (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9). CacheControl *string + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32 checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32C checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 160-bit SHA-1 digest of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 256-bit SHA-256 digest of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Specifies presentational information for the object. For more information, see // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1 // (http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1). @@ -197,7 +241,8 @@ type PutObjectInput struct { ContentType *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The date and time at which the object is no longer cacheable. For more @@ -238,8 +283,8 @@ type PutObjectInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -316,6 +361,38 @@ type PutObjectOutput struct { // encryption with Amazon Web Services KMS (SSE-KMS). BucketKeyEnabled bool + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Entity tag for the uploaded object. ETag *string @@ -324,7 +401,7 @@ type PutObjectOutput struct { // (https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html)), // the response includes this header. It includes the expiry-date and rule-id // key-value pairs that provide information about object expiration. The value of - // the rule-id is URL encoded. + // the rule-id is URL-encoded. Expiration *string // If present, indicates that the requester was successfully charged for the @@ -423,6 +500,9 @@ func (c *Client) addOperationPutObjectMiddlewares(stack *middleware.Stack, optio if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutObjectInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutObjectUpdateEndpoint(stack, options); err != nil { return err } @@ -453,6 +533,26 @@ func newServiceMetadataMiddleware_opPutObject(region string) *awsmiddleware.Regi } } +// getPutObjectRequestAlgorithmMember gets the request checksum algorithm value +// provided as input. +func getPutObjectRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutObjectInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutObjectInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutObjectRequestAlgorithmMember, + RequireChecksum: false, + EnableTrailingChecksum: true, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutObjectBucketMember returns a pointer to string denoting a provided bucket // member valueand a boolean indicating if the input has a modeled bucket name, func getPutObjectBucketMember(input interface{}) (*string, bool) { diff --git a/service/s3/api_op_PutObjectAcl.go b/service/s3/api_op_PutObjectAcl.go index d6dd3d3069f..05a377b5bc6 100644 --- a/service/s3/api_op_PutObjectAcl.go +++ b/service/s3/api_op_PutObjectAcl.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -188,9 +189,9 @@ type PutObjectAclInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -204,6 +205,17 @@ type PutObjectAclInput struct { // Contains the elements that set the ACL permissions for an object per grantee. AccessControlPolicy *types.AccessControlPolicy + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The base64-encoded 128-bit MD5 digest of the data. This header must be used as a // message integrity check to verify that the request body was not corrupted in // transit. For more information, go to RFC 1864.> @@ -213,7 +225,8 @@ type PutObjectAclInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Allows grantee the read, write, read ACP, and write ACP permissions on the @@ -239,8 +252,8 @@ type PutObjectAclInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -311,9 +324,6 @@ func (c *Client) addOperationPutObjectAclMiddlewares(stack *middleware.Stack, op if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutObjectAclValidationMiddleware(stack); err != nil { return err } @@ -323,6 +333,9 @@ func (c *Client) addOperationPutObjectAclMiddlewares(stack *middleware.Stack, op if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutObjectAclInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutObjectAclUpdateEndpoint(stack, options); err != nil { return err } @@ -350,6 +363,26 @@ func newServiceMetadataMiddleware_opPutObjectAcl(region string) *awsmiddleware.R } } +// getPutObjectAclRequestAlgorithmMember gets the request checksum algorithm value +// provided as input. +func getPutObjectAclRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutObjectAclInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutObjectAclInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutObjectAclRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutObjectAclBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutObjectLegalHold.go b/service/s3/api_op_PutObjectLegalHold.go index f7d85b0640e..b8004b59844 100644 --- a/service/s3/api_op_PutObjectLegalHold.go +++ b/service/s3/api_op_PutObjectLegalHold.go @@ -6,13 +6,14 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) -// Applies a Legal Hold configuration to the specified object. For more +// Applies a legal hold configuration to the specified object. For more // information, see Locking Objects // (https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html). This action // is not supported by Amazon S3 on Outposts. @@ -33,7 +34,7 @@ func (c *Client) PutObjectLegalHold(ctx context.Context, params *PutObjectLegalH type PutObjectLegalHoldInput struct { - // The bucket name containing the object that you want to place a Legal Hold on. + // The bucket name containing the object that you want to place a legal hold on. // When using this action with an access point, you must direct requests to the // access point hostname. The access point hostname takes the form // AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this @@ -46,33 +47,45 @@ type PutObjectLegalHoldInput struct { // This member is required. Bucket *string - // The key name for the object that you want to place a Legal Hold on. + // The key name for the object that you want to place a legal hold on. // // This member is required. Key *string + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The MD5 hash for the request body. For requests made using the Amazon Web // Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is // calculated automatically. ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string - // Container element for the Legal Hold configuration you want to apply to the + // Container element for the legal hold configuration you want to apply to the // specified object. LegalHold *types.ObjectLockLegalHold // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer - // The version ID of the object that you want to place a Legal Hold on. + // The version ID of the object that you want to place a legal hold on. VersionId *string noSmithyDocumentSerde @@ -138,9 +151,6 @@ func (c *Client) addOperationPutObjectLegalHoldMiddlewares(stack *middleware.Sta if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutObjectLegalHoldValidationMiddleware(stack); err != nil { return err } @@ -150,6 +160,9 @@ func (c *Client) addOperationPutObjectLegalHoldMiddlewares(stack *middleware.Sta if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutObjectLegalHoldInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutObjectLegalHoldUpdateEndpoint(stack, options); err != nil { return err } @@ -177,6 +190,26 @@ func newServiceMetadataMiddleware_opPutObjectLegalHold(region string) *awsmiddle } } +// getPutObjectLegalHoldRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutObjectLegalHoldRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutObjectLegalHoldInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutObjectLegalHoldInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutObjectLegalHoldRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutObjectLegalHoldBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutObjectLockConfiguration.go b/service/s3/api_op_PutObjectLockConfiguration.go index 461c9b81840..9740967a754 100644 --- a/service/s3/api_op_PutObjectLockConfiguration.go +++ b/service/s3/api_op_PutObjectLockConfiguration.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -49,13 +50,25 @@ type PutObjectLockConfigurationInput struct { // This member is required. Bucket *string + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The MD5 hash for the request body. For requests made using the Amazon Web // Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is // calculated automatically. ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // The Object Lock configuration that you want to apply to the specified bucket. @@ -63,8 +76,8 @@ type PutObjectLockConfigurationInput struct { // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -135,9 +148,6 @@ func (c *Client) addOperationPutObjectLockConfigurationMiddlewares(stack *middle if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutObjectLockConfigurationValidationMiddleware(stack); err != nil { return err } @@ -147,6 +157,9 @@ func (c *Client) addOperationPutObjectLockConfigurationMiddlewares(stack *middle if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutObjectLockConfigurationInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutObjectLockConfigurationUpdateEndpoint(stack, options); err != nil { return err } @@ -174,6 +187,26 @@ func newServiceMetadataMiddleware_opPutObjectLockConfiguration(region string) *a } } +// getPutObjectLockConfigurationRequestAlgorithmMember gets the request checksum +// algorithm value provided as input. +func getPutObjectLockConfigurationRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutObjectLockConfigurationInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutObjectLockConfigurationInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutObjectLockConfigurationRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutObjectLockConfigurationBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutObjectRetention.go b/service/s3/api_op_PutObjectRetention.go index 4be8b901d58..c4918f3cbca 100644 --- a/service/s3/api_op_PutObjectRetention.go +++ b/service/s3/api_op_PutObjectRetention.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -18,10 +19,7 @@ import ( // accounts require the s3:PutObjectRetention permission in order to place an // Object Retention configuration on objects. Bypassing a Governance Retention // configuration requires the s3:BypassGovernanceRetention permission. This action -// is not supported by Amazon S3 on Outposts. Permissions When the Object Lock -// retention mode is set to compliance, you need s3:PutObjectRetention and -// s3:BypassGovernanceRetention permissions. For other requests to -// PutObjectRetention, only s3:PutObjectRetention permissions are required. +// is not supported by Amazon S3 on Outposts. func (c *Client) PutObjectRetention(ctx context.Context, params *PutObjectRetentionInput, optFns ...func(*Options)) (*PutObjectRetentionOutput, error) { if params == nil { params = &PutObjectRetentionInput{} @@ -61,19 +59,31 @@ type PutObjectRetentionInput struct { // Indicates whether this action should bypass Governance-mode restrictions. BypassGovernanceRetention bool + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The MD5 hash for the request body. For requests made using the Amazon Web // Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is // calculated automatically. ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -148,9 +158,6 @@ func (c *Client) addOperationPutObjectRetentionMiddlewares(stack *middleware.Sta if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutObjectRetentionValidationMiddleware(stack); err != nil { return err } @@ -160,6 +167,9 @@ func (c *Client) addOperationPutObjectRetentionMiddlewares(stack *middleware.Sta if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutObjectRetentionInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutObjectRetentionUpdateEndpoint(stack, options); err != nil { return err } @@ -187,6 +197,26 @@ func newServiceMetadataMiddleware_opPutObjectRetention(region string) *awsmiddle } } +// getPutObjectRetentionRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutObjectRetentionRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutObjectRetentionInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutObjectRetentionInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutObjectRetentionRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutObjectRetentionBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_PutObjectTagging.go b/service/s3/api_op_PutObjectTagging.go index d496008a0eb..43effb9eb9a 100644 --- a/service/s3/api_op_PutObjectTagging.go +++ b/service/s3/api_op_PutObjectTagging.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -91,9 +92,9 @@ type PutObjectTaggingInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -110,19 +111,31 @@ type PutObjectTaggingInput struct { // This member is required. Tagging *types.Tagging + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The MD5 hash for the request body. For requests made using the Amazon Web // Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is // calculated automatically. ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -192,9 +205,6 @@ func (c *Client) addOperationPutObjectTaggingMiddlewares(stack *middleware.Stack if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutObjectTaggingValidationMiddleware(stack); err != nil { return err } @@ -204,6 +214,9 @@ func (c *Client) addOperationPutObjectTaggingMiddlewares(stack *middleware.Stack if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutObjectTaggingInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutObjectTaggingUpdateEndpoint(stack, options); err != nil { return err } @@ -231,6 +244,26 @@ func newServiceMetadataMiddleware_opPutObjectTagging(region string) *awsmiddlewa } } +// getPutObjectTaggingRequestAlgorithmMember gets the request checksum algorithm +// value provided as input. +func getPutObjectTaggingRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutObjectTaggingInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutObjectTaggingInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutObjectTaggingRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutObjectTaggingBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_PutPublicAccessBlock.go b/service/s3/api_op_PutPublicAccessBlock.go index 301ebbf5524..922102b58a7 100644 --- a/service/s3/api_op_PutPublicAccessBlock.go +++ b/service/s3/api_op_PutPublicAccessBlock.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -74,13 +75,25 @@ type PutPublicAccessBlockInput struct { // This member is required. PublicAccessBlockConfiguration *types.PublicAccessBlockConfiguration + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The MD5 hash of the PutPublicAccessBlock request body. For requests made using // the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services // SDKs, this field is calculated automatically. ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string noSmithyDocumentSerde @@ -141,9 +154,6 @@ func (c *Client) addOperationPutPublicAccessBlockMiddlewares(stack *middleware.S if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil { return err } - if err = smithyhttp.AddContentChecksumMiddleware(stack); err != nil { - return err - } if err = addOpPutPublicAccessBlockValidationMiddleware(stack); err != nil { return err } @@ -153,6 +163,9 @@ func (c *Client) addOperationPutPublicAccessBlockMiddlewares(stack *middleware.S if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addPutPublicAccessBlockInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addPutPublicAccessBlockUpdateEndpoint(stack, options); err != nil { return err } @@ -180,6 +193,26 @@ func newServiceMetadataMiddleware_opPutPublicAccessBlock(region string) *awsmidd } } +// getPutPublicAccessBlockRequestAlgorithmMember gets the request checksum +// algorithm value provided as input. +func getPutPublicAccessBlockRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*PutPublicAccessBlockInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addPutPublicAccessBlockInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getPutPublicAccessBlockRequestAlgorithmMember, + RequireChecksum: true, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getPutPublicAccessBlockBucketMember returns a pointer to string denoting a // provided bucket member valueand a boolean indicating if the input has a modeled // bucket name, diff --git a/service/s3/api_op_RestoreObject.go b/service/s3/api_op_RestoreObject.go index 754bbb6b7b6..01319757029 100644 --- a/service/s3/api_op_RestoreObject.go +++ b/service/s3/api_op_RestoreObject.go @@ -6,6 +6,7 @@ import ( "context" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -259,9 +260,9 @@ type RestoreObjectInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -273,14 +274,26 @@ type RestoreObjectInput struct { // This member is required. Key *string + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. + ChecksumAlgorithm types.ChecksumAlgorithm + // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -367,6 +380,9 @@ func (c *Client) addOperationRestoreObjectMiddlewares(stack *middleware.Stack, o if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addRestoreObjectInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addRestoreObjectUpdateEndpoint(stack, options); err != nil { return err } @@ -394,6 +410,26 @@ func newServiceMetadataMiddleware_opRestoreObject(region string) *awsmiddleware. } } +// getRestoreObjectRequestAlgorithmMember gets the request checksum algorithm value +// provided as input. +func getRestoreObjectRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*RestoreObjectInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addRestoreObjectInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getRestoreObjectRequestAlgorithmMember, + RequireChecksum: false, + EnableTrailingChecksum: false, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getRestoreObjectBucketMember returns a pointer to string denoting a provided // bucket member valueand a boolean indicating if the input has a modeled bucket // name, diff --git a/service/s3/api_op_SelectObjectContent.go b/service/s3/api_op_SelectObjectContent.go index 23e9250c68b..1b9dbc7bcda 100644 --- a/service/s3/api_op_SelectObjectContent.go +++ b/service/s3/api_op_SelectObjectContent.go @@ -157,25 +157,32 @@ type SelectObjectContentInput struct { OutputSerialization *types.OutputSerialization // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Specifies if periodic request progress information should be enabled. RequestProgress *types.RequestProgress - // The SSE Algorithm used to encrypt the object. For more information, see - // Server-Side Encryption (Using Customer-Provided Encryption Keys - // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html). + // The server-side encryption (SSE) algorithm used to encrypt the object. This + // parameter is needed only when the object was created using a checksum algorithm. + // For more information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. SSECustomerAlgorithm *string - // The SSE Customer Key. For more information, see Server-Side Encryption (Using - // Customer-Provided Encryption Keys - // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html). + // The server-side encryption (SSE) customer managed key. This parameter is needed + // only when the object was created using a checksum algorithm. For more + // information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. SSECustomerKey *string - // The SSE Customer Key MD5. For more information, see Server-Side Encryption - // (Using Customer-Provided Encryption Keys - // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html). + // The MD5 server-side encryption (SSE) customer managed key. This parameter is + // needed only when the object was created using a checksum algorithm. For more + // information, see Protecting data using SSE-C keys + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html) + // in the Amazon S3 User Guide. SSECustomerKeyMD5 *string // Specifies the byte range of the object to get the records from. A record is diff --git a/service/s3/api_op_UploadPart.go b/service/s3/api_op_UploadPart.go index 430aa644cf1..fe7a8e81f04 100644 --- a/service/s3/api_op_UploadPart.go +++ b/service/s3/api_op_UploadPart.go @@ -7,6 +7,7 @@ import ( awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" + internalChecksum "github.com/aws/aws-sdk-go-v2/service/internal/checksum" s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go/middleware" @@ -139,9 +140,9 @@ type UploadPartInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -167,6 +168,51 @@ type UploadPartInput struct { // Object data. Body io.Reader + // Indicates the algorithm used to create the checksum for the object when using + // the SDK. This header will not provide any additional functionality if not using + // the SDK. When sending this header, there must be a corresponding x-amz-checksum + // or x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the + // HTTP status code 400 Bad Request. For more information, see Checking object + // integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. If you provide an individual checksum, Amazon S3 + // ignores any provided ChecksumAlgorithm parameter. This checksum algorithm must + // be the same for all parts and it match the checksum value supplied in the + // CreateMultipartUpload request. + ChecksumAlgorithm types.ChecksumAlgorithm + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32 checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32C checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 160-bit SHA-1 digest of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 256-bit SHA-256 digest of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Size of the body in bytes. This parameter is useful when the size of the body // cannot be determined automatically. ContentLength int64 @@ -177,13 +223,14 @@ type UploadPartInput struct { ContentMD5 *string // The account ID of the expected bucket owner. If the bucket is owned by a - // different account, the request will fail with an HTTP 403 (Access Denied) error. + // different account, the request fails with the HTTP status code 403 Forbidden + // (access denied). ExpectedBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer @@ -214,6 +261,38 @@ type UploadPartOutput struct { // encryption with Amazon Web Services KMS (SSE-KMS). BucketKeyEnabled bool + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Entity tag for the uploaded object. ETag *string @@ -302,6 +381,9 @@ func (c *Client) addOperationUploadPartMiddlewares(stack *middleware.Stack, opti if err = addMetadataRetrieverMiddleware(stack); err != nil { return err } + if err = addUploadPartInputChecksumMiddlewares(stack, options); err != nil { + return err + } if err = addUploadPartUpdateEndpoint(stack, options); err != nil { return err } @@ -332,6 +414,26 @@ func newServiceMetadataMiddleware_opUploadPart(region string) *awsmiddleware.Reg } } +// getUploadPartRequestAlgorithmMember gets the request checksum algorithm value +// provided as input. +func getUploadPartRequestAlgorithmMember(input interface{}) (string, bool) { + in := input.(*UploadPartInput) + if len(in.ChecksumAlgorithm) == 0 { + return "", false + } + return string(in.ChecksumAlgorithm), true +} + +func addUploadPartInputChecksumMiddlewares(stack *middleware.Stack, options Options) error { + return internalChecksum.AddInputMiddleware(stack, internalChecksum.InputMiddlewareOptions{ + GetAlgorithm: getUploadPartRequestAlgorithmMember, + RequireChecksum: false, + EnableTrailingChecksum: true, + EnableComputeSHA256PayloadHash: true, + EnableDecodedContentLengthHeader: true, + }) +} + // getUploadPartBucketMember returns a pointer to string denoting a provided bucket // member valueand a boolean indicating if the input has a modeled bucket name, func getUploadPartBucketMember(input interface{}) (*string, bool) { diff --git a/service/s3/api_op_UploadPartCopy.go b/service/s3/api_op_UploadPartCopy.go index b4c89d3cc09..c8a9a55a13f 100644 --- a/service/s3/api_op_UploadPartCopy.go +++ b/service/s3/api_op_UploadPartCopy.go @@ -38,7 +38,7 @@ import ( // Amazon S3 User Guide. // // * For information about copying objects using a single -// atomic action vs. the multipart upload, see Operations on Objects +// atomic action vs. a multipart upload, see Operations on Objects // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectOperations.html) in the // Amazon S3 User Guide. // @@ -148,9 +148,9 @@ type UploadPartCopyInput struct { // you must direct requests to the S3 on Outposts hostname. The S3 on Outposts // hostname takes the form // AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using - // this action using S3 on Outposts through the Amazon Web Services SDKs, you + // this action with S3 on Outposts through the Amazon Web Services SDKs, you // provide the Outposts bucket ARN in place of the bucket name. For more - // information about S3 on Outposts ARNs, see Using S3 on Outposts + // information about S3 on Outposts ARNs, see Using Amazon S3 on Outposts // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the // Amazon S3 User Guide. // @@ -166,7 +166,7 @@ type UploadPartCopyInput struct { // For objects not accessed through an access point, specify the name of the source // bucket and key of the source object, separated by a slash (/). For example, to // copy the object reports/january.pdf from the bucket awsexamplebucket, use - // awsexamplebucket/reports/january.pdf. The value must be URL encoded. + // awsexamplebucket/reports/january.pdf. The value must be URL-encoded. // // * For // objects accessed through access points, specify the Amazon Resource Name (ARN) @@ -183,7 +183,7 @@ type UploadPartCopyInput struct { // reports/january.pdf through outpost my-outpost owned by account 123456789012 in // Region us-west-2, use the URL encoding of // arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf. - // The value must be URL encoded. + // The value must be URL-encoded. // // To copy a specific version of an object, append // ?versionId= to the value (for example, @@ -244,19 +244,19 @@ type UploadPartCopyInput struct { CopySourceSSECustomerKeyMD5 *string // The account ID of the expected destination bucket owner. If the destination - // bucket is owned by a different account, the request will fail with an HTTP 403 - // (Access Denied) error. + // bucket is owned by a different account, the request fails with the HTTP status + // code 403 Forbidden (access denied). ExpectedBucketOwner *string // The account ID of the expected source bucket owner. If the source bucket is - // owned by a different account, the request will fail with an HTTP 403 (Access - // Denied) error. + // owned by a different account, the request fails with the HTTP status code 403 + // Forbidden (access denied). ExpectedSourceBucketOwner *string // Confirms that the requester knows that they will be charged for the request. // Bucket owners need not specify this parameter in their requests. For information - // about downloading objects from requester pays buckets, see Downloading Objects - // in Requestor Pays Buckets + // about downloading objects from Requester Pays buckets, see Downloading Objects + // in Requester Pays Buckets // (https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html) // in the Amazon S3 User Guide. RequestPayer types.RequestPayer diff --git a/service/s3/api_op_WriteGetObjectResponse.go b/service/s3/api_op_WriteGetObjectResponse.go index 0da1d94fb40..78eeadd45a1 100644 --- a/service/s3/api_op_WriteGetObjectResponse.go +++ b/service/s3/api_op_WriteGetObjectResponse.go @@ -96,6 +96,54 @@ type WriteGetObjectResponseInput struct { // Specifies caching behavior along the request/reply chain. CacheControl *string + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This specifies the + // base64-encoded, 32-bit CRC32 checksum of the object returned by the Object + // Lambda function. This may not match the checksum for the object stored in Amazon + // S3. Amazon S3 will perform validation of the checksum values only when the + // original GetObject request required checksum validation. For more information + // about checksums, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. Only one checksum header can be specified at a + // time. If you supply multiple checksum headers, this request will fail. + ChecksumCRC32 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This specifies the + // base64-encoded, 32-bit CRC32C checksum of the object returned by the Object + // Lambda function. This may not match the checksum for the object stored in Amazon + // S3. Amazon S3 will perform validation of the checksum values only when the + // original GetObject request required checksum validation. For more information + // about checksums, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. Only one checksum header can be specified at a + // time. If you supply multiple checksum headers, this request will fail. + ChecksumCRC32C *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This specifies the + // base64-encoded, 160-bit SHA-1 digest of the object returned by the Object Lambda + // function. This may not match the checksum for the object stored in Amazon S3. + // Amazon S3 will perform validation of the checksum values only when the original + // GetObject request required checksum validation. For more information about + // checksums, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. Only one checksum header can be specified at a + // time. If you supply multiple checksum headers, this request will fail. + ChecksumSHA1 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This specifies the + // base64-encoded, 256-bit SHA-256 digest of the object returned by the Object + // Lambda function. This may not match the checksum for the object stored in Amazon + // S3. Amazon S3 will perform validation of the checksum values only when the + // original GetObject request required checksum validation. For more information + // about checksums, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. Only one checksum header can be specified at a + // time. If you supply multiple checksum headers, this request will fail. + ChecksumSHA256 *string + // Specifies presentational information for the object. ContentDisposition *string @@ -127,8 +175,8 @@ type WriteGetObjectResponseInput struct { // A string that uniquely identifies an error condition. Returned in the tag of // the error XML response for a corresponding GetObject call. Cannot be used with a // successful StatusCode header or when the transformed object is provided in the - // body. All error codes from S3 are sentence-cased. Regex value is - // "^[A-Z][a-zA-Z]+$". + // body. All error codes from S3 are sentence-cased. The regular expression (regex) + // value is "^[A-Z][a-zA-Z]+$". ErrorCode *string // Contains a generic description of the error condition. Returned in the tag of @@ -136,9 +184,10 @@ type WriteGetObjectResponseInput struct { // successful StatusCode header or when the transformed object is provided in body. ErrorMessage *string - // If object stored in Amazon S3 expiration is configured (see PUT Bucket - // lifecycle) it includes expiry-date and rule-id key-value pairs providing object - // expiration information. The value of the rule-id is URL encoded. + // If the object expiration is configured (see PUT Bucket lifecycle), the response + // includes this header. It includes the expiry-date and rule-id key-value pairs + // that provide the object expiration information. The value of the rule-id is + // URL-encoded. Expiration *string // The date and time at which the object is no longer cacheable. @@ -238,7 +287,10 @@ type WriteGetObjectResponseInput struct { // * 503 - Service Unavailable StatusCode int32 - // The class of storage used to store object in Amazon S3. + // Provides storage class information of the object. Amazon S3 returns this header + // for all objects except for S3 Standard storage class objects. For more + // information, see Storage Classes + // (https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html). StorageClass types.StorageClass // The number of tags, if any, on the object. diff --git a/service/s3/deserializers.go b/service/s3/deserializers.go index 451a0fcd09a..995d909cf8c 100644 --- a/service/s3/deserializers.go +++ b/service/s3/deserializers.go @@ -295,6 +295,58 @@ func awsRestxml_deserializeOpDocumentCompleteMultipartUploadOutput(v **CompleteM sv.Bucket = ptr.String(xtv) } + case strings.EqualFold("ChecksumCRC32", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumCRC32C", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32C = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA1", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA1 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA256", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA256 = ptr.String(xtv) + } + case strings.EqualFold("ETag", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -779,6 +831,11 @@ func awsRestxml_deserializeOpHttpBindingsCreateMultipartUploadOutput(v *CreateMu v.BucketKeyEnabled = vv } + if headerValues := response.Header.Values("x-amz-checksum-algorithm"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumAlgorithm = types.ChecksumAlgorithm(headerValues[0]) + } + if headerValues := response.Header.Values("x-amz-request-charged"); len(headerValues) != 0 { headerValues[0] = strings.TrimSpace(headerValues[0]) v.RequestCharged = types.RequestCharged(headerValues[0]) @@ -5214,6 +5271,26 @@ func awsRestxml_deserializeOpHttpBindingsGetObjectOutput(v *GetObjectOutput, res v.CacheControl = ptr.String(headerValues[0]) } + if headerValues := response.Header.Values("x-amz-checksum-crc32"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-crc32c"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32C = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha1"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA1 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha256"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA256 = ptr.String(headerValues[0]) + } + if headerValues := response.Header.Values("Content-Disposition"); len(headerValues) != 0 { headerValues[0] = strings.TrimSpace(headerValues[0]) v.ContentDisposition = ptr.String(headerValues[0]) @@ -5566,14 +5643,14 @@ func awsRestxml_deserializeOpDocumentGetObjectAclOutput(v **GetObjectAclOutput, return nil } -type awsRestxml_deserializeOpGetObjectLegalHold struct { +type awsRestxml_deserializeOpGetObjectAttributes struct { } -func (*awsRestxml_deserializeOpGetObjectLegalHold) ID() string { +func (*awsRestxml_deserializeOpGetObjectAttributes) ID() string { return "OperationDeserializer" } -func (m *awsRestxml_deserializeOpGetObjectLegalHold) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +func (m *awsRestxml_deserializeOpGetObjectAttributes) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) @@ -5587,11 +5664,16 @@ func (m *awsRestxml_deserializeOpGetObjectLegalHold) HandleDeserialize(ctx conte } if response.StatusCode < 200 || response.StatusCode >= 300 { - return out, metadata, awsRestxml_deserializeOpErrorGetObjectLegalHold(response, &metadata) + return out, metadata, awsRestxml_deserializeOpErrorGetObjectAttributes(response, &metadata) } - output := &GetObjectLegalHoldOutput{} + output := &GetObjectAttributesOutput{} out.Result = output + err = awsRestxml_deserializeOpHttpBindingsGetObjectAttributesOutput(output, response) + if err != nil { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("failed to decode response with invalid Http bindings, %w", err)} + } + var buff [1024]byte ringBuffer := smithyio.NewRingBuffer(buff[:]) body := io.TeeReader(response.Body, ringBuffer) @@ -5610,7 +5692,7 @@ func (m *awsRestxml_deserializeOpGetObjectLegalHold) HandleDeserialize(ctx conte } decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) - err = awsRestxml_deserializeDocumentObjectLockLegalHold(&output.LegalHold, decoder) + err = awsRestxml_deserializeOpDocumentGetObjectAttributesOutput(&output, decoder) if err != nil { var snapshot bytes.Buffer io.Copy(&snapshot, ringBuffer) @@ -5623,7 +5705,7 @@ func (m *awsRestxml_deserializeOpGetObjectLegalHold) HandleDeserialize(ctx conte return out, metadata, err } -func awsRestxml_deserializeOpErrorGetObjectLegalHold(response *smithyhttp.Response, metadata *middleware.Metadata) error { +func awsRestxml_deserializeOpErrorGetObjectAttributes(response *smithyhttp.Response, metadata *middleware.Metadata) error { var errorBuffer bytes.Buffer if _, err := io.Copy(&errorBuffer, response.Body); err != nil { return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} @@ -5653,6 +5735,9 @@ func awsRestxml_deserializeOpErrorGetObjectLegalHold(response *smithyhttp.Respon } errorBody.Seek(0, io.SeekStart) switch { + case strings.EqualFold("NoSuchKey", errorCode): + return awsRestxml_deserializeErrorNoSuchKey(response, errorBody) + default: genericError := &smithy.GenericAPIError{ Code: errorCode, @@ -5663,13 +5748,48 @@ func awsRestxml_deserializeOpErrorGetObjectLegalHold(response *smithyhttp.Respon } } -func awsRestxml_deserializeOpDocumentGetObjectLegalHoldOutput(v **GetObjectLegalHoldOutput, decoder smithyxml.NodeDecoder) error { +func awsRestxml_deserializeOpHttpBindingsGetObjectAttributesOutput(v *GetObjectAttributesOutput, response *smithyhttp.Response) error { + if v == nil { + return fmt.Errorf("unsupported deserialization for nil %T", v) + } + + if headerValues := response.Header.Values("x-amz-delete-marker"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + vv, err := strconv.ParseBool(headerValues[0]) + if err != nil { + return err + } + v.DeleteMarker = vv + } + + if headerValues := response.Header.Values("Last-Modified"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + t, err := smithytime.ParseHTTPDate(headerValues[0]) + if err != nil { + return err + } + v.LastModified = ptr.Time(t) + } + + if headerValues := response.Header.Values("x-amz-request-charged"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.RequestCharged = types.RequestCharged(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-version-id"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.VersionId = ptr.String(headerValues[0]) + } + + return nil +} +func awsRestxml_deserializeOpDocumentGetObjectAttributesOutput(v **GetObjectAttributesOutput, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) } - var sv *GetObjectLegalHoldOutput + var sv *GetObjectAttributesOutput if *v == nil { - sv = &GetObjectLegalHoldOutput{} + sv = &GetObjectAttributesOutput{} } else { sv = *v } @@ -5685,11 +5805,60 @@ func awsRestxml_deserializeOpDocumentGetObjectLegalHoldOutput(v **GetObjectLegal originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { - case strings.EqualFold("LegalHold", t.Name.Local): + case strings.EqualFold("Checksum", t.Name.Local): nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) - if err := awsRestxml_deserializeDocumentObjectLockLegalHold(&sv.LegalHold, nodeDecoder); err != nil { + if err := awsRestxml_deserializeDocumentChecksum(&sv.Checksum, nodeDecoder); err != nil { + return err + } + + case strings.EqualFold("ETag", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ETag = ptr.String(xtv) + } + + case strings.EqualFold("ObjectParts", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentGetObjectAttributesParts(&sv.ObjectParts, nodeDecoder); err != nil { + return err + } + + case strings.EqualFold("ObjectSize", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.ObjectSize = i64 + } + + case strings.EqualFold("StorageClass", t.Name.Local): + val, err := decoder.Value() + if err != nil { return err } + if val == nil { + break + } + { + xtv := string(val) + sv.StorageClass = types.StorageClass(xtv) + } default: // Do nothing and ignore the unexpected tag element @@ -5705,14 +5874,14 @@ func awsRestxml_deserializeOpDocumentGetObjectLegalHoldOutput(v **GetObjectLegal return nil } -type awsRestxml_deserializeOpGetObjectLockConfiguration struct { +type awsRestxml_deserializeOpGetObjectLegalHold struct { } -func (*awsRestxml_deserializeOpGetObjectLockConfiguration) ID() string { +func (*awsRestxml_deserializeOpGetObjectLegalHold) ID() string { return "OperationDeserializer" } -func (m *awsRestxml_deserializeOpGetObjectLockConfiguration) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +func (m *awsRestxml_deserializeOpGetObjectLegalHold) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) @@ -5726,9 +5895,9 @@ func (m *awsRestxml_deserializeOpGetObjectLockConfiguration) HandleDeserialize(c } if response.StatusCode < 200 || response.StatusCode >= 300 { - return out, metadata, awsRestxml_deserializeOpErrorGetObjectLockConfiguration(response, &metadata) + return out, metadata, awsRestxml_deserializeOpErrorGetObjectLegalHold(response, &metadata) } - output := &GetObjectLockConfigurationOutput{} + output := &GetObjectLegalHoldOutput{} out.Result = output var buff [1024]byte @@ -5749,7 +5918,7 @@ func (m *awsRestxml_deserializeOpGetObjectLockConfiguration) HandleDeserialize(c } decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) - err = awsRestxml_deserializeDocumentObjectLockConfiguration(&output.ObjectLockConfiguration, decoder) + err = awsRestxml_deserializeDocumentObjectLockLegalHold(&output.LegalHold, decoder) if err != nil { var snapshot bytes.Buffer io.Copy(&snapshot, ringBuffer) @@ -5762,7 +5931,7 @@ func (m *awsRestxml_deserializeOpGetObjectLockConfiguration) HandleDeserialize(c return out, metadata, err } -func awsRestxml_deserializeOpErrorGetObjectLockConfiguration(response *smithyhttp.Response, metadata *middleware.Metadata) error { +func awsRestxml_deserializeOpErrorGetObjectLegalHold(response *smithyhttp.Response, metadata *middleware.Metadata) error { var errorBuffer bytes.Buffer if _, err := io.Copy(&errorBuffer, response.Body); err != nil { return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} @@ -5802,13 +5971,13 @@ func awsRestxml_deserializeOpErrorGetObjectLockConfiguration(response *smithyhtt } } -func awsRestxml_deserializeOpDocumentGetObjectLockConfigurationOutput(v **GetObjectLockConfigurationOutput, decoder smithyxml.NodeDecoder) error { +func awsRestxml_deserializeOpDocumentGetObjectLegalHoldOutput(v **GetObjectLegalHoldOutput, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) } - var sv *GetObjectLockConfigurationOutput + var sv *GetObjectLegalHoldOutput if *v == nil { - sv = &GetObjectLockConfigurationOutput{} + sv = &GetObjectLegalHoldOutput{} } else { sv = *v } @@ -5824,9 +5993,9 @@ func awsRestxml_deserializeOpDocumentGetObjectLockConfigurationOutput(v **GetObj originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { - case strings.EqualFold("ObjectLockConfiguration", t.Name.Local): + case strings.EqualFold("LegalHold", t.Name.Local): nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) - if err := awsRestxml_deserializeDocumentObjectLockConfiguration(&sv.ObjectLockConfiguration, nodeDecoder); err != nil { + if err := awsRestxml_deserializeDocumentObjectLockLegalHold(&sv.LegalHold, nodeDecoder); err != nil { return err } @@ -5844,14 +6013,14 @@ func awsRestxml_deserializeOpDocumentGetObjectLockConfigurationOutput(v **GetObj return nil } -type awsRestxml_deserializeOpGetObjectRetention struct { +type awsRestxml_deserializeOpGetObjectLockConfiguration struct { } -func (*awsRestxml_deserializeOpGetObjectRetention) ID() string { +func (*awsRestxml_deserializeOpGetObjectLockConfiguration) ID() string { return "OperationDeserializer" } -func (m *awsRestxml_deserializeOpGetObjectRetention) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +func (m *awsRestxml_deserializeOpGetObjectLockConfiguration) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) @@ -5865,9 +6034,9 @@ func (m *awsRestxml_deserializeOpGetObjectRetention) HandleDeserialize(ctx conte } if response.StatusCode < 200 || response.StatusCode >= 300 { - return out, metadata, awsRestxml_deserializeOpErrorGetObjectRetention(response, &metadata) + return out, metadata, awsRestxml_deserializeOpErrorGetObjectLockConfiguration(response, &metadata) } - output := &GetObjectRetentionOutput{} + output := &GetObjectLockConfigurationOutput{} out.Result = output var buff [1024]byte @@ -5888,7 +6057,7 @@ func (m *awsRestxml_deserializeOpGetObjectRetention) HandleDeserialize(ctx conte } decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) - err = awsRestxml_deserializeDocumentObjectLockRetention(&output.Retention, decoder) + err = awsRestxml_deserializeDocumentObjectLockConfiguration(&output.ObjectLockConfiguration, decoder) if err != nil { var snapshot bytes.Buffer io.Copy(&snapshot, ringBuffer) @@ -5901,7 +6070,7 @@ func (m *awsRestxml_deserializeOpGetObjectRetention) HandleDeserialize(ctx conte return out, metadata, err } -func awsRestxml_deserializeOpErrorGetObjectRetention(response *smithyhttp.Response, metadata *middleware.Metadata) error { +func awsRestxml_deserializeOpErrorGetObjectLockConfiguration(response *smithyhttp.Response, metadata *middleware.Metadata) error { var errorBuffer bytes.Buffer if _, err := io.Copy(&errorBuffer, response.Body); err != nil { return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} @@ -5941,13 +6110,13 @@ func awsRestxml_deserializeOpErrorGetObjectRetention(response *smithyhttp.Respon } } -func awsRestxml_deserializeOpDocumentGetObjectRetentionOutput(v **GetObjectRetentionOutput, decoder smithyxml.NodeDecoder) error { +func awsRestxml_deserializeOpDocumentGetObjectLockConfigurationOutput(v **GetObjectLockConfigurationOutput, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) } - var sv *GetObjectRetentionOutput + var sv *GetObjectLockConfigurationOutput if *v == nil { - sv = &GetObjectRetentionOutput{} + sv = &GetObjectLockConfigurationOutput{} } else { sv = *v } @@ -5963,9 +6132,9 @@ func awsRestxml_deserializeOpDocumentGetObjectRetentionOutput(v **GetObjectReten originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { - case strings.EqualFold("Retention", t.Name.Local): + case strings.EqualFold("ObjectLockConfiguration", t.Name.Local): nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) - if err := awsRestxml_deserializeDocumentObjectLockRetention(&sv.Retention, nodeDecoder); err != nil { + if err := awsRestxml_deserializeDocumentObjectLockConfiguration(&sv.ObjectLockConfiguration, nodeDecoder); err != nil { return err } @@ -5983,14 +6152,14 @@ func awsRestxml_deserializeOpDocumentGetObjectRetentionOutput(v **GetObjectReten return nil } -type awsRestxml_deserializeOpGetObjectTagging struct { +type awsRestxml_deserializeOpGetObjectRetention struct { } -func (*awsRestxml_deserializeOpGetObjectTagging) ID() string { +func (*awsRestxml_deserializeOpGetObjectRetention) ID() string { return "OperationDeserializer" } -func (m *awsRestxml_deserializeOpGetObjectTagging) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +func (m *awsRestxml_deserializeOpGetObjectRetention) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) @@ -6004,16 +6173,11 @@ func (m *awsRestxml_deserializeOpGetObjectTagging) HandleDeserialize(ctx context } if response.StatusCode < 200 || response.StatusCode >= 300 { - return out, metadata, awsRestxml_deserializeOpErrorGetObjectTagging(response, &metadata) + return out, metadata, awsRestxml_deserializeOpErrorGetObjectRetention(response, &metadata) } - output := &GetObjectTaggingOutput{} + output := &GetObjectRetentionOutput{} out.Result = output - err = awsRestxml_deserializeOpHttpBindingsGetObjectTaggingOutput(output, response) - if err != nil { - return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("failed to decode response with invalid Http bindings, %w", err)} - } - var buff [1024]byte ringBuffer := smithyio.NewRingBuffer(buff[:]) body := io.TeeReader(response.Body, ringBuffer) @@ -6032,7 +6196,7 @@ func (m *awsRestxml_deserializeOpGetObjectTagging) HandleDeserialize(ctx context } decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) - err = awsRestxml_deserializeOpDocumentGetObjectTaggingOutput(&output, decoder) + err = awsRestxml_deserializeDocumentObjectLockRetention(&output.Retention, decoder) if err != nil { var snapshot bytes.Buffer io.Copy(&snapshot, ringBuffer) @@ -6045,7 +6209,7 @@ func (m *awsRestxml_deserializeOpGetObjectTagging) HandleDeserialize(ctx context return out, metadata, err } -func awsRestxml_deserializeOpErrorGetObjectTagging(response *smithyhttp.Response, metadata *middleware.Metadata) error { +func awsRestxml_deserializeOpErrorGetObjectRetention(response *smithyhttp.Response, metadata *middleware.Metadata) error { var errorBuffer bytes.Buffer if _, err := io.Copy(&errorBuffer, response.Body); err != nil { return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} @@ -6085,25 +6249,13 @@ func awsRestxml_deserializeOpErrorGetObjectTagging(response *smithyhttp.Response } } -func awsRestxml_deserializeOpHttpBindingsGetObjectTaggingOutput(v *GetObjectTaggingOutput, response *smithyhttp.Response) error { - if v == nil { - return fmt.Errorf("unsupported deserialization for nil %T", v) - } - - if headerValues := response.Header.Values("x-amz-version-id"); len(headerValues) != 0 { - headerValues[0] = strings.TrimSpace(headerValues[0]) - v.VersionId = ptr.String(headerValues[0]) - } - - return nil -} -func awsRestxml_deserializeOpDocumentGetObjectTaggingOutput(v **GetObjectTaggingOutput, decoder smithyxml.NodeDecoder) error { +func awsRestxml_deserializeOpDocumentGetObjectRetentionOutput(v **GetObjectRetentionOutput, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) } - var sv *GetObjectTaggingOutput + var sv *GetObjectRetentionOutput if *v == nil { - sv = &GetObjectTaggingOutput{} + sv = &GetObjectRetentionOutput{} } else { sv = *v } @@ -6119,9 +6271,9 @@ func awsRestxml_deserializeOpDocumentGetObjectTaggingOutput(v **GetObjectTagging originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { - case strings.EqualFold("TagSet", t.Name.Local): + case strings.EqualFold("Retention", t.Name.Local): nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) - if err := awsRestxml_deserializeDocumentTagSet(&sv.TagSet, nodeDecoder); err != nil { + if err := awsRestxml_deserializeDocumentObjectLockRetention(&sv.Retention, nodeDecoder); err != nil { return err } @@ -6139,14 +6291,14 @@ func awsRestxml_deserializeOpDocumentGetObjectTaggingOutput(v **GetObjectTagging return nil } -type awsRestxml_deserializeOpGetObjectTorrent struct { +type awsRestxml_deserializeOpGetObjectTagging struct { } -func (*awsRestxml_deserializeOpGetObjectTorrent) ID() string { +func (*awsRestxml_deserializeOpGetObjectTagging) ID() string { return "OperationDeserializer" } -func (m *awsRestxml_deserializeOpGetObjectTorrent) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +func (m *awsRestxml_deserializeOpGetObjectTagging) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) @@ -6160,9 +6312,165 @@ func (m *awsRestxml_deserializeOpGetObjectTorrent) HandleDeserialize(ctx context } if response.StatusCode < 200 || response.StatusCode >= 300 { - return out, metadata, awsRestxml_deserializeOpErrorGetObjectTorrent(response, &metadata) + return out, metadata, awsRestxml_deserializeOpErrorGetObjectTagging(response, &metadata) } - output := &GetObjectTorrentOutput{} + output := &GetObjectTaggingOutput{} + out.Result = output + + err = awsRestxml_deserializeOpHttpBindingsGetObjectTaggingOutput(output, response) + if err != nil { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("failed to decode response with invalid Http bindings, %w", err)} + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + body := io.TeeReader(response.Body, ringBuffer) + rootDecoder := xml.NewDecoder(body) + t, err := smithyxml.FetchRootElement(rootDecoder) + if err == io.EOF { + return out, metadata, nil + } + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) + err = awsRestxml_deserializeOpDocumentGetObjectTaggingOutput(&output, decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + return out, metadata, err +} + +func awsRestxml_deserializeOpErrorGetObjectTagging(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := s3shared.GetErrorResponseComponents(errorBody, s3shared.ErrorResponseDeserializerOptions{ + UseStatusCode: true, StatusCode: response.StatusCode, + }) + if err != nil { + return err + } + if hostID := errorComponents.HostID; len(hostID) != 0 { + s3shared.SetHostIDMetadata(metadata, hostID) + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +func awsRestxml_deserializeOpHttpBindingsGetObjectTaggingOutput(v *GetObjectTaggingOutput, response *smithyhttp.Response) error { + if v == nil { + return fmt.Errorf("unsupported deserialization for nil %T", v) + } + + if headerValues := response.Header.Values("x-amz-version-id"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.VersionId = ptr.String(headerValues[0]) + } + + return nil +} +func awsRestxml_deserializeOpDocumentGetObjectTaggingOutput(v **GetObjectTaggingOutput, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *GetObjectTaggingOutput + if *v == nil { + sv = &GetObjectTaggingOutput{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("TagSet", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentTagSet(&sv.TagSet, nodeDecoder); err != nil { + return err + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + +type awsRestxml_deserializeOpGetObjectTorrent struct { +} + +func (*awsRestxml_deserializeOpGetObjectTorrent) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpGetObjectTorrent) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorGetObjectTorrent(response, &metadata) + } + output := &GetObjectTorrentOutput{} out.Result = output err = awsRestxml_deserializeOpHttpBindingsGetObjectTorrentOutput(output, response) @@ -6558,6 +6866,26 @@ func awsRestxml_deserializeOpHttpBindingsHeadObjectOutput(v *HeadObjectOutput, r v.CacheControl = ptr.String(headerValues[0]) } + if headerValues := response.Header.Values("x-amz-checksum-crc32"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-crc32c"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32C = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha1"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA1 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha256"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA256 = ptr.String(headerValues[0]) + } + if headerValues := response.Header.Values("Content-Disposition"); len(headerValues) != 0 { headerValues[0] = strings.TrimSpace(headerValues[0]) v.ContentDisposition = ptr.String(headerValues[0]) @@ -8874,6 +9202,19 @@ func awsRestxml_deserializeOpDocumentListPartsOutput(v **ListPartsOutput, decode sv.Bucket = ptr.String(xtv) } + case strings.EqualFold("ChecksumAlgorithm", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumAlgorithm = types.ChecksumAlgorithm(xtv) + } + case strings.EqualFold("Initiator", t.Name.Local): nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) if err := awsRestxml_deserializeDocumentInitiator(&sv.Initiator, nodeDecoder); err != nil { @@ -10442,6 +10783,26 @@ func awsRestxml_deserializeOpHttpBindingsPutObjectOutput(v *PutObjectOutput, res v.BucketKeyEnabled = vv } + if headerValues := response.Header.Values("x-amz-checksum-crc32"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-crc32c"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32C = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha1"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA1 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha256"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA256 = ptr.String(headerValues[0]) + } + if headerValues := response.Header.Values("ETag"); len(headerValues) != 0 { headerValues[0] = strings.TrimSpace(headerValues[0]) v.ETag = ptr.String(headerValues[0]) @@ -11255,6 +11616,26 @@ func awsRestxml_deserializeOpHttpBindingsUploadPartOutput(v *UploadPartOutput, r v.BucketKeyEnabled = vv } + if headerValues := response.Header.Values("x-amz-checksum-crc32"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-crc32c"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumCRC32C = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha1"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA1 = ptr.String(headerValues[0]) + } + + if headerValues := response.Header.Values("x-amz-checksum-sha256"); len(headerValues) != 0 { + headerValues[0] = strings.TrimSpace(headerValues[0]) + v.ChecksumSHA256 = ptr.String(headerValues[0]) + } + if headerValues := response.Header.Values("ETag"); len(headerValues) != 0 { headerValues[0] = strings.TrimSpace(headerValues[0]) v.ETag = ptr.String(headerValues[0]) @@ -13067,13 +13448,13 @@ func awsRestxml_deserializeDocumentBucketsUnwrapped(v *[]types.Bucket, decoder s *v = sv return nil } -func awsRestxml_deserializeDocumentCommonPrefix(v **types.CommonPrefix, decoder smithyxml.NodeDecoder) error { +func awsRestxml_deserializeDocumentChecksum(v **types.Checksum, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) } - var sv *types.CommonPrefix + var sv *types.Checksum if *v == nil { - sv = &types.CommonPrefix{} + sv = &types.Checksum{} } else { sv = *v } @@ -13089,7 +13470,7 @@ func awsRestxml_deserializeDocumentCommonPrefix(v **types.CommonPrefix, decoder originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { - case strings.EqualFold("Prefix", t.Name.Local): + case strings.EqualFold("ChecksumCRC32", t.Name.Local): val, err := decoder.Value() if err != nil { return err @@ -13099,7 +13480,46 @@ func awsRestxml_deserializeDocumentCommonPrefix(v **types.CommonPrefix, decoder } { xtv := string(val) - sv.Prefix = ptr.String(xtv) + sv.ChecksumCRC32 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumCRC32C", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32C = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA1", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA1 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA256", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA256 = ptr.String(xtv) } default: @@ -13116,13 +13536,13 @@ func awsRestxml_deserializeDocumentCommonPrefix(v **types.CommonPrefix, decoder return nil } -func awsRestxml_deserializeDocumentCommonPrefixList(v *[]types.CommonPrefix, decoder smithyxml.NodeDecoder) error { +func awsRestxml_deserializeDocumentChecksumAlgorithmList(v *[]types.ChecksumAlgorithm, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) } - var sv []types.CommonPrefix + var sv []types.ChecksumAlgorithm if *v == nil { - sv = make([]types.CommonPrefix, 0) + sv = make([]types.ChecksumAlgorithm, 0) } else { sv = *v } @@ -13136,18 +13556,147 @@ func awsRestxml_deserializeDocumentCommonPrefixList(v *[]types.CommonPrefix, dec if done { break } + memberDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + decoder = memberDecoder switch { case strings.EqualFold("member", t.Name.Local): - var col types.CommonPrefix - nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) - destAddr := &col - if err := awsRestxml_deserializeDocumentCommonPrefix(&destAddr, nodeDecoder); err != nil { + var col types.ChecksumAlgorithm + val, err := decoder.Value() + if err != nil { return err } - col = *destAddr - sv = append(sv, col) - - default: + if val == nil { + break + } + { + xtv := string(val) + col = types.ChecksumAlgorithm(xtv) + } + sv = append(sv, col) + + default: + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + +func awsRestxml_deserializeDocumentChecksumAlgorithmListUnwrapped(v *[]types.ChecksumAlgorithm, decoder smithyxml.NodeDecoder) error { + var sv []types.ChecksumAlgorithm + if *v == nil { + sv = make([]types.ChecksumAlgorithm, 0) + } else { + sv = *v + } + + switch { + default: + var mv types.ChecksumAlgorithm + t := decoder.StartEl + _ = t + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + mv = types.ChecksumAlgorithm(xtv) + } + sv = append(sv, mv) + } + *v = sv + return nil +} +func awsRestxml_deserializeDocumentCommonPrefix(v **types.CommonPrefix, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *types.CommonPrefix + if *v == nil { + sv = &types.CommonPrefix{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("Prefix", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.Prefix = ptr.String(xtv) + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + +func awsRestxml_deserializeDocumentCommonPrefixList(v *[]types.CommonPrefix, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv []types.CommonPrefix + if *v == nil { + sv = make([]types.CommonPrefix, 0) + } else { + sv = *v + } + + originalDecoder := decoder + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + switch { + case strings.EqualFold("member", t.Name.Local): + var col types.CommonPrefix + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + destAddr := &col + if err := awsRestxml_deserializeDocumentCommonPrefix(&destAddr, nodeDecoder); err != nil { + return err + } + col = *destAddr + sv = append(sv, col) + + default: err = decoder.Decoder.Skip() if err != nil { return err @@ -13268,6 +13817,58 @@ func awsRestxml_deserializeDocumentCopyObjectResult(v **types.CopyObjectResult, originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { + case strings.EqualFold("ChecksumCRC32", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumCRC32C", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32C = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA1", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA1 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA256", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA256 = ptr.String(xtv) + } + case strings.EqualFold("ETag", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -13334,6 +13935,58 @@ func awsRestxml_deserializeDocumentCopyPartResult(v **types.CopyPartResult, deco originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { + case strings.EqualFold("ChecksumCRC32", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumCRC32C", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32C = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA1", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA1 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA256", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA256 = ptr.String(xtv) + } + case strings.EqualFold("ETag", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -14700,30 +15353,148 @@ func awsRestxml_deserializeDocumentFilterRuleList(v *[]types.FilterRule, decoder return nil } -func awsRestxml_deserializeDocumentFilterRuleListUnwrapped(v *[]types.FilterRule, decoder smithyxml.NodeDecoder) error { - var sv []types.FilterRule - if *v == nil { - sv = make([]types.FilterRule, 0) - } else { - sv = *v - } - - switch { - default: - var mv types.FilterRule - t := decoder.StartEl - _ = t - nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) - destAddr := &mv - if err := awsRestxml_deserializeDocumentFilterRule(&destAddr, nodeDecoder); err != nil { - return err - } - mv = *destAddr - sv = append(sv, mv) - } - *v = sv - return nil -} +func awsRestxml_deserializeDocumentFilterRuleListUnwrapped(v *[]types.FilterRule, decoder smithyxml.NodeDecoder) error { + var sv []types.FilterRule + if *v == nil { + sv = make([]types.FilterRule, 0) + } else { + sv = *v + } + + switch { + default: + var mv types.FilterRule + t := decoder.StartEl + _ = t + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + destAddr := &mv + if err := awsRestxml_deserializeDocumentFilterRule(&destAddr, nodeDecoder); err != nil { + return err + } + mv = *destAddr + sv = append(sv, mv) + } + *v = sv + return nil +} +func awsRestxml_deserializeDocumentGetObjectAttributesParts(v **types.GetObjectAttributesParts, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *types.GetObjectAttributesParts + if *v == nil { + sv = &types.GetObjectAttributesParts{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("IsTruncated", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv, err := strconv.ParseBool(string(val)) + if err != nil { + return fmt.Errorf("expected IsTruncated to be of type *bool, got %T instead", val) + } + sv.IsTruncated = xtv + } + + case strings.EqualFold("MaxParts", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.MaxParts = int32(i64) + } + + case strings.EqualFold("NextPartNumberMarker", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.NextPartNumberMarker = ptr.String(xtv) + } + + case strings.EqualFold("PartNumberMarker", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.PartNumberMarker = ptr.String(xtv) + } + + case strings.EqualFold("Part", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentPartsListUnwrapped(&sv.Parts, nodeDecoder); err != nil { + return err + } + + case strings.EqualFold("PartsCount", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.TotalPartsCount = int32(i64) + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + func awsRestxml_deserializeDocumentGrant(v **types.Grant, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) @@ -16943,6 +17714,19 @@ func awsRestxml_deserializeDocumentMultipartUpload(v **types.MultipartUpload, de originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { + case strings.EqualFold("ChecksumAlgorithm", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumAlgorithm = types.ChecksumAlgorithm(xtv) + } + case strings.EqualFold("Initiated", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -17522,6 +18306,12 @@ func awsRestxml_deserializeDocumentObject(v **types.Object, decoder smithyxml.No originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { + case strings.EqualFold("ChecksumAlgorithm", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentChecksumAlgorithmListUnwrapped(&sv.ChecksumAlgorithm, nodeDecoder); err != nil { + return err + } + case strings.EqualFold("ETag", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -17967,6 +18757,128 @@ func awsRestxml_deserializeDocumentObjectNotInActiveTierError(v **types.ObjectNo return nil } +func awsRestxml_deserializeDocumentObjectPart(v **types.ObjectPart, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *types.ObjectPart + if *v == nil { + sv = &types.ObjectPart{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("ChecksumCRC32", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumCRC32C", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32C = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA1", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA1 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA256", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA256 = ptr.String(xtv) + } + + case strings.EqualFold("PartNumber", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.PartNumber = int32(i64) + } + + case strings.EqualFold("Size", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + i64, err := strconv.ParseInt(xtv, 10, 64) + if err != nil { + return err + } + sv.Size = i64 + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + func awsRestxml_deserializeDocumentObjectVersion(v **types.ObjectVersion, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) @@ -17989,6 +18901,12 @@ func awsRestxml_deserializeDocumentObjectVersion(v **types.ObjectVersion, decode originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { + case strings.EqualFold("ChecksumAlgorithm", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentChecksumAlgorithmListUnwrapped(&sv.ChecksumAlgorithm, nodeDecoder); err != nil { + return err + } + case strings.EqualFold("ETag", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -18422,6 +19340,58 @@ func awsRestxml_deserializeDocumentPart(v **types.Part, decoder smithyxml.NodeDe originalDecoder := decoder decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) switch { + case strings.EqualFold("ChecksumCRC32", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumCRC32C", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumCRC32C = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA1", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA1 = ptr.String(xtv) + } + + case strings.EqualFold("ChecksumSHA256", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.ChecksumSHA256 = ptr.String(xtv) + } + case strings.EqualFold("ETag", t.Name.Local): val, err := decoder.Value() if err != nil { @@ -18568,6 +19538,74 @@ func awsRestxml_deserializeDocumentPartsUnwrapped(v *[]types.Part, decoder smith *v = sv return nil } +func awsRestxml_deserializeDocumentPartsList(v *[]types.ObjectPart, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv []types.ObjectPart + if *v == nil { + sv = make([]types.ObjectPart, 0) + } else { + sv = *v + } + + originalDecoder := decoder + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + switch { + case strings.EqualFold("member", t.Name.Local): + var col types.ObjectPart + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + destAddr := &col + if err := awsRestxml_deserializeDocumentObjectPart(&destAddr, nodeDecoder); err != nil { + return err + } + col = *destAddr + sv = append(sv, col) + + default: + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + +func awsRestxml_deserializeDocumentPartsListUnwrapped(v *[]types.ObjectPart, decoder smithyxml.NodeDecoder) error { + var sv []types.ObjectPart + if *v == nil { + sv = make([]types.ObjectPart, 0) + } else { + sv = *v + } + + switch { + default: + var mv types.ObjectPart + t := decoder.StartEl + _ = t + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + destAddr := &mv + if err := awsRestxml_deserializeDocumentObjectPart(&destAddr, nodeDecoder); err != nil { + return err + } + mv = *destAddr + sv = append(sv, mv) + } + *v = sv + return nil +} func awsRestxml_deserializeDocumentPolicyStatus(v **types.PolicyStatus, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) diff --git a/service/s3/generated.json b/service/s3/generated.json index dbcc6ce77d0..ff5ea4896a8 100644 --- a/service/s3/generated.json +++ b/service/s3/generated.json @@ -5,6 +5,7 @@ "github.com/aws/aws-sdk-go-v2/internal/configsources": "v0.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2": "v2.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding": "v1.0.5", + "github.com/aws/aws-sdk-go-v2/service/internal/checksum": "v0.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/service/internal/presigned-url": "v1.0.7", "github.com/aws/aws-sdk-go-v2/service/internal/s3shared": "v1.2.3", "github.com/aws/smithy-go": "v1.4.0" @@ -56,6 +57,7 @@ "api_op_GetBucketWebsite.go", "api_op_GetObject.go", "api_op_GetObjectAcl.go", + "api_op_GetObjectAttributes.go", "api_op_GetObjectLegalHold.go", "api_op_GetObjectLockConfiguration.go", "api_op_GetObjectRetention.go", diff --git a/service/s3/go.mod b/service/s3/go.mod index d64b5c24f72..d5b76ee6ebd 100644 --- a/service/s3/go.mod +++ b/service/s3/go.mod @@ -8,6 +8,7 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.7.0 + github.com/aws/aws-sdk-go-v2/service/internal/checksum v0.0.0-00010101000000-000000000000 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.11.0 github.com/aws/smithy-go v1.10.1-0.20220223172659-66863935410f @@ -24,6 +25,8 @@ replace github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 => ../../internal/end replace github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding => ../../service/internal/accept-encoding/ +replace github.com/aws/aws-sdk-go-v2/service/internal/checksum => ../../service/internal/checksum/ + replace github.com/aws/aws-sdk-go-v2/service/internal/presigned-url => ../../service/internal/presigned-url/ replace github.com/aws/aws-sdk-go-v2/service/internal/s3shared => ../../service/internal/s3shared/ diff --git a/service/s3/internal/customizations/presign_test.go b/service/s3/internal/customizations/presign_test.go index 6dcaae06f01..4d323f944bf 100644 --- a/service/s3/internal/customizations/presign_test.go +++ b/service/s3/internal/customizations/presign_test.go @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/service/s3" + s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" ) func TestPutObject_PresignURL(t *testing.T) { @@ -184,6 +185,52 @@ func TestPutObject_PresignURL(t *testing.T) { }, expectError: "Multi-Region access point ARNs are disabled", }, + "standard case with checksum preset checksum": { + input: s3.PutObjectInput{ + Bucket: aws.String("mock-bucket"), + Key: aws.String("mockkey"), + Body: strings.NewReader("hello world"), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32: aws.String("DUoRhQ=="), + }, + expectPresignedURLHost: "https://mock-bucket.s3.us-west-2.amazonaws.com/mockkey?", + expectRequestURIQuery: []string{ + "X-Amz-Expires=900", + "X-Amz-Credential", + "X-Amz-Date", + "x-id=PutObject", + "X-Amz-Signature", + "X-Amz-Checksum-Crc32", + }, + expectMethod: "PUT", + expectSignedHeader: http.Header{ + "Content-Length": []string{"11"}, + "Content-Type": []string{"application/octet-stream"}, + "Host": []string{"mock-bucket.s3.us-west-2.amazonaws.com"}, + }, + }, + "standard case with checksum empty body": { + input: s3.PutObjectInput{ + Bucket: aws.String("mock-bucket"), + Key: aws.String("mockkey"), + Body: strings.NewReader(""), + ChecksumAlgorithm: s3types.ChecksumAlgorithmCrc32c, + ChecksumCRC32: aws.String("AAAAAA=="), + }, + expectPresignedURLHost: "https://mock-bucket.s3.us-west-2.amazonaws.com/mockkey?", + expectRequestURIQuery: []string{ + "X-Amz-Expires=900", + "X-Amz-Credential", + "X-Amz-Date", + "x-id=PutObject", + "X-Amz-Signature", + "X-Amz-Checksum-Crc32", + }, + expectMethod: "PUT", + expectSignedHeader: http.Header{ + "Host": []string{"mock-bucket.s3.us-west-2.amazonaws.com"}, + }, + }, } for name, c := range cases { diff --git a/service/s3/serializers.go b/service/s3/serializers.go index 85b137df6b2..f398aa95c64 100644 --- a/service/s3/serializers.go +++ b/service/s3/serializers.go @@ -14,6 +14,7 @@ import ( smithytime "github.com/aws/smithy-go/time" smithyhttp "github.com/aws/smithy-go/transport/http" "net/http" + "strconv" "strings" ) @@ -176,6 +177,26 @@ func awsRestxml_serializeOpHttpBindingsCompleteMultipartUploadInput(v *CompleteM } } + if v.ChecksumCRC32 != nil && len(*v.ChecksumCRC32) > 0 { + locationName := "X-Amz-Checksum-Crc32" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32) + } + + if v.ChecksumCRC32C != nil && len(*v.ChecksumCRC32C) > 0 { + locationName := "X-Amz-Checksum-Crc32c" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32C) + } + + if v.ChecksumSHA1 != nil && len(*v.ChecksumSHA1) > 0 { + locationName := "X-Amz-Checksum-Sha1" + encoder.SetHeader(locationName).String(*v.ChecksumSHA1) + } + + if v.ChecksumSHA256 != nil && len(*v.ChecksumSHA256) > 0 { + locationName := "X-Amz-Checksum-Sha256" + encoder.SetHeader(locationName).String(*v.ChecksumSHA256) + } + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { locationName := "X-Amz-Expected-Bucket-Owner" encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) @@ -195,6 +216,21 @@ func awsRestxml_serializeOpHttpBindingsCompleteMultipartUploadInput(v *CompleteM encoder.SetHeader(locationName).String(string(v.RequestPayer)) } + if v.SSECustomerAlgorithm != nil && len(*v.SSECustomerAlgorithm) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Algorithm" + encoder.SetHeader(locationName).String(*v.SSECustomerAlgorithm) + } + + if v.SSECustomerKey != nil && len(*v.SSECustomerKey) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Key" + encoder.SetHeader(locationName).String(*v.SSECustomerKey) + } + + if v.SSECustomerKeyMD5 != nil && len(*v.SSECustomerKeyMD5) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Key-Md5" + encoder.SetHeader(locationName).String(*v.SSECustomerKeyMD5) + } + if v.UploadId != nil { encoder.SetQuery("uploadId").String(*v.UploadId) } @@ -272,6 +308,11 @@ func awsRestxml_serializeOpHttpBindingsCopyObjectInput(v *CopyObjectInput, encod encoder.SetHeader(locationName).String(*v.CacheControl) } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentDisposition != nil && len(*v.ContentDisposition) > 0 { locationName := "Content-Disposition" encoder.SetHeader(locationName).String(*v.ContentDisposition) @@ -654,6 +695,11 @@ func awsRestxml_serializeOpHttpBindingsCreateMultipartUploadInput(v *CreateMulti encoder.SetHeader(locationName).String(*v.CacheControl) } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentDisposition != nil && len(*v.ContentDisposition) > 0 { locationName := "Content-Disposition" encoder.SetHeader(locationName).String(*v.ContentDisposition) @@ -1794,6 +1840,11 @@ func awsRestxml_serializeOpHttpBindingsDeleteObjectsInput(v *DeleteObjectsInput, encoder.SetHeader(locationName).Boolean(v.BypassGovernanceRetention) } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { locationName := "X-Amz-Expected-Bucket-Owner" encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) @@ -3277,6 +3328,11 @@ func awsRestxml_serializeOpHttpBindingsGetObjectInput(v *GetObjectInput, encoder } } + if len(v.ChecksumMode) > 0 { + locationName := "X-Amz-Checksum-Mode" + encoder.SetHeader(locationName).String(string(v.ChecksumMode)) + } + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { locationName := "X-Amz-Expected-Bucket-Owner" encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) @@ -3452,6 +3508,126 @@ func awsRestxml_serializeOpHttpBindingsGetObjectAclInput(v *GetObjectAclInput, e return nil } +type awsRestxml_serializeOpGetObjectAttributes struct { +} + +func (*awsRestxml_serializeOpGetObjectAttributes) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpGetObjectAttributes) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*GetObjectAttributesInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/{Bucket}/{Key+}?attributes") + request.URL.Path = smithyhttp.JoinPath(request.URL.Path, opPath) + request.URL.RawQuery = smithyhttp.JoinRawQuery(request.URL.RawQuery, opQuery) + request.Method = "GET" + restEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if err := awsRestxml_serializeOpHttpBindingsGetObjectAttributesInput(input, restEncoder); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsGetObjectAttributesInput(v *GetObjectAttributesInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + if v.Bucket == nil || len(*v.Bucket) == 0 { + return &smithy.SerializationError{Err: fmt.Errorf("input member Bucket must not be empty")} + } + if v.Bucket != nil { + if err := encoder.SetURI("Bucket").String(*v.Bucket); err != nil { + return err + } + } + + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { + locationName := "X-Amz-Expected-Bucket-Owner" + encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) + } + + if v.Key == nil || len(*v.Key) == 0 { + return &smithy.SerializationError{Err: fmt.Errorf("input member Key must not be empty")} + } + if v.Key != nil { + if err := encoder.SetURI("Key").String(*v.Key); err != nil { + return err + } + } + + if v.MaxParts != 0 { + locationName := "X-Amz-Max-Parts" + encoder.SetHeader(locationName).Integer(v.MaxParts) + } + + if v.ObjectAttributes != nil { + locationName := "X-Amz-Object-Attributes" + for i := range v.ObjectAttributes { + if len(v.ObjectAttributes[i]) > 0 { + escaped := string(v.ObjectAttributes[i]) + if strings.Index(string(v.ObjectAttributes[i]), `,`) != -1 || strings.Index(string(v.ObjectAttributes[i]), `"`) != -1 { + escaped = strconv.Quote(string(v.ObjectAttributes[i])) + } + + encoder.AddHeader(locationName).String(string(escaped)) + } + } + } + + if v.PartNumberMarker != nil && len(*v.PartNumberMarker) > 0 { + locationName := "X-Amz-Part-Number-Marker" + encoder.SetHeader(locationName).String(*v.PartNumberMarker) + } + + if len(v.RequestPayer) > 0 { + locationName := "X-Amz-Request-Payer" + encoder.SetHeader(locationName).String(string(v.RequestPayer)) + } + + if v.SSECustomerAlgorithm != nil && len(*v.SSECustomerAlgorithm) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Algorithm" + encoder.SetHeader(locationName).String(*v.SSECustomerAlgorithm) + } + + if v.SSECustomerKey != nil && len(*v.SSECustomerKey) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Key" + encoder.SetHeader(locationName).String(*v.SSECustomerKey) + } + + if v.SSECustomerKeyMD5 != nil && len(*v.SSECustomerKeyMD5) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Key-Md5" + encoder.SetHeader(locationName).String(*v.SSECustomerKeyMD5) + } + + if v.VersionId != nil { + encoder.SetQuery("versionId").String(*v.VersionId) + } + + return nil +} + type awsRestxml_serializeOpGetObjectLegalHold struct { } @@ -4016,6 +4192,11 @@ func awsRestxml_serializeOpHttpBindingsHeadObjectInput(v *HeadObjectInput, encod } } + if len(v.ChecksumMode) > 0 { + locationName := "X-Amz-Checksum-Mode" + encoder.SetHeader(locationName).String(string(v.ChecksumMode)) + } + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { locationName := "X-Amz-Expected-Bucket-Owner" encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) @@ -4834,6 +5015,21 @@ func awsRestxml_serializeOpHttpBindingsListPartsInput(v *ListPartsInput, encoder encoder.SetHeader(locationName).String(string(v.RequestPayer)) } + if v.SSECustomerAlgorithm != nil && len(*v.SSECustomerAlgorithm) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Algorithm" + encoder.SetHeader(locationName).String(*v.SSECustomerAlgorithm) + } + + if v.SSECustomerKey != nil && len(*v.SSECustomerKey) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Key" + encoder.SetHeader(locationName).String(*v.SSECustomerKey) + } + + if v.SSECustomerKeyMD5 != nil && len(*v.SSECustomerKeyMD5) > 0 { + locationName := "X-Amz-Server-Side-Encryption-Customer-Key-Md5" + encoder.SetHeader(locationName).String(*v.SSECustomerKeyMD5) + } + if v.UploadId != nil { encoder.SetQuery("uploadId").String(*v.UploadId) } @@ -4919,6 +5115,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketAccelerateConfigurationInput(v * } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { locationName := "X-Amz-Expected-Bucket-Owner" encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) @@ -5010,6 +5211,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketAclInput(v *PutBucketAclInput, e } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -5216,6 +5422,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketCorsInput(v *PutBucketCorsInput, } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -5307,6 +5518,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketEncryptionInput(v *PutBucketEncr } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -5573,6 +5789,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketLifecycleConfigurationInput(v *P } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { locationName := "X-Amz-Expected-Bucket-Owner" encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) @@ -5659,6 +5880,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketLoggingInput(v *PutBucketLogging } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -6010,6 +6236,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketPolicyInput(v *PutBucketPolicyIn } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ConfirmRemoveSelfBucketAccess { locationName := "X-Amz-Confirm-Remove-Self-Bucket-Access" encoder.SetHeader(locationName).Boolean(v.ConfirmRemoveSelfBucketAccess) @@ -6106,6 +6337,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketReplicationInput(v *PutBucketRep } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -6202,6 +6438,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketRequestPaymentInput(v *PutBucket } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -6293,6 +6534,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketTaggingInput(v *PutBucketTagging } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -6384,6 +6630,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketVersioningInput(v *PutBucketVers } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -6480,6 +6731,11 @@ func awsRestxml_serializeOpHttpBindingsPutBucketWebsiteInput(v *PutBucketWebsite } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -6574,6 +6830,31 @@ func awsRestxml_serializeOpHttpBindingsPutObjectInput(v *PutObjectInput, encoder encoder.SetHeader(locationName).String(*v.CacheControl) } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + + if v.ChecksumCRC32 != nil && len(*v.ChecksumCRC32) > 0 { + locationName := "X-Amz-Checksum-Crc32" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32) + } + + if v.ChecksumCRC32C != nil && len(*v.ChecksumCRC32C) > 0 { + locationName := "X-Amz-Checksum-Crc32c" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32C) + } + + if v.ChecksumSHA1 != nil && len(*v.ChecksumSHA1) > 0 { + locationName := "X-Amz-Checksum-Sha1" + encoder.SetHeader(locationName).String(*v.ChecksumSHA1) + } + + if v.ChecksumSHA256 != nil && len(*v.ChecksumSHA256) > 0 { + locationName := "X-Amz-Checksum-Sha256" + encoder.SetHeader(locationName).String(*v.ChecksumSHA256) + } + if v.ContentDisposition != nil && len(*v.ContentDisposition) > 0 { locationName := "Content-Disposition" encoder.SetHeader(locationName).String(*v.ContentDisposition) @@ -6803,6 +7084,11 @@ func awsRestxml_serializeOpHttpBindingsPutObjectAclInput(v *PutObjectAclInput, e } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -6937,6 +7223,11 @@ func awsRestxml_serializeOpHttpBindingsPutObjectLegalHoldInput(v *PutObjectLegal } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -7046,6 +7337,11 @@ func awsRestxml_serializeOpHttpBindingsPutObjectLockConfigurationInput(v *PutObj } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -7152,6 +7448,11 @@ func awsRestxml_serializeOpHttpBindingsPutObjectRetentionInput(v *PutObjectReten encoder.SetHeader(locationName).Boolean(v.BypassGovernanceRetention) } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -7261,6 +7562,11 @@ func awsRestxml_serializeOpHttpBindingsPutObjectTaggingInput(v *PutObjectTagging } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -7370,6 +7676,11 @@ func awsRestxml_serializeOpHttpBindingsPutPublicAccessBlockInput(v *PutPublicAcc } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ContentMD5 != nil && len(*v.ContentMD5) > 0 { locationName := "Content-Md5" encoder.SetHeader(locationName).String(*v.ContentMD5) @@ -7461,6 +7772,11 @@ func awsRestxml_serializeOpHttpBindingsRestoreObjectInput(v *RestoreObjectInput, } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + if v.ExpectedBucketOwner != nil && len(*v.ExpectedBucketOwner) > 0 { locationName := "X-Amz-Expected-Bucket-Owner" encoder.SetHeader(locationName).String(*v.ExpectedBucketOwner) @@ -7737,6 +8053,31 @@ func awsRestxml_serializeOpHttpBindingsUploadPartInput(v *UploadPartInput, encod } } + if len(v.ChecksumAlgorithm) > 0 { + locationName := "X-Amz-Sdk-Checksum-Algorithm" + encoder.SetHeader(locationName).String(string(v.ChecksumAlgorithm)) + } + + if v.ChecksumCRC32 != nil && len(*v.ChecksumCRC32) > 0 { + locationName := "X-Amz-Checksum-Crc32" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32) + } + + if v.ChecksumCRC32C != nil && len(*v.ChecksumCRC32C) > 0 { + locationName := "X-Amz-Checksum-Crc32c" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32C) + } + + if v.ChecksumSHA1 != nil && len(*v.ChecksumSHA1) > 0 { + locationName := "X-Amz-Checksum-Sha1" + encoder.SetHeader(locationName).String(*v.ChecksumSHA1) + } + + if v.ChecksumSHA256 != nil && len(*v.ChecksumSHA256) > 0 { + locationName := "X-Amz-Checksum-Sha256" + encoder.SetHeader(locationName).String(*v.ChecksumSHA256) + } + if v.ContentLength != 0 { locationName := "Content-Length" encoder.SetHeader(locationName).Long(v.ContentLength) @@ -8014,6 +8355,26 @@ func awsRestxml_serializeOpHttpBindingsWriteGetObjectResponseInput(v *WriteGetOb encoder.SetHeader(locationName).String(*v.CacheControl) } + if v.ChecksumCRC32 != nil && len(*v.ChecksumCRC32) > 0 { + locationName := "X-Amz-Fwd-Header-X-Amz-Checksum-Crc32" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32) + } + + if v.ChecksumCRC32C != nil && len(*v.ChecksumCRC32C) > 0 { + locationName := "X-Amz-Fwd-Header-X-Amz-Checksum-Crc32c" + encoder.SetHeader(locationName).String(*v.ChecksumCRC32C) + } + + if v.ChecksumSHA1 != nil && len(*v.ChecksumSHA1) > 0 { + locationName := "X-Amz-Fwd-Header-X-Amz-Checksum-Sha1" + encoder.SetHeader(locationName).String(*v.ChecksumSHA1) + } + + if v.ChecksumSHA256 != nil && len(*v.ChecksumSHA256) > 0 { + locationName := "X-Amz-Fwd-Header-X-Amz-Checksum-Sha256" + encoder.SetHeader(locationName).String(*v.ChecksumSHA256) + } + if v.ContentDisposition != nil && len(*v.ContentDisposition) > 0 { locationName := "X-Amz-Fwd-Header-Content-Disposition" encoder.SetHeader(locationName).String(*v.ContentDisposition) @@ -8540,6 +8901,50 @@ func awsRestxml_serializeDocumentCompletedMultipartUpload(v *types.CompletedMult func awsRestxml_serializeDocumentCompletedPart(v *types.CompletedPart, value smithyxml.Value) error { defer value.Close() + if v.ChecksumCRC32 != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "ChecksumCRC32", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.String(*v.ChecksumCRC32) + } + if v.ChecksumCRC32C != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "ChecksumCRC32C", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.String(*v.ChecksumCRC32C) + } + if v.ChecksumSHA1 != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "ChecksumSHA1", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.String(*v.ChecksumSHA1) + } + if v.ChecksumSHA256 != nil { + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "ChecksumSHA256", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + el.String(*v.ChecksumSHA256) + } if v.ETag != nil { rootAttr := []smithyxml.Attr{} root := smithyxml.StartElement{ diff --git a/service/s3/types/enums.go b/service/s3/types/enums.go index fa75ab8f4bc..5b5254083eb 100644 --- a/service/s3/types/enums.go +++ b/service/s3/types/enums.go @@ -178,6 +178,44 @@ func (BucketVersioningStatus) Values() []BucketVersioningStatus { } } +type ChecksumAlgorithm string + +// Enum values for ChecksumAlgorithm +const ( + ChecksumAlgorithmCrc32 ChecksumAlgorithm = "CRC32" + ChecksumAlgorithmCrc32c ChecksumAlgorithm = "CRC32C" + ChecksumAlgorithmSha1 ChecksumAlgorithm = "SHA1" + ChecksumAlgorithmSha256 ChecksumAlgorithm = "SHA256" +) + +// Values returns all known values for ChecksumAlgorithm. Note that this can be +// expanded in the future, and so it is only as up to date as the client. The +// ordering of this slice is not guaranteed to be stable across updates. +func (ChecksumAlgorithm) Values() []ChecksumAlgorithm { + return []ChecksumAlgorithm{ + "CRC32", + "CRC32C", + "SHA1", + "SHA256", + } +} + +type ChecksumMode string + +// Enum values for ChecksumMode +const ( + ChecksumModeEnabled ChecksumMode = "ENABLED" +) + +// Values returns all known values for ChecksumMode. Note that this can be expanded +// in the future, and so it is only as up to date as the client. The ordering of +// this slice is not guaranteed to be stable across updates. +func (ChecksumMode) Values() []ChecksumMode { + return []ChecksumMode{ + "ENABLED", + } +} + type CompressionType string // Enum values for CompressionType @@ -470,6 +508,7 @@ const ( InventoryOptionalFieldObjectLockLegalHoldStatus InventoryOptionalField = "ObjectLockLegalHoldStatus" InventoryOptionalFieldIntelligentTieringAccessTier InventoryOptionalField = "IntelligentTieringAccessTier" InventoryOptionalFieldBucketKeyStatus InventoryOptionalField = "BucketKeyStatus" + InventoryOptionalFieldChecksumAlgorithm InventoryOptionalField = "ChecksumAlgorithm" ) // Values returns all known values for InventoryOptionalField. Note that this can @@ -489,6 +528,7 @@ func (InventoryOptionalField) Values() []InventoryOptionalField { "ObjectLockLegalHoldStatus", "IntelligentTieringAccessTier", "BucketKeyStatus", + "ChecksumAlgorithm", } } @@ -582,6 +622,30 @@ func (MFADeleteStatus) Values() []MFADeleteStatus { } } +type ObjectAttributes string + +// Enum values for ObjectAttributes +const ( + ObjectAttributesEtag ObjectAttributes = "ETag" + ObjectAttributesChecksum ObjectAttributes = "Checksum" + ObjectAttributesObjectParts ObjectAttributes = "ObjectParts" + ObjectAttributesStorageClass ObjectAttributes = "StorageClass" + ObjectAttributesObjectSize ObjectAttributes = "ObjectSize" +) + +// Values returns all known values for ObjectAttributes. Note that this can be +// expanded in the future, and so it is only as up to date as the client. The +// ordering of this slice is not guaranteed to be stable across updates. +func (ObjectAttributes) Values() []ObjectAttributes { + return []ObjectAttributes{ + "ETag", + "Checksum", + "ObjectParts", + "StorageClass", + "ObjectSize", + } +} + type ObjectCannedACL string // Enum values for ObjectCannedACL diff --git a/service/s3/types/types.go b/service/s3/types/types.go index 83dc0389cd2..422e630c341 100644 --- a/service/s3/types/types.go +++ b/service/s3/types/types.go @@ -215,6 +215,44 @@ type BucketLoggingStatus struct { noSmithyDocumentSerde } +// Contains all the possible checksum or digest values for an object. +type Checksum struct { + + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + + noSmithyDocumentSerde +} + // Container for all (if there are any) keys between Prefix and the next occurrence // of the string specified by a delimiter. CommonPrefixes lists keys that act like // subdirectories in the directory specified by Prefix. For example, if the prefix @@ -241,6 +279,38 @@ type CompletedMultipartUpload struct { // Details of the parts that were uploaded. type CompletedPart struct { + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Entity tag returned when the part was uploaded. ETag *string @@ -287,6 +357,38 @@ type ContinuationEvent struct { // Container for all response elements. type CopyObjectResult struct { + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Returns the ETag of the new object. The ETag reflects only changes to the // contents of an object, not its metadata. ETag *string @@ -300,6 +402,38 @@ type CopyObjectResult struct { // Container for all response elements. type CopyPartResult struct { + // The base64-encoded, 32-bit CRC32 checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Entity tag of the object. ETag *string @@ -1658,6 +1792,35 @@ type FilterRule struct { noSmithyDocumentSerde } +// A collection of parts associated with a multipart upload. +type GetObjectAttributesParts struct { + + // Indicates whether the returned list of parts is truncated. A value of true + // indicates that the list was truncated. A list can be truncated if the number of + // parts exceeds the limit returned in the MaxParts element. + IsTruncated bool + + // The maximum number of parts allowed in the response. + MaxParts int32 + + // When a list is truncated, this element specifies the last part in the list, as + // well as the value to use for the PartNumberMarker request parameter in a + // subsequent request. + NextPartNumberMarker *string + + // The marker for the current part. + PartNumberMarker *string + + // A container for elements related to a particular part. A response can contain + // zero or more Parts elements. + Parts []ObjectPart + + // The total number of parts. + TotalPartsCount int32 + + noSmithyDocumentSerde +} + // Container for S3 Glacier job parameters. type GlacierJobParameters struct { @@ -2060,7 +2223,7 @@ type LifecycleRule struct { // The Filter is used to identify objects that a Lifecycle Rule applies to. A // Filter must have exactly one of Prefix, Tag, or And specified. Filter is - // required if the LifecycleRule does not containt a Prefix element. + // required if the LifecycleRule does not contain a Prefix element. Filter LifecycleRuleFilter // Unique identifier for the rule. The value cannot be longer than 255 characters. @@ -2335,6 +2498,9 @@ func (*MetricsFilterMemberTag) isMetricsFilter() {} // Container for the MultipartUpload for the Amazon S3 object. type MultipartUpload struct { + // The algorithm that was used to create a checksum of the object. + ChecksumAlgorithm ChecksumAlgorithm + // Date and time at which the multipart upload was initiated. Initiated *time.Time @@ -2449,6 +2615,9 @@ type NotificationConfigurationFilter struct { // An object consists of data and its descriptive metadata. type Object struct { + // The algorithm that was used to create a checksum of the object. + ChecksumAlgorithm []ChecksumAlgorithm + // The entity tag is a hash of the object. The ETag reflects changes only to the // contents of an object, not its metadata. The ETag may or may not be an MD5 // digest of the object data. Whether or not it is depends on how the object was @@ -2521,10 +2690,10 @@ type ObjectLockConfiguration struct { noSmithyDocumentSerde } -// A Legal Hold configuration for an object. +// A legal hold configuration for an object. type ObjectLockLegalHold struct { - // Indicates whether the specified object has a Legal Hold in place. + // Indicates whether the specified object has a legal hold in place. Status ObjectLockLegalHoldStatus noSmithyDocumentSerde @@ -2554,9 +2723,57 @@ type ObjectLockRule struct { noSmithyDocumentSerde } +// A container for elements related to an individual part. +type ObjectPart struct { + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32 checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // The base64-encoded, 256-bit SHA-256 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + + // The part number identifying the part. This value is a positive integer between 1 + // and 10,000. + PartNumber int32 + + // The size of the uploaded part in bytes. + Size int64 + + noSmithyDocumentSerde +} + // The version of an object. type ObjectVersion struct { + // The algorithm that was used to create a checksum of the object. + ChecksumAlgorithm []ChecksumAlgorithm + // The entity tag is an MD5 hash of that version of the object. ETag *string @@ -2658,6 +2875,38 @@ type ParquetInput struct { // Container for elements related to a part. type Part struct { + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 32-bit CRC32 checksum of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumCRC32 *string + + // The base64-encoded, 32-bit CRC32C checksum of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumCRC32C *string + + // The base64-encoded, 160-bit SHA-1 digest of the object. This will only be + // present if it was uploaded with the object. With multipart uploads, this may not + // be a checksum value of the object. For more information about how checksums are + // calculated with multipart uploads, see Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums) + // in the Amazon S3 User Guide. + ChecksumSHA1 *string + + // This header can be used as a data integrity check to verify that the data + // received is the same data that was originally sent. This header specifies the + // base64-encoded, 256-bit SHA-256 digest of the object. For more information, see + // Checking object integrity + // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html) + // in the Amazon S3 User Guide. + ChecksumSHA256 *string + // Entity tag returned when the part was uploaded. ETag *string @@ -2720,7 +2969,7 @@ type PublicAccessBlockConfiguration struct { // this bucket and objects in this bucket. Setting this element to TRUE causes the // following behavior: // - // * PUT Bucket acl and PUT Object acl calls fail if the + // * PUT Bucket ACL and PUT Object ACL calls fail if the // specified ACL is public. // // * PUT Object calls fail if the request includes a @@ -3190,7 +3439,7 @@ type ScanRange struct { // Specifies the start of the byte range. This parameter is optional. Valid values: // non-negative integers. The default value is 0. If only start is supplied, it - // means scan from that point to the end of the file.For example; 50 means scan + // means scan from that point to the end of the file. For example, 50 means scan // from byte 50 until the end of the file. Start int64 diff --git a/service/s3/validators.go b/service/s3/validators.go index a711ea619c7..ccd845a71e9 100644 --- a/service/s3/validators.go +++ b/service/s3/validators.go @@ -870,6 +870,26 @@ func (m *validateOpGetObjectAcl) HandleInitialize(ctx context.Context, in middle return next.HandleInitialize(ctx, in) } +type validateOpGetObjectAttributes struct { +} + +func (*validateOpGetObjectAttributes) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpGetObjectAttributes) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*GetObjectAttributesInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpGetObjectAttributesInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + type validateOpGetObject struct { } @@ -2002,6 +2022,10 @@ func addOpGetObjectAclValidationMiddleware(stack *middleware.Stack) error { return stack.Initialize.Add(&validateOpGetObjectAcl{}, middleware.After) } +func addOpGetObjectAttributesValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpGetObjectAttributes{}, middleware.After) +} + func addOpGetObjectValidationMiddleware(stack *middleware.Stack) error { return stack.Initialize.Add(&validateOpGetObject{}, middleware.After) } @@ -4511,6 +4535,27 @@ func validateOpGetObjectAclInput(v *GetObjectAclInput) error { } } +func validateOpGetObjectAttributesInput(v *GetObjectAttributesInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "GetObjectAttributesInput"} + if v.Bucket == nil { + invalidParams.Add(smithy.NewErrParamRequired("Bucket")) + } + if v.Key == nil { + invalidParams.Add(smithy.NewErrParamRequired("Key")) + } + if v.ObjectAttributes == nil { + invalidParams.Add(smithy.NewErrParamRequired("ObjectAttributes")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} + func validateOpGetObjectInput(v *GetObjectInput) error { if v == nil { return nil