aws-sdk-s3 1.10.0 → 1.208.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 (153) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1517 -0
  3. data/LICENSE.txt +202 -0
  4. data/VERSION +1 -0
  5. data/lib/aws-sdk-s3/access_grants_credentials.rb +57 -0
  6. data/lib/aws-sdk-s3/access_grants_credentials_provider.rb +250 -0
  7. data/lib/aws-sdk-s3/bucket.rb +1062 -99
  8. data/lib/aws-sdk-s3/bucket_acl.rb +67 -17
  9. data/lib/aws-sdk-s3/bucket_cors.rb +80 -17
  10. data/lib/aws-sdk-s3/bucket_lifecycle.rb +71 -19
  11. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +126 -20
  12. data/lib/aws-sdk-s3/bucket_logging.rb +68 -18
  13. data/lib/aws-sdk-s3/bucket_notification.rb +56 -20
  14. data/lib/aws-sdk-s3/bucket_policy.rb +108 -17
  15. data/lib/aws-sdk-s3/bucket_region_cache.rb +11 -5
  16. data/lib/aws-sdk-s3/bucket_request_payment.rb +60 -15
  17. data/lib/aws-sdk-s3/bucket_tagging.rb +71 -17
  18. data/lib/aws-sdk-s3/bucket_versioning.rb +166 -17
  19. data/lib/aws-sdk-s3/bucket_website.rb +78 -17
  20. data/lib/aws-sdk-s3/client.rb +20068 -3879
  21. data/lib/aws-sdk-s3/client_api.rb +1957 -209
  22. data/lib/aws-sdk-s3/customizations/bucket.rb +57 -38
  23. data/lib/aws-sdk-s3/customizations/errors.rb +40 -0
  24. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
  25. data/lib/aws-sdk-s3/customizations/object.rb +338 -68
  26. data/lib/aws-sdk-s3/customizations/object_summary.rb +17 -0
  27. data/lib/aws-sdk-s3/customizations/object_version.rb +13 -0
  28. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
  29. data/lib/aws-sdk-s3/customizations/types/permanent_redirect.rb +26 -0
  30. data/lib/aws-sdk-s3/customizations.rb +30 -27
  31. data/lib/aws-sdk-s3/default_executor.rb +103 -0
  32. data/lib/aws-sdk-s3/encryption/client.rb +29 -8
  33. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +71 -29
  34. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +45 -5
  35. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
  36. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +15 -2
  37. data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
  38. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +11 -3
  39. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +11 -3
  40. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
  41. data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
  42. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +48 -11
  43. data/lib/aws-sdk-s3/encryption/materials.rb +8 -6
  44. data/lib/aws-sdk-s3/encryption/utils.rb +25 -0
  45. data/lib/aws-sdk-s3/encryption.rb +4 -0
  46. data/lib/aws-sdk-s3/encryptionV2/client.rb +645 -0
  47. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +68 -0
  48. data/lib/aws-sdk-s3/encryptionV2/decryption.rb +205 -0
  49. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +187 -0
  50. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +40 -0
  51. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +67 -0
  52. data/lib/aws-sdk-s3/encryptionV2/errors.rb +37 -0
  53. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +58 -0
  54. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +37 -0
  55. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +75 -0
  56. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +31 -0
  57. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +181 -0
  58. data/lib/aws-sdk-s3/encryptionV2/materials.rb +60 -0
  59. data/lib/aws-sdk-s3/encryptionV2/utils.rb +108 -0
  60. data/lib/aws-sdk-s3/encryptionV3/client.rb +885 -0
  61. data/lib/aws-sdk-s3/encryptionV3/decrypt_handler.rb +98 -0
  62. data/lib/aws-sdk-s3/encryptionV3/decryption.rb +244 -0
  63. data/lib/aws-sdk-s3/encryptionV3/default_cipher_provider.rb +159 -0
  64. data/lib/aws-sdk-s3/encryptionV3/default_key_provider.rb +35 -0
  65. data/lib/aws-sdk-s3/encryptionV3/encrypt_handler.rb +98 -0
  66. data/lib/aws-sdk-s3/encryptionV3/errors.rb +47 -0
  67. data/lib/aws-sdk-s3/encryptionV3/io_auth_decrypter.rb +60 -0
  68. data/lib/aws-sdk-s3/encryptionV3/io_decrypter.rb +35 -0
  69. data/lib/aws-sdk-s3/encryptionV3/io_encrypter.rb +84 -0
  70. data/lib/aws-sdk-s3/encryptionV3/key_provider.rb +28 -0
  71. data/lib/aws-sdk-s3/encryptionV3/kms_cipher_provider.rb +159 -0
  72. data/lib/aws-sdk-s3/encryptionV3/materials.rb +58 -0
  73. data/lib/aws-sdk-s3/encryptionV3/utils.rb +321 -0
  74. data/lib/aws-sdk-s3/encryption_v2.rb +24 -0
  75. data/lib/aws-sdk-s3/encryption_v3.rb +24 -0
  76. data/lib/aws-sdk-s3/endpoint_parameters.rb +181 -0
  77. data/lib/aws-sdk-s3/endpoint_provider.rb +886 -0
  78. data/lib/aws-sdk-s3/endpoints.rb +1544 -0
  79. data/lib/aws-sdk-s3/errors.rb +181 -1
  80. data/lib/aws-sdk-s3/event_streams.rb +69 -0
  81. data/lib/aws-sdk-s3/express_credentials.rb +55 -0
  82. data/lib/aws-sdk-s3/express_credentials_provider.rb +59 -0
  83. data/lib/aws-sdk-s3/file_downloader.rb +261 -82
  84. data/lib/aws-sdk-s3/file_part.rb +16 -13
  85. data/lib/aws-sdk-s3/file_uploader.rb +37 -22
  86. data/lib/aws-sdk-s3/legacy_signer.rb +19 -26
  87. data/lib/aws-sdk-s3/multipart_download_error.rb +8 -0
  88. data/lib/aws-sdk-s3/multipart_file_uploader.rb +142 -80
  89. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +191 -0
  90. data/lib/aws-sdk-s3/multipart_upload.rb +342 -31
  91. data/lib/aws-sdk-s3/multipart_upload_error.rb +5 -4
  92. data/lib/aws-sdk-s3/multipart_upload_part.rb +387 -47
  93. data/lib/aws-sdk-s3/object.rb +2733 -204
  94. data/lib/aws-sdk-s3/object_acl.rb +112 -25
  95. data/lib/aws-sdk-s3/object_copier.rb +9 -5
  96. data/lib/aws-sdk-s3/object_multipart_copier.rb +50 -23
  97. data/lib/aws-sdk-s3/object_summary.rb +2265 -181
  98. data/lib/aws-sdk-s3/object_version.rb +542 -74
  99. data/lib/aws-sdk-s3/plugins/accelerate.rb +17 -64
  100. data/lib/aws-sdk-s3/plugins/access_grants.rb +178 -0
  101. data/lib/aws-sdk-s3/plugins/arn.rb +70 -0
  102. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +7 -43
  103. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +20 -3
  104. data/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +31 -0
  105. data/lib/aws-sdk-s3/plugins/dualstack.rb +7 -50
  106. data/lib/aws-sdk-s3/plugins/endpoints.rb +86 -0
  107. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +5 -4
  108. data/lib/aws-sdk-s3/plugins/express_session_auth.rb +88 -0
  109. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +3 -1
  110. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +62 -17
  111. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +44 -0
  112. data/lib/aws-sdk-s3/plugins/location_constraint.rb +5 -1
  113. data/lib/aws-sdk-s3/plugins/md5s.rb +14 -67
  114. data/lib/aws-sdk-s3/plugins/redirects.rb +5 -1
  115. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
  116. data/lib/aws-sdk-s3/plugins/s3_signer.rb +67 -93
  117. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +3 -1
  118. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +137 -0
  119. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +4 -1
  120. data/lib/aws-sdk-s3/presigned_post.rb +160 -99
  121. data/lib/aws-sdk-s3/presigner.rb +178 -81
  122. data/lib/aws-sdk-s3/resource.rb +164 -15
  123. data/lib/aws-sdk-s3/transfer_manager.rb +303 -0
  124. data/lib/aws-sdk-s3/types.rb +15981 -4168
  125. data/lib/aws-sdk-s3/waiters.rb +67 -1
  126. data/lib/aws-sdk-s3.rb +46 -31
  127. data/sig/bucket.rbs +231 -0
  128. data/sig/bucket_acl.rbs +78 -0
  129. data/sig/bucket_cors.rbs +69 -0
  130. data/sig/bucket_lifecycle.rbs +88 -0
  131. data/sig/bucket_lifecycle_configuration.rbs +115 -0
  132. data/sig/bucket_logging.rbs +76 -0
  133. data/sig/bucket_notification.rbs +114 -0
  134. data/sig/bucket_policy.rbs +59 -0
  135. data/sig/bucket_request_payment.rbs +54 -0
  136. data/sig/bucket_tagging.rbs +65 -0
  137. data/sig/bucket_versioning.rbs +77 -0
  138. data/sig/bucket_website.rbs +93 -0
  139. data/sig/client.rbs +2612 -0
  140. data/sig/customizations/bucket.rbs +19 -0
  141. data/sig/customizations/object.rbs +38 -0
  142. data/sig/customizations/object_summary.rbs +35 -0
  143. data/sig/errors.rbs +44 -0
  144. data/sig/multipart_upload.rbs +120 -0
  145. data/sig/multipart_upload_part.rbs +109 -0
  146. data/sig/object.rbs +464 -0
  147. data/sig/object_acl.rbs +86 -0
  148. data/sig/object_summary.rbs +347 -0
  149. data/sig/object_version.rbs +143 -0
  150. data/sig/resource.rbs +141 -0
  151. data/sig/types.rbs +2899 -0
  152. data/sig/waiters.rbs +95 -0
  153. metadata +97 -14
