aws-sdk-s3 1.103.0 → 1.202.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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +664 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-s3/access_grants_credentials.rb +57 -0
  5. data/lib/aws-sdk-s3/access_grants_credentials_provider.rb +250 -0
  6. data/lib/aws-sdk-s3/bucket.rb +858 -116
  7. data/lib/aws-sdk-s3/bucket_acl.rb +32 -9
  8. data/lib/aws-sdk-s3/bucket_cors.rb +38 -13
  9. data/lib/aws-sdk-s3/bucket_lifecycle.rb +43 -12
  10. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +100 -13
  11. data/lib/aws-sdk-s3/bucket_logging.rb +35 -6
  12. data/lib/aws-sdk-s3/bucket_notification.rb +27 -9
  13. data/lib/aws-sdk-s3/bucket_policy.rb +79 -10
  14. data/lib/aws-sdk-s3/bucket_region_cache.rb +9 -5
  15. data/lib/aws-sdk-s3/bucket_request_payment.rb +29 -7
  16. data/lib/aws-sdk-s3/bucket_tagging.rb +35 -11
  17. data/lib/aws-sdk-s3/bucket_versioning.rb +108 -17
  18. data/lib/aws-sdk-s3/bucket_website.rb +35 -11
  19. data/lib/aws-sdk-s3/client.rb +11799 -3636
  20. data/lib/aws-sdk-s3/client_api.rb +1201 -276
  21. data/lib/aws-sdk-s3/customizations/bucket.rb +23 -47
  22. data/lib/aws-sdk-s3/customizations/errors.rb +40 -0
  23. data/lib/aws-sdk-s3/customizations/object.rb +216 -70
  24. data/lib/aws-sdk-s3/customizations/object_summary.rb +5 -0
  25. data/lib/aws-sdk-s3/customizations/object_version.rb +13 -0
  26. data/lib/aws-sdk-s3/customizations/types/permanent_redirect.rb +26 -0
  27. data/lib/aws-sdk-s3/customizations.rb +27 -29
  28. data/lib/aws-sdk-s3/default_executor.rb +103 -0
  29. data/lib/aws-sdk-s3/encryption/client.rb +6 -2
  30. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +13 -9
  31. data/lib/aws-sdk-s3/encryptionV2/client.rb +6 -2
  32. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +1 -0
  33. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +10 -6
  34. data/lib/aws-sdk-s3/endpoint_parameters.rb +181 -0
  35. data/lib/aws-sdk-s3/endpoint_provider.rb +716 -0
  36. data/lib/aws-sdk-s3/endpoints.rb +1518 -0
  37. data/lib/aws-sdk-s3/errors.rb +58 -0
  38. data/lib/aws-sdk-s3/express_credentials.rb +55 -0
  39. data/lib/aws-sdk-s3/express_credentials_provider.rb +59 -0
  40. data/lib/aws-sdk-s3/file_downloader.rb +241 -87
  41. data/lib/aws-sdk-s3/file_uploader.rb +16 -13
  42. data/lib/aws-sdk-s3/legacy_signer.rb +2 -1
  43. data/lib/aws-sdk-s3/multipart_download_error.rb +8 -0
  44. data/lib/aws-sdk-s3/multipart_file_uploader.rb +108 -86
  45. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +110 -92
  46. data/lib/aws-sdk-s3/multipart_upload.rb +294 -19
  47. data/lib/aws-sdk-s3/multipart_upload_error.rb +3 -4
  48. data/lib/aws-sdk-s3/multipart_upload_part.rb +297 -31
  49. data/lib/aws-sdk-s3/object.rb +2224 -269
  50. data/lib/aws-sdk-s3/object_acl.rb +59 -17
  51. data/lib/aws-sdk-s3/object_copier.rb +7 -5
  52. data/lib/aws-sdk-s3/object_multipart_copier.rb +48 -23
  53. data/lib/aws-sdk-s3/object_summary.rb +1915 -220
  54. data/lib/aws-sdk-s3/object_version.rb +450 -58
  55. data/lib/aws-sdk-s3/plugins/accelerate.rb +3 -44
  56. data/lib/aws-sdk-s3/plugins/access_grants.rb +178 -0
  57. data/lib/aws-sdk-s3/plugins/arn.rb +0 -197
  58. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +3 -39
  59. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +1 -6
  60. data/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +31 -0
  61. data/lib/aws-sdk-s3/plugins/dualstack.rb +1 -55
  62. data/lib/aws-sdk-s3/plugins/endpoints.rb +86 -0
  63. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +2 -1
  64. data/lib/aws-sdk-s3/plugins/express_session_auth.rb +88 -0
  65. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +55 -18
  66. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +6 -29
  67. data/lib/aws-sdk-s3/plugins/location_constraint.rb +3 -1
  68. data/lib/aws-sdk-s3/plugins/md5s.rb +10 -68
  69. data/lib/aws-sdk-s3/plugins/s3_signer.rb +42 -111
  70. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +28 -9
  71. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -1
  72. data/lib/aws-sdk-s3/presigned_post.rb +99 -78
  73. data/lib/aws-sdk-s3/presigner.rb +32 -41
  74. data/lib/aws-sdk-s3/resource.rb +139 -12
  75. data/lib/aws-sdk-s3/transfer_manager.rb +304 -0
  76. data/lib/aws-sdk-s3/types.rb +10204 -5378
  77. data/lib/aws-sdk-s3.rb +35 -27
  78. data/sig/bucket.rbs +231 -0
  79. data/sig/bucket_acl.rbs +78 -0
  80. data/sig/bucket_cors.rbs +69 -0
  81. data/sig/bucket_lifecycle.rbs +88 -0
  82. data/sig/bucket_lifecycle_configuration.rbs +115 -0
  83. data/sig/bucket_logging.rbs +76 -0
  84. data/sig/bucket_notification.rbs +114 -0
  85. data/sig/bucket_policy.rbs +59 -0
  86. data/sig/bucket_request_payment.rbs +54 -0
  87. data/sig/bucket_tagging.rbs +65 -0
  88. data/sig/bucket_versioning.rbs +77 -0
  89. data/sig/bucket_website.rbs +93 -0
  90. data/sig/client.rbs +2586 -0
  91. data/sig/customizations/bucket.rbs +19 -0
  92. data/sig/customizations/object.rbs +38 -0
  93. data/sig/customizations/object_summary.rbs +35 -0
  94. data/sig/errors.rbs +44 -0
  95. data/sig/multipart_upload.rbs +120 -0
  96. data/sig/multipart_upload_part.rbs +109 -0
  97. data/sig/object.rbs +464 -0
  98. data/sig/object_acl.rbs +86 -0
  99. data/sig/object_summary.rbs +347 -0
  100. data/sig/object_version.rbs +143 -0
  101. data/sig/resource.rbs +141 -0
  102. data/sig/types.rbs +2868 -0
  103. data/sig/waiters.rbs +95 -0
  104. metadata +51 -16
  105. data/lib/aws-sdk-s3/arn/access_point_arn.rb +0 -69
  106. data/lib/aws-sdk-s3/arn/multi_region_access_point_arn.rb +0 -69
  107. data/lib/aws-sdk-s3/arn/object_lambda_arn.rb +0 -69
  108. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +0 -73
  109. data/lib/aws-sdk-s3/plugins/object_lambda_endpoint.rb +0 -25
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # WARNING ABOUT GENERATED CODE
4
+ #
5
+ # This file is generated. See the contributing guide for more information:
6
+ # https://github.com/aws/aws-sdk-ruby/blob/version-3/CONTRIBUTING.md
7
+ #
8
+ # WARNING ABOUT GENERATED CODE
9
+
10
+
11
+ module Aws::S3
12
+ module Plugins
13
+ class Endpoints < Seahorse::Client::Plugin
14
+ option(
15
+ :endpoint_provider,
16
+ doc_type: 'Aws::S3::EndpointProvider',
17
+ rbs_type: 'untyped',
18
+ docstring: <<~DOCS) do |_cfg|
19
+ The endpoint provider used to resolve endpoints. Any object that responds to
20
+ `#resolve_endpoint(parameters)` where `parameters` is a Struct similar to
21
+ `Aws::S3::EndpointParameters`.
22
+ DOCS
23
+ Aws::S3::EndpointProvider.new
24
+ end
25
+
26
+ option(
27
+ :disable_s3_express_session_auth,
28
+ doc_type: 'boolean',
29
+ docstring: <<~DOCS) do |cfg|
30
+ Parameter to indicate whether S3Express session auth should be disabled
31
+ DOCS
32
+ nil
33
+ end
34
+
35
+ # @api private
36
+ class Handler < Seahorse::Client::Handler
37
+ def call(context)
38
+ unless context[:discovered_endpoint]
39
+ params = Aws::S3::Endpoints.parameters_for_operation(context)
40
+ endpoint = context.config.endpoint_provider.resolve_endpoint(params)
41
+
42
+ context.http_request.endpoint = endpoint.url
43
+ apply_endpoint_headers(context, endpoint.headers)
44
+
45
+ context[:endpoint_params] = params
46
+ context[:endpoint_properties] = endpoint.properties
47
+ end
48
+
49
+ context[:auth_scheme] =
50
+ Aws::Endpoints.resolve_auth_scheme(context, endpoint)
51
+
52
+ with_metrics(context) { @handler.call(context) }
53
+ end
54
+
55
+ private
56
+
57
+ def with_metrics(context, &block)
58
+ metrics = []
59
+ metrics << 'ENDPOINT_OVERRIDE' unless context.config.regional_endpoint
60
+ if context[:auth_scheme] && context[:auth_scheme]['name'] == 'sigv4a'
61
+ metrics << 'SIGV4A_SIGNING'
62
+ end
63
+ if context.config.credentials&.credentials&.account_id
64
+ metrics << 'RESOLVED_ACCOUNT_ID'
65
+ end
66
+ Aws::Plugins::UserAgent.metric(*metrics, &block)
67
+ end
68
+
69
+ def apply_endpoint_headers(context, headers)
70
+ headers.each do |key, values|
71
+ value = values
72
+ .compact
73
+ .map { |s| Seahorse::Util.escape_header_list_string(s.to_s) }
74
+ .join(',')
75
+
76
+ context.http_request.headers[key] = value
77
+ end
78
+ end
79
+ end
80
+
81
+ def add_handlers(handlers, _config)
82
+ handlers.add(Handler, step: :build, priority: 75)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -16,7 +16,8 @@ module Aws
16
16
 
