aws-sdk-s3 1.36.0 → 1.95.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +768 -0
  3. data/LICENSE.txt +202 -0
  4. data/VERSION +1 -0
  5. data/lib/aws-sdk-s3/arn/access_point_arn.rb +69 -0
  6. data/lib/aws-sdk-s3/arn/object_lambda_arn.rb +69 -0
  7. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +73 -0
  8. data/lib/aws-sdk-s3/bucket.rb +277 -76
  9. data/lib/aws-sdk-s3/bucket_acl.rb +40 -15
  10. data/lib/aws-sdk-s3/bucket_cors.rb +50 -14
  11. data/lib/aws-sdk-s3/bucket_lifecycle.rb +33 -14
  12. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +32 -14
  13. data/lib/aws-sdk-s3/bucket_logging.rb +35 -15
  14. data/lib/aws-sdk-s3/bucket_notification.rb +32 -18
  15. data/lib/aws-sdk-s3/bucket_policy.rb +34 -13
  16. data/lib/aws-sdk-s3/bucket_region_cache.rb +2 -0
  17. data/lib/aws-sdk-s3/bucket_request_payment.rb +34 -12
  18. data/lib/aws-sdk-s3/bucket_tagging.rb +42 -14
  19. data/lib/aws-sdk-s3/bucket_versioning.rb +67 -12
  20. data/lib/aws-sdk-s3/bucket_website.rb +49 -17
  21. data/lib/aws-sdk-s3/client.rb +7494 -618
  22. data/lib/aws-sdk-s3/client_api.rb +417 -2
  23. data/lib/aws-sdk-s3/customizations/bucket.rb +59 -16
  24. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +2 -0
  25. data/lib/aws-sdk-s3/customizations/object.rb +125 -60
  26. data/lib/aws-sdk-s3/customizations/object_summary.rb +5 -0
  27. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +2 -0
  28. data/lib/aws-sdk-s3/customizations.rb +4 -1
  29. data/lib/aws-sdk-s3/encryption/client.rb +22 -5
  30. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +72 -26
  31. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +43 -5
  32. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +2 -0
  33. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +13 -2
  34. data/lib/aws-sdk-s3/encryption/errors.rb +2 -0
  35. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +2 -0
  36. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +11 -3
  37. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +2 -0
  38. data/lib/aws-sdk-s3/encryption/key_provider.rb +2 -0
  39. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +34 -3
  40. data/lib/aws-sdk-s3/encryption/materials.rb +8 -6
  41. data/lib/aws-sdk-s3/encryption/utils.rb +25 -0
  42. data/lib/aws-sdk-s3/encryption.rb +4 -0
  43. data/lib/aws-sdk-s3/encryptionV2/client.rb +566 -0
  44. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +226 -0
  45. data/lib/aws-sdk-s3/encryptionV2/default_cipher_provider.rb +170 -0
  46. data/lib/aws-sdk-s3/encryptionV2/default_key_provider.rb +40 -0
  47. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +69 -0
  48. data/lib/aws-sdk-s3/encryptionV2/errors.rb +37 -0
  49. data/lib/aws-sdk-s3/encryptionV2/io_auth_decrypter.rb +58 -0
  50. data/lib/aws-sdk-s3/encryptionV2/io_decrypter.rb +37 -0
  51. data/lib/aws-sdk-s3/encryptionV2/io_encrypter.rb +73 -0
  52. data/lib/aws-sdk-s3/encryptionV2/key_provider.rb +31 -0
  53. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +169 -0
  54. data/lib/aws-sdk-s3/encryptionV2/materials.rb +60 -0
  55. data/lib/aws-sdk-s3/encryptionV2/utils.rb +103 -0
  56. data/lib/aws-sdk-s3/encryption_v2.rb +23 -0
  57. data/lib/aws-sdk-s3/errors.rb +123 -1
  58. data/lib/aws-sdk-s3/event_streams.rb +15 -8
  59. data/lib/aws-sdk-s3/file_downloader.rb +10 -8
  60. data/lib/aws-sdk-s3/file_part.rb +11 -6
  61. data/lib/aws-sdk-s3/file_uploader.rb +28 -14
  62. data/lib/aws-sdk-s3/legacy_signer.rb +17 -25
  63. data/lib/aws-sdk-s3/multipart_file_uploader.rb +53 -13
  64. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +20 -7
  65. data/lib/aws-sdk-s3/multipart_upload.rb +64 -29
  66. data/lib/aws-sdk-s3/multipart_upload_error.rb +2 -0
  67. data/lib/aws-sdk-s3/multipart_upload_part.rb +115 -42
  68. data/lib/aws-sdk-s3/object.rb +656 -151
  69. data/lib/aws-sdk-s3/object_acl.rb +64 -21
  70. data/lib/aws-sdk-s3/object_copier.rb +2 -0
  71. data/lib/aws-sdk-s3/object_multipart_copier.rb +2 -0
  72. data/lib/aws-sdk-s3/object_summary.rb +474 -138
  73. data/lib/aws-sdk-s3/object_version.rb +122 -58
  74. data/lib/aws-sdk-s3/plugins/accelerate.rb +32 -38
  75. data/lib/aws-sdk-s3/plugins/arn.rb +228 -0
  76. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +7 -7
  77. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +25 -3
  78. data/lib/aws-sdk-s3/plugins/dualstack.rb +15 -4
  79. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +4 -4
  80. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +2 -0
  81. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +11 -3
  82. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +67 -0
  83. data/lib/aws-sdk-s3/plugins/location_constraint.rb +2 -0
  84. data/lib/aws-sdk-s3/plugins/md5s.rb +30 -28
  85. data/lib/aws-sdk-s3/plugins/object_lambda_endpoint.rb +25 -0
  86. data/lib/aws-sdk-s3/plugins/redirects.rb +2 -0
  87. data/lib/aws-sdk-s3/plugins/s3_host_id.rb +2 -0
  88. data/lib/aws-sdk-s3/plugins/s3_signer.rb +64 -35
  89. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +3 -1
  90. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +118 -0
  91. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +2 -0
  92. data/lib/aws-sdk-s3/presigned_post.rb +72 -32
  93. data/lib/aws-sdk-s3/presigner.rb +162 -66
  94. data/lib/aws-sdk-s3/resource.rb +23 -5
  95. data/lib/aws-sdk-s3/types.rb +6441 -952
  96. data/lib/aws-sdk-s3/waiters.rb +67 -1
  97. data/lib/aws-sdk-s3.rb +12 -6
  98. metadata +35 -12
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../arn/access_point_arn'
4
+ require_relative '../arn/object_lambda_arn'
5
+ require_relative '../arn/outpost_access_point_arn'
6
+
7
+ module Aws
8
+ module S3
9
+ module Plugins
10
+ # When an accesspoint ARN is provided for :bucket in S3 operations, this
11
+ # plugin resolves the request endpoint from the ARN when possible.
12
+ # @api private
13
+ class ARN < Seahorse::Client::Plugin
14
+ option(
15
+ :s3_use_arn_region,
16
+ default: true,
17
+ doc_type: 'Boolean',
18
+ docstring: <<-DOCS) do |cfg|
19
+ For S3 ARNs passed into the `:bucket` parameter, this option will
20
+ use the region in the ARN, allowing for cross-region requests to
21
+ be made. Set to `false` to use the client's region instead.
22
+ DOCS
23
+ resolve_s3_use_arn_region(cfg)
24
+ end
25
+
26
+ # param validator is validate:50
27
+ # endpoint is build:90 (populates the URI for the first time)
28
+ # endpoint pattern is build:10
29
+ def add_handlers(handlers, _config)
30
+ handlers.add(ARNHandler, step: :validate, priority: 75)
31
+ handlers.add(UrlHandler)
32
+ end
33
+
34
+ # After extracting out any ARN input, resolve a new URL with it.
35
+ class UrlHandler < Seahorse::Client::Handler
36
+ def call(context)
37
+ if context.metadata[:s3_arn]
38
+ ARN.resolve_url!(
39
+ context.http_request.endpoint,
40
+ context.metadata[:s3_arn][:arn],
41
+ context.metadata[:s3_arn][:resolved_region],
42
+ context.metadata[:s3_arn][:fips],
43
+ context.metadata[:s3_arn][:dualstack],
44
+ # if regional_endpoint is false, a custom endpoint was provided
45
+ # in this case, we want to prefix the endpoint using the ARN
46
+ !context.config.regional_endpoint
47
+ )
48
+ end
49
+ @handler.call(context)
50
+ end
51
+ end
52
+
53
+ # This plugin will extract out any ARN input and set context for other
54
+ # plugins to use without having to translate the ARN again.
55
+ class ARNHandler < Seahorse::Client::Handler
56
+ def call(context)
57
+ bucket_member = _bucket_member(context.operation.input.shape)
58
+ if bucket_member && (bucket = context.params[bucket_member])
59
+ resolved_region, arn = ARN.resolve_arn!(
60
+ bucket,
61
+ context.config.region,
62
+ context.config.s3_use_arn_region
63
+ )
64
+ if arn
65
+ validate_config!(context, arn)
66
+
67
+ fips = false
68
+ if resolved_region.include?('fips')
69
+ fips = true
70
+ resolved_region = resolved_region.gsub('fips-', '')
71
+ .gsub('-fips', '')
72
+ end
73
+
74
+ context.metadata[:s3_arn] = {
75
+ arn: arn,
76
+ resolved_region: resolved_region,
77
+ fips: fips,
78
+ dualstack: extract_dualstack_config!(context)
79
+ }
80
+ end
81
+ end
82
+ @handler.call(context)
83
+ end
84
+
85
+ private
86
+
87
+ def _bucket_member(input)
88
+ input.members.each do |member, ref|
89
+ return member if ref.shape.name == 'BucketName'
90
+ end
91
+ nil
92
+ end
93
+
94
+ # other plugins use dualstack so disable it when we're done
95
+ def extract_dualstack_config!(context)
96
+ dualstack = context[:use_dualstack_endpoint]
97
+ context[:use_dualstack_endpoint] = false if dualstack
98
+ dualstack
99
+ end
100
+
101
+ def validate_config!(context, arn)
102
+ if context.config.force_path_style
103
+ raise ArgumentError,
104
+ 'Cannot provide an Access Point ARN when '\
105
+ '`:force_path_style` is set to true.'
106
+ end
107
+
108
+ if context.config.use_accelerate_endpoint
109
+ raise ArgumentError,
110
+ 'Cannot provide an Access Point ARN when '\
111
+ '`:use_accelerate_endpoint` is set to true.'
112
+ end
113
+
114
+ if !arn.support_dualstack? && context[:use_dualstack_endpoint]
115
+ raise ArgumentError,
116
+ 'Cannot provide an Outpost Access Point ARN when '\
117
+ '`:use_dualstack_endpoint` is set to true.'
118
+ end
119
+ end
120
+ end
121
+
122
+ class << self
123
+ # @api private
124
+ def resolve_arn!(member_value, region, use_arn_region)
125
+ if Aws::ARNParser.arn?(member_value)
126
+ arn = Aws::ARNParser.parse(member_value)
127
+ s3_arn = resolve_arn_type!(arn)
128
+ s3_arn.validate_arn!
129
+ validate_region_config!(s3_arn, region, use_arn_region)
130
+ region = s3_arn.region if use_arn_region && !region.include?('fips')
131
+ [region, s3_arn]
132
+ else
133
+ [region]
134
+ end
135
+ end
136
+
137
+ # @api private
138
+ def resolve_url!(url, arn, region, fips = false, dualstack = false, has_custom_endpoint = false)
139
+ custom_endpoint = url.host if has_custom_endpoint
140
+ url.host = arn.host_url(region, fips, dualstack, custom_endpoint)
141
+ url.path = url_path(url.path, arn)
142
+ url
143
+ end
144
+
145
+ private
146
+
147
+ def resolve_arn_type!(arn)
148
+ case arn.service
149
+ when 's3'
150
+ Aws::S3::AccessPointARN.new(arn.to_h)
151
+ when 's3-outposts'
152
+ Aws::S3::OutpostAccessPointARN.new(arn.to_h)
153
+ when 's3-object-lambda'
154
+ Aws::S3::ObjectLambdaARN.new(arn.to_h)
155
+ else
156
+ raise ArgumentError,
157
+ 'Only Access Point, Outposts, and Object Lambdas ARNs '\
158
+ 'are currently supported.'
159
+ end
160
+ end
161
+
162
+ def resolve_s3_use_arn_region(cfg)
163
+ value = ENV['AWS_S3_USE_ARN_REGION'] ||
164
+ Aws.shared_config.s3_use_arn_region(profile: cfg.profile) ||
165
+ 'true'
166
+ value = Aws::Util.str_2_bool(value)
167
+ # Raise if provided value is not true or false
168
+ if value.nil?
169
+ raise ArgumentError,
170
+ 'Must provide either `true` or `false` for the '\
171
+ '`s3_use_arn_region` profile option or for '\
172
+ "ENV['AWS_S3_USE_ARN_REGION']."
173
+ end
174
+ value
175
+ end
176
+
177
+ # Remove ARN from the path because we've already set the new host
178
+ def url_path(path, arn)
179
+ path = path.sub("/#{Seahorse::Util.uri_escape(arn.to_s)}", '')
180
+ .sub("/#{arn}", '')
181
+ "/#{path}" unless path =~ /^\//
182
+ path
183
+ end
184
+
185
+ def validate_region_config!(arn, region, use_arn_region)
186
+ if ['s3-external-1', 'aws-global'].include?(region)
187
+ # These "regions" are not regional endpoints
188
+ unless use_arn_region
189
+ raise Aws::Errors::InvalidARNRegionError,
190
+ 'Configured client region is not a regional endpoint.'
191
+ end
192
+ # These "regions" are in the AWS partition
193
+ # Cannot use ARN region unless it's the same partition
194
+ unless arn.partition == 'aws'
195
+ raise Aws::Errors::InvalidARNPartitionError
196
+ end
197
+ else
198
+ if region.include?('fips')
199
+ # If ARN type doesn't support FIPS but the client region is FIPS
200
+ unless arn.support_fips?
201
+ raise ArgumentError,
202
+ 'FIPS client regions are not supported for this type '\
203
+ 'of ARN.'
204
+ end
205
+
206
+ fips = true
207
+ # Normalize the region so we can compare partition and regions
208
+ region = region.gsub('fips-', '').gsub('-fips', '')
209
+ end
210
+
211
+ # Raise if the ARN and client regions are in different partitions
212
+ if use_arn_region &&
213
+ !Aws::Partitions.partition(arn.partition).region?(region)
214
+ raise Aws::Errors::InvalidARNPartitionError
215
+ end
216
+
217
+ # Raise if regions mismatch
218
+ # Either when it's a fips client or not using the ARN region
219
+ if (!use_arn_region || fips) && region != arn.region
220
+ raise Aws::Errors::InvalidARNRegionError
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -38,11 +40,9 @@ request URI and never moved to the host as a sub-domain.
38
40
  def move_dns_compat_bucket_to_subdomain(context)
