aws-sdk-s3 1.78.0 → 1.87.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aws-sdk-s3.rb +3 -2
  3. data/lib/aws-sdk-s3/arn/access_point_arn.rb +62 -0
  4. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +71 -0
  5. data/lib/aws-sdk-s3/bucket.rb +65 -6
  6. data/lib/aws-sdk-s3/bucket_acl.rb +8 -0
  7. data/lib/aws-sdk-s3/bucket_cors.rb +15 -1
  8. data/lib/aws-sdk-s3/bucket_lifecycle.rb +14 -1
  9. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +12 -1
  10. data/lib/aws-sdk-s3/bucket_logging.rb +8 -0
  11. data/lib/aws-sdk-s3/bucket_notification.rb +5 -0
  12. data/lib/aws-sdk-s3/bucket_policy.rb +15 -1
  13. data/lib/aws-sdk-s3/bucket_request_payment.rb +8 -0
  14. data/lib/aws-sdk-s3/bucket_tagging.rb +15 -1
  15. data/lib/aws-sdk-s3/bucket_versioning.rb +24 -0
  16. data/lib/aws-sdk-s3/bucket_website.rb +15 -1
  17. data/lib/aws-sdk-s3/client.rb +2659 -778
  18. data/lib/aws-sdk-s3/client_api.rb +297 -20
  19. data/lib/aws-sdk-s3/customizations.rb +1 -1
  20. data/lib/aws-sdk-s3/customizations/bucket.rb +7 -4
  21. data/lib/aws-sdk-s3/customizations/object.rb +4 -3
  22. data/lib/aws-sdk-s3/errors.rb +21 -0
  23. data/lib/aws-sdk-s3/file_uploader.rb +1 -1
  24. data/lib/aws-sdk-s3/legacy_signer.rb +15 -25
  25. data/lib/aws-sdk-s3/multipart_upload.rb +15 -0
  26. data/lib/aws-sdk-s3/multipart_upload_part.rb +63 -6
  27. data/lib/aws-sdk-s3/object.rb +212 -24
  28. data/lib/aws-sdk-s3/object_acl.rb +16 -0
  29. data/lib/aws-sdk-s3/object_summary.rb +179 -14
  30. data/lib/aws-sdk-s3/object_version.rb +27 -3
  31. data/lib/aws-sdk-s3/plugins/arn.rb +187 -0
  32. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +0 -2
  33. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +1 -1
  34. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +7 -2
  35. data/lib/aws-sdk-s3/plugins/s3_signer.rb +29 -7
  36. data/lib/aws-sdk-s3/presigned_post.rb +1 -0
  37. data/lib/aws-sdk-s3/presigner.rb +19 -5
  38. data/lib/aws-sdk-s3/types.rb +2301 -287
  39. metadata +7 -5
  40. data/lib/aws-sdk-s3/plugins/bucket_arn.rb +0 -212
@@ -234,6 +234,7 @@ module Aws::S3
234
234
  # mfa: "MFA",
235
235
  # request_payer: "requester", # accepts requester
236
236
  # bypass_governance_retention: false,
237
+ # expected_bucket_owner: "AccountId",
237
238
  # })
238
239
  # @param [Hash] options ({})
239
240
  # @option options [String] :mfa
@@ -254,6 +255,10 @@ module Aws::S3
254
255
  # @option options [Boolean] :bypass_governance_retention
255
256
  # Indicates whether S3 Object Lock should bypass Governance-mode
256
257
  # restrictions to process this operation.
258
+ # @option options [String] :expected_bucket_owner
259
+ # 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.
257
262
  # @return [Types::DeleteObjectOutput]
258
263
  def delete(options = {})