17
17
  def call(context)
18
18
  body = context.http_request.body
19
- if body.respond_to?(:size) && body.size > 0
19
+ if body.respond_to?(:size) && body.size > 0 &&
20
+ !context[:use_accelerate_endpoint]
20
21
  context.http_request.headers['expect'] = '100-continue'
21
22
  end
22
23
  @handler.call(context)
@@ -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
@@ -15,22 +15,67 @@ module Aws
15
15
 
16
16
  def call(context)
17
17
  @handler.call(context).on(200) do |response|
18
- if error = check_for_error(context)
19
- context.http_response.status_code = 500
20
- response.data = nil
21
- response.error = error
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
22
53
  end
54
+
55
+ if structure_shape?(shape)
56
+ shape.members.any? { |_, k| k.location.nil? }
57
+ else
58
+ false
23
59
  end
24
60
  end
25
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
+
26
72
  def check_for_error(context)
27
73
  xml = context.http_response.body_contents
28
- if xml.match(/<Error>/)
29
- error_code = xml.match(/<Code>(.+?)<\/Code>/)[1]
30
- error_message = xml.match(/<Message>(.+?)<\/Message>/)[1]
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]
31
77
  S3::Errors.error_class(error_code).new(context, error_message)
32
- elsif !xml.match(/<\w/) # Must have the start of an XML Tag
33
- # Other incomplete xml bodies will result in XML ParsingError
78
+ elsif incomplete_xml_body?(xml, context.operation.output)
34
79
  Seahorse::Client::NetworkingError.new(
35
80
  S3::Errors
36
81
  .error_class('InternalError')
@@ -40,15 +85,7 @@ module Aws
40
85
  end
41
86
  end
42
87
 
43
- handler(
44
- Handler,
45
- step: :sign,
46
- operations: [
47
- :complete_multipart_upload,
48
- :copy_object,
49
- :upload_part_copy,
50
- ]
51
- )
88
+ handler(Handler, step: :sign)
52
89
  end
53
90
  end
54
91
  end
@@ -16,40 +16,17 @@ Defaults to `legacy` mode which uses the global endpoint.
16
16
  resolve_iad_regional_endpoint(cfg)
17
17
  end
18
18
 
19
- def add_handlers(handlers, config)
20
- # only modify non-custom endpoints
21
- if config.regional_endpoint && config.region == 'us-east-1'
22
- handlers.add(Handler)
23
- end
24
- end
25
-
26
- # @api private
27
- class Handler < Seahorse::Client::Handler
28
-
29
- def call(context)
30
- # WriteGetObjectResponse does not have a global endpoint
31
- # ARNs are regionalized, so don't touch those either.
32
- if context.operation.name != 'WriteGetObjectResponse' &&
33
- context.config.s3_us_east_1_regional_endpoint == 'legacy' &&
34
- !context.metadata[:s3_arn]
35
- host = context.http_request.endpoint.host
36
- legacy_host = IADRegionalEndpoint.legacy_host(host)
37
- context.http_request.endpoint.host = legacy_host
38
- end
39
- @handler.call(context)
40
- end
41
-
42
- end
43
-
44
- def self.legacy_host(host)
45
- host.sub(".us-east-1", '')
46
- end
47
-
48
19
  private
49
20
 
50
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
+
51
27
  mode = ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] ||