39
41
  bucket_name = context.params[:bucket]
40
42
  endpoint = context.http_request.endpoint
41
- if
42
- bucket_name &&
43
- BucketDns.dns_compatible?(bucket_name, https?(endpoint)) &&
44
- context.operation_name.to_s != 'get_bucket_location'
45
- then
43
+ if bucket_name &&
44
+ BucketDns.dns_compatible?(bucket_name, https?(endpoint)) &&
45
+ context.operation_name.to_s != 'get_bucket_location'
46
46
  move_bucket_to_subdomain(bucket_name, endpoint)
47
47
  end
48
48
  end
@@ -73,8 +73,8 @@ request URI and never moved to the host as a sub-domain.
73
73
  end
74
74
  end
75
75
 
76
- private
77
-
76
+ # @param [String] bucket_name
77
+ # @return [Boolean]
78
78
  def valid_subdomain?(bucket_name)
79
79
  bucket_name.size < 64 &&
80
80
  bucket_name =~ /^[a-z0-9][a-z0-9.-]+[a-z0-9]$/ &&
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -5,14 +7,34 @@ module Aws
5
7
  class BucketNameRestrictions < Seahorse::Client::Plugin
6
8
  class Handler < Seahorse::Client::Handler
7
9
 
10
+ # Useful because Aws::S3::Errors::SignatureDoesNotMatch is thrown
11
+ # when passed a bucket with a forward slash. Instead provide a more
12
+ # helpful error. Ideally should not be a plugin?
8
13
  def call(context)