@@ -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(/>(.+?)<\/LocationConstraint>/)
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
- if error = check_for_error(context)
17
- context.http_response.status_code = 500
18
- response.data = nil
19
- 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
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(/<Error>/)
27
- error_code = xml.match(/<Code>(.+?)<\/Code>/)[1]
28
- 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]
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][:location_constraint] ||= region
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,78 +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
- ]
17
-
18
- # @api private
19
- class Handler < Seahorse::Client::Handler
20
-
21
- CHUNK_SIZE = 1 * 1024 * 1024 # one MB
22
-
23
- def call(context)
24
- body = context.http_request.body
25
- if body.size > 0
26
- context.http_request.headers['Content-Md5'] ||= md5(body)
27
- end
28
- @handler.call(context)
29
- end
30
-
31
- private
32
-
33
- # @param [File, Tempfile, IO#read, String] value
34
- # @return [String<MD5>]
35
- def md5(value)
36
- if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path)
37
- Base64.encode64(OpenSSL::Digest::MD5.file(value).digest).strip
38
- elsif value.respond_to?(:read)
39
- md5 = OpenSSL::Digest::MD5.new
40
- update_in_chunks(md5, value)
41
- Base64.encode64(md5.digest).strip
42
- else
43
- Base64.encode64(OpenSSL::Digest::MD5.digest(value)).strip
44
- end
45
- end
46
-
47
- def update_in_chunks(digest, io)
48
- while chunk = io.read(CHUNK_SIZE)
49
- digest.update(chunk)
50
- end
51
- io.rewind
52
- end
53
-
54
- end
55
-
56
12
  option(:compute_checksums,
57
- default: true,
58
- doc_type: 'Boolean',
59
- docstring: <<-DOCS)
60
- When `true` a MD5 checksum will be computed for every request that
61
- sends a body. When `false`, MD5 checksums will only be computed
62
- for operations that require them. Checksum errors returned by Amazon
63
- S3 are automatically retried up to `:retry_limit` times.
64
- DOCS
65
-
66
- def add_handlers(handlers, config)
67
- # priority set low to ensure md5 is computed AFTER the request is
68
- # built but before it is signed
69
- handlers.add(Handler, {
70
- priority: 10,
71
- step: :build,
72
- operations: config.compute_checksums ? nil : REQUIRED_OPERATIONS,
73
- })
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
74
22
  end