52
28
  Aws.shared_config.s3_us_east_1_regional_endpoint(profile: cfg.profile) ||
29
+ default_mode_value ||
53
30
  'legacy'
54
31
  mode = mode.downcase
55
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][:location_constraint] ||= region
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 effectively deprecated in favor of modeled
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.respond_to?(:size) && 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
- default: true,
61
- doc_type: 'Boolean',
62
- docstring: <<-DOCS)
63
- When `true` a MD5 checksum will be computed and sent in the Content Md5
64
- header for :put_object and :upload_part. When `false`, MD5 checksums
65
- will not be computed for these operations. Checksums are still computed
66
- for operations requiring them. Checksum errors returned by Amazon S3 are
67
- automatically retried up to `:retry_limit` times.
68
- DOCS
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,27 +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 is an implementation detail and may be modified.
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
- service: 's3',
16
- region: cfg.sigv4_region,
17
- credentials: cfg.credentials
18
- )
19
- end
20
-
21
- option(:sigv4_region) do |cfg|
22
- # S3 removes core's signature_v4 plugin that checks for this
23
- raise Aws::Errors::MissingRegionError if cfg.region.nil?
24
-
25
- Aws::Partitions::EndpointProvider.signing_region(cfg.region, 's3')
26
- end
27
-
28
20
  def add_handlers(handlers, cfg)