9
- if context.params.key?(:bucket) && context.params[:bucket].include?('/')
10
- msg = ":bucket option must not contain a forward-slash (/)"
11
- raise ArgumentError, msg
14
+ bucket_member = _bucket_member(context.operation.input.shape)
15
+ if bucket_member && (bucket = context.params[bucket_member])
16
+ _resolved_region, arn = ARN.resolve_arn!(
17
+ bucket,
18
+ context.config.region,
19
+ context.config.s3_use_arn_region
20
+ )
21
+ if !arn && bucket.include?('/')
22
+ raise ArgumentError,
23
+ 'bucket name must not contain a forward-slash (/)'
24
+ end
12
25
  end
13
26
  @handler.call(context)
14
27
  end
15
28
 
29
+ private
30
+
31
+ def _bucket_member(input)
32
+ input.members.each do |member, ref|
33
+ return member if ref.shape.name == 'BucketName'
34
+ end
35
+ nil
36
+ end
37
+
16
38
  end
17
39
 
18
40
  handler(Handler)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -14,14 +16,22 @@ for all operations.
14
16
 
15
17
  def add_handlers(handlers, config)
16
18
  handlers.add(OptionHandler, step: :initialize)
17
- handlers.add(DualstackHandler, step: :build, priority: 0)
19
+ handlers.add(DualstackHandler, step: :build, priority: 11)
18
20
  end
