aws-sdk-s3 1.48.0 → 1.183.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 +5 -5
- data/CHANGELOG.md +1352 -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 +1005 -106
- data/lib/aws-sdk-s3/bucket_acl.rb +65 -18
- data/lib/aws-sdk-s3/bucket_cors.rb +80 -18
- data/lib/aws-sdk-s3/bucket_lifecycle.rb +71 -20
- data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +126 -21
- data/lib/aws-sdk-s3/bucket_logging.rb +68 -16
- data/lib/aws-sdk-s3/bucket_notification.rb +52 -20
- data/lib/aws-sdk-s3/bucket_policy.rb +108 -17
- data/lib/aws-sdk-s3/bucket_region_cache.rb +11 -5
- data/lib/aws-sdk-s3/bucket_request_payment.rb +60 -15
- data/lib/aws-sdk-s3/bucket_tagging.rb +71 -18
- data/lib/aws-sdk-s3/bucket_versioning.rb +133 -17
- data/lib/aws-sdk-s3/bucket_website.rb +78 -21
- data/lib/aws-sdk-s3/client.rb +14517 -941
- data/lib/aws-sdk-s3/client_api.rb +1296 -197
- data/lib/aws-sdk-s3/customizations/bucket.rb +56 -37
- data/lib/aws-sdk-s3/customizations/errors.rb +40 -0
- data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
- data/lib/aws-sdk-s3/customizations/object.rb +288 -68
- data/lib/aws-sdk-s3/customizations/object_summary.rb +10 -0
- data/lib/aws-sdk-s3/customizations/object_version.rb +13 -0
- data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
- data/lib/aws-sdk-s3/customizations/types/permanent_redirect.rb +26 -0
- data/lib/aws-sdk-s3/customizations.rb +27 -28
- data/lib/aws-sdk-s3/encryption/client.rb +28 -7
- data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +71 -29
- data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +43 -5
- data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
- data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +13 -2
- data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
- data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +2 -0
- data/lib/aws-sdk-s3/encryption/io_decrypter.rb +11 -3
- data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
- data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
- data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +46 -11
- data/lib/aws-sdk-s3/encryption/materials.rb +8 -6
- data/lib/aws-sdk-s3/encryption/utils.rb +25 -0
- data/lib/aws-sdk-s3/encryption.rb +4 -0
- data/lib/aws-sdk-s3/encryptionV2/client.rb +570 -0
- data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +223 -0
- data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +170 -0
- data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +40 -0
- data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +65 -0
- data/lib/aws-sdk-s3/encryptionV2/errors.rb +37 -0
- data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +58 -0
- data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +37 -0
- data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +73 -0
- data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +31 -0
- data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +173 -0
- data/lib/aws-sdk-s3/encryptionV2/materials.rb +60 -0
- data/lib/aws-sdk-s3/encryptionV2/utils.rb +103 -0
- data/lib/aws-sdk-s3/encryption_v2.rb +23 -0
- data/lib/aws-sdk-s3/endpoint_parameters.rb +181 -0
- data/lib/aws-sdk-s3/endpoint_provider.rb +716 -0
- data/lib/aws-sdk-s3/endpoints.rb +1434 -0
- data/lib/aws-sdk-s3/errors.rb +170 -1
- data/lib/aws-sdk-s3/event_streams.rb +8 -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 +161 -46
- data/lib/aws-sdk-s3/file_part.rb +11 -6
- data/lib/aws-sdk-s3/file_uploader.rb +39 -18
- data/lib/aws-sdk-s3/legacy_signer.rb +17 -25
- data/lib/aws-sdk-s3/multipart_file_uploader.rb +104 -27
- data/lib/aws-sdk-s3/multipart_stream_uploader.rb +61 -21
- data/lib/aws-sdk-s3/multipart_upload.rb +342 -32
- data/lib/aws-sdk-s3/multipart_upload_error.rb +2 -0
- data/lib/aws-sdk-s3/multipart_upload_part.rb +384 -46
- data/lib/aws-sdk-s3/object.rb +2600 -231
- data/lib/aws-sdk-s3/object_acl.rb +103 -25
- data/lib/aws-sdk-s3/object_copier.rb +9 -5
- data/lib/aws-sdk-s3/object_multipart_copier.rb +48 -22
- data/lib/aws-sdk-s3/object_summary.rb +2174 -204
- data/lib/aws-sdk-s3/object_version.rb +539 -80
- data/lib/aws-sdk-s3/plugins/accelerate.rb +17 -64
- 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 +7 -43
- data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +20 -3
- data/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +31 -0
- data/lib/aws-sdk-s3/plugins/dualstack.rb +7 -50
- data/lib/aws-sdk-s3/plugins/endpoints.rb +86 -0
- data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +5 -4
- data/lib/aws-sdk-s3/plugins/express_session_auth.rb +88 -0
- data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +3 -1
- data/lib/aws-sdk-s3/plugins/http_200_errors.rb +62 -17
- data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +44 -0
- data/lib/aws-sdk-s3/plugins/location_constraint.rb +5 -1
- data/lib/aws-sdk-s3/plugins/md5s.rb +14 -70
- data/lib/aws-sdk-s3/plugins/redirects.rb +2 -0
- data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
- data/lib/aws-sdk-s3/plugins/s3_signer.rb +63 -94
- data/lib/aws-sdk-s3/plugins/sse_cpk.rb +3 -1
- data/lib/aws-sdk-s3/plugins/streaming_retry.rb +139 -0
- data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -0
- data/lib/aws-sdk-s3/presigned_post.rb +160 -99
- data/lib/aws-sdk-s3/presigner.rb +141 -62
- data/lib/aws-sdk-s3/resource.rb +156 -17
- data/lib/aws-sdk-s3/types.rb +13021 -4106
- data/lib/aws-sdk-s3/waiters.rb +67 -1
- data/lib/aws-sdk-s3.rb +46 -32
- data/sig/bucket.rbs +222 -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 +2472 -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 +42 -0
- data/sig/multipart_upload.rbs +120 -0
- data/sig/multipart_upload_part.rbs +109 -0
- data/sig/object.rbs +459 -0
- data/sig/object_acl.rbs +86 -0
- data/sig/object_summary.rbs +345 -0
- data/sig/object_version.rbs +143 -0
- data/sig/resource.rbs +134 -0
- data/sig/types.rbs +2712 -0
- data/sig/waiters.rbs +95 -0
- metadata +74 -15
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module S3
|
5
|
+
module Plugins
|
6
|
+
# @api private
|
7
|
+
class ExpressSessionAuth < Seahorse::Client::Plugin
|
8
|
+
# This should be s3_disable_express_auth instead
|
9
|
+
# But this is not a built in. We're overwriting the generated value
|
10
|
+
option(:disable_s3_express_session_auth,
|
11
|
+
default: false,
|
12
|
+
doc_type: 'Boolean',
|
13
|
+
docstring: <<-DOCS) do |cfg|
|
14
|
+
When `true`, S3 Express session authentication is disabled.
|
15
|
+
DOCS
|
16
|
+
resolve_disable_s3_express_session_auth(cfg)
|
17
|
+
end
|
18
|
+
|
19
|
+
option(:express_credentials_provider,
|
20
|
+
doc_type: 'Aws::S3::ExpressCredentialsProvider',
|
21
|
+
rbs_type: 'untyped',
|
22
|
+
docstring: <<-DOCS) do |_cfg|
|
23
|
+
Credential Provider for S3 Express endpoints. Manages credentials
|
24
|
+
for different buckets.
|
25
|
+
DOCS
|
26
|
+
Aws::S3::ExpressCredentialsProvider.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
class Handler < Seahorse::Client::Handler
|
31
|
+
def call(context)
|
32
|
+
context[:s3_express_endpoint] = true if s3_express_endpoint?(context)
|
33
|
+
|
34
|
+
# if s3 express auth, use new credentials and sign additional header
|
35
|
+
if context[:auth_scheme]['name'] == 'sigv4-s3express' &&
|
36
|
+
!context.config.disable_s3_express_session_auth
|
37
|
+
bucket = context.params[:bucket]
|
38
|
+
credentials_provider = context.config.express_credentials_provider
|
39
|
+
credentials = credentials_provider.express_credentials_for(bucket)
|
40
|
+
context[:sigv4_credentials] = credentials # Sign will use this
|
41
|
+
end
|
42
|
+
|
43
|
+
with_metric(credentials) { @handler.call(context) }
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def with_metric(credentials, &block)
|
49
|
+
return block.call unless credentials
|
50
|
+
|
51
|
+
Aws::Plugins::UserAgent.metric('S3_EXPRESS_BUCKET', &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def s3_express_endpoint?(context)
|
55
|
+
context[:endpoint_properties]['backend'] == 'S3Express'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
handler(Handler)
|
60
|
+
|
61
|
+
# Optimization - sets this client as the client to create sessions.
|
62
|
+
def after_initialize(client)
|
63
|
+
provider = client.config.express_credentials_provider
|
64
|
+
provider.client = client unless provider.client
|
65
|
+
end
|
66
|
+
|
67
|
+
class << self
|
68
|
+
private
|
69
|
+
|
70
|
+
def resolve_disable_s3_express_session_auth(cfg)
|
71
|
+
value = ENV['AWS_S3_DISABLE_EXPRESS_SESSION_AUTH'] ||
|
72
|
+
Aws.shared_config.s3_disable_express_session_auth(profile: cfg.profile) ||
|
73
|
+
'false'
|
74
|
+
value = Aws::Util.str_2_bool(value)
|
75
|
+
# Raise if provided value is not true or false
|
76
|
+
if value.nil?
|
77
|
+
raise ArgumentError,
|
78
|
+
'Must provide either `true` or `false` for the '\
|
79
|
+
'`s3_disable_express_session_auth` profile option or for '\
|
80
|
+
"ENV['AWS_S3_DISABLE_EXPRESS_SESSION_AUTH']."
|
81
|
+
end
|
82
|
+
value
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws
|
2
4
|
module S3
|
3
5
|
module Plugins
|
@@ -9,7 +11,7 @@ module Aws
|
|
9
11
|
@handler.call(context).on(200) do |response|
|
10
12
|
response.data = S3::Types::GetBucketLocationOutput.new
|
11
13
|
xml = context.http_response.body_contents
|
12
|
-
matches = xml.match(
|
14
|
+
matches = xml.match(/<LocationConstraint.*?>(.+?)<\/LocationConstraint>/)
|
13
15
|
response.data[:location_constraint] = matches ? matches[1] : ''
|
14
16
|
end
|
15
17
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws
|
2
4
|
module S3
|
3
5
|
module Plugins
|
@@ -13,34 +15,77 @@ module Aws
|
|
13
15
|
|
14
16
|
def call(context)
|
15
17
|
@handler.call(context).on(200) do |response|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
return response if streaming_output?(context.operation.output)
|
19
|
+
|
20
|
+
error = check_for_error(context)
|
21
|
+
return response unless error
|
22
|
+
|
23
|
+
context.http_response.status_code = 500
|
24
|
+
response.data = nil
|
25
|
+
response.error = error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Streaming outputs are not subject to 200 errors.
|
32
|
+
def streaming_output?(output)
|
33
|
+
if (payload = output[:payload_member])
|
34
|
+
# checking ref and shape
|
35
|
+
payload['streaming'] || payload.shape['streaming'] ||
|
36
|
+
payload.eventstream
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Checks if the output shape is a structure shape and has members that
|
43
|
+
# are in the body for the case of a payload and a normal structure. A
|
44
|
+
# non-structure shape will not have members in the body. In the case
|
45
|
+
# of a string or blob, the body contents would have been checked first
|
46
|
+
# before this method is called in incomplete_xml_body?.
|
47
|
+
def members_in_body?(output)
|
48
|
+
shape =
|
49
|
+
if output[:payload_member]
|
50
|
+
output[:payload_member].shape
|
51
|
+
else
|
52
|
+
output.shape
|
20
53
|
end
|
54
|
+
|
55
|
+
if structure_shape?(shape)
|
56
|
+
shape.members.any? { |_, k| k.location.nil? }
|
57
|
+
else
|
58
|
+
false
|
21
59
|
end
|
22
60
|
end
|
23
61
|
|
62
|
+
def structure_shape?(shape)
|
63
|
+
shape.is_a?(Seahorse::Model::Shapes::StructureShape)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Must have a member in the body and have the start of an XML Tag.
|
67
|
+
# Other incomplete xml bodies will result in an XML ParsingError.
|
68
|
+
def incomplete_xml_body?(xml, output)
|
69
|
+
members_in_body?(output) && !xml.match(/<\w/)
|
70
|
+
end
|
71
|
+
|
24
72
|
def check_for_error(context)
|
25
73
|
xml = context.http_response.body_contents
|
26
|
-
if xml.match(
|
27
|
-
error_code = xml.match(
|
28
|
-
error_message = xml.match(
|
74
|
+
if xml.match(/<\?xml\s[^>]*\?>\s*<Error>/)
|
75
|
+
error_code = xml.match(%r{<Code>(.+?)</Code>})[1]
|
76
|
+
error_message = xml.match(%r{<Message>(.+?)</Message>})[1]
|
29
77
|
S3::Errors.error_class(error_code).new(context, error_message)
|
78
|
+
elsif incomplete_xml_body?(xml, context.operation.output)
|
79
|
+
Seahorse::Client::NetworkingError.new(
|
80
|
+
S3::Errors
|
81
|
+
.error_class('InternalError')
|
82
|
+
.new(context, 'Empty or incomplete response body')
|
83
|
+
)
|
30
84
|
end
|
31
85
|
end
|
32
|
-
|
33
86
|
end
|
34
87
|
|
35
|
-
handler(Handler,
|
36
|
-
step: :sign,
|
37
|
-
operations: [
|
38
|
-
:complete_multipart_upload,
|
39
|
-
:copy_object,
|
40
|
-
:upload_part_copy,
|
41
|
-
]
|
42
|
-
)
|
43
|
-
|
88
|
+
handler(Handler, step: :sign)
|
44
89
|
end
|
45
90
|
end
|
46
91
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module S3
|
5
|
+
module Plugins
|
6
|
+
|
7
|
+
class IADRegionalEndpoint < Seahorse::Client::Plugin
|
8
|
+
|
9
|
+
option(:s3_us_east_1_regional_endpoint,
|
10
|
+
default: 'legacy',
|
11
|
+
doc_type: String,
|
12
|
+
docstring: <<-DOCS) do |cfg|
|
13
|
+
Pass in `regional` to enable the `us-east-1` regional endpoint.
|
14
|
+
Defaults to `legacy` mode which uses the global endpoint.
|
15
|
+
DOCS
|
16
|
+
resolve_iad_regional_endpoint(cfg)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
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
|
+
|
27
|
+
mode = ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] ||
|
28
|
+
Aws.shared_config.s3_us_east_1_regional_endpoint(profile: cfg.profile) ||
|
29
|
+
default_mode_value ||
|
30
|
+
'legacy'
|
31
|
+
mode = mode.downcase
|
32
|
+
unless %w(legacy regional).include?(mode)
|
33
|
+
raise ArgumentError, "expected :s3_us_east_1_regional_endpoint or"\
|
34
|
+
" ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] to be `legacy` or"\
|
35
|
+
" `regional`."
|
36
|
+
end
|
37
|
+
mode
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws
|
2
4
|
module S3
|
3
5
|
module Plugins
|
@@ -20,7 +22,9 @@ module Aws
|
|
20
22
|
|
21
23
|
def populate_location_constraint(params, region)
|
22
24
|
params[:create_bucket_configuration] ||= {}
|
23
|
-
params[:create_bucket_configuration][:
|
25
|
+
unless params[:create_bucket_configuration][:location]
|
26
|
+
params[:create_bucket_configuration][:location_constraint] ||= region
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
30
|
end
|
@@ -1,81 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'openssl'
|
2
|
-
require 'base64'
|
3
4
|
|
4
5
|
module Aws
|
5
6
|
module S3
|
6
7
|
module Plugins
|
8
|
+
# @api private
|
9
|
+
# This plugin is deprecated in favor of modeled
|
10
|
+
# httpChecksumRequired traits.
|
7
11
|
class Md5s < Seahorse::Client::Plugin
|
8
|
-
|
9
|
-
# Amazon S3 requires these operations to have an MD5 checksum
|
10
|
-
REQUIRED_OPERATIONS = [
|
11
|
-
:delete_objects,
|
12
|
-
:put_bucket_cors,
|
13
|
-
:put_bucket_lifecycle,
|
14
|
-
:put_bucket_policy,
|
15
|
-
:put_bucket_tagging,
|
16
|
-
:put_object_legal_hold,
|
17
|
-
:put_object_lock_configuration,
|
18
|
-
:put_object_retention
|
19
|
-
]
|
20
|
-
|
21
|
-
# @api private
|
22
|
-
class Handler < Seahorse::Client::Handler
|
23
|
-
|
24
|
-
CHUNK_SIZE = 1 * 1024 * 1024 # one MB
|
25
|
-
|
26
|
-
def call(context)
|
27
|
-
body = context.http_request.body
|
28
|
-
if body.size > 0
|
29
|
-
context.http_request.headers['Content-Md5'] ||= md5(body)
|
30
|
-
end
|
31
|
-
@handler.call(context)
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
# @param [File, Tempfile, IO#read, String] value
|
37
|
-
# @return [String<MD5>]
|
38
|
-
def md5(value)
|
39
|
-
if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path)
|
40
|
-
Base64.encode64(OpenSSL::Digest::MD5.file(value).digest).strip
|
41
|
-
elsif value.respond_to?(:read)
|
42
|
-
md5 = OpenSSL::Digest::MD5.new
|
43
|
-
update_in_chunks(md5, value)
|
44
|
-
Base64.encode64(md5.digest).strip
|
45
|
-
else
|
46
|
-
Base64.encode64(OpenSSL::Digest::MD5.digest(value)).strip
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def update_in_chunks(digest, io)
|
51
|
-
while chunk = io.read(CHUNK_SIZE, buffer ||= "")
|
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
|
-
def add_handlers(handlers, config)
|
70
|
-
# priority set low to ensure md5 is computed AFTER the request is
|
71
|
-
# built but before it is signed
|
72
|
-
handlers.add(Handler, {
|
73
|
-
priority: 10,
|
74
|
-
step: :build,
|
75
|
-
operations: config.compute_checksums ? nil : REQUIRED_OPERATIONS,
|
76
|
-
})
|
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
|
77
22
|
end
|
78
|
-
|
79
23
|
end
|
80
24
|
end
|
81
25
|
end
|
@@ -1,25 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aws-sigv4'
|
2
4
|
|
3
5
|
module Aws
|
4
6
|
module S3
|
7
|
+
# @api private
|
8
|
+
def self.bucket_region_cache
|
9
|
+
@bucket_region_cache ||= BucketRegionCache.new
|
10
|
+
end
|
11
|
+
|
5
12
|
module Plugins
|
6
|
-
# 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
|
+
#
|
7
16
|
# @api private
|
8
17
|
class S3Signer < Seahorse::Client::Plugin
|
9
|
-
|
10
18
|
option(:signature_version, 'v4')
|
11
19
|
|
12
|
-
option(:sigv4_signer) do |cfg|
|
13
|
-
S3Signer.build_v4_signer(
|
14
|
-
region: cfg.sigv4_region,
|
15
|
-
credentials: cfg.credentials
|
16
|
-
)
|
17
|
-
end
|
18
|
-
|
19
|
-
option(:sigv4_region) do |cfg|
|
20
|
-
Aws::Partitions::EndpointProvider.signing_region(cfg.region, 's3')
|
21
|
-
end
|
22
|
-
|
23
20
|
def add_handlers(handlers, cfg)
|
24
21
|
case cfg.signature_version
|
25
22
|
when 'v4' then add_v4_handlers(handlers)
|
@@ -32,11 +29,11 @@ module Aws
|
|
32
29
|
|
33
30
|
def add_v4_handlers(handlers)
|
34
31
|
handlers.add(CachedBucketRegionHandler, step: :sign, priority: 60)
|
35
|
-
handlers.add(V4Handler, step: :sign)
|
36
32
|
handlers.add(BucketRegionErrorHandler, step: :sign, priority: 40)
|
37
33
|
end
|
38
34
|
|
39
35
|
def add_legacy_handler(handlers)
|
36
|
+
# generic Sign plugin will be skipped if it sees sigv2
|
40
37
|
handlers.add(LegacyHandler, step: :sign)
|
41
38
|
end
|
42
39
|
|
@@ -47,40 +44,9 @@ module Aws
|
|
47
44
|
end
|
48
45
|
end
|
49
46
|
|
50
|
-
class V4Handler < Seahorse::Client::Handler
|
51
|
-
|
52
|
-
def call(context)
|
53
|
-
Aws::Plugins::SignatureV4.apply_signature(
|
54
|
-
context: context,
|
55
|
-
signer: sigv4_signer(context)
|
56
|
-
)
|
57
|
-
@handler.call(context)
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def sigv4_signer(context)
|
63
|
-
# If the client was configured with the wrong region,
|
64
|
-
# we have to build a new signer.
|
65
|
-
if
|
66
|
-
context[:cached_sigv4_region] &&
|
67
|
-
context[:cached_sigv4_region] != context.config.sigv4_signer.region
|
68
|
-
then
|
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
|
-
|
78
|
-
end
|
79
|
-
|
80
47
|
# This handler will update the http endpoint when the bucket region
|
81
48
|
# is known/cached.
|
82
49
|
class CachedBucketRegionHandler < Seahorse::Client::Handler
|
83
|
-
|
84
50
|
def call(context)
|
85
51
|
bucket = context.params[:bucket]
|
86
52
|
check_for_cached_region(context, bucket) if bucket
|
@@ -90,21 +56,24 @@ module Aws
|
|
90
56
|
private
|
91
57
|
|
92
58
|
def check_for_cached_region(context, bucket)
|
93
|
-
cached_region = S3
|
94
|
-
if cached_region &&
|
95
|
-
|
96
|
-
|
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
|
97
67
|
end
|
98
68
|
end
|
99
|
-
|
100
69
|
end
|
101
70
|
|
102
71
|
# This handler detects when a request fails because of a mismatched bucket
|
103
72
|
# region. It follows up by making a request to determine the correct
|
104
73
|
# region, then finally a version 4 signed request against the correct
|
105
|
-
# 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.
|
106
76
|
class BucketRegionErrorHandler < Seahorse::Client::Handler
|
107
|
-
|
108
77
|
def call(context)
|
109
78
|
response = @handler.call(context)
|
110
79
|
handle_region_errors(response)
|
@@ -113,7 +82,10 @@ module Aws
|
|
113
82
|
private
|
114
83
|
|
115
84
|
def handle_region_errors(response)
|
116
|
-
if wrong_sigv4_region?(response) &&
|
85
|
+
if wrong_sigv4_region?(response) &&
|
86
|
+
!fips_region?(response) &&
|
87
|
+
!S3Signer.custom_endpoint?(response.context) &&
|
88
|
+
!expired_credentials?(response)
|
117
89
|
get_region_and_retry(response.context)
|
118
90
|
else
|
119
91
|
response
|
@@ -130,37 +102,42 @@ module Aws
|
|
130
102
|
end
|
131
103
|
|
132
104
|
def update_bucket_cache(context, actual_region)
|
133
|
-
S3
|
105
|
+
Aws::S3.bucket_region_cache[context.params[:bucket]] = actual_region
|
134
106
|
end
|
135
107
|
|
136
108
|
def fips_region?(resp)
|
137
|
-
resp.context.http_request.endpoint.host.include?('fips')
|
109
|
+
resp.context.http_request.endpoint.host.include?('s3-fips.')
|
110
|
+
end
|
111
|
+
|
112
|
+
def expired_credentials?(resp)
|
113
|
+
resp.context.http_response.body_contents.match(/<Code>ExpiredToken<\/Code>/)
|
138
114
|
end
|
139
115
|
|
140
116
|
def wrong_sigv4_region?(resp)
|
141
117
|
resp.context.http_response.status_code == 400 &&
|
142
|
-
|
143
|
-
|
144
|
-
resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/)
|
145
|
-
)
|
118
|
+
(resp.context.http_response.headers['x-amz-bucket-region'] ||
|
119
|
+
resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/))
|
146
120
|
end
|
147
121
|
|
148
122
|
def resign_with_new_region(context, actual_region)
|
149
123
|
context.http_response.body.truncate(0)
|
150
|
-
context.http_request.endpoint.host = S3Signer.new_hostname(
|
124
|
+
context.http_request.endpoint.host = S3Signer.new_hostname(
|
125
|
+
context, actual_region
|
126
|
+
)
|
151
127
|
context.metadata[:redirect_region] = actual_region
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
)
|
128
|
+
|
129
|
+
signer = Aws::Plugins::Sign.signer_for(
|
130
|
+
context[:auth_scheme],
|
131
|
+
context.config,
|
132
|
+
actual_region
|
158
133
|
)
|
134
|
+
|
135
|
+
signer.sign(context)
|
159
136
|
end
|
160
137
|
|
161
138
|
def region_from_body(body)
|
162
139
|
region = body.match(/<Region>(.+?)<\/Region>/)[1]
|
163
|
-
if region.nil? || region ==
|
140
|
+
if region.nil? || region == ''
|
164
141
|
raise "couldn't get region from body: #{body}"
|
165
142
|
else
|
166
143
|
region
|
@@ -168,44 +145,36 @@ module Aws
|
|
168
145
|
end
|
169
146
|
|
170
147
|
def log_warning(context, actual_region)
|
171
|
-
msg = "S3 client configured for #{context.config.region.inspect} "
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
if logger = context.config.logger
|
148
|
+
msg = "S3 client configured for #{context.config.region.inspect} " \
|
149
|
+
"but the bucket #{context.params[:bucket].inspect} is in " \
|
150
|
+
"#{actual_region.inspect}; Please configure the proper region " \
|
151
|
+
"to avoid multiple unnecessary redirects and signing attempts\n"
|
152
|
+
if (logger = context.config.logger)
|
176
153
|
logger.warn(msg)
|
177
154
|
else
|
178
155
|
warn(msg)
|
179
156
|
end
|
180
157
|
end
|
181
|
-
|
182
158
|
end
|
183
159
|
|
184
160
|
class << self
|
185
|
-
|
186
|
-
# @option options [required, String] :region
|
187
|
-
# @option options [required, #credentials] :credentials
|
188
|
-
# @api private
|
189
|
-
def build_v4_signer(options = {})
|
190
|
-
Aws::Sigv4::Signer.new({
|
191
|
-
service: 's3',
|
192
|
-
region: options[:region],
|
193
|
-
credentials_provider: options[:credentials],
|
194
|
-
uri_escape_path: false,
|
195
|
-
unsigned_headers: ['content-length', 'x-amzn-trace-id'],
|
196
|
-
})
|
197
|
-
end
|
198
|
-
|
199
161
|
def new_hostname(context, region)
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
end
|
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
|
207
168
|
end
|
208
169
|
|
170
|
+
def custom_endpoint?(context)
|
171
|
+
region = context.config.region
|
172
|
+
partition = Aws::Endpoints::Matchers.aws_partition(region)
|
173
|
+
endpoint = context.http_request.endpoint
|
174
|
+
|
175
|
+
!endpoint.hostname.include?(partition['dnsSuffix']) &&
|
176
|
+
!endpoint.hostname.include?(partition['dualStackDnsSuffix'])
|
177
|
+
end
|
209
178
|
end
|
210
179
|
end
|
211
180
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'openssl'
|
3
5
|
|
@@ -18,7 +20,7 @@ This should only be disabled for local testing.
|
|
18
20
|
class Handler < Seahorse::Client::Handler
|
19
21
|
|
20
22
|
def call(context)
|
21
|
-
compute_key_md5(context)
|
23
|
+
compute_key_md5(context) if context.params.is_a?(Hash)
|
22
24
|
@handler.call(context)
|
23
25
|
end
|
24
26
|
|