29
21
  case cfg.signature_version
30
22
  when 'v4' then add_v4_handlers(handlers)
@@ -37,11 +29,11 @@ module Aws
37
29
 
38
30
  def add_v4_handlers(handlers)
39
31
  handlers.add(CachedBucketRegionHandler, step: :sign, priority: 60)
40
- handlers.add(V4Handler, step: :sign)
41
32
  handlers.add(BucketRegionErrorHandler, step: :sign, priority: 40)
42
33
  end
43
34
 
44
35
  def add_legacy_handler(handlers)
36
+ # generic Sign plugin will be skipped if it sees sigv2
45
37
  handlers.add(LegacyHandler, step: :sign)
46
38
  end
47
39
 
@@ -52,53 +44,6 @@ module Aws
52
44
  end
53
45
  end
54
46
 
55
- class V4Handler < Seahorse::Client::Handler
56
- def call(context)
57
- Aws::Plugins::SignatureV4.apply_signature(
58
- context: context,
59
- signer: sigv4_signer(context)
60
- )
61
- @handler.call(context)
62
- end
63
-
64
- private
65
-
66
- def sigv4_signer(context)
67
- # If the client was configured with the wrong region,
68
- # we have to build a new signer.
69
- if context[:cached_sigv4_region] &&
70
- context[:cached_sigv4_region] != context.config.sigv4_signer.region
71
- S3Signer.build_v4_signer(
72
- service: 's3',
73
- region: context[:cached_sigv4_region],
74
- credentials: context.config.credentials
75
- )
76
- elsif (arn = context.metadata[:s3_arn])
77
- if arn[:arn].is_a?(MultiRegionAccessPointARN)
78
- signing_region = '*'
79
- signing_algorithm = :sigv4a
80
- else
81
- signing_region = arn[:resolved_region]
82
- signing_algorithm = :sigv4
83
- end
84
- S3Signer.build_v4_signer(
85
- service: arn[:arn].service,
86
- signing_algorithm: signing_algorithm,
87
- region: signing_region,
88
- credentials: context.config.credentials
89
- )
90
- elsif context.operation.name == 'WriteGetObjectResponse'
91
- S3Signer.build_v4_signer(
92
- service: 's3-object-lambda',
93
- region: context.config.sigv4_region,
94
- credentials: context.config.credentials
95
- )
96
- else
97
- context.config.sigv4_signer
98
- end
99
- end
100
- end
101
-
102
47
  # This handler will update the http endpoint when the bucket region
103
48
  # is known/cached.
104
49
  class CachedBucketRegionHandler < Seahorse::Client::Handler
@@ -111,12 +56,14 @@ module Aws
111
56
  private
112
57
 
113
58
  def check_for_cached_region(context, bucket)
