aws-sdk-s3 1.0.0.rc1

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/lib/aws-sdk-s3.rb +66 -0
  3. data/lib/aws-sdk-s3/bucket.rb +595 -0
  4. data/lib/aws-sdk-s3/bucket_acl.rb +168 -0
  5. data/lib/aws-sdk-s3/bucket_cors.rb +146 -0
  6. data/lib/aws-sdk-s3/bucket_lifecycle.rb +164 -0
  7. data/lib/aws-sdk-s3/bucket_logging.rb +142 -0
  8. data/lib/aws-sdk-s3/bucket_notification.rb +187 -0
  9. data/lib/aws-sdk-s3/bucket_policy.rb +138 -0
  10. data/lib/aws-sdk-s3/bucket_region_cache.rb +79 -0
  11. data/lib/aws-sdk-s3/bucket_request_payment.rb +128 -0
  12. data/lib/aws-sdk-s3/bucket_tagging.rb +143 -0
  13. data/lib/aws-sdk-s3/bucket_versioning.rb +188 -0
  14. data/lib/aws-sdk-s3/bucket_website.rb +177 -0
  15. data/lib/aws-sdk-s3/client.rb +3171 -0
  16. data/lib/aws-sdk-s3/client_api.rb +1991 -0
  17. data/lib/aws-sdk-s3/customizations.rb +29 -0
  18. data/lib/aws-sdk-s3/customizations/bucket.rb +127 -0
  19. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +42 -0
  20. data/lib/aws-sdk-s3/customizations/object.rb +257 -0
  21. data/lib/aws-sdk-s3/customizations/object_summary.rb +65 -0
  22. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +11 -0
  23. data/lib/aws-sdk-s3/encryption.rb +19 -0
  24. data/lib/aws-sdk-s3/encryption/client.rb +369 -0
  25. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +178 -0
  26. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +63 -0
  27. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +38 -0
  28. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +50 -0
  29. data/lib/aws-sdk-s3/encryption/errors.rb +13 -0
  30. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +50 -0
  31. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +29 -0
  32. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +69 -0
  33. data/lib/aws-sdk-s3/encryption/key_provider.rb +29 -0
  34. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +71 -0
  35. data/lib/aws-sdk-s3/encryption/materials.rb +58 -0
  36. data/lib/aws-sdk-s3/encryption/utils.rb +79 -0
  37. data/lib/aws-sdk-s3/errors.rb +23 -0
  38. data/lib/aws-sdk-s3/file_part.rb +75 -0
  39. data/lib/aws-sdk-s3/file_uploader.rb +58 -0
  40. data/lib/aws-sdk-s3/legacy_signer.rb +186 -0
  41. data/lib/aws-sdk-s3/multipart_file_uploader.rb +187 -0
  42. data/lib/aws-sdk-s3/multipart_upload.rb +287 -0
  43. data/lib/aws-sdk-s3/multipart_upload_error.rb +16 -0
  44. data/lib/aws-sdk-s3/multipart_upload_part.rb +314 -0
  45. data/lib/aws-sdk-s3/object.rb +942 -0
  46. data/lib/aws-sdk-s3/object_acl.rb +214 -0
  47. data/lib/aws-sdk-s3/object_copier.rb +99 -0
  48. data/lib/aws-sdk-s3/object_multipart_copier.rb +179 -0
  49. data/lib/aws-sdk-s3/object_summary.rb +794 -0
  50. data/lib/aws-sdk-s3/object_version.rb +406 -0
  51. data/lib/aws-sdk-s3/plugins/accelerate.rb +92 -0
  52. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +89 -0
  53. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +23 -0
  54. data/lib/aws-sdk-s3/plugins/dualstack.rb +70 -0
  55. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +29 -0
  56. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +23 -0
  57. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +47 -0
  58. data/lib/aws-sdk-s3/plugins/location_constraint.rb +33 -0
  59. data/lib/aws-sdk-s3/plugins/md5s.rb +79 -0
  60. data/lib/aws-sdk-s3/plugins/redirects.rb +41 -0
  61. data/lib/aws-sdk-s3/plugins/s3_signer.rb +208 -0
  62. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +68 -0
  63. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +94 -0
  64. data/lib/aws-sdk-s3/presigned_post.rb +647 -0
  65. data/lib/aws-sdk-s3/presigner.rb +160 -0
  66. data/lib/aws-sdk-s3/resource.rb +96 -0
  67. data/lib/aws-sdk-s3/types.rb +5750 -0
  68. data/lib/aws-sdk-s3/waiters.rb +178 -0
  69. metadata +154 -0
