aws-sdk-s3 1.122.0 → 1.136.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +94 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-s3/bucket.rb +108 -49
  5. data/lib/aws-sdk-s3/bucket_acl.rb +9 -3
  6. data/lib/aws-sdk-s3/bucket_cors.rb +12 -4
  7. data/lib/aws-sdk-s3/bucket_lifecycle.rb +12 -4
  8. data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +12 -4
  9. data/lib/aws-sdk-s3/bucket_logging.rb +9 -3
  10. data/lib/aws-sdk-s3/bucket_notification.rb +9 -3
  11. data/lib/aws-sdk-s3/bucket_policy.rb +12 -4
  12. data/lib/aws-sdk-s3/bucket_request_payment.rb +9 -3
  13. data/lib/aws-sdk-s3/bucket_tagging.rb +12 -4
  14. data/lib/aws-sdk-s3/bucket_versioning.rb +15 -5
  15. data/lib/aws-sdk-s3/bucket_website.rb +12 -4
  16. data/lib/aws-sdk-s3/client.rb +727 -626
  17. data/lib/aws-sdk-s3/client_api.rb +24 -0
  18. data/lib/aws-sdk-s3/customizations/bucket.rb +3 -1
  19. data/lib/aws-sdk-s3/customizations/errors.rb +1 -1
  20. data/lib/aws-sdk-s3/customizations/object.rb +91 -18
  21. data/lib/aws-sdk-s3/encryption/client.rb +6 -2
  22. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +13 -9
  23. data/lib/aws-sdk-s3/encryptionV2/client.rb +6 -2
  24. data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +1 -0
  25. data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +10 -6
  26. data/lib/aws-sdk-s3/endpoint_parameters.rb +4 -0
  27. data/lib/aws-sdk-s3/endpoint_provider.rb +22 -246
  28. data/lib/aws-sdk-s3/endpoints.rb +1 -0
  29. data/lib/aws-sdk-s3/file_downloader.rb +170 -44
  30. data/lib/aws-sdk-s3/file_uploader.rb +8 -6
  31. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +5 -3
  32. data/lib/aws-sdk-s3/multipart_upload.rb +27 -13
  33. data/lib/aws-sdk-s3/multipart_upload_part.rb +19 -9
  34. data/lib/aws-sdk-s3/object.rb +125 -84
  35. data/lib/aws-sdk-s3/object_acl.rb +14 -6
  36. data/lib/aws-sdk-s3/object_copier.rb +7 -5
  37. data/lib/aws-sdk-s3/object_multipart_copier.rb +33 -17
  38. data/lib/aws-sdk-s3/object_summary.rb +123 -74
  39. data/lib/aws-sdk-s3/object_version.rb +49 -17
  40. data/lib/aws-sdk-s3/presigned_post.rb +52 -43
  41. data/lib/aws-sdk-s3/presigner.rb +4 -2
  42. data/lib/aws-sdk-s3/resource.rb +7 -3
  43. data/lib/aws-sdk-s3/types.rb +529 -299
  44. data/lib/aws-sdk-s3.rb +1 -1
  45. metadata +6 -6
@@ -32,39 +32,68 @@ module Aws
32
32
  }
33
33
  @params[:version_id] = options[:version_id] if options[:version_id]
34
34
 
35
- case @mode
36
- when 'auto' then multipart_download
37
- when 'single_request' then single_request
38
- when 'get_range'
39
- if @chunk_size
40
- resp = @client.head_object(@params)
41
- multithreaded_get_by_ranges(construct_chunks(resp.content_length))
35
+ # checksum_mode only supports the value "ENABLED"
36
+ # falsey values (false/nil) or "DISABLED" should be considered
37
+ # disabled and the api parameter should be unset.
38
+ if (checksum_mode = options.fetch(:checksum_mode, 'ENABLED'))
39
+ @params[:checksum_mode] = checksum_mode unless checksum_mode.upcase == 'DISABLED'
40
+ end
41
+ @on_checksum_validated = options[:on_checksum_validated]
42
+
43
+ @progress_callback = options[:progress_callback]
44
+
45
+ validate!
46
+
47
+ Aws::Plugins::UserAgent.feature('s3-transfer') do
48
+ case @mode
49
+ when 'auto' then multipart_download
50
+ when 'single_request' then single_request
51
+ when 'get_range'
52
+ if @chunk_size
53
+ resp = @client.head_object(@params)
54
+ multithreaded_get_by_ranges(resp.content_length)
55
+ else
56
+ msg = 'In :get_range mode, :chunk_size must be provided'
57
+ raise ArgumentError, msg
58
+ end
42
59
  else