19
21
 
20
22
  # @api private
21
23
  class OptionHandler < Seahorse::Client::Handler
22
24
  def call(context)
23
- dualstack = context.params.delete(:use_dualstack_endpoint)
25
+ # Support client configuration and per-operation configuration
26
+ if context.params.is_a?(Hash)
27
+ dualstack = context.params.delete(:use_dualstack_endpoint)
28
+ end
24
29
  dualstack = context.config.use_dualstack_endpoint if dualstack.nil?
30
+ # Raise if :endpoint and dualstack are both provided
31
+ if dualstack && !context.config.regional_endpoint
32
+ raise ArgumentError,
33
+ 'Cannot use both :use_dualstack_endpoint and :endpoint'
34
+ end
25
35
  context[:use_dualstack_endpoint] = dualstack
26
36
  @handler.call(context)
27
37
  end
@@ -30,7 +40,9 @@ for all operations.
30
40
  # @api private
31
41
  class DualstackHandler < Seahorse::Client::Handler
32
42
  def call(context)
33
- apply_dualstack_endpoint(context) if use_dualstack_endpoint?(context)
43
+ if context.config.regional_endpoint && use_dualstack_endpoint?(context)
44
+ apply_dualstack_endpoint(context)
45
+ end
34
46
  @handler.call(context)