259
264
  options = options.merge(
@@ -284,6 +289,7 @@ module Aws::S3
284
289
  # sse_customer_key_md5: "SSECustomerKeyMD5",
285
290
  # request_payer: "requester", # accepts requester
286
291
  # part_number: 1,
292
+ # expected_bucket_owner: "AccountId",
287
293
  # })
288
294
  # @param [Hash] options ({})
289
295
  # @option options [String] :if_match
@@ -331,7 +337,7 @@ module Aws::S3
331
337
  # encrypting data. This value is used to store the object and then it is
332
338
  # discarded; Amazon S3 does not store the encryption key. The key must
333
339
  # be appropriate for use with the algorithm specified in the
334
- # `x-amz-server-side​-encryption​-customer-algorithm` header.
340
+ # `x-amz-server-side-encryption-customer-algorithm` header.
335
341
  # @option options [String] :sse_customer_key_md5
336
342
  # Specifies the 128-bit MD5 digest of the encryption key according to
337
343
  # RFC 1321. Amazon S3 uses this header for a message integrity check to
@@ -351,6 +357,10 @@ module Aws::S3
351
357
  # between 1 and 10,000. Effectively performs a 'ranged' GET request
352
358
  # for the part specified. Useful for downloading just a part of an
353
359
  # object.
360
+ # @option options [String] :expected_bucket_owner
361
+ # 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.
354
364
  # @return [Types::GetObjectOutput]
355
365
  def get(options = {}, &block)
356
366
  options = options.merge(
@@ -375,6 +385,7 @@ module Aws::S3
375
385
  # sse_customer_key_md5: "SSECustomerKeyMD5",
376
386
  # request_payer: "requester", # accepts requester
377
387
  # part_number: 1,
388
+ # expected_bucket_owner: "AccountId",
378
389
  # })
379
390
  # @param [Hash] options ({})
380
391
  # @option options [String] :if_match
@@ -392,12 +403,16 @@ module Aws::S3
392
403
  # @option options [String] :range
393
404
  # Downloads the specified range bytes of an object. For more information
394
405
  # about the HTTP Range header, see
395
- # [http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35]().
406
+ # [http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35][1].
396
407
  #
397
408
  # <note markdown="1"> Amazon S3 doesn't support retrieving multiple ranges of data per
398
409
  # `GET` request.
399
410
  #
400
411
  # </note>
412
+ #
413
+ #
414
+ #
415
+ # [1]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
401
416
  # @option options [String] :sse_customer_algorithm
402
417
  # Specifies the algorithm to use to when encrypting the object (for
403
418
  # example, AES256).
@@ -406,7 +421,7 @@ module Aws::S3
406
421
  # encrypting data. This value is used to store the object and then it is
407
422
  # discarded; Amazon S3 does not store the encryption key. The key must
408
423
  # be appropriate for use with the algorithm specified in the
409
- # `x-amz-server-side​-encryption​-customer-algorithm` header.
424
+ # `x-amz-server-side-encryption-customer-algorithm` header.
410
425
  # @option options [String] :sse_customer_key_md5
411
426
  # Specifies the 128-bit MD5 digest of the encryption key according to
412
427
  # RFC 1321. Amazon S3 uses this header for a message integrity check to
@@ -426,6 +441,10 @@ module Aws::S3
426
441
  # between 1 and 10,000. Effectively performs a 'ranged' HEAD request
427
442
  # for the part specified. Useful querying about the size of the part and
428
443
  # the number of parts in this object.
444
+ # @option options [String] :expected_bucket_owner
445
+ # 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.
429
448
  # @return [Types::HeadObjectOutput]
430
449
  def head(options = {})
431
450
  options = options.merge(
@@ -504,6 +523,7 @@ module Aws::S3
504
523
  # mfa: "MFA",
505
524
  # request_payer: "requester", # accepts requester
506
525
  # bypass_governance_retention: false,
526
+ # expected_bucket_owner: "AccountId",
507
527
  # })
508
528
  # @param options ({})
509
529
  # @option options [String] :mfa
@@ -525,6 +545,10 @@ module Aws::S3
525
545
  # Specifies whether you want to delete this object even if it has a
526
546
  # Governance-type Object Lock in place. You must have sufficient
527
547
  # permissions to perform this operation.
548
+ # @option options [String] :expected_bucket_owner
549
+ # 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.
528
552
  # @return [void]
529
553
  def batch_delete!(options = {})
530
554
  batch_enum.each do |batch|
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../arn/access_point_arn'
4
+ require_relative '../arn/outpost_access_point_arn'
5
+
6
+ module Aws
7
+ module S3
8
+ module Plugins
9
+ # When an accesspoint ARN is provided for :bucket in S3 operations, this
10
+ # plugin resolves the request endpoint from the ARN when possible.
11
+ # @api private
12
+ class ARN < Seahorse::Client::Plugin
13
+ option(
14
+ :s3_use_arn_region,
15
+ default: true,
16
+ doc_type: 'Boolean',
17
+ docstring: <<-DOCS) do |cfg|
18
+ For S3 ARNs passed into the `:bucket` parameter, this option will
19
+ use the region in the ARN, allowing for cross-region requests to
20
+ be made. Set to `false` to use the client's region instead.
21
+ DOCS
22
+ resolve_s3_use_arn_region(cfg)
23
+ end
24
+
25
+ def add_handlers(handlers, _config)
26
+ handlers.add(Handler)
27
+ end
28
+
29
+ class Handler < Seahorse::Client::Handler
30
+ def call(context)
31
+ bucket_member = _bucket_member(context.operation.input.shape)
32
+ if bucket_member && (bucket = context.params[bucket_member])
33
+ resolved_region, arn = ARN.resolve_arn!(
34
+ bucket,
35
+ context.config.region,
36
+ context.config.s3_use_arn_region
37
+ )
38
+ if arn
39
+ validate_config!(context, arn)
40
+
41
+ ARN.resolve_url!(
42
+ context.http_request.endpoint,
43
+ arn,
44
+ resolved_region,
45
+ extract_dualstack_config!(context)
46
+ )
47
+ end
48
+ end
49
+ @handler.call(context)
50
+ end
51
+
52
+ private
53
+
54
+ def _bucket_member(input)
55
+ input.members.each do |member, ref|
56
+ return member if ref.shape.name == 'BucketName'
57
+ end
58
+ nil
59
+ end
60
+
61
+ # other plugins use dualstack so disable it when we're done
62
+ def extract_dualstack_config!(context)
63
+ dualstack = context[:use_dualstack_endpoint]
64
+ context[:use_dualstack_endpoint] = false if dualstack
65
+ dualstack
66
+ end
67
+
68
+ def validate_config!(context, arn)
69
+ unless context.config.regional_endpoint
70
+ raise ArgumentError,
71
+ 'Cannot provide both an Access Point ARN and setting '\
72
+ ':endpoint.'
73
+ end
74
+
75
+ if context.config.force_path_style
76
+ raise ArgumentError,
77
+ 'Cannot provide both an Access Point ARN and setting '\
78
+ ':force_path_style to true.'
79
+ end
80
+
81
+ if context.config.use_accelerate_endpoint
82
+ raise ArgumentError,
83
+ 'Cannot provide both an Access Point ARN and setting '\
84
+ ':use_accelerate_endpoint to true.'
85
+ end
86
+
87
+ if !arn.support_dualstack? && context[:use_dualstack_endpoint]
88
+ raise ArgumentError,
89
+ 'Cannot provide both an Outpost Access Point ARN and '\
90
+ 'setting :use_dualstack_endpoint to true.'
91
+ end
92
+ end
93
+ end
94
+
95
+ class << self
96
+ # @api private
97
+ def resolve_arn!(member_value, region, use_arn_region)
98
+ if Aws::ARNParser.arn?(member_value)
99
+ arn = Aws::ARNParser.parse(member_value)
100
+ if arn.resource.start_with?('accesspoint')
101
+ s3_arn = Aws::S3::AccessPointARN.new(arn.to_h)
102
+ elsif arn.resource.start_with?('outpost')
103
+ s3_arn = Aws::S3::OutpostAccessPointARN.new(arn.to_h)
104
+ else
105
+ raise ArgumentError,
106
+ 'Only Access Point and Outpost Access Point type ARNs '\
107
+ 'are currently supported.'
108
+ end
109
+ s3_arn.validate_arn!
110
+ validate_region_config!(s3_arn, region, use_arn_region)
111
+ region = s3_arn.region if use_arn_region
112
+ [region, s3_arn]
113
+ else
114
+ [region]
115
+ end
116
+ end
117
+
118
+ # @api private
119
+ def resolve_url!(url, arn, region, dualstack = false)
120
+ url.host = arn.host_url(region, dualstack)
121
+ url.path = url_path(url.path, arn)
122
+ url
123
+ end
124
+
125
+ private
126
+
127
+ def resolve_s3_use_arn_region(cfg)
128
+ value = ENV['AWS_S3_USE_ARN_REGION'] ||
129
+ Aws.shared_config.s3_use_arn_region(profile: cfg.profile) ||
130
+ 'true'
131
+ value = Aws::Util.str_2_bool(value)
132
+ # Raise if provided value is not true or false
133
+ if value.nil?
134
+ raise ArgumentError,
135
+ 'Must provide either `true` or `false` for '\
136
+ 's3_use_arn_region profile option or for '\
137
+ "ENV['AWS_S3_USE_ARN_REGION']"
138
+ end
139
+ value
140
+ end
141
+
142
+ # Remove ARN from the path since it was substituted already
143
+ # This only works because accesspoints care about the URL
144
+ def url_path(path, arn)
145
+ path = path.sub("/#{Seahorse::Util.uri_escape(arn.to_s)}", '')
146
+ .sub("/#{arn}", '')
147
+ "/#{path}" unless path =~ /^\//
148
+ path
149
+ end
150
+
151
+ def validate_region_config!(arn, region, use_arn_region)
152
+ fips = arn.support_fips?
153
+
154
+ # s3-external-1 is specific just to s3 and not part of partitions
155
+ # aws-global is a partition region
156
+ unless arn.partition == 'aws' &&
157
+ (region == 's3-external-1' || region == 'aws-global')
158
+ if !fips && arn.region.include?('fips')
159
+ raise ArgumentError,
160
+ 'FIPS region ARNs are not supported for this type of ARN.'
161
+ end
162
+
163
+ if !fips && !use_arn_region && region.include?('fips')
164
+ raise ArgumentError,
165
+ 'FIPS client regions are not supported for this type of '\
166
+ 'ARN without s3_use_arn_region.'
167
+ end
168
+
169
+ # if it's a fips region, attempt to normalize it
170
+ if fips || use_arn_region
171
+ region = region.gsub('fips-', '').gsub('-fips', '')
172
+ end
173
+ if use_arn_region &&
174
+ !Aws::Partitions.partition(arn.partition).region?(region)
175
+ raise Aws::Errors::InvalidARNPartitionError
176
+ end
177
+
178
+ if !use_arn_region && region != arn.region
179
+ raise Aws::Errors::InvalidARNRegionError
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
@@ -73,8 +73,6 @@ request URI and never moved to the host as a sub-domain.
73
73
  end
74
74
  end
75
75
 
76
- # Checks for a valid RFC-3986 host name
77
- # @see https://tools.ietf.org/html/rfc3986#section-3.2.2
78
76
  # @param [String] bucket_name
79
77
  # @return [Boolean]
80
78
  def valid_subdomain?(bucket_name)
@@ -13,7 +13,7 @@ module Aws
13
13
  def call(context)
14
14
  bucket_member = _bucket_member(context.operation.input.shape)
15
15
  if bucket_member && (bucket = context.params[bucket_member])
16
- _resolved_bucket, _resolved_region, arn = BucketARN.resolve_arn!(
16
+ _resolved_region, arn = ARN.resolve_arn!(
17
17
  bucket,
18
18
  context.config.region,
19
19
  context.config.s3_use_arn_region
@@ -28,8 +28,13 @@ region. Defaults to `legacy` mode using global endpoint.
28
28
  def call(context)
29
29
  # keep legacy global endpoint pattern by default
30
30
  if context.config.s3_us_east_1_regional_endpoint == 'legacy'
31
- context.http_request.endpoint.host = IADRegionalEndpoint.legacy_host(
32
- context.http_request.endpoint.host)
31
+ host = context.http_request.endpoint.host
32
+ # if it's an ARN, don't touch the endpoint at all
33
+ # TODO this should use context.metadata[:s3_arn] later
34
+ unless host.include?('.s3-outposts.') || host.include?('.s3-accesspoint.')
35
+ legacy_host = IADRegionalEndpoint.legacy_host(host)
36
+ context.http_request.endpoint.host = legacy_host
37
+ end
33
38
  end
34
39
  @handler.call(context)
35
40
  end
@@ -12,12 +12,14 @@ module Aws
12
12
 
13
13
  option(:sigv4_signer) do |cfg|
14
14
  S3Signer.build_v4_signer(
15
+ service: 's3',
15
16
  region: cfg.sigv4_region,
16
17
  credentials: cfg.credentials
17
18
  )
18
19
  end
19
20
 
20
21
  option(:sigv4_region) do |cfg|
22
+ # S3 removes core's signature_v4 plugin that checks for this
21
23
  raise Aws::Errors::MissingRegionError if cfg.region.nil?
22
24
 
23
25
  Aws::Partitions::EndpointProvider.signing_region(cfg.region, 's3')
@@ -67,11 +69,26 @@ module Aws
67
69
  if context[:cached_sigv4_region] &&
68
70
  context[:cached_sigv4_region] != context.config.sigv4_signer.region
69
71
  S3Signer.build_v4_signer(
72
+ service: 's3',
70
73
  region: context[:cached_sigv4_region],
71
74
  credentials: context.config.credentials
72
75
  )
73
76
  else
74
- context.config.sigv4_signer
77
+ resolved_region, arn = ARN.resolve_arn!(
78
+ context.params[:bucket],
79
+ context.config.sigv4_signer.region,
80
+ context.config.s3_use_arn_region
81
+ )
82
+
83
+ if arn
84
+ S3Signer.build_v4_signer(
85
+ service: arn.service,
86
+ region: resolved_region,
87
+ credentials: context.config.credentials
88
+ )
89
+ else
90
+ context.config.sigv4_signer
91
+ end
75
92
  end
76
93
  end
77
94
  end
@@ -90,7 +107,9 @@ module Aws
90
107
  def check_for_cached_region(context, bucket)
91
108
  cached_region = S3::BUCKET_REGIONS[bucket]
92
109
  if cached_region && cached_region != context.config.region
93
- context.http_request.endpoint.host = S3Signer.new_hostname(context, cached_region)
110
+ context.http_request.endpoint.host = S3Signer.new_hostname(
111
+ context, cached_region
112
+ )
94
113
  context[:cached_sigv4_region] = cached_region
95
114
  end
96
115
  end
@@ -150,11 +169,14 @@ module Aws
150
169
 
151
170
  def resign_with_new_region(context, actual_region)
152
171
  context.http_response.body.truncate(0)
153
- context.http_request.endpoint.host = S3Signer.new_hostname(context, actual_region)
172
+ context.http_request.endpoint.host = S3Signer.new_hostname(
173
+ context, actual_region
174
+ )
154
175
  context.metadata[:redirect_region] = actual_region
155
176
  Aws::Plugins::SignatureV4.apply_signature(
156
177
  context: context,
157
178
  signer: S3Signer.build_v4_signer(
179
+ service: 's3',
158
180
  region: actual_region,
159
181
  credentials: context.config.credentials
160
182
  )
@@ -189,7 +211,7 @@ module Aws
189
211
  # @api private
190
212
  def build_v4_signer(options = {})
191
213
  Aws::Sigv4::Signer.new(
192
- service: 's3',
214
+ service: options[:service],
193
215
  region: options[:region],
194
216
  credentials_provider: options[:credentials],
195
217
  uri_escape_path: false,
@@ -200,7 +222,7 @@ module Aws
200
222
  def new_hostname(context, region)
201
223
  # Check to see if the bucket is actually an ARN and resolve it
202
224
  # Otherwise it will retry with the ARN as the bucket name.
203
- resolved_bucket, resolved_region, arn = BucketARN.resolve_arn!(
225
+ resolved_region, arn = ARN.resolve_arn!(
204
226
  context.params[:bucket],
205
227
  region,
206
228
  context.config.s3_use_arn_region
@@ -210,9 +232,9 @@ module Aws
210
232
  )
211
233
 
212
234
  if arn
213
- BucketARN.resolve_url!(uri, arn).host
235
+ ARN.resolve_url!(uri, arn).host
214
236
  else
215
- resolved_bucket + '.' + uri.host
237
+ "#{context.params[:bucket]}.#{uri.host}"
216
238
  end
217
239
  end
218
240
  end
@@ -237,6 +237,7 @@ module Aws
237
237
  @bucket_region = bucket_region
238
238
  @bucket_name = bucket_name
239
239
  @accelerate = !!options.delete(:use_accelerate_endpoint)
240
+ options.delete(:url) if @accelerate # resource methods pass url
240
241
  @url = options.delete(:url) || bucket_url
241
242
  @fields = {}
242
243
  @key_set = false
@@ -12,6 +12,7 @@ module Aws
12
12
  # @api private
13
13
  BLACKLISTED_HEADERS = [
14
14
  'accept',
15
+ 'amz-sdk-request',
15
16
  'cache-control',
16
17
  'content-length', # due to a ELB bug
17
18
  'expect',
@@ -195,7 +196,7 @@ module Aws
195
196
  req.handlers.remove(Aws::S3::Plugins::S3Signer::V4Handler)
196
197
  req.handlers.remove(Seahorse::Client::Plugins::ContentLength::Handler)
197
198
 
198
- signer = build_signer(req.context.config, unsigned_headers)
199
+ signer = build_signer(req.context, unsigned_headers)
199
200
 
200
201
  req.handle(step: :send) do |context|
201
202
  if scheme != http_req.endpoint.scheme
@@ -239,14 +240,27 @@ module Aws
239
240
  x_amz_headers
240
241
  end
241
242
 
242
- def build_signer(cfg, unsigned_headers)
243
- Aws::Sigv4::Signer.new(
243
+ def build_signer(context, unsigned_headers)
244
+ signer_opts = {
244
245
  service: 's3',
245
- region: cfg.region,
246
- credentials_provider: cfg.credentials,
246
+ region: context.config.region,
247
+ credentials_provider: context.config.credentials,
247
248
  unsigned_headers: unsigned_headers,
248
249
  uri_escape_path: false
250
+ }
251
+
252
+ resolved_region, arn = Aws::S3::Plugins::ARN.resolve_arn!(
253
+ context.params[:bucket],
254
+ context.config.sigv4_signer.region,
255
+ context.config.s3_use_arn_region
249
256
  )
257
+
258
+ if arn
259
+ signer_opts[:region] = resolved_region
260
+ signer_opts[:service] = arn.service
261
+ end
262
+
263
+ Aws::Sigv4::Signer.new(signer_opts)
250
264
  end
251
265
  end
252
266
  end