aws-sdk-s3 1.121.0 → 1.136.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +99 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-s3/bucket.rb +122 -60
  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 +2017 -1674
  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 +151 -105
  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 +144 -89
  39. data/lib/aws-sdk-s3/object_version.rb +55 -21
  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 +854 -484
  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