@@ -0,0 +1,187 @@
1
+ require 'pathname'
2
+ require 'thread'
3
+ require 'set'
4
+
5
+ module Aws
6
+ module S3
7
+ # @api private
8
+ class MultipartFileUploader
9
+
10
+ MIN_PART_SIZE = 5 * 1024 * 1024 # 5MB
11
+
12
+ FILE_TOO_SMALL = "unable to multipart upload files smaller than 5MB"
13
+
14
+ MAX_PARTS = 10_000
15
+
16
+ THREAD_COUNT = 10
17
+
18
+ # @api private
19
+ CREATE_OPTIONS =
20
+ Set.new(Client.api.operation(:create_multipart_upload).input.shape.member_names)
21
+
22
+ # @api private
23
+ UPLOAD_PART_OPTIONS =
24
+ Set.new(Client.api.operation(:upload_part).input.shape.member_names)
25
+
26
+ # @option options [Client] :client
27
+ def initialize(options = {})
28
+ @client = options[:client] || Client.new
29
+ @thread_count = options[:thread_count] || THREAD_COUNT
30
+ end
31
+
32
+ # @return [Client]
33
+ attr_reader :client
34
+
35
+ # @param [String,Pathname,File,Tempfile] source
36
+ # @option options [required,String] :bucket
37
+ # @option options [required,String] :key
38
+ # @return [void]
39
+ def upload(source, options = {})
40
+ if File.size(source) < MIN_PART_SIZE
41
+ raise ArgumentError, FILE_TOO_SMALL
42
+ else
43
+ upload_id = initiate_upload(options)
44
+ parts = upload_parts(upload_id, source, options)
45
+ complete_upload(upload_id, parts, options)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def initiate_upload(options)
52
+ @client.create_multipart_upload(create_opts(options)).upload_id
53
+ end
54
+
55
+ def complete_upload(upload_id, parts, options)
56
+ @client.complete_multipart_upload(
57
+ bucket: options[:bucket],
58
+ key: options[:key],
59
+ upload_id: upload_id,
60
+ multipart_upload: { parts: parts })
61
+ end
62
+
63
+ def upload_parts(upload_id, source, options)
64
+ pending = PartList.new(compute_parts(upload_id, source, options))
65
+ completed = PartList.new
66
+ errors = upload_in_threads(pending, completed)
67
+ if errors.empty?
68
+ completed.to_a.sort_by { |part| part[:part_number] }
69
+ else
70
+ abort_upload(upload_id, options, errors)
71
+ end
72
+ end
73
+
74
+ def abort_upload(upload_id, options, errors)
75
+ @client.abort_multipart_upload(
76
+ bucket: options[:bucket],
77
+ key: options[:key],
78
+ upload_id: upload_id
79
+ )
80
+ msg = "multipart upload failed: #{errors.map(&:message).join("; ")}"
81
+ raise MultipartUploadError.new(msg, errors)
82
+ rescue MultipartUploadError => error
83
+ raise error
84
+ rescue => error
85
+ msg = "failed to abort multipart upload: #{error.message}"
86
+ raise MultipartUploadError.new(msg, errors + [error])
87
+ end
88
+
89
+ def compute_parts(upload_id, source, options)
90
+ size = File.size(source)
91
+ default_part_size = compute_default_part_size(size)
92
+ offset = 0
93
+ part_number = 1
94
+ parts = []
95
+ while offset < size
96
+ parts << upload_part_opts(options).merge({
97
+ upload_id: upload_id,
98
+ part_number: part_number,
99
+ body: FilePart.new(
100
+ source: source,
101
+ offset: offset,
102
+ size: part_size(size, default_part_size, offset)
103
+ )
104
+ })
105
+ part_number += 1
106
+ offset += default_part_size
107
+ end
108
+ parts
109
+ end
110
+
111
+ def create_opts(options)
112
+ CREATE_OPTIONS.inject({}) do |hash, key|
113
+ hash[key] = options[key] if options.key?(key)
114
+ hash
115
+ end
116
+ end
117
+
118
+ def upload_part_opts(options)
119
+ UPLOAD_PART_OPTIONS.inject({}) do |hash, key|
120
+ hash[key] = options[key] if options.key?(key)
121
+ hash
122
+ end
123
+ end
124
+
125
+ def upload_in_threads(pending, completed)
126
+ threads = []
127
+ @thread_count.times do
128
+ thread = Thread.new do
129
+ begin
130
+ while part = pending.shift
131
+ resp = @client.upload_part(part)
132
+ part[:body].close
133
+ completed.push(etag: resp.etag, part_number: part[:part_number])
134
+ end
135
+ nil
136
+ rescue => error
137
+ # keep other threads from uploading other parts
138
+ pending.clear!
139
+ error
140
+ end
141
+ end
142
+ thread.abort_on_exception = true
143
+ threads << thread
144
+ end
145
+ threads.map(&:value).compact
146
+ end
147
+
148
+ def compute_default_part_size(source_size)
149
+ [(source_size.to_f / MAX_PARTS).ceil, MIN_PART_SIZE].max.to_i
150
+ end
151
+
152
+ def part_size(total_size, part_size, offset)
153
+ if offset + part_size > total_size
154
+ total_size - offset
155
+ else
156
+ part_size
157
+ end
158
+ end
159
+
160
+ # @api private
161
+ class PartList
162
+
163
+ def initialize(parts = [])
164
+ @parts = parts
165
+ @mutex = Mutex.new
166
+ end
167
+
168
+ def push(part)
169
+ @mutex.synchronize { @parts.push(part) }
170
+ end
171
+
172
+ def shift
173
+ @mutex.synchronize { @parts.shift }
174
+ end
175
+
176
+ def clear!
177
+ @mutex.synchronize { @parts.clear }
178
+ end
179
+
180
+ def to_a
181
+ @mutex.synchronize { @parts.dup }
182
+ end
183
+
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,287 @@
1
+ # WARNING ABOUT GENERATED CODE
2
+ #
3
+ # This file is generated. See the contributing for info on making contributions:
4
+ # https://github.com/aws/aws-sdk-ruby/blob/master/CONTRIBUTING.md
5
+ #
6
+ # WARNING ABOUT GENERATED CODE
7
+
8
+ module Aws
9
+ module S3
10
+ class MultipartUpload
11
+
12
+ extend Aws::Deprecations
13
+
14
+ # @overload def initialize(bucket_name, object_key, id, options = {})
15
+ # @param [String] bucket_name
16
+ # @param [String] object_key
17
+ # @param [String] id
18
+ # @option options [Client] :client
19
+ # @overload def initialize(options = {})
20
+ # @option options [required, String] :bucket_name
21
+ # @option options [required, String] :object_key
22
+ # @option options [required, String] :id
23
+ # @option options [Client] :client
24
+ def initialize(*args)
25
+ options = Hash === args.last ? args.pop.dup : {}
26
+ @bucket_name = extract_bucket_name(args, options)
27
+ @object_key = extract_object_key(args, options)
28
+ @id = extract_id(args, options)
29
+ @data = options.delete(:data)
30
+ @client = options.delete(:client) || Client.new(options)
31
+ end
32
+
33
+ # @!group Read-Only Attributes
34
+
35
+ # @return [String]
36
+ def bucket_name
37
+ @bucket_name
38
+ end
39
+
40
+ # @return [String]
41
+ def object_key
42
+ @object_key
43
+ end
44
+
45
+ # @return [String]
46
+ def id
47
+ @id
48
+ end
49
+
50
+ # Upload ID that identifies the multipart upload.
51
+ # @return [String]
52
+ def upload_id
53
+ data.upload_id
54
+ end
55
+
56
+ # Key of the object for which the multipart upload was initiated.
57
+ # @return [String]
58
+ def key
59
+ data.key
60
+ end
61
+
62
+ # Date and time at which the multipart upload was initiated.
63
+ # @return [Time]
64
+ def initiated
65
+ data.initiated
66
+ end
67
+
68
+ # The class of storage used to store the object.
69
+ # @return [String]
70
+ def storage_class
71
+ data.storage_class
72
+ end
73
+
74
+ # @return [Types::Owner]
75
+ def owner
76
+ data.owner
77
+ end
78
+
79
+ # Identifies who initiated the multipart upload.
80
+ # @return [Types::Initiator]
81
+ def initiator
82
+ data.initiator
83
+ end
84
+
85
+ # @!endgroup
86
+
87
+ # @return [Client]
88
+ def client
89
+ @client
90
+ end
91
+
92
+ # @raise [Errors::ResourceNotLoadable]
93
+ # @api private
94
+ def load
95
+ msg = "#load is not implemented, data only available via enumeration"
96
+ raise Errors::ResourceNotLoadable, msg
97
+ end
98
+ alias :reload :load
99
+
100
+ # @raise [Errors::ResourceNotLoadableError] Raises when {#data_loaded?} is `false`.
101
+ # @return [Types::MultipartUpload]
102
+ # Returns the data for this {MultipartUpload}.
103
+ def data
104
+ load unless @data
105
+ @data
106
+ end
107
+
108
+ # @return [Boolean]
109
+ # Returns `true` if this resource is loaded. Accessing attributes or
110
+ # {#data} on an unloaded resource will trigger a call to {#load}.
111
+ def data_loaded?
112
+ !!@data
113
+ end
114
+
115
+ # @!group Actions
116
+
117
+ # @example Request syntax with placeholder values
118
+ #
119
+ # multipart_upload.abort({
120
+ # request_payer: "requester", # accepts requester
121
+ # })
122
+ # @param [Hash] options ({})
123
+ # @option options [String] :request_payer
124
+ # Confirms that the requester knows that she or he will be charged for
125
+ # the request. Bucket owners need not specify this parameter in their
126
+ # requests. Documentation on downloading objects from requester pays
127
+ # buckets can be found at
128
+ # http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html
129
+ # @return [Types::AbortMultipartUploadOutput]
130
+ def abort(options = {})
131
+ options = options.merge(
132
+ bucket: @bucket_name,
133
+ key: @object_key,
134
+ upload_id: @id
135
+ )
136
+ resp = @client.abort_multipart_upload(options)
137
+ resp.data
138
+ end
139
+
140
+ # @example Request syntax with placeholder values
141
+ #
142
+ # object = multipart_upload.complete({
143
+ # multipart_upload: {
144
+ # parts: [
145
+ # {
146
+ # etag: "ETag",
147
+ # part_number: 1,
148
+ # },
149
+ # ],
150
+ # },
151
+ # request_payer: "requester", # accepts requester
152
+ # })
153
+ # @param [Hash] options ({})
154
+ # @option options [Types::CompletedMultipartUpload] :multipart_upload
155
+ # @option options [String] :request_payer
156
+ # Confirms that the requester knows that she or he will be charged for
157
+ # the request. Bucket owners need not specify this parameter in their
158
+ # requests. Documentation on downloading objects from requester pays
159
+ # buckets can be found at
160
+ # http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html
161
+ # @return [Object]
162
+ def complete(options = {})
163
+ options = options.merge(
164
+ bucket: @bucket_name,
165
+ key: @object_key,
166
+ upload_id: @id
167
+ )
168
+ resp = @client.complete_multipart_upload(options)
169
+ Object.new(
170
+ bucket_name: @bucket_name,
171
+ key: @object_key,
172
+ client: @client
173
+ )
174
+ end
175
+
176
+ # @!group Associations
177
+
178
+ # @return [Object]
179
+ def object
180
+ Object.new(
181
+ bucket_name: @bucket_name,
182
+ key: @object_key,
183
+ client: @client
184
+ )
185
+ end
186
+
187
+ # @param [String] part_number
188
+ # @return [MultipartUploadPart]
189
+ def part(part_number)
190
+ MultipartUploadPart.new(
191
+ bucket_name: @bucket_name,
192
+ object_key: @object_key,
193
+ multipart_upload_id: @id,
194
+ part_number: part_number,
195
+ client: @client
196
+ )
197
+ end
198
+
199
+ # @example Request syntax with placeholder values
200
+ #
201
+ # parts = multipart_upload.parts({
202
+ # request_payer: "requester", # accepts requester
203
+ # })
204
+ # @param [Hash] options ({})
205
+ # @option options [String] :request_payer
206
+ # Confirms that the requester knows that she or he will be charged for
207
+ # the request. Bucket owners need not specify this parameter in their
208
+ # requests. Documentation on downloading objects from requester pays
209
+ # buckets can be found at
210
+ # http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html
211
+ # @return [MultipartUploadPart::Collection]
212
+ def parts(options = {})
213
+ batches = Enumerator.new do |y|
214
+ options = options.merge(
215
+ bucket: @bucket_name,
216
+ key: @object_key,
217
+ upload_id: @id
218
+ )
219
+ resp = @client.list_parts(options)
220
+ resp.each_page do |page|
221
+ batch = []
222
+ page.data.parts.each do |p|
223
+ batch << MultipartUploadPart.new(
224
+ bucket_name: options[:bucket],
225
+ object_key: options[:key],
226
+ multipart_upload_id: options[:upload_id],
227
+ part_number: p.part_number,
228
+ data: p,
229
+ client: @client
230
+ )
231
+ end
232
+ y.yield(batch)
233
+ end
234
+ end
235
+ MultipartUploadPart::Collection.new(batches)
236
+ end
237
+
238
+ # @deprecated
239
+ # @api private
240
+ def identifiers
241
+ {
242
+ bucket_name: @bucket_name,
243
+ object_key: @object_key,
244
+ id: @id
245
+ }
246
+ end
247
+ deprecated(:identifiers)
248
+
249
+ private
250
+
251
+ def extract_bucket_name(args, options)
252
+ value = args[0] || options.delete(:bucket_name)
253
+ case value
254
+ when String then value
255
+ when nil then raise ArgumentError, "missing required option :bucket_name"
256
+ else
257
+ msg = "expected :bucket_name to be a String, got #{value.class}"
258
+ raise ArgumentError, msg
259
+ end
260
+ end
261
+
262
+ def extract_object_key(args, options)
263
+ value = args[1] || options.delete(:object_key)
264
+ case value
265
+ when String then value
266
+ when nil then raise ArgumentError, "missing required option :object_key"
267
+ else
268
+ msg = "expected :object_key to be a String, got #{value.class}"
269
+ raise ArgumentError, msg
270
+ end
271
+ end
272
+
273
+ def extract_id(args, options)
274
+ value = args[2] || options.delete(:id)
275
+ case value
276
+ when String then value
277
+ when nil then raise ArgumentError, "missing required option :id"
278
+ else
279
+ msg = "expected :id to be a String, got #{value.class}"
280
+ raise ArgumentError, msg
281
+ end
282
+ end
283
+
284
+ class Collection < Aws::Resources::Collection; end
285
+ end
286
+ end
287
+ end