43
- msg = 'In :get_range mode, :chunk_size must be provided'
60
+ msg = "Invalid mode #{@mode} provided, "\
61
+ 'mode should be :single_request, :get_range or :auto'
44
62
  raise ArgumentError, msg
45
63
  end
46
- else
47
- msg = "Invalid mode #{@mode} provided, "\
48
- 'mode should be :single_request, :get_range or :auto'
49
- raise ArgumentError, msg
50
64
  end
51
65
  end
52
66
 
53
67
  private
54
68
 
69
+ def validate!
70
+ if @on_checksum_validated && @params[:checksum_mode] != 'ENABLED'
71
+ raise ArgumentError, "You must set checksum_mode: 'ENABLED' " +
72
+ "when providing a on_checksum_validated callback"
73
+ end
74
+
75
+ if @on_checksum_validated && !@on_checksum_validated.respond_to?(:call)
76
+ raise ArgumentError, 'on_checksum_validated must be callable'
77
+ end
78
+ end
79
+
55
80
  def multipart_download
56
81
  resp = @client.head_object(@params.merge(part_number: 1))
57
82
  count = resp.parts_count
58
83
  if count.nil? || count <= 1
59
- resp.content_length < MIN_CHUNK_SIZE ?
60
- single_request :
61
- multithreaded_get_by_ranges(construct_chunks(resp.content_length))
84
+ if resp.content_length <= MIN_CHUNK_SIZE
85
+ single_request
86
+ else
87
+ multithreaded_get_by_ranges(resp.content_length)
88
+ end
62
89
  else
63
90
  # partNumber is an option
64
91
  resp = @client.head_object(@params)
65
- resp.content_length < MIN_CHUNK_SIZE ?
66
- single_request :
92
+ if resp.content_length <= MIN_CHUNK_SIZE
93
+ single_request
94
+ else
67
95
  compute_mode(resp.content_length, count)
96
+ end
68
97
  end
69
98
  end
70
99
 
@@ -72,9 +101,9 @@ module Aws
72
101
  chunk_size = compute_chunk(file_size)
73
102
  part_size = (file_size.to_f / count.to_f).ceil
74
103
  if chunk_size < part_size
75
- multithreaded_get_by_ranges(construct_chunks(file_size))
104
+ multithreaded_get_by_ranges(file_size)
76
105
  else
77
- multithreaded_get_by_parts(count)
106
+ multithreaded_get_by_parts(count, file_size)
78
107
  end
79
108
  end
80
109
 
@@ -82,10 +111,11 @@ module Aws
82
111
  offset = 0
83
112
  default_chunk_size = compute_chunk(file_size)
84
113
  chunks = []
85
- while offset <= file_size
114
+ while offset < file_size
86
115
  progress = offset + default_chunk_size
87
- chunks << "bytes=#{offset}-#{progress < file_size ? progress : file_size}"
88
- offset = progress + 1
116
+ progress = file_size if progress > file_size
117
+ chunks << "bytes=#{offset}-#{progress - 1}"
118
+ offset = progress
89
119
  end
90
120
  chunks
91
121
  end
@@ -94,12 +124,9 @@ module Aws
94
124
  if @chunk_size && @chunk_size > file_size
95
125
  raise ArgumentError, ":chunk_size shouldn't exceed total file size."
96
126
  else
