aws-sdk 1.6.2 → 1.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/aws/core.rb +13 -2
- data/lib/aws/core/autoloader.rb +1 -1
- data/lib/aws/core/client.rb +69 -30
- data/lib/aws/core/configuration.rb +12 -1
- data/lib/aws/core/http/handler.rb +28 -16
- data/lib/aws/core/http/net_http_handler.rb +31 -11
- data/lib/aws/core/http/request.rb +52 -16
- data/lib/aws/core/http/response.rb +20 -16
- data/lib/aws/core/indifferent_hash.rb +14 -14
- data/lib/aws/core/query_client.rb +1 -0
- data/lib/aws/core/response.rb +32 -14
- data/lib/aws/core/signature/version_2.rb +1 -0
- data/lib/aws/core/signature/version_4.rb +16 -16
- data/lib/aws/dynamo_db/client.rb +2 -2
- data/lib/aws/dynamo_db/request.rb +0 -6
- data/lib/aws/ec2/security_group/ip_permission.rb +4 -1
- data/lib/aws/rails.rb +10 -10
- data/lib/aws/s3.rb +44 -29
- data/lib/aws/s3/bucket.rb +171 -6
- data/lib/aws/s3/cipher_io.rb +119 -0
- data/lib/aws/s3/client.rb +75 -45
- data/lib/aws/s3/config.rb +6 -0
- data/lib/aws/s3/data_options.rb +136 -49
- data/lib/aws/s3/encryption_utils.rb +144 -0
- data/lib/aws/s3/errors.rb +14 -0
- data/lib/aws/s3/multipart_upload.rb +7 -4
- data/lib/aws/s3/object_collection.rb +2 -2
- data/lib/aws/s3/policy.rb +1 -1
- data/lib/aws/s3/request.rb +21 -33
- data/lib/aws/s3/s3_object.rb +797 -237
- data/lib/aws/simple_email_service/request.rb +0 -2
- data/lib/aws/simple_workflow/request.rb +0 -3
- data/lib/net/http/connection_pool.rb +63 -75
- data/lib/net/http/connection_pool/connection.rb +69 -15
- data/lib/net/http/connection_pool/session.rb +39 -6
- metadata +4 -2
data/lib/aws/s3.rb
CHANGED
@@ -26,7 +26,7 @@ module AWS
|
|
26
26
|
# * {Amazon S3}[http://aws.amazon.com/s3/]
|
27
27
|
# * {Amazon S3 Documentation}[http://aws.amazon.com/documentation/s3/]
|
28
28
|
#
|
29
|
-
#
|
29
|
+
# = Credentials
|
30
30
|
#
|
31
31
|
# You can setup default credentials for all AWS services via
|
32
32
|
# AWS.config:
|
@@ -34,63 +34,76 @@ module AWS
|
|
34
34
|
# AWS.config(
|
35
35
|
# :access_key_id => 'YOUR_ACCESS_KEY_ID',
|
36
36
|
# :secret_access_key => 'YOUR_SECRET_ACCESS_KEY')
|
37
|
-
#
|
37
|
+
#
|
38
38
|
# Or you can set them directly on the S3 interface:
|
39
39
|
#
|
40
40
|
# s3 = AWS::S3.new(
|
41
41
|
# :access_key_id => 'YOUR_ACCESS_KEY_ID',
|
42
42
|
# :secret_access_key => 'YOUR_SECRET_ACCESS_KEY')
|
43
43
|
#
|
44
|
-
#
|
44
|
+
# = Buckets
|
45
45
|
#
|
46
|
-
# S3
|
46
|
+
# Before you can upload files to S3, you need to create a bucket.
|
47
47
|
#
|
48
|
-
#
|
48
|
+
# s3 = AWS::S3.new
|
49
|
+
# bucket = s3.buckets.create('my-bucket')
|
49
50
|
#
|
50
|
-
#
|
51
|
+
# If a bucket already exists, you can get a reference to the bucket.
|
51
52
|
#
|
52
|
-
#
|
53
|
+
# bucket = s3.buckets['my-bucket'] # no request made
|
53
54
|
#
|
54
|
-
#
|
55
|
-
# bucket = s3.buckets['mybucket']
|
55
|
+
# You can also enumerate all buckets in your account.
|
56
56
|
#
|
57
|
-
# Listing buckets:
|
58
|
-
#
|
59
57
|
# s3.buckets.each do |bucket|
|
60
58
|
# puts bucket.name
|
61
59
|
# end
|
62
60
|
#
|
63
|
-
# See {
|
64
|
-
# with
|
61
|
+
# See {BucketCollection} and {Bucket} for more information on working
|
62
|
+
# with buckets.
|
65
63
|
#
|
66
|
-
#
|
64
|
+
# = Objects
|
67
65
|
#
|
68
|
-
#
|
66
|
+
# Buckets contain objects. Each object in a bucket has a unique key.
|
69
67
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
68
|
+
# == Getting an Object
|
69
|
+
#
|
70
|
+
# If the object already exists, you can get a reference to the object.
|
73
71
|
#
|
74
|
-
#
|
75
|
-
#
|
72
|
+
# # makes no request, returns an AWS::S3::S3Object
|
73
|
+
# obj = bucket.objects['key']
|
76
74
|
#
|
77
|
-
# == Reading and Writing
|
75
|
+
# == Reading and Writing an Object
|
78
76
|
#
|
79
|
-
#
|
77
|
+
# The example above returns an {S3Object}. You call {S3Object#write} and
|
78
|
+
# {S3Object#read} to upload to and download from S3 respectively.
|
80
79
|
#
|
81
|
-
#
|
80
|
+
# # streaming upload a file to S3
|
81
|
+
# obj.write(Pathname.new('/path/to/file.txt'))
|
82
82
|
#
|
83
|
-
#
|
83
|
+
# # streaming download from S3 to a file on disk
|
84
|
+
# File.open('file.txt', 'w') do |file|
|
85
|
+
# obj.read do |chunk|
|
86
|
+
# file.write(chunk)
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# == Enumerating Objects
|
84
91
|
#
|
85
|
-
#
|
92
|
+
# You can enumerate objects in your buckets.
|
86
93
|
#
|
87
|
-
#
|
94
|
+
# # enumerate ALL objects in the bucket (even if the bucket contains
|
95
|
+
# # more than 1k objects)
|
96
|
+
# bucket.objects.each do |obj|
|
97
|
+
# puts obj.key
|
98
|
+
# end
|
88
99
|
#
|
89
|
-
#
|
90
|
-
#
|
100
|
+
# # enumerate at most 20 objects with the given prefix
|
101
|
+
# bucket.objects.with_prefix('photos/').each(:limit => 20).each do |photo|
|
102
|
+
# puts photo.key
|
91
103
|
# end
|
92
104
|
#
|
93
|
-
# See {S3Object} for more information on
|
105
|
+
# See {ObjectCollection} and {S3Object} for more information on working
|
106
|
+
# with objects.
|
94
107
|
#
|
95
108
|
class S3
|
96
109
|
|
@@ -104,6 +117,8 @@ module AWS
|
|
104
117
|
autoload :BucketVersionCollection, 'bucket_version_collection'
|
105
118
|
autoload :Client, 'client'
|
106
119
|
autoload :DataOptions, 'data_options'
|
120
|
+
autoload :EncryptionUtils, 'encryption_utils'
|
121
|
+
autoload :CipherIO, 'cipher_io'
|
107
122
|
autoload :Errors, 'errors'
|
108
123
|
autoload :MultipartUpload, 'multipart_upload'
|
109
124
|
autoload :MultipartUploadCollection, 'multipart_upload_collection'
|
data/lib/aws/s3/bucket.rb
CHANGED
@@ -14,15 +14,180 @@
|
|
14
14
|
module AWS
|
15
15
|
class S3
|
16
16
|
|
17
|
-
# Represents a
|
17
|
+
# Represents a bucket in S3.
|
18
18
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# bucket = s3.buckets.create('mybucket')
|
19
|
+
# = Creating Buckets
|
22
20
|
#
|
23
|
-
#
|
21
|
+
# You create a bucket by name. Bucket names must be globally unique
|
22
|
+
# and must be DNS compatible.
|
24
23
|
#
|
25
|
-
#
|
24
|
+
# s3 = AWS::S3.new
|
25
|
+
# bucket = s3.buckets.create('dns-compat-bucket-name')
|
26
|
+
#
|
27
|
+
# = Getting a Bucket
|
28
|
+
#
|
29
|
+
# You can create a reference to a bucket, given its name.
|
30
|
+
#
|
31
|
+
# bucket = s3.buckets['bucket-name'] # makes no request
|
32
|
+
# bucket.exists? #=> returns true/false
|
33
|
+
#
|
34
|
+
# = Enumerating Buckets
|
35
|
+
#
|
36
|
+
# The {BucketCollection} class is enumerable.
|
37
|
+
#
|
38
|
+
# s3.buckets.each do |bucket|
|
39
|
+
# puts bucket.name
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# = Deleting a Bucket
|
43
|
+
#
|
44
|
+
# You can delete an empty bucket you own.
|
45
|
+
#
|
46
|
+
# bucket = s3.buckets.create('my-temp-bucket')
|
47
|
+
# bucket.objects['abc'].write('xyz')
|
48
|
+
#
|
49
|
+
# bucket.clear! # deletes all object versions in batches
|
50
|
+
# bucket.delete
|
51
|
+
#
|
52
|
+
# You can alternatively call {#delete!} which will clear
|
53
|
+
# the bucket for your first.
|
54
|
+
#
|
55
|
+
# bucket.delete!
|
56
|
+
#
|
57
|
+
# = Objects
|
58
|
+
#
|
59
|
+
# Given a bucket you can access its objects, either by key or by
|
60
|
+
# enumeration.
|
61
|
+
#
|
62
|
+
# bucket.objects['key'] #=> makes no request, returns an S3Object
|
63
|
+
#
|
64
|
+
# bucket.objects.each do |obj|
|
65
|
+
# puts obj.key
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# See {ObjectCollection} and {S3Object} for more information on working
|
69
|
+
# with objects.
|
70
|
+
#
|
71
|
+
# = Bucket Policies and ACLs
|
72
|
+
#
|
73
|
+
# You can control access to your bucket and its contents a number
|
74
|
+
# of ways. You can specify a bucket ACL (access control list)
|
75
|
+
# or a bucket policy.
|
76
|
+
#
|
77
|
+
# == ACLs
|
78
|
+
#
|
79
|
+
# ACLs control access to your bucket and its contents via a list of
|
80
|
+
# grants and grantees.
|
81
|
+
#
|
82
|
+
# === Canned ACLs
|
83
|
+
#
|
84
|
+
# The simplest way to specify an ACL is to use one of Amazon's "canned"
|
85
|
+
# ACLs. Amazon accepts the following canned ACLs:
|
86
|
+
#
|
87
|
+
# * +:private+
|
88
|
+
# * +:public_read+
|
89
|
+
# * +:public_read_write+
|
90
|
+
# * +:authenticated_read+
|
91
|
+
# * +:bucket_owner_read+
|
92
|
+
# * +:bucket_owner_full_control+
|
93
|
+
#
|
94
|
+
# You can specify a the ACL at bucket creation or later update a bucket.
|
95
|
+
#
|
96
|
+
# # at create time, defaults to :private when not specified
|
97
|
+
# bucket = s3.buckets.create('name', :acl => :public_read)
|
98
|
+
#
|
99
|
+
# # replacing an existing bucket ACL
|
100
|
+
# bucket.acl = :private
|
101
|
+
#
|
102
|
+
# === Grants
|
103
|
+
#
|
104
|
+
# Alternatively you can specify a hash of grants. Each entry in the
|
105
|
+
# +:grant+ hash has a grant (key) and a list of grantees (values).
|
106
|
+
# Valid grant keys are:
|
107
|
+
#
|
108
|
+
# * +:grant_read+
|
109
|
+
# * +:grant_write+
|
110
|
+
# * +:grant_read_acp+
|
111
|
+
# * +:grant_write_acp+
|
112
|
+
# * +:grant_full_control+
|
113
|
+
#
|
114
|
+
# Each grantee can be a String, Hash or array of strings or hashes.
|
115
|
+
# The following example uses grants to provide public read
|
116
|
+
# to everyone while providing full control to a user by email address
|
117
|
+
# and to another by their account id (cannonical user id).
|
118
|
+
#
|
119
|
+
# bucket = s3.buckets.create('name', :grants => {
|
120
|
+
# :grant_read => [
|
121
|
+
# { :uri => "http://acs.amazonaws.com/groups/global/AllUsers" },
|
122
|
+
# ],
|
123
|
+
# :grant_full_control => [
|
124
|
+
# { :id => 'abc...mno' } # cannonical user id
|
125
|
+
# { :email_address => 'foo@bar.com' }, # email address
|
126
|
+
# ]
|
127
|
+
# })
|
128
|
+
#
|
129
|
+
# === ACL Object
|
130
|
+
#
|
131
|
+
# Lastly, you can build an ACL object and use a Ruby DSL to specify grants
|
132
|
+
# and grantees. See {ACLObject} for more information.
|
133
|
+
#
|
134
|
+
# # updating an existing bucket acl using ACLObject
|
135
|
+
# bucket.acl.change do |acl|
|
136
|
+
# acl.grants.reject! do |g|
|
137
|
+
# g.grantee.canonical_user_id != bucket.owner.id
|
138
|
+
# end
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# == Policies
|
142
|
+
#
|
143
|
+
# You can also work with bucket policies.
|
144
|
+
#
|
145
|
+
# policy = AWS::S3::Policy.new
|
146
|
+
# policy.allow(
|
147
|
+
# :actions => [:put_object, :get_object]
|
148
|
+
# :resources => [bucket]
|
149
|
+
# :principals => :any)
|
150
|
+
#
|
151
|
+
# bucket.policy = policy
|
152
|
+
#
|
153
|
+
# See {Core::Policy} and {S3::Policy} for more information on build
|
154
|
+
# policy objects.
|
155
|
+
#
|
156
|
+
# = Versioned Buckets
|
157
|
+
#
|
158
|
+
# You can enable versioning on a bucket you control. When versioning
|
159
|
+
# is enabled, S3 will keep track of each version of each object you
|
160
|
+
# write to the bucket (even deletions).
|
161
|
+
#
|
162
|
+
# bucket.versioning_enabled? #=> false
|
163
|
+
# bucket.enable_versioning
|
164
|
+
# # there is also a #disable_versioning method
|
165
|
+
#
|
166
|
+
# obj = bucket.objects['my-obj']
|
167
|
+
# obj.write('a')
|
168
|
+
# obj.write('b')
|
169
|
+
# obj.delete
|
170
|
+
# obj.write('c')
|
171
|
+
#
|
172
|
+
# obj.versions.each do |obj_version|
|
173
|
+
# if obj_version.delete_marker?
|
174
|
+
# puts obj_version.read
|
175
|
+
# else
|
176
|
+
# puts "- DELETE MARKER"
|
177
|
+
# end
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
# Alternatively you can enumerate all versions of all objects in your
|
181
|
+
# bucket.
|
182
|
+
#
|
183
|
+
# bucket.versions.each do |obj_version|
|
184
|
+
# puts obj_version.key + " : " + obj_version.version_id
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# See {BucketVersionCollection}, {ObjectVersionCollection} and
|
188
|
+
# {ObjectVersion} for more information on working with objects in
|
189
|
+
# a versioned bucket. Also see the S3 documentation for information
|
190
|
+
# on object versioning.
|
26
191
|
#
|
27
192
|
class Bucket
|
28
193
|
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
module AWS
|
15
|
+
class S3
|
16
|
+
|
17
|
+
# @private
|
18
|
+
class CipherIO
|
19
|
+
|
20
|
+
def initialize cipher, stream, stream_size = nil
|
21
|
+
|
22
|
+
@stream = stream
|
23
|
+
@stream_size = stream_size
|
24
|
+
@orig_cipher = cipher.clone
|
25
|
+
|
26
|
+
reset_cipher
|
27
|
+
|
28
|
+
# add a #rewind method if the original stream can be rewound
|
29
|
+
if @stream.respond_to?(:rewind)
|
30
|
+
Core::MetaUtils.extend_method(self, :rewind) do
|
31
|
+
reset_cipher
|
32
|
+
@stream.rewind
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# add a #size method if the stream size is known
|
37
|
+
if stream_size
|
38
|
+
Core::MetaUtils.extend_method(self, :size) do
|
39
|
+
EncryptionUtils.get_encrypted_size(@stream_size)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [String] Returns the requested number of bytes. If no byte
|
46
|
+
# amount is given, it will return the entire body of encrypted data
|
47
|
+
def read bytes = nil
|
48
|
+
if bytes
|
49
|
+
(@eof) ? nil : read_chunk(bytes)
|
50
|
+
else
|
51
|
+
(@eof) ? "" : read_all()
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Boolean] Returns +true+ when the entire stream has been read.
|
56
|
+
def eof?
|
57
|
+
@eof
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
attr_reader :cipher
|
63
|
+
|
64
|
+
# Sets the CipherIO in a reset state without having to know anything
|
65
|
+
# about the cipher
|
66
|
+
def reset_cipher
|
67
|
+
@cipher = @orig_cipher.clone
|
68
|
+
@eof = false
|
69
|
+
@final = nil
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [String] Returns an encrytped chunk
|
73
|
+
def read_chunk bytes
|
74
|
+
unless @final
|
75
|
+
# If given a number of bytes, read it out and work out encryption
|
76
|
+
# issues
|
77
|
+
chunk = @stream.read(bytes)
|
78
|
+
|
79
|
+
# If there is nothing, finish the encryption
|
80
|
+
if chunk and chunk.length > 0
|
81
|
+
handle_finish(bytes, cipher.update(chunk))
|
82
|
+
else
|
83
|
+
@eof = true
|
84
|
+
cipher.final
|
85
|
+
end
|
86
|
+
# Read as much as possible if not given a byte size
|
87
|
+
else
|
88
|
+
@eof = true
|
89
|
+
@final
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [String] Returns the entire encrypted data
|
94
|
+
def read_all
|
95
|
+
@eof = true
|
96
|
+
body = @stream.read()
|
97
|
+
data = (body and body.length > 0) ? cipher.update(body) : ""
|
98
|
+
data << cipher.final
|
99
|
+
end
|
100
|
+
|
101
|
+
# Figures out how much of the final block goes into the current chunk
|
102
|
+
# and adds it.
|
103
|
+
# @return [String] Returns the encrypted chunk with possible padding.
|
104
|
+
def handle_finish(bytes, chunk)
|
105
|
+
free_space = bytes - chunk.size
|
106
|
+
|
107
|
+
if free_space > 0
|
108
|
+
@final = cipher.final
|
109
|
+
chunk << @final[0..free_space-1]
|
110
|
+
@final = @final[free_space-1..@final.size-1]
|
111
|
+
@eof = true unless @final and @final.size > 0
|
112
|
+
end
|
113
|
+
|
114
|
+
chunk
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/aws/s3/client.rb
CHANGED
@@ -295,7 +295,7 @@ module AWS
|
|
295
295
|
|
296
296
|
process_response do |response|
|
297
297
|
regex = />(.*)<\/LocationConstraint>/
|
298
|
-
matches = response.http_response.body.match(regex)
|
298
|
+
matches = response.http_response.body.to_s.match(regex)
|
299
299
|
response.data[:location_constraint] = matches ? matches[1] : nil
|
300
300
|
end
|
301
301
|
|
@@ -573,10 +573,14 @@ module AWS
|
|
573
573
|
# * +:private+
|
574
574
|
# * +:public_read+
|
575
575
|
# * ...
|
576
|
-
# @option options [
|
576
|
+
# @option options [String] :storage_class+ ('STANDARD')
|
577
577
|
# Controls whether Reduced Redundancy Storage is enabled for
|
578
|
-
# the object. Valid values are
|
579
|
-
#
|
578
|
+
# the object. Valid values are 'STANDARD' and
|
579
|
+
# 'REDUCED_REDUNDANCY'.
|
580
|
+
# @option options [Symbol,String] :server_side_encryption (nil) The
|
581
|
+
# algorithm used to encrypt the object on the server side
|
582
|
+
# (e.g. :aes256).
|
583
|
+
# object on the server side, e.g. +:aes256+)
|
580
584
|
# @option options [String] :cache_control
|
581
585
|
# Can be used to specify caching behavior.
|
582
586
|
# @option options [String] :content_disposition
|
@@ -610,19 +614,20 @@ module AWS
|
|
610
614
|
:content_disposition => 'Content-Disposition',
|
611
615
|
:content_encoding => 'Content-Encoding',
|
612
616
|
:content_type => 'Content-Type',
|
613
|
-
:storage_class => 'x-amz-storage-class',
|
614
|
-
:server_side_encryption => 'x-amz-server-side-encryption',
|
615
617
|
:expires => 'Expires'
|
616
618
|
}) do
|
617
619
|
|
618
|
-
configure_request do |request, options
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
set_request_data(request, options, block)
|
620
|
+
configure_request do |request, options|
|
621
|
+
|
622
|
+
options = compute_write_options(options)
|
623
|
+
set_body_stream_and_content_length(request, options)
|
624
|
+
|
624
625
|
request.metadata = options[:metadata]
|
625
626
|
request.storage_class = options[:storage_class]
|
627
|
+
request.server_side_encryption = options[:server_side_encryption]
|
628
|
+
|
629
|
+
super(request, options)
|
630
|
+
|
626
631
|
end
|
627
632
|
|
628
633
|
process_response do |response|
|
@@ -637,6 +642,7 @@ module AWS
|
|
637
642
|
end
|
638
643
|
|
639
644
|
add_sse_to_response(response)
|
645
|
+
|
640
646
|
end
|
641
647
|
|
642
648
|
simulate_response do |response|
|
@@ -826,8 +832,13 @@ module AWS
|
|
826
832
|
# @option options [String] :content_disposition
|
827
833
|
# @option options [String] :content_encoding
|
828
834
|
# @option options [String] :content_type
|
829
|
-
# @option options [String] :storage_class
|
830
|
-
#
|
835
|
+
# @option options [String] :storage_class+ ('STANDARD')
|
836
|
+
# Controls whether Reduced Redundancy Storage is enabled for
|
837
|
+
# the object. Valid values are 'STANDARD' and
|
838
|
+
# 'REDUCED_REDUNDANCY'.
|
839
|
+
# @option options [Symbol,String] :server_side_encryption (nil) The
|
840
|
+
# algorithm used to encrypt the object on the server side
|
841
|
+
# (e.g. :aes256).
|
831
842
|
# @option options [String] :expires
|
832
843
|
# @option options [String] :acl A canned ACL (e.g. 'private',
|
833
844
|
# 'public-read', etc). See the S3 API documentation for
|
@@ -851,23 +862,20 @@ module AWS
|
|
851
862
|
:content_disposition => 'Content-Disposition',
|
852
863
|
:content_encoding => 'Content-Encoding',
|
853
864
|
:content_type => 'Content-Type',
|
854
|
-
:storage_class => 'x-amz-storage-class',
|
855
|
-
:server_side_encryption => 'x-amz-server-side-encryption',
|
856
865
|
:expires => 'Expires'
|
857
866
|
}) do
|
858
867
|
|
859
868
|
configure_request do |req, options|
|
860
|
-
options[:server_side_encryption] =
|
861
|
-
options[:server_side_encryption].to_s.upcase if
|
862
|
-
options[:server_side_encryption].kind_of?(Symbol)
|
863
|
-
super(req, options)
|
864
869
|
req.metadata = options[:metadata]
|
865
870
|
req.storage_class = options[:storage_class]
|
871
|
+
req.server_side_encryption = options[:server_side_encryption]
|
872
|
+
super(req, options)
|
866
873
|
end
|
867
874
|
|
868
875
|
process_response do |response|
|
869
876
|
add_sse_to_response(response)
|
870
877
|
end
|
878
|
+
|
871
879
|
end
|
872
880
|
|
873
881
|
# @overload list_multipart_uploads(options = {})
|
@@ -933,26 +941,30 @@ module AWS
|
|
933
941
|
# @param [Hash] options
|
934
942
|
# @option options [required,String] :bucket_name
|
935
943
|
# @option options [required,String] :key
|
944
|
+
# @option options [required,String] :upload_id
|
945
|
+
# @option options [required,Integer] :part_number
|
936
946
|
# @option options [required,String,Pathname,File,IO] :data
|
937
947
|
# The data to upload. This can be provided as a string,
|
938
948
|
# a Pathname object, or any object that responds to
|
939
949
|
# +#read+ and +#eof?+ (e.g. IO, File, Tempfile, StringIO, etc).
|
940
|
-
# @option options [required,String] :upload_id
|
941
|
-
# @option options [required,Integer] :part_number
|
942
950
|
# @return [Core::Response]
|
943
951
|
object_method(:upload_part, :put,
|
944
952
|
:header_options => {
|
945
953
|
:content_md5 => 'Content-MD5'
|
946
954
|
}) do
|
947
|
-
configure_request do |request, options
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
set_request_data(request, options, block)
|
955
|
+
configure_request do |request, options|
|
956
|
+
|
957
|
+
options = compute_write_options(options)
|
958
|
+
set_body_stream_and_content_length(request, options)
|
959
|
+
|
960
|
+
require_upload_id!(options[:upload_id])
|
954
961
|
request.add_param('uploadId', options[:upload_id])
|
962
|
+
|
963
|
+
require_part_number!(options[:part_number])
|
955
964
|
request.add_param('partNumber', options[:part_number])
|
965
|
+
|
966
|
+
super(request, options)
|
967
|
+
|
956
968
|
end
|
957
969
|
|
958
970
|
process_response do |response|
|
@@ -1051,6 +1063,13 @@ module AWS
|
|
1051
1063
|
# @option options [String] :acl A canned ACL (e.g. 'private',
|
1052
1064
|
# 'public-read', etc). See the S3 API documentation for
|
1053
1065
|
# a complete list of valid values.
|
1066
|
+
# @option options [Symbol,String] :server_side_encryption (nil) The
|
1067
|
+
# algorithm used to encrypt the object on the server side
|
1068
|
+
# (e.g. :aes256).
|
1069
|
+
# @option options [String] :storage_class+ ('STANDARD')
|
1070
|
+
# Controls whether Reduced Redundancy Storage is enabled for
|
1071
|
+
# the object. Valid values are 'STANDARD' and
|
1072
|
+
# 'REDUCED_REDUNDANCY'.
|
1054
1073
|
# @option options [String] :grant_read
|
1055
1074
|
# @option options [String] :grant_write
|
1056
1075
|
# @option options [String] :grant_read_acp
|
@@ -1067,25 +1086,21 @@ module AWS
|
|
1067
1086
|
:copy_source => 'x-amz-copy-source',
|
1068
1087
|
:cache_control => 'Cache-Control',
|
1069
1088
|
:metadata_directive => 'x-amz-metadata-directive',
|
1070
|
-
:storage_class => 'x-amz-storage-class',
|
1071
|
-
:server_side_encryption => 'x-amz-server-side-encryption',
|
1072
1089
|
:content_type => 'Content-Type',
|
1073
1090
|
}) do
|
1074
1091
|
|
1075
1092
|
configure_request do |req, options|
|
1076
|
-
|
1077
|
-
# TODO : validate storage class STANDARD / REDUCED_REDUNDANCY
|
1078
|
-
# TODO : add validations for storage class in other places used
|
1093
|
+
|
1079
1094
|
validate!(:copy_source, options[:copy_source]) do
|
1080
1095
|
"may not be blank" if options[:copy_source].to_s.empty?
|
1081
1096
|
end
|
1097
|
+
|
1082
1098
|
options = options.merge(:copy_source => escape_path(options[:copy_source]))
|
1083
|
-
options[:server_side_encryption] =
|
1084
|
-
options[:server_side_encryption].to_s.upcase if
|
1085
|
-
options[:server_side_encryption].kind_of?(Symbol)
|
1086
1099
|
super(req, options)
|
1087
1100
|
req.metadata = options[:metadata]
|
1088
1101
|
req.storage_class = options[:storage_class]
|
1102
|
+
req.server_side_encryption = options[:server_side_encryption]
|
1103
|
+
|
1089
1104
|
if options[:version_id]
|
1090
1105
|
req.headers['x-amz-copy-source'] += "?versionId=#{options[:version_id]}"
|
1091
1106
|
end
|
@@ -1130,20 +1145,15 @@ module AWS
|
|
1130
1145
|
end
|
1131
1146
|
end
|
1132
1147
|
|
1133
|
-
def
|
1148
|
+
def retryable_error? response
|
1134
1149
|
super or
|
1135
|
-
response.request_type == :complete_multipart_upload &&
|
1136
|
-
extract_error_details(response)
|
1150
|
+
(response.request_type == :complete_multipart_upload &&
|
1151
|
+
extract_error_details(response))
|
1137
1152
|
# complete multipart upload can return an error inside a
|
1138
1153
|
# 200 level response -- this forces us to parse the
|
1139
1154
|
# response for errors every time
|
1140
1155
|
end
|
1141
1156
|
|
1142
|
-
def set_request_data request, options, block
|
1143
|
-
request.body_stream = data_stream_from(options, &block)
|
1144
|
-
request.headers['Content-Length'] = content_length_from(options)
|
1145
|
-
end
|
1146
|
-
|
1147
1157
|
def new_request
|
1148
1158
|
req = S3::Request.new
|
1149
1159
|
req.force_path_style = config.s3_force_path_style?
|
@@ -1320,12 +1330,32 @@ module AWS
|
|
1320
1330
|
end
|
1321
1331
|
end
|
1322
1332
|
|
1333
|
+
def set_body_stream_and_content_length request, options
|
1334
|
+
|
1335
|
+
unless options[:content_length]
|
1336
|
+
msg = "S3 requires a content-length header, unable to determine "
|
1337
|
+
msg << "the content length of the data provided, please set "
|
1338
|
+
msg << ":content_length"
|
1339
|
+
raise ArgumentError, msg
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
request.headers['content-length'] = options[:content_length]
|
1343
|
+
request.body_stream = options[:data]
|
1344
|
+
|
1345
|
+
end
|
1346
|
+
|
1323
1347
|
def require_upload_id!(upload_id)
|
1324
1348
|
validate!("upload_id", upload_id) do
|
1325
1349
|
"must not be blank" if upload_id.to_s.empty?
|
1326
1350
|
end
|
1327
1351
|
end
|
1328
1352
|
|
1353
|
+
def require_part_number! part_number
|
1354
|
+
validate!("part_number", part_number) do
|
1355
|
+
"must not be blank" if part_number.to_s.empty?
|
1356
|
+
end
|
1357
|
+
end
|
1358
|
+
|
1329
1359
|
def validate_parts!(parts)
|
1330
1360
|
validate!("parts", parts) do
|
1331
1361
|
if !parts.kind_of?(Array)
|