35
47
  end
36
48
 
@@ -38,7 +50,6 @@ for all operations.
38
50
  def apply_dualstack_endpoint(context)
39
51
  bucket_name = context.params[:bucket]
40
52
  region = context.config.region
41
- context.config.force_path_style
42
53
  dns_suffix = Aws::Partitions::EndpointProvider.dns_suffix_for(region)
43
54
 
44
55
  if use_bucket_dns?(bucket_name, context)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -13,10 +15,8 @@ module Aws
13
15
  class Handler < Seahorse::Client::Handler
14
16
 
15
17
  def call(context)
16
- if
17
- context.http_request.body &&
18
- context.http_request.body.size > 0
19
- then
18
+ body = context.http_request.body
19
+ if body.respond_to?(:size) && body.size > 0
20
20
  context.http_request.headers['expect'] = '100-continue'
21
21
  end
22
22
  @handler.call(context)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -27,12 +29,19 @@ module Aws
27
29
  error_code = xml.match(/<Code>(.+?)<\/Code>/)[1]
28
30
  error_message = xml.match(/<Message>(.+?)<\/Message>/)[1]
29
31
  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
34
+ Seahorse::Client::NetworkingError.new(
35
+ S3::Errors
36
+ .error_class('InternalError')
37
+ .new(context, 'Empty or incomplete response body')
38
+ )
30
39
  end