97
- chunk_size = @chunk_size || [
98
- (file_size.to_f / MAX_PARTS).ceil,
99
- MIN_CHUNK_SIZE
127
+ @chunk_size || [
128
+ (file_size.to_f / MAX_PARTS).ceil, MIN_CHUNK_SIZE
100
129
  ].max.to_i
101
- chunk_size -= 1 if file_size % chunk_size == 1
102
- chunk_size
103
130
  end
104
131
  end
105
132
 
@@ -108,27 +135,65 @@ module Aws
108
135
  chunks.each_slice(@thread_count).to_a
109
136
  end
110
137
 
111
- def multithreaded_get_by_ranges(chunks)
112
- thread_batches(chunks, 'range')
138
+ def multithreaded_get_by_ranges(file_size)
139
+ offset = 0
140
+ default_chunk_size = compute_chunk(file_size)
141
+ chunks = []
142
+ part_number = 1 # parts start at 1
143
+ while offset < file_size
144
+ progress = offset + default_chunk_size
145
+ progress = file_size if progress > file_size
146
+ range = "bytes=#{offset}-#{progress - 1}"
147
+ chunks << Part.new(
148
+ part_number: part_number,
149
+ size: (progress-offset),
150
+ params: @params.merge(range: range)
151
+ )
152
+ part_number += 1
153
+ offset = progress
154
+ end
155
+ download_in_threads(PartList.new(chunks), file_size)
113
156
  end
114
157
 
115
- def multithreaded_get_by_parts(parts)
116
- thread_batches(parts, 'part_number')
158
+ def multithreaded_get_by_parts(n_parts, total_size)
159
+ parts = (1..n_parts).map do |part|
160
+ Part.new(part_number: part, params: @params.merge(part_number: part))
161
+ end
162
+ download_in_threads(PartList.new(parts), total_size)
117
163
  end
118
164
 
119
- def thread_batches(chunks, param)
120
- batches(chunks, param).each do |batch|
121
- threads = []
122
- batch.each do |chunk|
123
- threads << Thread.new do
124
- resp = @client.get_object(
125
- @params.merge(param.to_sym => chunk)
126
- )
127
- write(resp)
165
+ def download_in_threads(pending, total_size)
166
+ threads = []
167
+ if @progress_callback
168
+ progress = MultipartProgress.new(pending, total_size, @progress_callback)
169
+ end
170
+ @thread_count.times do
171
+ thread = Thread.new do
172
+ begin
173
+ while part = pending.shift
174
+ if progress
175
+ part.params[:on_chunk_received] =
176
+ proc do |_chunk, bytes, total|
177
+ progress.call(part.part_number, bytes, total)
178
+ end
179
+ end
180
+ resp = @client.get_object(part.params)
181
+ write(resp)
182
+ if @on_checksum_validated && resp.checksum_validated
183
+ @on_checksum_validated.call(resp.checksum_validated, resp)
184
+ end
185
+ end
186
+ nil
187
+ rescue => error
188
+ # keep other threads from downloading other parts
189
+ pending.clear!
190
+ raise error
128
191
  end
129
192
  end
130
- threads.each(&:join)
193
+ thread.abort_on_exception = true
194
+ threads << thread
131
195
  end
196
+ threads.map(&:value).compact
132
197
  end
133
198
 
134
199
  def write(resp)
@@ -138,9 +203,70 @@ module Aws
138
203
  end
139
204
 
140
205
  def single_request
141
- @client.get_object(
142
- @params.merge(response_target: @path)
143
- )
206
+ params = @params.merge(response_target: @path)
207
+ params[:on_chunk_received] = single_part_progress if @progress_callback
208
+ resp = @client.get_object(params)
209
+
210
+ return resp unless @on_checksum_validated
211
+
212
+ if resp.checksum_validated
213
+ @on_checksum_validated.call(resp.checksum_validated, resp)
214
+ end
215
+
216
+ resp
217
+ end
218
+
219
+ def single_part_progress
220
+ proc do |_chunk, bytes_read, total_size|
221
+ @progress_callback.call([bytes_read], [total_size], total_size)
222
+ end
223
+ end
224
+
225
+ class Part < Struct.new(:part_number, :size, :params)
226
+ include Aws::Structure
227
+ end
228
+
229
+ # @api private
230
+ class PartList
231
+ include Enumerable
232
+ def initialize(parts = [])
233
+ @parts = parts
234
+ @mutex = Mutex.new
235
+ end
236
+
237
+ def shift
238
+ @mutex.synchronize { @parts.shift }
239
+ end
240
+
241
+ def size
242
+ @mutex.synchronize { @parts.size }
243
+ end
244
+
245
+ def clear!
246
+ @mutex.synchronize { @parts.clear }
247
+ end
248
+
249
+ def each(&block)
250
+ @mutex.synchronize { @parts.each(&block) }
251
+ end
252
+ end
253
+
254
+ # @api private
255
+ class MultipartProgress
256
+ def initialize(parts, total_size, progress_callback)
257
+ @bytes_received = Array.new(parts.size, 0)
258
+ @part_sizes = parts.map(&:size)
259
+ @total_size = total_size
260
+ @progress_callback = progress_callback
261
+ end
262
+
263
+ def call(part_number, bytes_received, total)
264
+ # part numbers start at 1
265
+ @bytes_received[part_number - 1] = bytes_received
266
+ # part size may not be known until we get the first response
267
+ @part_sizes[part_number - 1] ||= total
268
+ @progress_callback.call(@bytes_received, @part_sizes, @total_size)
269
+ end
144
270
  end
145
271
  end
146
272
  end
@@ -37,12 +37,14 @@ module Aws
37
37
  # objects smaller than the multipart threshold.
38
38
  # @return [void]
39
39
  def upload(source, options = {})
40
- if File.size(source) >= multipart_threshold
41
- MultipartFileUploader.new(@options).upload(source, options)
42
- else
43
- # remove multipart parameters not supported by put_object
44
- options.delete(:thread_count)
45
- put_object(source, options)
40
+ Aws::Plugins::UserAgent.feature('s3-transfer') do
41
+ if File.size(source) >= multipart_threshold
42
+ MultipartFileUploader.new(@options).upload(source, options)
43
+ else
44
+ # remove multipart parameters not supported by put_object
45
+ options.delete(:thread_count)
46
+ put_object(source, options)
47
+ end
46
48
  end
47
49
  end
48
50
 
@@ -45,9 +45,11 @@ module Aws
45
45
  # @option options [required,String] :key
46
46
  # @return [Seahorse::Client::Response] - the CompleteMultipartUploadResponse
47
47
  def upload(options = {}, &block)
48
- upload_id = initiate_upload(options)
49
- parts = upload_parts(upload_id, options, &block)
50
- complete_upload(upload_id, parts, options)
48
+ Aws::Plugins::UserAgent.feature('s3-transfer') do
49
+ upload_id = initiate_upload(options)
50
+ parts = upload_parts(upload_id, options, &block)
51
+ complete_upload(upload_id, parts, options)
52
+ end
51
53
  end
52
54
 
53
55
  private
@@ -217,7 +217,9 @@ module Aws::S3
217
217
  :retry
218
218
  end
219
219
  end
220
- Aws::Waiters::Waiter.new(options).wait({})
220
+ Aws::Plugins::UserAgent.feature('resource') do
221
+ Aws::Waiters::Waiter.new(options).wait({})
222
+ end
221
223
  end
222
224
 
223
225
  # @!group Actions
@@ -232,9 +234,11 @@ module Aws::S3
232
234
  # @option options [String] :request_payer
233
235
  # Confirms that the requester knows that they will be charged for the
234
236
  # request. Bucket owners need not specify this parameter in their
235
- # requests. For information about downloading objects from Requester
236
- # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
237
- # in the *Amazon S3 User Guide*.
237
+ # requests. If either the source or destination Amazon S3 bucket has
238
+ # Requester Pays enabled, the requester will pay for corresponding
239
+ # charges to copy the object. For information about downloading objects
240
+ # from Requester Pays buckets, see [Downloading Objects in Requester
241
+ # Pays Buckets][1] in the *Amazon S3 User Guide*.
238
242
  #
239
243
  #
240
244
  #
@@ -250,7 +254,9 @@ module Aws::S3
250
254
  key: @object_key,
251
255
  upload_id: @id
252
256
  )
