aws-sdk-s3 1.79.1 → 1.212.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1548 -0
- data/LICENSE.txt +202 -0
- data/VERSION +1 -0
- data/lib/aws-sdk-s3/access_grants_credentials.rb +57 -0
- data/lib/aws-sdk-s3/access_grants_credentials_provider.rb +250 -0
- data/lib/aws-sdk-s3/bucket.rb +900 -98
- data/lib/aws-sdk-s3/bucket_acl.rb +44 -10
- data/lib/aws-sdk-s3/bucket_cors.rb +51 -11
- data/lib/aws-sdk-s3/bucket_lifecycle.rb +53 -8
- data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +107 -9
- data/lib/aws-sdk-s3/bucket_logging.rb +43 -6
- data/lib/aws-sdk-s3/bucket_notification.rb +32 -9
- data/lib/aws-sdk-s3/bucket_policy.rb +90 -6
- data/lib/aws-sdk-s3/bucket_region_cache.rb +9 -5
- data/lib/aws-sdk-s3/bucket_request_payment.rb +38 -8
- data/lib/aws-sdk-s3/bucket_tagging.rb +46 -7
- data/lib/aws-sdk-s3/bucket_versioning.rb +127 -9
- data/lib/aws-sdk-s3/bucket_website.rb +46 -7
- data/lib/aws-sdk-s3/client.rb +13729 -3146
- data/lib/aws-sdk-s3/client_api.rb +1604 -277
- data/lib/aws-sdk-s3/customizations/bucket.rb +31 -47
- data/lib/aws-sdk-s3/customizations/errors.rb +40 -0
- data/lib/aws-sdk-s3/customizations/object.rb +253 -82
- data/lib/aws-sdk-s3/customizations/object_summary.rb +5 -0
- data/lib/aws-sdk-s3/customizations/object_version.rb +13 -0
- data/lib/aws-sdk-s3/customizations/types/permanent_redirect.rb +26 -0
- data/lib/aws-sdk-s3/customizations.rb +28 -29
- data/lib/aws-sdk-s3/default_executor.rb +103 -0
- data/lib/aws-sdk-s3/encryption/client.rb +9 -5
- data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +0 -4
- data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +2 -0
- data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +2 -0
- data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +15 -9
- data/lib/aws-sdk-s3/encryptionV2/client.rb +105 -26
- data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +7 -165
- data/lib/aws-sdk-s3/encryptionV2/decryption.rb +205 -0
- data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +20 -3
- data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +2 -4
- data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +2 -0
- data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +18 -6
- data/lib/aws-sdk-s3/encryptionV2/utils.rb +5 -0
- data/lib/aws-sdk-s3/encryptionV3/client.rb +885 -0
- data/lib/aws-sdk-s3/encryptionV3/decrypt_handler.rb +98 -0
- data/lib/aws-sdk-s3/encryptionV3/decryption.rb +244 -0
- data/lib/aws-sdk-s3/encryptionV3/default_cipher_provider.rb +159 -0
- data/lib/aws-sdk-s3/encryptionV3/default_key_provider.rb +35 -0
- data/lib/aws-sdk-s3/encryptionV3/encrypt_handler.rb +98 -0
- data/lib/aws-sdk-s3/encryptionV3/errors.rb +47 -0
- data/lib/aws-sdk-s3/encryptionV3/io_auth_decrypter.rb +60 -0
- data/lib/aws-sdk-s3/encryptionV3/io_decrypter.rb +35 -0
- data/lib/aws-sdk-s3/encryptionV3/io_encrypter.rb +84 -0
- data/lib/aws-sdk-s3/encryptionV3/key_provider.rb +28 -0
- data/lib/aws-sdk-s3/encryptionV3/kms_cipher_provider.rb +159 -0
- data/lib/aws-sdk-s3/encryptionV3/materials.rb +58 -0
- data/lib/aws-sdk-s3/encryptionV3/utils.rb +321 -0
- data/lib/aws-sdk-s3/encryption_v2.rb +1 -0
- data/lib/aws-sdk-s3/encryption_v3.rb +24 -0
- data/lib/aws-sdk-s3/endpoint_parameters.rb +181 -0
- data/lib/aws-sdk-s3/endpoint_provider.rb +889 -0
- data/lib/aws-sdk-s3/endpoints.rb +1544 -0
- data/lib/aws-sdk-s3/errors.rb +80 -1
- data/lib/aws-sdk-s3/event_streams.rb +1 -1
- data/lib/aws-sdk-s3/express_credentials.rb +55 -0
- data/lib/aws-sdk-s3/express_credentials_provider.rb +59 -0
- data/lib/aws-sdk-s3/file_downloader.rb +258 -82
- data/lib/aws-sdk-s3/file_uploader.rb +25 -14
- data/lib/aws-sdk-s3/legacy_signer.rb +17 -26
- data/lib/aws-sdk-s3/multipart_download_error.rb +8 -0
- data/lib/aws-sdk-s3/multipart_file_uploader.rb +111 -86
- data/lib/aws-sdk-s3/multipart_stream_uploader.rb +110 -92
- data/lib/aws-sdk-s3/multipart_upload.rb +304 -14
- data/lib/aws-sdk-s3/multipart_upload_error.rb +3 -4
- data/lib/aws-sdk-s3/multipart_upload_part.rb +344 -20
- data/lib/aws-sdk-s3/object.rb +2457 -225
- data/lib/aws-sdk-s3/object_acl.rb +76 -15
- data/lib/aws-sdk-s3/object_copier.rb +7 -5
- data/lib/aws-sdk-s3/object_multipart_copier.rb +48 -23
- data/lib/aws-sdk-s3/object_summary.rb +2033 -169
- data/lib/aws-sdk-s3/object_version.rb +470 -53
- data/lib/aws-sdk-s3/plugins/accelerate.rb +1 -39
- data/lib/aws-sdk-s3/plugins/access_grants.rb +178 -0
- data/lib/aws-sdk-s3/plugins/arn.rb +70 -0
- data/lib/aws-sdk-s3/plugins/bucket_dns.rb +3 -41
- data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +1 -6
- data/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +44 -0
- data/lib/aws-sdk-s3/plugins/dualstack.rb +2 -49
- data/lib/aws-sdk-s3/plugins/endpoints.rb +86 -0
- data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +3 -1
- data/lib/aws-sdk-s3/plugins/express_session_auth.rb +88 -0
- data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +1 -1
- data/lib/aws-sdk-s3/plugins/http_200_errors.rb +87 -26
- data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +8 -26
- data/lib/aws-sdk-s3/plugins/location_constraint.rb +3 -1
- data/lib/aws-sdk-s3/plugins/md5s.rb +10 -68
- data/lib/aws-sdk-s3/plugins/s3_signer.rb +48 -88
- data/lib/aws-sdk-s3/plugins/streaming_retry.rb +28 -9
- data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -1
- data/lib/aws-sdk-s3/presigned_post.rb +99 -78
- data/lib/aws-sdk-s3/presigner.rb +50 -42
- data/lib/aws-sdk-s3/resource.rb +144 -15
- data/lib/aws-sdk-s3/transfer_manager.rb +321 -0
- data/lib/aws-sdk-s3/types.rb +12223 -4723
- data/lib/aws-sdk-s3/waiters.rb +1 -1
- data/lib/aws-sdk-s3.rb +37 -28
- data/sig/bucket.rbs +231 -0
- data/sig/bucket_acl.rbs +78 -0
- data/sig/bucket_cors.rbs +69 -0
- data/sig/bucket_lifecycle.rbs +88 -0
- data/sig/bucket_lifecycle_configuration.rbs +115 -0
- data/sig/bucket_logging.rbs +76 -0
- data/sig/bucket_notification.rbs +114 -0
- data/sig/bucket_policy.rbs +59 -0
- data/sig/bucket_request_payment.rbs +54 -0
- data/sig/bucket_tagging.rbs +65 -0
- data/sig/bucket_versioning.rbs +77 -0
- data/sig/bucket_website.rbs +93 -0
- data/sig/client.rbs +2612 -0
- data/sig/customizations/bucket.rbs +19 -0
- data/sig/customizations/object.rbs +38 -0
- data/sig/customizations/object_summary.rbs +35 -0
- data/sig/errors.rbs +44 -0
- data/sig/multipart_upload.rbs +120 -0
- data/sig/multipart_upload_part.rbs +109 -0
- data/sig/object.rbs +464 -0
- data/sig/object_acl.rbs +86 -0
- data/sig/object_summary.rbs +347 -0
- data/sig/object_version.rbs +143 -0
- data/sig/resource.rbs +141 -0
- data/sig/types.rbs +2899 -0
- data/sig/waiters.rbs +95 -0
- metadata +74 -16
- data/lib/aws-sdk-s3/plugins/bucket_arn.rb +0 -212
|
@@ -11,7 +11,7 @@ module Aws
|
|
|
11
11
|
@handler.call(context).on(200) do |response|
|
|
12
12
|
response.data = S3::Types::GetBucketLocationOutput.new
|
|
13
13
|
xml = context.http_response.body_contents
|
|
14
|
-
matches = xml.match(
|
|
14
|
+
matches = xml.match(/<LocationConstraint.*?>(.+?)<\/LocationConstraint>/)
|
|
15
15
|
response.data[:location_constraint] = matches ? matches[1] : ''
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -3,52 +3,113 @@
|
|
|
3
3
|
module Aws
|
|
4
4
|
module S3
|
|
5
5
|
module Plugins
|
|
6
|
-
|
|
7
6
|
# A handful of Amazon S3 operations will respond with a 200 status
|
|
8
7
|
# code but will send an error in the response body. This plugin
|
|
9
8
|
# injects a handler that will parse 200 response bodies for potential
|
|
10
9
|
# errors, allowing them to be retried.
|
|
11
10
|
# @api private
|
|
12
11
|
class Http200Errors < Seahorse::Client::Plugin
|
|
13
|
-
|
|
14
12
|
class Handler < Seahorse::Client::Handler
|
|
13
|
+
# A regular expression to match error codes in the response body
|
|
14
|
+
CODE_PATTERN = %r{<Code>(.+?)</Code>}.freeze
|
|
15
|
+
private_constant :CODE_PATTERN
|
|
16
|
+
|
|
17
|
+
# A list of encodings we force into UTF-8
|
|
18
|
+
ENCODINGS_TO_FIX = [Encoding::US_ASCII, Encoding::ASCII_8BIT].freeze
|
|
19
|
+
private_constant :ENCODINGS_TO_FIX
|
|
20
|
+
|
|
21
|
+
# A regular expression to match detect errors in the response body
|
|
22
|
+
ERROR_PATTERN = /<\?xml\s[^>]*\?>\s*<Error>/.freeze
|
|
23
|
+
private_constant :ERROR_PATTERN
|
|
24
|
+
|
|
25
|
+
# A regular expression to match an error message in the response body
|
|
26
|
+
MESSAGE_PATTERN = %r{<Message>(.+?)</Message>}.freeze
|
|
27
|
+
private_constant :MESSAGE_PATTERN
|
|
15
28
|
|
|
16
29
|
def call(context)
|
|
17
30
|
@handler.call(context).on(200) do |response|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
return response if streaming_output?(context.operation.output)
|
|
32
|
+
|
|
33
|
+
error = check_for_error(context)
|
|
34
|
+
return response unless error
|
|
35
|
+
|
|
36
|
+
context.http_response.status_code = 500
|
|
37
|
+
response.data = nil
|
|
38
|
+
response.error = error
|
|
23
39
|
end
|
|
24
40
|
end
|
|
25
41
|
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def build_error(context, code, message)
|
|
45
|
+
S3::Errors.error_class(code).new(context, message)
|
|
46
|
+
end
|
|
47
|
+
|
|
26
48
|
def check_for_error(context)
|
|
27
|
-
xml = context.http_response.body_contents
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
xml = normalize_encoding(context.http_response.body_contents)
|
|
50
|
+
|
|
51
|
+
if xml.match?(ERROR_PATTERN)
|
|
52
|
+
error_code = xml.match(CODE_PATTERN)[1]
|
|
53
|
+
error_message = xml.match(MESSAGE_PATTERN)[1]
|
|
54
|
+
build_error(context, error_code, error_message)
|
|
55
|
+
elsif incomplete_xml_body?(xml, context.operation.output)
|
|
34
56
|
Seahorse::Client::NetworkingError.new(
|
|
35
|
-
|
|
36
|
-
.error_class('InternalError')
|
|
37
|
-
.new(context, 'Empty or incomplete response body')
|
|
57
|
+
build_error(context, 'InternalError', 'Empty or incomplete response body')
|
|
38
58
|
)
|
|
39
59
|
end
|
|
40
60
|
end
|
|
61
|
+
|
|
62
|
+
# Must have a member in the body and have the start of an XML Tag.
|
|
63
|
+
# Other incomplete xml bodies will result in an XML ParsingError.
|
|
64
|
+
def incomplete_xml_body?(xml, output)
|
|
65
|
+
members_in_body?(output) && !xml.match(/<\w/)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Checks if the output shape is a structure shape and has members that
|
|
69
|
+
# are in the body for the case of a payload and a normal structure. A
|
|
70
|
+
# non-structure shape will not have members in the body. In the case
|
|
71
|
+
# of a string or blob, the body contents would have been checked first
|
|
72
|
+
# before this method is called in incomplete_xml_body?.
|
|
73
|
+
def members_in_body?(output)
|
|
74
|
+
shape = resolve_shape(output)
|
|
75
|
+
|
|
76
|
+
if structure_shape?(shape)
|
|
77
|
+
shape.members.any? { |_, k| k.location.nil? }
|
|
78
|
+
else
|
|
79
|
+
false
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Fixes encoding issues when S3 returns UTF-8 content with missing charset in Content-Type header or omits
|
|
84
|
+
# Content-Type header entirely. Net::HTTP defaults to US-ASCII or ASCII-8BIT when charset is unspecified.
|
|
85
|
+
def normalize_encoding(xml)
|
|
86
|
+
return xml unless xml.is_a?(String) && ENCODINGS_TO_FIX.include?(xml.encoding)
|
|
87
|
+
|
|
88
|
+
xml.force_encoding('UTF-8')
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def resolve_shape(output)
|
|
92
|
+
return output.shape unless output[:payload_member]
|
|
93
|
+
|
|
94
|
+
output[:payload_member].shape
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Streaming outputs are not subject to 200 errors.
|
|
98
|
+
def streaming_output?(output)
|
|
99
|
+
if (payload = output[:payload_member])
|
|
100
|
+
# checking ref and shape
|
|
101
|
+
payload['streaming'] || payload.shape['streaming'] || payload.eventstream
|
|
102
|
+
else
|
|
103
|
+
false
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def structure_shape?(shape)
|
|
108
|
+
shape.is_a?(Seahorse::Model::Shapes::StructureShape)
|
|
109
|
+
end
|
|
41
110
|
end
|
|
42
111
|
|
|
43
|
-
handler(
|
|
44
|
-
Handler,
|
|
45
|
-
step: :sign,
|
|
46
|
-
operations: [
|
|
47
|
-
:complete_multipart_upload,
|
|
48
|
-
:copy_object,
|
|
49
|
-
:upload_part_copy,
|
|
50
|
-
]
|
|
51
|
-
)
|
|
112
|
+
handler(Handler, step: :sign)
|
|
52
113
|
end
|
|
53
114
|
end
|
|
54
115
|
end
|
|
@@ -10,41 +10,23 @@ module Aws
|
|
|
10
10
|
default: 'legacy',
|
|
11
11
|
doc_type: String,
|
|
12
12
|
docstring: <<-DOCS) do |cfg|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
Pass in `regional` to enable the `us-east-1` regional endpoint.
|
|
14
|
+
Defaults to `legacy` mode which uses the global endpoint.
|
|
15
15
|
DOCS
|
|
16
16
|
resolve_iad_regional_endpoint(cfg)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def add_handlers(handlers, config)
|
|
20
|
-
if config.region == 'us-east-1'
|
|
21
|
-
handlers.add(Handler)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# @api private
|
|
26
|
-
class Handler < Seahorse::Client::Handler
|
|
27
|
-
|
|
28
|
-
def call(context)
|
|
29
|
-
# keep legacy global endpoint pattern by default
|
|
30
|
-
if context.config.s3_us_east_1_regional_endpoint == 'legacy'
|
|
31
|
-
context.http_request.endpoint.host = IADRegionalEndpoint.legacy_host(
|
|
32
|
-
context.http_request.endpoint.host)
|
|
33
|
-
end
|
|
34
|
-
@handler.call(context)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.legacy_host(host)
|
|
40
|
-
host.sub(".us-east-1", '')
|
|
41
|
-
end
|
|
42
|
-
|
|
43
19
|
private
|
|
44
20
|
|
|
45
21
|
def self.resolve_iad_regional_endpoint(cfg)
|
|
22
|
+
default_mode_value =
|
|
23
|
+
if cfg.respond_to?(:defaults_mode_config_resolver)
|
|
24
|
+
cfg.defaults_mode_config_resolver.resolve(:s3_us_east_1_regional_endpoint)
|
|
25
|
+
end
|
|
26
|
+
|
|
46
27
|
mode = ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] ||
|
|
47
28
|
Aws.shared_config.s3_us_east_1_regional_endpoint(profile: cfg.profile) ||
|
|
29
|
+
default_mode_value ||
|
|
48
30
|
'legacy'
|
|
49
31
|
mode = mode.downcase
|
|
50
32
|
unless %w(legacy regional).include?(mode)
|
|
@@ -22,7 +22,9 @@ module Aws
|
|
|
22
22
|
|
|
23
23
|
def populate_location_constraint(params, region)
|
|
24
24
|
params[:create_bucket_configuration] ||= {}
|
|
25
|
-
params[:create_bucket_configuration][:
|
|
25
|
+
unless params[:create_bucket_configuration][:location]
|
|
26
|
+
params[:create_bucket_configuration][:location_constraint] ||= region
|
|
27
|
+
end
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
end
|
|
@@ -6,78 +6,20 @@ module Aws
|
|
|
6
6
|
module S3
|
|
7
7
|
module Plugins
|
|
8
8
|
# @api private
|
|
9
|
-
# This plugin is
|
|
9
|
+
# This plugin is deprecated in favor of modeled
|
|
10
10
|
# httpChecksumRequired traits.
|
|
11
11
|
class Md5s < Seahorse::Client::Plugin
|
|
12
|
-
# These operations allow Content MD5 but are not required by
|
|
13
|
-
# httpChecksumRequired. This list should not grow.
|
|
14
|
-
OPTIONAL_OPERATIONS = [
|
|
15
|
-
:put_object,
|
|
16
|
-
:upload_part
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
# @api private
|
|
20
|
-
class Handler < Seahorse::Client::Handler
|
|
21
|
-
|
|
22
|
-
CHUNK_SIZE = 1 * 1024 * 1024 # one MB
|
|
23
|
-
|
|
24
|
-
def call(context)
|
|
25
|
-
body = context.http_request.body
|
|
26
|
-
if body.size > 0
|
|
27
|
-
context.http_request.headers['Content-Md5'] ||= md5(body)
|
|
28
|
-
end
|
|
29
|
-
@handler.call(context)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
# @param [File, Tempfile, IO#read, String] value
|
|
35
|
-
# @return [String<MD5>]
|
|
36
|
-
def md5(value)
|
|
37
|
-
if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path)
|
|
38
|
-
OpenSSL::Digest::MD5.file(value).base64digest
|
|
39
|
-
elsif value.respond_to?(:read)
|
|
40
|
-
md5 = OpenSSL::Digest::MD5.new
|
|
41
|
-
update_in_chunks(md5, value)
|
|
42
|
-
md5.base64digest
|
|
43
|
-
else
|
|
44
|
-
OpenSSL::Digest::MD5.digest(value).base64digest
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def update_in_chunks(digest, io)
|
|
49
|
-
loop do
|
|
50
|
-
chunk = io.read(CHUNK_SIZE)
|
|
51
|
-
break unless chunk
|
|
52
|
-
digest.update(chunk)
|
|
53
|
-
end
|
|
54
|
-
io.rewind
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
end
|
|
58
|
-
|
|
59
12
|
option(:compute_checksums,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def add_handlers(handlers, config)
|
|
71
|
-
if config.compute_checksums
|
|
72
|
-
# priority set low to ensure md5 is computed AFTER the request is
|
|
73
|
-
# built but before it is signed
|
|
74
|
-
handlers.add(
|
|
75
|
-
Handler,
|
|
76
|
-
priority: 10, step: :build, operations: OPTIONAL_OPERATIONS
|
|
77
|
-
)
|
|
78
|
-
end
|
|
13
|
+
default: true,
|
|
14
|
+
doc_type: 'Boolean',
|
|
15
|
+
docstring: <<~DOCS)
|
|
16
|
+
This option is deprecated. Please use `:request_checksum_calculation` instead.
|
|
17
|
+
When `false`, `request_checksum_calculation` is overridden to `when_required`.
|
|
18
|
+
DOCS
|
|
19
|
+
|
|
20
|
+
def after_initialize(client)
|
|
21
|
+
client.config.request_checksum_calculation = 'when_required' unless client.config.compute_checksums
|
|
79
22
|
end
|
|
80
|
-
|
|
81
23
|
end
|
|
82
24
|
end
|
|
83
25
|
end
|
|
@@ -4,25 +4,19 @@ require 'aws-sigv4'
|
|
|
4
4
|
|
|
5
5
|
module Aws
|
|
6
6
|
module S3
|
|
7
|
+
# @api private
|
|
8
|
+
def self.bucket_region_cache
|
|
9
|
+
@bucket_region_cache ||= BucketRegionCache.new
|
|
10
|
+
end
|
|
11
|
+
|
|
7
12
|
module Plugins
|
|
8
|
-
# This plugin
|
|
13
|
+
# This plugin used to have a V4 signer but it was removed in favor of
|
|
14
|
+
# generic Sign plugin that uses endpoint auth scheme.
|
|
15
|
+
#
|
|
9
16
|
# @api private
|
|
10
17
|
class S3Signer < Seahorse::Client::Plugin
|
|
11
18
|
option(:signature_version, 'v4')
|
|
12
19
|
|
|
13
|
-
option(:sigv4_signer) do |cfg|
|
|
14
|
-
S3Signer.build_v4_signer(
|
|
15
|
-
region: cfg.sigv4_region,
|
|
16
|
-
credentials: cfg.credentials
|
|
17
|
-
)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
option(:sigv4_region) do |cfg|
|
|
21
|
-
raise Aws::Errors::MissingRegionError if cfg.region.nil?
|
|
22
|
-
|
|
23
|
-
Aws::Partitions::EndpointProvider.signing_region(cfg.region, 's3')
|
|
24
|
-
end
|
|
25
|
-
|
|
26
20
|
def add_handlers(handlers, cfg)
|
|
27
21
|
case cfg.signature_version
|
|
28
22
|
when 'v4' then add_v4_handlers(handlers)
|
|
@@ -35,11 +29,11 @@ module Aws
|
|
|
35
29
|
|
|
36
30
|
def add_v4_handlers(handlers)
|
|
37
31
|
handlers.add(CachedBucketRegionHandler, step: :sign, priority: 60)
|
|
38
|
-
handlers.add(V4Handler, step: :sign)
|
|
39
32
|
handlers.add(BucketRegionErrorHandler, step: :sign, priority: 40)
|
|
40
33
|
end
|
|
41
34
|
|
|
42
35
|
def add_legacy_handler(handlers)
|
|
36
|
+
# generic Sign plugin will be skipped if it sees sigv2
|
|
43
37
|
handlers.add(LegacyHandler, step: :sign)
|
|
44
38
|
end
|
|
45
39
|
|
|
@@ -50,32 +44,6 @@ module Aws
|
|
|
50
44
|
end
|
|
51
45
|
end
|
|
52
46
|
|
|
53
|
-
class V4Handler < Seahorse::Client::Handler
|
|
54
|
-
def call(context)
|
|
55
|
-
Aws::Plugins::SignatureV4.apply_signature(
|
|
56
|
-
context: context,
|
|
57
|
-
signer: sigv4_signer(context)
|
|
58
|
-
)
|
|
59
|
-
@handler.call(context)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
def sigv4_signer(context)
|
|
65
|
-
# If the client was configured with the wrong region,
|
|
66
|
-
# we have to build a new signer.
|
|
67
|
-
if context[:cached_sigv4_region] &&
|
|
68
|
-
context[:cached_sigv4_region] != context.config.sigv4_signer.region
|
|
69
|
-
S3Signer.build_v4_signer(
|
|
70
|
-
region: context[:cached_sigv4_region],
|
|
71
|
-
credentials: context.config.credentials
|
|
72
|
-
)
|
|
73
|
-
else
|
|
74
|
-
context.config.sigv4_signer
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
47
|
# This handler will update the http endpoint when the bucket region
|
|
80
48
|
# is known/cached.
|
|
81
49
|
class CachedBucketRegionHandler < Seahorse::Client::Handler
|
|
@@ -88,10 +56,14 @@ module Aws
|
|
|
88
56
|
private
|
|
89
57
|
|
|
90
58
|
def check_for_cached_region(context, bucket)
|
|
91
|
-
cached_region = S3
|
|
92
|
-
if cached_region &&
|
|
93
|
-
|
|
94
|
-
|
|
59
|
+
cached_region = Aws::S3.bucket_region_cache[bucket]
|
|
60
|
+
if cached_region &&
|
|
61
|
+
cached_region != context.config.region &&
|
|
62
|
+
!S3Signer.custom_endpoint?(context)
|
|
63
|
+
context.http_request.endpoint.host = S3Signer.new_hostname(
|
|
64
|
+
context, cached_region
|
|
65
|
+
)
|
|
66
|
+
context[:sigv4_region] = cached_region # Sign plugin will use this
|
|
95
67
|
end
|
|
96
68
|
end
|
|
97
69
|
end
|
|
@@ -99,7 +71,8 @@ module Aws
|
|
|
99
71
|
# This handler detects when a request fails because of a mismatched bucket
|
|
100
72
|
# region. It follows up by making a request to determine the correct
|
|
101
73
|
# region, then finally a version 4 signed request against the correct
|
|
102
|
-
# regional endpoint.
|
|
74
|
+
# regional endpoint. This is intended for s3's global endpoint which
|
|
75
|
+
# will return 400 if the bucket is not in region.
|
|
103
76
|
class BucketRegionErrorHandler < Seahorse::Client::Handler
|
|
104
77
|
def call(context)
|
|
105
78
|
response = @handler.call(context)
|
|
@@ -111,7 +84,8 @@ module Aws
|
|
|
111
84
|
def handle_region_errors(response)
|
|
112
85
|
if wrong_sigv4_region?(response) &&
|
|
113
86
|
!fips_region?(response) &&
|
|
114
|
-
!custom_endpoint?(response)
|
|
87
|
+
!S3Signer.custom_endpoint?(response.context) &&
|
|
88
|
+
!expired_credentials?(response)
|
|
115
89
|
get_region_and_retry(response.context)
|
|
116
90
|
else
|
|
117
91
|
response
|
|
@@ -128,18 +102,15 @@ module Aws
|
|
|
128
102
|
end
|
|
129
103
|
|
|
130
104
|
def update_bucket_cache(context, actual_region)
|
|
131
|
-
S3
|
|
105
|
+
Aws::S3.bucket_region_cache[context.params[:bucket]] = actual_region
|
|
132
106
|
end
|
|
133
107
|
|
|
134
108
|
def fips_region?(resp)
|
|
135
|
-
resp.context.http_request.endpoint.host.include?('fips')
|
|
109
|
+
resp.context.http_request.endpoint.host.include?('s3-fips.')
|
|
136
110
|
end
|
|
137
111
|
|
|
138
|
-
def
|
|
139
|
-
|
|
140
|
-
resp.context.config.region
|
|
141
|
-
)
|
|
142
|
-
!resp.context.http_request.endpoint.hostname.include?(resolved_suffix)
|
|
112
|
+
def expired_credentials?(resp)
|
|
113
|
+
resp.context.http_response.body_contents.match(/<Code>ExpiredToken<\/Code>/)
|
|
143
114
|
end
|
|
144
115
|
|
|
145
116
|
def wrong_sigv4_region?(resp)
|
|
@@ -150,15 +121,18 @@ module Aws
|
|
|
150
121
|
|
|
151
122
|
def resign_with_new_region(context, actual_region)
|
|
152
123
|
context.http_response.body.truncate(0)
|
|
153
|
-
context.http_request.endpoint.host = S3Signer.new_hostname(
|
|
124
|
+
context.http_request.endpoint.host = S3Signer.new_hostname(
|
|
125
|
+
context, actual_region
|
|
126
|
+
)
|
|
154
127
|
context.metadata[:redirect_region] = actual_region
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
128
|
+
|
|
129
|
+
signer = Aws::Plugins::Sign.signer_for(
|
|
130
|
+
context[:auth_scheme],
|
|
131
|
+
context.config,
|
|
132
|
+
actual_region
|
|
161
133
|
)
|
|
134
|
+
|
|
135
|
+
signer.sign(context)
|
|
162
136
|
end
|
|
163
137
|
|
|
164
138
|
def region_from_body(body)
|
|
@@ -184,36 +158,22 @@ module Aws
|
|
|
184
158
|
end
|
|
185
159
|
|
|
186
160
|
class << self
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
credentials_provider: options[:credentials],
|
|
195
|
-
uri_escape_path: false,
|
|
196
|
-
unsigned_headers: ['content-length', 'x-amzn-trace-id']
|
|
197
|
-
)
|
|
161
|
+
def new_hostname(context, region)
|
|
162
|
+
endpoint_params = context[:endpoint_params].dup
|
|
163
|
+
endpoint_params.region = region
|
|
164
|
+
endpoint_params.endpoint = nil
|
|
165
|
+
endpoint =
|
|
166
|
+
context.config.endpoint_provider.resolve_endpoint(endpoint_params)
|
|
167
|
+
URI(endpoint.url).host
|
|
198
168
|
end
|
|
199
169
|
|
|
200
|
-
def
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
context.params[:bucket],
|
|
205
|
-
region,
|
|
206
|
-
context.config.s3_use_arn_region
|
|
207
|
-
)
|
|
208
|
-
uri = URI.parse(
|
|
209
|
-
Aws::Partitions::EndpointProvider.resolve(resolved_region, 's3')
|
|
210
|
-
)
|
|
170
|
+
def custom_endpoint?(context)
|
|
171
|
+
region = context.config.region
|
|
172
|
+
partition = Aws::Endpoints::Matchers.aws_partition(region)
|
|
173
|
+
endpoint = context.http_request.endpoint
|
|
211
174
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
else
|
|
215
|
-
resolved_bucket + '.' + uri.host
|
|
216
|
-
end
|
|
175
|
+
!endpoint.hostname.include?(partition['dnsSuffix']) &&
|
|
176
|
+
!endpoint.hostname.include?(partition['dualStackDnsSuffix'])
|
|
217
177
|
end
|
|
218
178
|
end
|
|
219
179
|
end
|
|
@@ -36,6 +36,17 @@ module Aws
|
|
|
36
36
|
def rewind; end
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
class NonRetryableStreamingError < StandardError
|
|
40
|
+
|
|
41
|
+
def initialize(error)
|
|
42
|
+
super('Unable to retry request - retry could result in processing duplicated chunks.')
|
|
43
|
+
set_backtrace(error.backtrace)
|
|
44
|
+
@original_error = error
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
attr_reader :original_error
|
|
48
|
+
end
|
|
49
|
+
|
|
39
50
|
# This handler works with the ResponseTarget plugin to provide smart
|
|
40
51
|
# retries of S3 streaming operations that support the range parameter
|
|
41
52
|
# (currently only: get_object). When a 200 OK with a TruncatedBodyError
|
|
@@ -51,18 +62,16 @@ module Aws
|
|
|
51
62
|
class Handler < Seahorse::Client::Handler
|
|
52
63
|
|
|
53
64
|
def call(context)
|
|
54
|
-
target = context.params[:response_target] || context[:response_target]
|
|
55
|
-
|
|
56
65
|
# retry is only supported when range is NOT set on the initial request
|
|
57
|
-
if supported_target?(
|
|
58
|
-
add_event_listeners(context
|
|
66
|
+
if supported_target?(context) && !context.params[:range]
|
|
67
|
+
add_event_listeners(context)
|
|
59
68
|
end
|
|
60
69
|
@handler.call(context)
|
|
61
70
|
end
|
|
62
71
|
|
|
63
72
|
private
|
|
64
73
|
|
|
65
|
-
def add_event_listeners(context
|
|
74
|
+
def add_event_listeners(context)
|
|
66
75
|
context.http_response.on_headers(200..299) do
|
|
67
76
|
case context.http_response.body
|
|
68
77
|
when Seahorse::Client::BlockIO then
|
|
@@ -84,8 +93,18 @@ module Aws
|
|
|
84
93
|
end
|
|
85
94
|
|
|
86
95
|
context.http_response.on_error do |error|
|
|
87
|
-
if retryable_body?(context)
|
|
88
|
-
|
|
96
|
+
if retryable_body?(context)
|
|
97
|
+
if truncated_body?(error)
|
|
98
|
+
context.http_request.headers[:range] = "bytes=#{context.http_response.body.size}-"
|
|
99
|
+
else
|
|
100
|
+
case context.http_response.body
|
|
101
|
+
when RetryableManagedFile
|
|
102
|
+
# call rewind on the underlying file
|
|
103
|
+
context.http_response.body.instance_variable_get(:@file).rewind
|
|
104
|
+
else
|
|
105
|
+
raise NonRetryableStreamingError, error
|
|
106
|
+
end
|
|
107
|
+
end
|
|
89
108
|
end
|
|
90
109
|
end
|
|
91
110
|
end
|
|
@@ -102,8 +121,8 @@ module Aws
|
|
|
102
121
|
context.http_response.body.is_a?(RetryableManagedFile)
|
|
103
122
|
end
|
|
104
123
|
|
|
105
|
-
def supported_target?(
|
|
106
|
-
case
|
|
124
|
+
def supported_target?(context)
|
|
125
|
+
case context[:response_target]
|
|
107
126
|
when Proc, String, Pathname then true
|
|
108
127
|
else false
|
|
109
128
|
end
|