aws-sdk-s3 1.92.0 → 1.114.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +167 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-s3/arn/access_point_arn.rb +12 -9
  5. data/lib/aws-sdk-s3/arn/multi_region_access_point_arn.rb +68 -0
  6. data/lib/aws-sdk-s3/arn/object_lambda_arn.rb +12 -9
  7. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +8 -9
  8. data/lib/aws-sdk-s3/bucket.rb +134 -36
  9. data/lib/aws-sdk-s3/bucket_acl.rb +25 -6
  10. data/lib/aws-sdk-s3/bucket_cors.rb +23 -6
  11. data/lib/aws-sdk-s3/bucket_lifecycle.rb +27 -8
  12. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +28 -6
  13. data/lib/aws-sdk-s3/bucket_logging.rb +22 -6
  14. data/lib/aws-sdk-s3/bucket_notification.rb +19 -7
  15. data/lib/aws-sdk-s3/bucket_policy.rb +23 -6
  16. data/lib/aws-sdk-s3/bucket_request_payment.rb +21 -4
  17. data/lib/aws-sdk-s3/bucket_tagging.rb +23 -6
  18. data/lib/aws-sdk-s3/bucket_versioning.rb +63 -12
  19. data/lib/aws-sdk-s3/bucket_website.rb +23 -6
  20. data/lib/aws-sdk-s3/client.rb +2902 -1449
  21. data/lib/aws-sdk-s3/client_api.rb +390 -21
  22. data/lib/aws-sdk-s3/customizations/object.rb +107 -15
  23. data/lib/aws-sdk-s3/encryption/client.rb +1 -1
  24. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +0 -4
  25. data/lib/aws-sdk-s3/encryptionV2/client.rb +1 -1
  26. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +0 -4
  27. data/lib/aws-sdk-s3/encryptionV2/encrypt_handler.rb +0 -4
  28. data/lib/aws-sdk-s3/file_downloader.rb +7 -2
  29. data/lib/aws-sdk-s3/file_uploader.rb +8 -3
  30. data/lib/aws-sdk-s3/multipart_file_uploader.rb +26 -7
  31. data/lib/aws-sdk-s3/multipart_upload.rb +129 -15
  32. data/lib/aws-sdk-s3/multipart_upload_part.rb +136 -16
  33. data/lib/aws-sdk-s3/object.rb +369 -108
  34. data/lib/aws-sdk-s3/object_acl.rb +28 -9
  35. data/lib/aws-sdk-s3/object_summary.rb +221 -93
  36. data/lib/aws-sdk-s3/object_version.rb +70 -43
  37. data/lib/aws-sdk-s3/plugins/accelerate.rb +7 -1
  38. data/lib/aws-sdk-s3/plugins/arn.rb +72 -30
  39. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +1 -1
  40. data/lib/aws-sdk-s3/plugins/dualstack.rb +25 -31
  41. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +1 -1
  42. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +6 -0
  43. data/lib/aws-sdk-s3/plugins/md5s.rb +5 -3
  44. data/lib/aws-sdk-s3/plugins/s3_signer.rb +35 -6
  45. data/lib/aws-sdk-s3/plugins/skip_whole_multipart_get_checksums.rb +31 -0
  46. data/lib/aws-sdk-s3/plugins/streaming_retry.rb +23 -2
  47. data/lib/aws-sdk-s3/presigned_post.rb +38 -19
  48. data/lib/aws-sdk-s3/presigner.rb +18 -3
  49. data/lib/aws-sdk-s3/resource.rb +22 -2
  50. data/lib/aws-sdk-s3/types.rb +3041 -1015
  51. data/lib/aws-sdk-s3.rb +1 -1
  52. metadata +12 -11
@@ -56,6 +56,12 @@ module Aws::S3
56
56
  data[:etag]
57
57
  end
58
58
 
59
+ # The algorithm that was used to create a checksum of the object.
60
+ # @return [Array<String>]
61
+ def checksum_algorithm
62
+ data[:checksum_algorithm]
63
+ end
64
+
59
65
  # Size in bytes of the object.
60
66
  # @return [Integer]
61
67
  def size
@@ -245,20 +251,21 @@ module Aws::S3
245
251
  # @option options [String] :request_payer
246
252
  # Confirms that the requester knows that they will be charged for the