253
- resp = @client.abort_multipart_upload(options)
257
+ resp = Aws::Plugins::UserAgent.feature('resource') do
258
+ @client.abort_multipart_upload(options)
259
+ end
254
260
  resp.data
255
261
  end
256
262
 
@@ -325,9 +331,11 @@ module Aws::S3
325
331
  # @option options [String] :request_payer
326
332
  # Confirms that the requester knows that they will be charged for the
327
333
  # request. Bucket owners need not specify this parameter in their
328
- # requests. For information about downloading objects from Requester
329
- # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
330
- # in the *Amazon S3 User Guide*.
334
+ # requests. If either the source or destination Amazon S3 bucket has
335
+ # Requester Pays enabled, the requester will pay for corresponding
336
+ # charges to copy the object. For information about downloading objects
337
+ # from Requester Pays buckets, see [Downloading Objects in Requester
338
+ # Pays Buckets][1] in the *Amazon S3 User Guide*.
331
339
  #
332
340
  #
333
341
  #
@@ -370,7 +378,9 @@ module Aws::S3
370
378
  key: @object_key,
371
379
  upload_id: @id
372
380
  )
373
- @client.complete_multipart_upload(options)
381
+ Aws::Plugins::UserAgent.feature('resource') do
382
+ @client.complete_multipart_upload(options)
383
+ end
374
384
  Object.new(
375
385
  bucket_name: @bucket_name,
376
386
  key: @object_key,
@@ -414,9 +424,11 @@ module Aws::S3
414
424
  # @option options [String] :request_payer
415
425
  # Confirms that the requester knows that they will be charged for the
416
426
  # request. Bucket owners need not specify this parameter in their
417
- # requests. For information about downloading objects from Requester
418
- # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
419
- # in the *Amazon S3 User Guide*.
427
+ # requests. If either the source or destination Amazon S3 bucket has
428
+ # Requester Pays enabled, the requester will pay for corresponding
429
+ # charges to copy the object. For information about downloading objects
430
+ # from Requester Pays buckets, see [Downloading Objects in Requester
431
+ # Pays Buckets][1] in the *Amazon S3 User Guide*.
420
432
  #
421
433
  #
422
434
  #
@@ -460,7 +472,9 @@ module Aws::S3
460
472
  key: @object_key,
461
473
  upload_id: @id
462
474
  )
