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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +94 -0
- data/VERSION +1 -1
- data/lib/aws-sdk-s3/bucket.rb +108 -49
- data/lib/aws-sdk-s3/bucket_acl.rb +9 -3
- data/lib/aws-sdk-s3/bucket_cors.rb +12 -4
- data/lib/aws-sdk-s3/bucket_lifecycle.rb +12 -4
- data/lib/aws-sdk-s3/bucket_lifecycle_configuration.rb +12 -4
- data/lib/aws-sdk-s3/bucket_logging.rb +9 -3
- data/lib/aws-sdk-s3/bucket_notification.rb +9 -3
- data/lib/aws-sdk-s3/bucket_policy.rb +12 -4
- data/lib/aws-sdk-s3/bucket_request_payment.rb +9 -3
- data/lib/aws-sdk-s3/bucket_tagging.rb +12 -4
- data/lib/aws-sdk-s3/bucket_versioning.rb +15 -5
- data/lib/aws-sdk-s3/bucket_website.rb +12 -4
- data/lib/aws-sdk-s3/client.rb +727 -626
- data/lib/aws-sdk-s3/client_api.rb +24 -0
- data/lib/aws-sdk-s3/customizations/bucket.rb +3 -1
- data/lib/aws-sdk-s3/customizations/errors.rb +1 -1
- data/lib/aws-sdk-s3/customizations/object.rb +91 -18
- data/lib/aws-sdk-s3/encryption/client.rb +6 -2
- data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +13 -9
- data/lib/aws-sdk-s3/encryptionV2/client.rb +6 -2
- data/lib/aws-sdk-s3/encryptionV2/decrypt_handler.rb +1 -0
- data/lib/aws-sdk-s3/encryptionV2/kms_cipher_provider.rb +10 -6
- data/lib/aws-sdk-s3/endpoint_parameters.rb +4 -0
- data/lib/aws-sdk-s3/endpoint_provider.rb +22 -246
- data/lib/aws-sdk-s3/endpoints.rb +1 -0
- data/lib/aws-sdk-s3/file_downloader.rb +170 -44
- data/lib/aws-sdk-s3/file_uploader.rb +8 -6
- data/lib/aws-sdk-s3/multipart_stream_uploader.rb +5 -3
- data/lib/aws-sdk-s3/multipart_upload.rb +27 -13
- data/lib/aws-sdk-s3/multipart_upload_part.rb +19 -9
- data/lib/aws-sdk-s3/object.rb +125 -84
- data/lib/aws-sdk-s3/object_acl.rb +14 -6
- data/lib/aws-sdk-s3/object_copier.rb +7 -5
- data/lib/aws-sdk-s3/object_multipart_copier.rb +33 -17
- data/lib/aws-sdk-s3/object_summary.rb +123 -74
- data/lib/aws-sdk-s3/object_version.rb +49 -17
- data/lib/aws-sdk-s3/presigned_post.rb +52 -43
- data/lib/aws-sdk-s3/presigner.rb +4 -2
- data/lib/aws-sdk-s3/resource.rb +7 -3
- data/lib/aws-sdk-s3/types.rb +529 -299
- data/lib/aws-sdk-s3.rb +1 -1
- 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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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 =
|
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
|
60
|
-
single_request
|
61
|
-
|
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
|
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(
|
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
|
114
|
+
while offset < file_size
|
86
115
|
progress = offset + default_chunk_size
|
87
|
-
|
88
|
-
|
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
|
-
|
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(
|
112
|
-
|
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(
|
116
|
-
|
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
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
-
|
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
|
-
@
|
142
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
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::
|
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.
|
236
|
-
# Pays
|
237
|
-
#
|
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 =
|
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.
|
329
|
-
# Pays
|
330
|
-
#
|
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
|
-
|
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.
|
418
|
-
# Pays
|
419
|
-
#
|
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 =
|
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::
|
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.
|
376
|
-
# Pays
|
377
|
-
#
|
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 =
|
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.
|
506
|
-
# Pays
|
507
|
-
#
|
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 =
|
532
|
+
resp = Aws::Plugins::UserAgent.feature('resource') do
|
533
|
+
@client.upload_part(options)
|
534
|
+
end
|
525
535
|
resp.data
|
526
536
|
end
|
527
537
|
|