247
253
  # request. Bucket owners need not specify this parameter in their
248
- # requests. For information about downloading objects from requester
249
- # pays buckets, see [Downloading Objects in Requestor Pays Buckets][1]
250
- # in the *Amazon S3 Developer Guide*.
254
+ # requests. For information about downloading objects from Requester
255
+ # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
256
+ # in the *Amazon S3 User Guide*.
251
257
  #
252
258
  #
253
259
  #
254
260
  # [1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html
255
261
  # @option options [Boolean] :bypass_governance_retention
256
262
  # Indicates whether S3 Object Lock should bypass Governance-mode
257
- # restrictions to process this operation.
263
+ # restrictions to process this operation. To use this header, you must
264
+ # have the `s3:BypassGovernanceRetention` permission.
258
265
  # @option options [String] :expected_bucket_owner
259
266
  # The account ID of the expected bucket owner. If the bucket is owned by
260
- # a different account, the request will fail with an HTTP `403 (Access
261
- # Denied)` error.
267
+ # a different account, the request fails with the HTTP status code `403
268
+ # Forbidden` (access denied).
262
269
  # @return [Types::DeleteObjectOutput]
263
270
  def delete(options = {})
264
271
  options = options.merge(
@@ -290,20 +297,21 @@ module Aws::S3
290
297
  # request_payer: "requester", # accepts requester
291
298
  # part_number: 1,
292
299
  # expected_bucket_owner: "AccountId",
300
+ # checksum_mode: "ENABLED", # accepts ENABLED
293
301
  # })
294
302
  # @param [Hash] options ({})
295
303
  # @option options [String] :if_match
296
304
  # Return the object only if its entity tag (ETag) is the same as the one
297
- # specified, otherwise return a 412 (precondition failed).
305
+ # specified; otherwise, return a 412 (precondition failed) error.
298
306
  # @option options [Time,DateTime,Date,Integer,String] :if_modified_since
299
307
  # Return the object only if it has been modified since the specified
300
- # time, otherwise return a 304 (not modified).
308
+ # time; otherwise, return a 304 (not modified) error.
301
309
  # @option options [String] :if_none_match
302
310
  # Return the object only if its entity tag (ETag) is different from the
303
- # one specified, otherwise return a 304 (not modified).
311
+ # one specified; otherwise, return a 304 (not modified) error.
304
312
  # @option options [Time,DateTime,Date,Integer,String] :if_unmodified_since
305
313
  # Return the object only if it has not been modified since the specified
306
- # time, otherwise return a 412 (precondition failed).
314
+ # time; otherwise, return a 412 (precondition failed) error.
307
315
  # @option options [String] :range
308
316
  # Downloads the specified range bytes of an object. For more information
309
317
  # about the HTTP Range header, see
@@ -345,9 +353,9 @@ module Aws::S3
345
353
  # @option options [String] :request_payer
346
354
  # Confirms that the requester knows that they will be charged for the
347
355
  # request. Bucket owners need not specify this parameter in their
348
- # requests. For information about downloading objects from requester
349
- # pays buckets, see [Downloading Objects in Requestor Pays Buckets][1]
350
- # in the *Amazon S3 Developer Guide*.
356
+ # requests. For information about downloading objects from Requester
357
+ # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
358
+ # in the *Amazon S3 User Guide*.
351
359
  #
352
360
  #
353
361
  #
@@ -359,8 +367,10 @@ module Aws::S3
359
367
  # object.
360
368
  # @option options [String] :expected_bucket_owner
361
369
  # The account ID of the expected bucket owner. If the bucket is owned by
362
- # a different account, the request will fail with an HTTP `403 (Access
363
- # Denied)` error.
370
+ # a different account, the request fails with the HTTP status code `403
371
+ # Forbidden` (access denied).
372
+ # @option options [String] :checksum_mode
373
+ # To retrieve the checksum, this mode must be enabled.
364
374
  # @return [Types::GetObjectOutput]
365
375
  def get(options = {}, &block)
366
376
  options = options.merge(
@@ -386,33 +396,24 @@ module Aws::S3
386
396
  # request_payer: "requester", # accepts requester
387
397
  # part_number: 1,
388
398
  # expected_bucket_owner: "AccountId",
399
+ # checksum_mode: "ENABLED", # accepts ENABLED
389
400
  # })
390
401
  # @param [Hash] options ({})
391
402
  # @option options [String] :if_match
392
403
  # Return the object only if its entity tag (ETag) is the same as the one
393
- # specified, otherwise return a 412 (precondition failed).
404
+ # specified; otherwise, return a 412 (precondition failed) error.
394
405
  # @option options [Time,DateTime,Date,Integer,String] :if_modified_since
395
406
  # Return the object only if it has been modified since the specified
396
- # time, otherwise return a 304 (not modified).
407
+ # time; otherwise, return a 304 (not modified) error.
397
408
  # @option options [String] :if_none_match
398
409
  # Return the object only if its entity tag (ETag) is different from the
399
- # one specified, otherwise return a 304 (not modified).
410
+ # one specified; otherwise, return a 304 (not modified) error.
400
411
  # @option options [Time,DateTime,Date,Integer,String] :if_unmodified_since
401
412
  # Return the object only if it has not been modified since the specified
402
- # time, otherwise return a 412 (precondition failed).
413
+ # time; otherwise, return a 412 (precondition failed) error.
403
414
  # @option options [String] :range
404
- # Downloads the specified range bytes of an object. For more information
405
- # about the HTTP Range header, see
406
- # [http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35][1].
407
- #
408
- # <note markdown="1"> Amazon S3 doesn't support retrieving multiple ranges of data per
409
- # `GET` request.
410
- #
411
- # </note>
412
- #
413
- #
414
- #
415
- # [1]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
415
+ # Because `HeadObject` returns only the metadata for an object, this
416
+ # parameter has no effect.
416
417
  # @option options [String] :sse_customer_algorithm
417
418
  # Specifies the algorithm to use to when encrypting the object (for
418
419
  # example, AES256).
@@ -429,9 +430,9 @@ module Aws::S3
429
430
  # @option options [String] :request_payer
430
431
  # Confirms that the requester knows that they will be charged for the
431
432
  # request. Bucket owners need not specify this parameter in their
432
- # requests. For information about downloading objects from requester
433
- # pays buckets, see [Downloading Objects in Requestor Pays Buckets][1]
434
- # in the *Amazon S3 Developer Guide*.
433
+ # requests. For information about downloading objects from Requester
434
+ # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
435
+ # in the *Amazon S3 User Guide*.
435
436
  #
436
437
  #
437
438
  #
@@ -443,8 +444,15 @@ module Aws::S3
443
444
  # the number of parts in this object.
444
445
  # @option options [String] :expected_bucket_owner
445
446
  # The account ID of the expected bucket owner. If the bucket is owned by
446
- # a different account, the request will fail with an HTTP `403 (Access
447
- # Denied)` error.
447
+ # a different account, the request fails with the HTTP status code `403
448
+ # Forbidden` (access denied).
449
+ # @option options [String] :checksum_mode
450
+ # To retrieve the checksum, this parameter must be enabled.
451
+ #
452
+ # In addition, if you enable `ChecksumMode` and the object is encrypted
453
+ # with Amazon Web Services Key Management Service (Amazon Web Services
454
+ # KMS), you must have permission to use the `kms:Decrypt` action for the
455
+ # request to succeed.
448
456
  # @return [Types::HeadObjectOutput]
449
457
  def head(options = {})
450
458
  options = options.merge(
@@ -524,6 +532,7 @@ module Aws::S3
524
532
  # request_payer: "requester", # accepts requester
525
533
  # bypass_governance_retention: false,
526
534
  # expected_bucket_owner: "AccountId",
535
+ # checksum_algorithm: "CRC32", # accepts CRC32, CRC32C, SHA1, SHA256
527
536
  # })
528
537
  # @param options ({})
529
538
  # @option options [String] :mfa
@@ -534,21 +543,39 @@ module Aws::S3
534
543
  # @option options [String] :request_payer
535
544
  # Confirms that the requester knows that they will be charged for the
536
545
  # request. Bucket owners need not specify this parameter in their
537
- # requests. For information about downloading objects from requester
538
- # pays buckets, see [Downloading Objects in Requestor Pays Buckets][1]
539
- # in the *Amazon S3 Developer Guide*.
546
+ # requests. For information about downloading objects from Requester
547
+ # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
548
+ # in the *Amazon S3 User Guide*.
540
549
  #
541
550
  #
542
551
  #
543
552
  # [1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html
544
553
  # @option options [Boolean] :bypass_governance_retention
545
554
  # Specifies whether you want to delete this object even if it has a
546
- # Governance-type Object Lock in place. You must have sufficient
547
- # permissions to perform this operation.
555
+ # Governance-type Object Lock in place. To use this header, you must
556
+ # have the `s3:BypassGovernanceRetention` permission.
548
557
  # @option options [String] :expected_bucket_owner
549
558
  # The account ID of the expected bucket owner. If the bucket is owned by
550
- # a different account, the request will fail with an HTTP `403 (Access
551
- # Denied)` error.
559
+ # a different account, the request fails with the HTTP status code `403
560
+ # Forbidden` (access denied).
561
+ # @option options [String] :checksum_algorithm
562
+ # Indicates the algorithm used to create the checksum for the object
563
+ # when using the SDK. This header will not provide any additional
564
+ # functionality if not using the SDK. When sending this header, there
565
+ # must be a corresponding `x-amz-checksum` or `x-amz-trailer` header
566
+ # sent. Otherwise, Amazon S3 fails the request with the HTTP status code
567
+ # `400 Bad Request`. For more information, see [Checking object
568
+ # integrity][1] in the *Amazon S3 User Guide*.
569
+ #
570
+ # If you provide an individual checksum, Amazon S3 ignores any provided
571
+ # `ChecksumAlgorithm` parameter.
572
+ #
573
+ # This checksum algorithm must be the same for all parts and it match
574
+ # the checksum value supplied in the `CreateMultipartUpload` request.
575
+ #
576
+ #
577
+ #
578
+ # [1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html
552
579
  # @return [void]
553
580
  def batch_delete!(options = {})
554
581
  batch_enum.each do |batch|
@@ -41,11 +41,17 @@ each bucket. [Go here for more information](http://docs.aws.amazon.com/AmazonS3/
41
41
  accelerate = context.params.delete(:use_accelerate_endpoint)
42
42
  end
43
43
  accelerate = context.config.use_accelerate_endpoint if accelerate.nil?
44
- # Raise if :endpoint and dualstack are both provided
44
+ # Raise if :endpoint and accelerate are both provided
45
45
  if accelerate && !context.config.regional_endpoint
46
46
  raise ArgumentError,
47
47
  'Cannot use both :use_accelerate_endpoint and :endpoint'
48
48
  end
49
+ # Raise if :use_fips_endpoint and accelerate are both provided
50
+ if accelerate && context.config.use_fips_endpoint
51
+ raise ArgumentError,
52
+ 'Cannot use both :use_accelerate_endpoint and '\
53
+ ':use_fips_endpoint'
54
+ end
49
55
  context[:use_accelerate_endpoint] = accelerate
50
56
  @handler.call(context)
51
57
  end
@@ -3,6 +3,7 @@
3
3
  require_relative '../arn/access_point_arn'
4
4
  require_relative '../arn/object_lambda_arn'
5
5
  require_relative '../arn/outpost_access_point_arn'
6
+ require_relative '../arn/multi_region_access_point_arn'
6
7
 
7
8
  module Aws
8
9
  module S3
@@ -23,6 +24,18 @@ be made. Set to `false` to use the client's region instead.
23
24
  resolve_s3_use_arn_region(cfg)
24
25
  end
25
26
 
27
+ option(
28
+ :s3_disable_multiregion_access_points,
29
+ default: false,
30
+ doc_type: 'Boolean',
31
+ docstring: <<-DOCS) do |cfg|
32
+ When set to `false` this will option will raise errors when multi-region
33
+ access point ARNs are used. Multi-region access points can potentially
34
+ result in cross region requests.
35
+ DOCS
36
+ resolve_s3_disable_multiregion_access_points(cfg)
37
+ end
38
+
26
39
  # param validator is validate:50
27
40
  # endpoint is build:90 (populates the URI for the first time)
28
41
  # endpoint pattern is build:10
@@ -39,6 +52,7 @@ be made. Set to `false` to use the client's region instead.
39
52
  context.http_request.endpoint,
40
53
  context.metadata[:s3_arn][:arn],
41
54
  context.metadata[:s3_arn][:resolved_region],
55
+ context.metadata[:s3_arn][:fips],
42
56
  context.metadata[:s3_arn][:dualstack],
43
57
  # if regional_endpoint is false, a custom endpoint was provided
44
58
  # in this case, we want to prefix the endpoint using the ARN
@@ -66,6 +80,7 @@ be made. Set to `false` to use the client's region instead.
66
80
  context.metadata[:s3_arn] = {
67
81
  arn: arn,
68
82
  resolved_region: resolved_region,
83
+ fips: context.config.use_fips_endpoint,
69
84
  dualstack: extract_dualstack_config!(context)
70
85
  }
71
86
  end
@@ -104,8 +119,21 @@ be made. Set to `false` to use the client's region instead.
104
119
 
105
120
  if !arn.support_dualstack? && context[:use_dualstack_endpoint]
106
121
  raise ArgumentError,
107
- 'Cannot provide an Outpost Access Point ARN when '\
108
- '`:use_dualstack_endpoint` is set to true.'
122
+ 'Cannot provide an Outpost Access Point, Object Lambda, '\
123
+ 'or Multi-region Access Point ARN'\
124
+ ' when `:use_dualstack_endpoint` is set to true.'
125
+ end
126
+
127
+ if arn.region.empty? && context.config.s3_disable_multiregion_access_points
128
+ raise ArgumentError,
129
+ 'Cannot provide a Multi-region Access Point ARN with '\
130
+ '`:s3_disable_multiregion_access_points` set to true'
131
+ end
132
+
133
+ if context.config.use_fips_endpoint && !arn.support_fips?
134
+ raise ArgumentError,
135
+ 'FIPS client regions are not supported for this type '\
136
+ 'of ARN.'
109
137
  end
110
138
  end
111
139
  end
@@ -126,9 +154,9 @@ be made. Set to `false` to use the client's region instead.
126
154
  end
127
155
 
128
156
  # @api private
129
- def resolve_url!(url, arn, region, dualstack = false, has_custom_endpoint = false)
157
+ def resolve_url!(url, arn, region, fips = false, dualstack = false, has_custom_endpoint = false)
130
158
  custom_endpoint = url.host if has_custom_endpoint
131
- url.host = arn.host_url(region, dualstack, custom_endpoint)
159
+ url.host = arn.host_url(region, fips, dualstack, custom_endpoint)
132
160
  url.path = url_path(url.path, arn)
133
161
  url
134
162
  end
@@ -138,7 +166,9 @@ be made. Set to `false` to use the client's region instead.
138
166
  def resolve_arn_type!(arn)
139
167
  case arn.service
140
168
  when 's3'
141
- Aws::S3::AccessPointARN.new(arn.to_h)
169
+ arn.region.empty? ?
170
+ Aws::S3::MultiRegionAccessPointARN.new(arn.to_h) :
171
+ Aws::S3::AccessPointARN.new(arn.to_h)
142
172
  when 's3-outposts'
143
173
  Aws::S3::OutpostAccessPointARN.new(arn.to_h)
144
174
  when 's3-object-lambda'
@@ -165,6 +195,21 @@ be made. Set to `false` to use the client's region instead.
165
195
  value
166
196
  end
167
197
 
198
+ def resolve_s3_disable_multiregion_access_points(cfg)
199
+ value = ENV['AWS_S3_DISABLE_MULTIREGION_ACCESS_POINTS'] ||
200
+ Aws.shared_config.s3_disable_multiregion_access_points(profile: cfg.profile) ||
201
+ 'false'
202
+ value = Aws::Util.str_2_bool(value)
203
+ # Raise if provided value is not true or false
204
+ if value.nil?
205
+ raise ArgumentError,
206
+ 'Must provide either `true` or `false` for '\
207
+ 's3_use_arn_region profile option or for '\
208
+ "ENV['AWS_S3_USE_ARN_REGION']"
209
+ end
210
+ value
211
+ end
212
+
168
213
  # Remove ARN from the path because we've already set the new host
169
214
  def url_path(path, arn)
170
215
  path = path.sub("/#{Seahorse::Util.uri_escape(arn.to_s)}", '')
@@ -174,34 +219,31 @@ be made. Set to `false` to use the client's region instead.
174
219
  end
175
220
 
176
221
  def validate_region_config!(arn, region, use_arn_region)
177
- fips = arn.support_fips?
178
-
179
- # s3-external-1 is specific just to s3 and not part of partitions
180
- # aws-global is a partition region
181
- unless arn.partition == 'aws' &&
182
- (region == 's3-external-1' || region == 'aws-global')
183
- if !fips && arn.region.include?('fips')
184
- raise ArgumentError,
185
- 'FIPS region ARNs are not supported for this type of ARN.'
222
+ if ['s3-external-1', 'aws-global'].include?(region)
223
+ # These "regions" are not regional endpoints
224
+ unless use_arn_region
225
+ raise Aws::Errors::InvalidARNRegionError,
226
+ 'Configured client region is not a regional endpoint.'
186
227
  end
187
-
188
- if !fips && !use_arn_region && region.include?('fips')
189
- raise ArgumentError,
190
- 'FIPS client regions are not supported for this type of '\
191
- 'ARN without `:s3_use_arn_region`.'
192
- end
193
-
194
- # if it's a fips region, attempt to normalize it
195
- if fips || use_arn_region
196
- region = region.gsub('fips-', '').gsub('-fips', '')
197
- end
198
- if use_arn_region &&
199
- !Aws::Partitions.partition(arn.partition).region?(region)
228
+ # These "regions" are in the AWS partition
229
+ # Cannot use ARN region unless it's the same partition
230
+ unless arn.partition == 'aws'
200
231
  raise Aws::Errors::InvalidARNPartitionError
201
232
  end
202
-
203
- if !use_arn_region && region != arn.region
204
- raise Aws::Errors::InvalidARNRegionError
233
+ else
234
+ # use_arn_region does not apply to MRAP (global) arns
235
+ unless arn.region.empty?
236
+ # Raise if the ARN and client regions are in different partitions
237
+ if use_arn_region &&
238
+ !Aws::Partitions.partition(arn.partition).region?(region)
239
+ raise Aws::Errors::InvalidARNPartitionError
240
+ end
241
+
242
+ # Raise if regions mismatch
243
+ # Either when it's a fips client or not using the ARN region
244
+ if !use_arn_region && region != arn.region
245
+ raise Aws::Errors::InvalidARNRegionError
246
+ end
205
247
  end
206
248
  end
207
249
  end
@@ -24,7 +24,7 @@ request URI and never moved to the host as a sub-domain.
24
24
  DOCS
25
25
 
26
26
  def add_handlers(handlers, config)
27
- handlers.add(Handler) unless config.force_path_style
27
+ handlers.add(Handler, priority: 48) unless config.force_path_style
28
28
  end
29
29
 
30
30
  # @api private
@@ -5,18 +5,9 @@ module Aws
5
5
  module Plugins
6
6
  # @api private
7
7
  class Dualstack < Seahorse::Client::Plugin
8
-
9
- option(:use_dualstack_endpoint,
10
- default: false,
11
- doc_type: 'Boolean',
12
- docstring: <<-DOCS)
13
- When set to `true`, IPv6-compatible bucket endpoints will be used
14
- for all operations.
15
- DOCS
16
-
17
8
  def add_handlers(handlers, config)
18
9
  handlers.add(OptionHandler, step: :initialize)
19
- handlers.add(DualstackHandler, step: :build, priority: 11)
10
+ handlers.add(DualstackHandler, step: :build, priority: 49)
20
11
  end
21
12
 
22
13
  # @api private
@@ -40,38 +31,41 @@ for all operations.
40
31
  # @api private
41
32
  class DualstackHandler < Seahorse::Client::Handler
42
33
  def call(context)
43
- if context.config.regional_endpoint && use_dualstack_endpoint?(context)
34
+ # only rewrite the endpoint if it's not a custom endpoint
35
+ # accelerate/ARN already handle dualstack cases, so ignore these
36
+ # check to see if dualstack is on but configured off via operation
37
+ if context.config.regional_endpoint &&
38
+ use_dualstack_endpoint?(context)
44
39
  apply_dualstack_endpoint(context)
45
40
  end
46
41
  @handler.call(context)
47
42
  end
48
43
 
49
44
  private
50
- def apply_dualstack_endpoint(context)
51
- bucket_name = context.params[:bucket]
52
- region = context.config.region
53
- dns_suffix = Aws::Partitions::EndpointProvider.dns_suffix_for(region)
54
45
 
55
- if use_bucket_dns?(bucket_name, context)
56
- host = "#{bucket_name}.s3.dualstack.#{region}.#{dns_suffix}"
57
- else
58
- host = "s3.dualstack.#{region}.#{dns_suffix}"
59
- end
46
+ def apply_dualstack_endpoint(context)
47
+ new_endpoint = Aws::Partitions::EndpointProvider.resolve(
48
+ context.config.region,
49
+ 's3',
50
+ 'regional',
51
+ {
52
+ dualstack: context[:use_dualstack_endpoint],
53
+ fips: context.config.use_fips_endpoint
54
+ }
55
+ )
60
56
  endpoint = URI.parse(context.http_request.endpoint.to_s)
61
- endpoint.scheme = context.http_request.endpoint.scheme
62
- endpoint.port = context.http_request.endpoint.port
63
- endpoint.host = host
64
- context.http_request.endpoint = endpoint.to_s
65
- end
66
-
67
- def use_bucket_dns?(bucket_name, context)
68
- ssl = context.http_request.endpoint.scheme == "https"
69
- bucket_name && BucketDns.dns_compatible?(bucket_name, ssl) &&
70
- !context.config.force_path_style
57
+ endpoint.host = URI.parse(new_endpoint).host
58
+ context.http_request.endpoint = endpoint
71
59
  end
72
60
 
73
61
  def use_dualstack_endpoint?(context)
74
- context[:use_dualstack_endpoint] && !context[:use_accelerate_endpoint]
62
+ # case when dualstack is turned off via operation
63
+ (context[:use_dualstack_endpoint] ||
64
+ context.config.use_dualstack_endpoint) &&
65
+ # accelerate plugin already applies dualstack
66
+ !context[:use_accelerate_endpoint] &&
67
+ # arns handle dualstack
68
+ !context.metadata[:s3_arn]
75
69
  end
76
70
  end
77
71
 
@@ -11,7 +11,7 @@ module Aws
11
11
  @handler.call(context).on(200) do |response|
12
12
  response.data = S3::Types::GetBucketLocationOutput.new
13
13
  xml = context.http_response.body_contents
14
- matches = xml.match(/>(.+?)<\/LocationConstraint>/)
14
+ matches = xml.match(/<LocationConstraint.*?>(.+?)<\/LocationConstraint>/)
15
15
  response.data[:location_constraint] = matches ? matches[1] : ''
16
16
  end
17
17
  end
@@ -48,8 +48,14 @@ Defaults to `legacy` mode which uses the global endpoint.
48
48
  private
49
49
 
50
50
  def self.resolve_iad_regional_endpoint(cfg)
51
+ default_mode_value =
52
+ if cfg.respond_to?(:defaults_mode_config_resolver)
53
+ cfg.defaults_mode_config_resolver.resolve(:s3_us_east_1_regional_endpoint)
54
+ end
55
+
51
56
  mode = ENV['AWS_S3_US_EAST_1_REGIONAL_ENDPOINT'] ||
52
57
  Aws.shared_config.s3_us_east_1_regional_endpoint(profile: cfg.profile) ||
58
+ default_mode_value ||
53
59
  'legacy'
54
60
  mode = mode.downcase
55
61
  unless %w(legacy regional).include?(mode)
@@ -22,9 +22,11 @@ module Aws
22
22
  CHUNK_SIZE = 1 * 1024 * 1024 # one MB
23
23
 
24
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)
25
+ if !context[:checksum_algorithms] # skip in favor of flexible checksum
26
+ body = context.http_request.body
27
+ if body.respond_to?(:size) && body.size > 0
28
+ context.http_request.headers['Content-Md5'] ||= md5(body)
29
+ end
28
30
  end
29
31
  @handler.call(context)
30
32
  end
@@ -22,7 +22,9 @@ module Aws
22
22
  # S3 removes core's signature_v4 plugin that checks for this
23
23
  raise Aws::Errors::MissingRegionError if cfg.region.nil?
24
24
 
25
- Aws::Partitions::EndpointProvider.signing_region(cfg.region, 's3')
25
+ Aws::Partitions::EndpointProvider.signing_region(
26
+ cfg.region, 's3'
27
+ )
26
28
  end
27
29
 
28
30
  def add_handlers(handlers, cfg)
@@ -74,9 +76,17 @@ module Aws
74
76
  credentials: context.config.credentials
75
77
  )
76
78
  elsif (arn = context.metadata[:s3_arn])
79
+ if arn[:arn].is_a?(MultiRegionAccessPointARN)
80
+ signing_region = '*'
81
+ signing_algorithm = :sigv4a
82
+ else
83
+ signing_region = arn[:resolved_region]
84
+ signing_algorithm = :sigv4
85
+ end
77
86
  S3Signer.build_v4_signer(
78
87
  service: arn[:arn].service,
79
- region: arn[:resolved_region],
88
+ signing_algorithm: signing_algorithm,
89
+ region: signing_region,
80
90
  credentials: context.config.credentials
81
91
  )
82
92
  elsif context.operation.name == 'WriteGetObjectResponse'
@@ -128,7 +138,8 @@ module Aws
128
138
  def handle_region_errors(response)
129
139
  if wrong_sigv4_region?(response) &&
130
140
  !fips_region?(response) &&
131
- !custom_endpoint?(response)
141
+ !custom_endpoint?(response) &&
142
+ !expired_credentials?(response)
132
143
  get_region_and_retry(response.context)
133
144
  else
134
145
  response
@@ -152,9 +163,18 @@ module Aws
152
163
  resp.context.http_request.endpoint.host.include?('fips')
153
164
  end
154
165
 
166
+ def expired_credentials?(resp)
167
+ resp.context.http_response.body_contents.match(/<Code>ExpiredToken<\/Code>/)
168
+ end
169
+
155
170
  def custom_endpoint?(resp)
156
171
  resolved_suffix = Aws::Partitions::EndpointProvider.dns_suffix_for(
157
- resp.context.config.region
172
+ resp.context.config.region,
173
+ 's3',
174
+ {
175
+ dualstack: resp.context[:use_dualstack_endpoint],
176
+ fips: resp.context.config.use_fips_endpoint
177
+ }
158
178
  )
159
179
  !resp.context.http_request.endpoint.hostname.include?(resolved_suffix)
160
180
  end
@@ -216,6 +236,7 @@ module Aws
216
236
  service: options[:service],
217
237
  region: options[:region],
218
238
  credentials_provider: options[:credentials],
239
+ signing_algorithm: options.fetch(:signing_algorithm, :sigv4),
219
240
  uri_escape_path: false,
220
241
  unsigned_headers: ['content-length', 'x-amzn-trace-id']
221
242
  )
@@ -225,12 +246,20 @@ module Aws
225
246
  # Otherwise it will retry with the ARN as the bucket name.
226
247
  def new_hostname(context, region)
227
248
  uri = URI.parse(
228
- Aws::Partitions::EndpointProvider.resolve(region, 's3')
249
+ Aws::Partitions::EndpointProvider.resolve(
250
+ region, 's3', 'regional',
251
+ {
252
+ dualstack: context[:use_dualstack_endpoint],
253
+ fips: context.config.use_fips_endpoint
254
+ }
255
+ )
229
256
  )
230
257
 
231
258
  if (arn = context.metadata[:s3_arn])
232
259
  # Retry with the response region and not the ARN resolved one
233
- ARN.resolve_url!(uri, arn[:arn], region).host
260
+ ARN.resolve_url!(
261
+ uri, arn[:arn], region, arn[:fips], arn[:dualstack]
262
+ ).host
234
263
  else
235
264
  "#{context.params[:bucket]}.#{uri.host}"
236
265
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module S3
5
+ module Plugins
6
+
7
+ # S3 GetObject results for whole Multipart Objects contain a checksum
8
+ # that cannot be validated. These should be skipped by the
9
+ # ChecksumAlgorithm plugin.
10
+ class SkipWholeMultipartGetChecksums < Seahorse::Client::Plugin
11
+
12
+ class Handler < Seahorse::Client::Handler
13
+
14
+ def call(context)
15
+ context[:http_checksum] ||= {}
16
+ context[:http_checksum][:skip_on_suffix] = true
17
+
18
+ @handler.call(context)
19
+ end
20
+
21
+ end
22
+
23
+ handler(
24
+ Handler,
25
+ step: :initialize,
26
+ operations: [:get_object]
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end