463
- resp = @client.list_parts(options)
475
+ resp = Aws::Plugins::UserAgent.feature('resource') do
476
+ @client.list_parts(options)
477
+ end
464
478
  resp.each_page do |page|
465
479
  batch = []
466
480
  page.data.parts.each do |p|
@@ -256,7 +256,9 @@ module Aws::S3
256
256
  :retry
257
257
  end
258
258
  end
259
- Aws::Waiters::Waiter.new(options).wait({})
259
+ Aws::Plugins::UserAgent.feature('resource') do
260
+ Aws::Waiters::Waiter.new(options).wait({})
261
+ end
260
262
  end
261
263
 
262
264
  # @!group Actions
@@ -372,9 +374,11 @@ module Aws::S3
372
374
  # @option options [String] :request_payer
373
375
  # Confirms that the requester knows that they will be charged for the
374
376
  # request. Bucket owners need not specify this parameter in their
375
- # requests. For information about downloading objects from Requester
376
- # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
377
- # in the *Amazon S3 User Guide*.
377
+ # requests. If either the source or destination Amazon S3 bucket has
378
+ # Requester Pays enabled, the requester will pay for corresponding
379
+ # charges to copy the object. For information about downloading objects
380
+ # from Requester Pays buckets, see [Downloading Objects in Requester
381
+ # Pays Buckets][1] in the *Amazon S3 User Guide*.
378
382
  #
379
383
  #
380
384
  #
@@ -395,7 +399,9 @@ module Aws::S3
395
399
  upload_id: @multipart_upload_id,
396
400
  part_number: @part_number
397
401
  )
398
- resp = @client.upload_part_copy(options)
402
+ resp = Aws::Plugins::UserAgent.feature('resource') do
403
+ @client.upload_part_copy(options)
404
+ end
399
405
  resp.data
400
406
  end
401
407
 
@@ -502,9 +508,11 @@ module Aws::S3
502
508
  # @option options [String] :request_payer
503
509
  # Confirms that the requester knows that they will be charged for the
504
510
  # request. Bucket owners need not specify this parameter in their
505
- # requests. For information about downloading objects from Requester
506
- # Pays buckets, see [Downloading Objects in Requester Pays Buckets][1]
507
- # in the *Amazon S3 User Guide*.
511
+ # requests. If either the source or destination Amazon S3 bucket has
512
+ # Requester Pays enabled, the requester will pay for corresponding
513
+ # charges to copy the object. For information about downloading objects
514
+ # from Requester Pays buckets, see [Downloading Objects in Requester
515
+ # Pays Buckets][1] in the *Amazon S3 User Guide*.
508
516
  #
509
517
  #
510
518
  #
@@ -521,7 +529,9 @@ module Aws::S3
521
529
  upload_id: @multipart_upload_id,
522
530
  part_number: @part_number
523
531
  )
524
- resp = @client.upload_part(options)
532
+ resp = Aws::Plugins::UserAgent.feature('resource') do
533
+ @client.upload_part(options)
534
+ end
525
535
  resp.data
526
536
  end
527
537