75
-
76
23
  end
77
24
  end
78
25
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -18,7 +20,9 @@ by Amazon S3.
18
20
  response = @handler.call(context)
19
21
  if context.http_response.status_code == 307
20
22
  endpoint = context.http_response.headers['location']
21
- context.http_request.endpoint = endpoint
23
+ unless context.http_request.endpoint.host.include?('fips')
24
+ context.http_request.endpoint = endpoint
25
+ end
22
26
  context.http_response.body.truncate(0)
23
27
  @handler.call(context)
24
28
  else
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -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 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
+ #
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::BUCKET_REGIONS[bucket]
94
- if cached_region && cached_region != context.config.region
95
- context.http_request.endpoint.host = S3Signer.new_hostname(context, cached_region)
96
- context[:cached_sigv4_region] = cached_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)
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,32 +102,42 @@ module Aws
130
102
  end
131
103
 
132
104
  def update_bucket_cache(context, actual_region)
133
- S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
105
+ Aws::S3.bucket_region_cache[context.params[:bucket]] = actual_region
106
+ end
107
+
108
+ def fips_region?(resp)
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>/)
134
114
  end
135
115
 
136
116
  def wrong_sigv4_region?(resp)
137
117
  resp.context.http_response.status_code == 400 &&
138
- (
139
- resp.context.http_response.headers['x-amz-bucket-region'] ||
140
- resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/)
141
- )
118
+ (resp.context.http_response.headers['x-amz-bucket-region'] ||
119
+ resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/))
142
120
  end