114
- cached_region = S3::BUCKET_REGIONS[bucket]
115
- if cached_region && cached_region != context.config.region
59
+ cached_region = Aws::S3.bucket_region_cache[bucket]
60
+ if cached_region &&
61
+ cached_region != context.config.region &&
62
+ !S3Signer.custom_endpoint?(context)
116
63
  context.http_request.endpoint.host = S3Signer.new_hostname(
117
64
  context, cached_region
118
65
  )
119
- context[:cached_sigv4_region] = cached_region
66
+ context[:sigv4_region] = cached_region # Sign plugin will use this
120
67
  end
121
68
  end
122
69
  end
@@ -124,7 +71,8 @@ module Aws
124
71
  # This handler detects when a request fails because of a mismatched bucket
125
72
  # region. It follows up by making a request to determine the correct
126
73
  # region, then finally a version 4 signed request against the correct
127
- # 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.
128
76
  class BucketRegionErrorHandler < Seahorse::Client::Handler
129
77
  def call(context)
130
78
  response = @handler.call(context)
@@ -136,7 +84,8 @@ module Aws
136
84
  def handle_region_errors(response)
137
85
  if wrong_sigv4_region?(response) &&
138
86
  !fips_region?(response) &&
139
- !custom_endpoint?(response)
87
+ !S3Signer.custom_endpoint?(response.context) &&
88
+ !expired_credentials?(response)
140
89
  get_region_and_retry(response.context)
141
90
  else
142
91
  response
@@ -153,18 +102,15 @@ module Aws
153
102
  end
154
103
 
155
104
  def update_bucket_cache(context, actual_region)
156
- S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
105
+ Aws::S3.bucket_region_cache[context.params[:bucket]] = actual_region
157
106
  end
158
107
 
159
108
  def fips_region?(resp)
160
- resp.context.http_request.endpoint.host.include?('fips')
109
+ resp.context.http_request.endpoint.host.include?('s3-fips.')
161
110
  end
162
111
 
163
- def custom_endpoint?(resp)
164
- resolved_suffix = Aws::Partitions::EndpointProvider.dns_suffix_for(
165
- resp.context.config.region
166
- )
167
- !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>/)
168
114
  end
169
115
 
170
116
  def wrong_sigv4_region?(resp)
@@ -179,18 +125,14 @@ module Aws
179
125
  context, actual_region
180
126
  )
181
127
  context.metadata[:redirect_region] = actual_region
182
- # if it's an ARN, use the service in the ARN
183
- if (arn = context.metadata[:s3_arn])
184
- service = arn[:arn].service
185
- end
186
- Aws::Plugins::SignatureV4.apply_signature(
187
- context: context,
188
- signer: S3Signer.build_v4_signer(
189
- service: service || 's3',
190
- region: actual_region,
191
- credentials: context.config.credentials
192
- )
128
+
129
+ signer = Aws::Plugins::Sign.signer_for(
130
+ context[:auth_scheme],
131
+ context.config,
132
+ actual_region
193
133
  )
134
+
135
+ signer.sign(context)
194
136
  end
195
137
 
196
138
  def region_from_body(body)
@@ -216,33 +158,22 @@ module Aws
216
158
  end
217
159
 
218
160
  class << self
219
- # @option options [required, String] :region
220
- # @option options [required, #credentials] :credentials
221
- # @api private
222
- def build_v4_signer(options = {})
223
- Aws::Sigv4::Signer.new(
224
- service: options[:service],
225
- region: options[:region],
226
- credentials_provider: options[:credentials],
227
- signing_algorithm: options.fetch(:signing_algorithm, :sigv4),
228
- uri_escape_path: false,
229
- unsigned_headers: ['content-length', 'x-amzn-trace-id']
230
- )
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
231
168
  end
232
169
 
233
- # Check to see if the bucket is actually an ARN
234
- # Otherwise it will retry with the ARN as the bucket name.
235
- def new_hostname(context, region)
236
- uri = URI.parse(
237
- Aws::Partitions::EndpointProvider.resolve(region, 's3')
238
- )
170
+ def custom_endpoint?(context)
171
+ region = context.config.region
172
+ partition = Aws::Endpoints::Matchers.aws_partition(region)
173
+ endpoint = context.http_request.endpoint
239
174
 
240
- if (arn = context.metadata[:s3_arn])
241
- # Retry with the response region and not the ARN resolved one
242
- ARN.resolve_url!(uri, arn[:arn], region).host
243
- else
244
- "#{context.params[:bucket]}.#{uri.host}"
245
- end
175
+ !endpoint.hostname.include?(partition['dnsSuffix']) &&
176
+ !endpoint.hostname.include?(partition['dualStackDnsSuffix'])
246
177
  end
247
178
  end
248
179
  end