31
40
  end
32
-
33
41
  end
34
42
 
35
- handler(Handler,
43
+ handler(
44
+ Handler,
36
45
  step: :sign,
37
46
  operations: [
38
47
  :complete_multipart_upload,
@@ -40,7 +49,6 @@ module Aws
40
49
  :upload_part_copy,
41
50
  ]
42
51
  )
43
-
44
52
  end
45
53
  end
46
54
  end
@@ -0,0 +1,67 @@
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
+ 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
+ private
49
+
50
+ def self.resolve_iad_regional_endpoint(cfg)
51
+ mode = ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] ||
52
+ Aws.shared_config.s3_us_east_1_regional_endpoint(profile: cfg.profile) ||
53
+ 'legacy'
54
+ mode = mode.downcase
55
+ unless %w(legacy regional).include?(mode)
56
+ raise ArgumentError, "expected :s3_us_east_1_regional_endpoint or"\
57
+ " ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] to be `legacy` or"\
58
+ " `regional`."
59
+ end
60
+ mode
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -1,21 +1,19 @@
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 effectively 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
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
19
17
  ]
20
18
 
21
19
  # @api private
@@ -25,7 +23,7 @@ module Aws
25
23
 
26
24
  def call(context)
27
25
  body = context.http_request.body
28
- if body.size > 0
26
+ if body.respond_to?(:size) && body.size > 0
29
27
  context.http_request.headers['Content-Md5'] ||= md5(body)
30
28
  end
31
29
  @handler.call(context)
@@ -37,18 +35,20 @@ module Aws
37
35
  # @return [String<MD5>]
38
36
  def md5(value)
39
37
  if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path)
40
- Base64.encode64(OpenSSL::Digest::MD5.file(value).digest).strip
38
+ OpenSSL::Digest::MD5.file(value).base64digest
41
39
  elsif value.respond_to?(:read)
42
40
  md5 = OpenSSL::Digest::MD5.new
43
41
  update_in_chunks(md5, value)
44
- Base64.encode64(md5.digest).strip
42
+ md5.base64digest
45
43
  else
46
- Base64.encode64(OpenSSL::Digest::MD5.digest(value)).strip
44
+ OpenSSL::Digest::MD5.digest(value).base64digest
47
45
  end
48
46
  end
49
47
 
50
48
  def update_in_chunks(digest, io)
51
- while chunk = io.read(CHUNK_SIZE, buffer ||= "")
49
+ loop do
50
+ chunk = io.read(CHUNK_SIZE)
51
+ break unless chunk
52
52
  digest.update(chunk)
53
53
  end
54
54
  io.rewind
@@ -60,20 +60,22 @@ module Aws
60
60
  default: true,
61
61
  doc_type: 'Boolean',
62
62
  docstring: <<-DOCS)
63
- When `true` a MD5 checksum will be computed for every request that
64
- sends a body. When `false`, MD5 checksums will only be computed
65
- for operations that require them. Checksum errors returned by Amazon
66
- S3 are automatically retried up to `:retry_limit` times.
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.
67
68
  DOCS
68
69
 
69
70
  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
- })
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
77
79
  end
78
80
 
79
81
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Plugins
6
+ # WriteGetObjectResponse is called from Lambda after a data transform.
7
+ # If there is no custom endpoint, we change the endpoint from s3 to
8
+ # s3-object-lambda just for this operation.
9
+ class ObjectLambdaEndpoint < Seahorse::Client::Plugin
10
+ class Handler < Seahorse::Client::Handler
11
+ def call(context)
12
+ if context.config.regional_endpoint
13
+ host = context.http_request.endpoint.host
14
+ host = host.sub('s3.', 's3-object-lambda.')
15
+ context.http_request.endpoint.host = host
16
+ end
17
+ @handler.call(context)
18
+ end
19
+ end
20
+
21
+ handler(Handler, operations: [:write_get_object_response])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module S3
3
5
  module Plugins