143
121
 
144
122
  def resign_with_new_region(context, actual_region)
145
123
  context.http_response.body.truncate(0)
146
- context.http_request.endpoint.host = S3Signer.new_hostname(context, actual_region)
147
- Aws::Plugins::SignatureV4.apply_signature(
148
- context: context,
149
- signer: S3Signer.build_v4_signer(
150
- region: actual_region,
151
- credentials: context.config.credentials
152
- )
124
+ context.http_request.endpoint.host = S3Signer.new_hostname(
125
+ context, actual_region
126
+ )
127
+ context.metadata[:redirect_region] = actual_region
128
+
129
+ signer = Aws::Plugins::Sign.signer_for(
130
+ context[:auth_scheme],
131
+ context.config,
132
+ actual_region
153
133
  )
134
+
135
+ signer.sign(context)
154
136
  end
155
137
 
156
138
  def region_from_body(body)
157
139
  region = body.match(/<Region>(.+?)<\/Region>/)[1]
158
- if region.nil? || region == ""
140
+ if region.nil? || region == ''
159
141
  raise "couldn't get region from body: #{body}"
160
142
  else
161
143
  region
@@ -163,44 +145,36 @@ module Aws
163
145
  end
164
146
 
165
147
  def log_warning(context, actual_region)
166
- msg = "S3 client configured for #{context.config.region.inspect} " +
167
- "but the bucket #{context.params[:bucket].inspect} is in " +
168
- "#{actual_region.inspect}; Please configure the proper region " +
169
- "to avoid multiple unnecessary redirects and signing attempts\n"
170
- 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)
171
153
  logger.warn(msg)
172
154
  else
173
155
  warn(msg)
174
156
  end
175
157
  end
176
-
177
158
  end
178
159
 
179
160
  class << self
180
-
181
- # @option options [required, String] :region
182
- # @option options [required, #credentials] :credentials
183
- # @api private
184
- def build_v4_signer(options = {})
185
- Aws::Sigv4::Signer.new({
186
- service: 's3',
187
- region: options[:region],
188
- credentials_provider: options[:credentials],
189
- uri_escape_path: false,
190
- unsigned_headers: ['content-length', 'x-amzn-trace-id'],
191
- })
192
- end
193
-
194
161
  def new_hostname(context, region)
195
- bucket = context.params[:bucket]
196
- if region == 'us-east-1'
197
- "#{bucket}.s3.amazonaws.com"
198
- else
199
- endpoint = Aws::Partitions::EndpointProvider.resolve(region, 's3')
200
- bucket + '.' + URI.parse(endpoint).host
201
- 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
202
168
  end
203
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
204
178
  end
205
179
  end
206
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