lib/aws/s3/s3_object.rb in aws-sdk-1.9.5 vs lib/aws/s3/s3_object.rb in aws-sdk-1.10.0
- old
+ new
@@ -61,21 +61,21 @@
#
# # also works this way
# obj.write(:file => path_to_file)
#
# # Also accepts an open file object
- # file = File.open(path_to_file, 'r')
+ # file = File.open(path_to_file, 'rb')
# obj.write(file)
#
# All three examples above produce the same result. The file
# will be streamed to S3 in chunks. It will not be loaded
# entirely into memory.
#
# ## Streaming Uploads
#
- # When you call {#write} with any IO-like object (must respond to
- # #read and #eof?), it will be streamed to S3 in chunks.
+ # When you call {#write} with an IO-like object, it will be streamed
+ # to S3 in chunks.
#
# While it is possible to determine the size of many IO objects, you may
# have to specify the :content_length of your IO object.
# If the exact size can not be known, you may provide an
# `:estimated_content_length`. Depending on the size (actual or
@@ -102,11 +102,11 @@
# ## Streaming Downloads
#
# If you want to stream an object from S3, you can pass a block
# to {#read}.
#
- # File.open('output', 'w') do |file|
+ # File.open('output', 'wb') do |file|
# large_object.read do |chunk|
# file.write(chunk)
# end
# end
#
@@ -458,11 +458,11 @@
#
# # files (by path)
# obj.write(Pathname.new('path/to/file.txt'))
#
# # file objects
- # obj.write(File.open('path/to/file.txt', 'r'))
+ # obj.write(File.open('path/to/file.txt', 'rb'))
#
# # IO objects (must respond to #read and #eof?)
# obj.write(io)
#
# ### Multipart Uploads vs Single Uploads
@@ -836,10 +836,13 @@
#
# @option options [Boolean] :client_side_encrypted (false) Set to true
# when the object being copied was client-side encrypted. This
# is important so the encryption metadata will be copied.
#
+ # @option options [Boolean] :use_multipart_copy (false) Set this to
+ # `true` if you need to copy an object that is larger than 5GB.
+ #
# @option options :cache_control [String] Can be used to specify
# caching behavior. See
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
#
# @option options [String] :expires The date and time at which the
@@ -887,11 +890,15 @@
'REDUCED_REDUNDANCY' : 'STANDARD'
options[:bucket_name] = bucket.name
options[:key] = key
- client.copy_object(options)
+ if use_multipart_copy?(options)
+ multipart_copy(options)
+ else
+ resp = client.copy_object(options)
+ end
nil
end
@@ -988,11 +995,11 @@
# When downloading large objects it is recommended to pass a block
# to #read. Data will be yielded to the block as it is read off
# the HTTP response.
#
# # read an object from S3 to a file
- # File.open('output.txt', 'w') do |file|
+ # File.open('output.txt', 'wb') do |file|
# bucket.objects['key'].read do |chunk|
# file.write(chunk)
# end
# end
#
@@ -1171,10 +1178,12 @@
# This option defaults to one hour after the current time.
#
# @option options [Boolean] :secure (true) Whether to generate a
# secure (HTTPS) URL or a plain HTTP url.
#
+ # @option options [String] :content_type
+ # @option options [String] :content_md5
# @option options [String] :endpoint Sets the hostname of the
# endpoint.
#
# @option options [Integer] :port Sets the port of the
# endpoint (overrides config.s3_port).
@@ -1206,27 +1215,27 @@
# @option options [String] :response_content_encoding Sets the
# Content-Encoding header of the response when performing an
# HTTP GET on the returned URL.
# @return [URI::HTTP, URI::HTTPS]
def url_for(method, options = {})
-
+ options = options.dup
options[:secure] = config.use_ssl? unless options.key?(:secure)
+ options[:expires] = expiration_timestamp(options[:expires])
req = request_for_signing(options)
-
- method = http_method(method)
- expires = expiration_timestamp(options[:expires])
- req.add_param("AWSAccessKeyId",
- config.credential_provider.access_key_id)
+ req.http_method = http_method(method)
+ req.add_param("AWSAccessKeyId", config.credential_provider.access_key_id)
req.add_param("versionId", options[:version_id]) if options[:version_id]
- req.add_param("Signature", signature(method, expires, req))
- req.add_param("Expires", expires)
- req.add_param("x-amz-security-token",
- config.credential_provider.session_token) if
- config.credential_provider.session_token
+ req.add_param("Signature", signature(req, options))
+ req.add_param("Expires", options[:expires])
+ if config.credential_provider.session_token
+ req.add_param(
+ "x-amz-security-token",
+ config.credential_provider.session_token
+ )
+ end
- secure = options.fetch(:secure, config.use_ssl?)
build_uri(req, options)
end
# Generates a public (not authenticated) URL for the object.
#
@@ -1270,10 +1279,38 @@
value
end
private
+ # Used to determine if the data needs to be copied in parts
+ def use_multipart_copy? options
+ options[:use_multipart_copy]
+ end
+
+ def multipart_copy options
+
+ unless options[:content_length]
+ msg = "unknown content length, must set :content_length " +
+ "to use multi-part copy"
+ raise ArgumentError, msg
+ end
+
+ part_size = compute_part_size(options)
+ clean_up_options(options)
+ source_length = options.delete(:content_length)
+
+ multipart_upload(options) do |upload|
+ pos = 0
+ # We copy in part_size chunks until we read the
+ until pos >= source_length
+ last_byte = (pos + part_size >= source_length) ? source_length - 1 : pos + part_size - 1
+ upload.copy_part(options[:copy_source], options.merge({:copy_source_range => "bytes=#{pos}-#{last_byte}"}))
+ pos += part_size
+ end
+ end
+ end
+
# @return [Boolean]
def should_decrypt? options
options[:encryption_key] or config.s3_encryption_key
end
@@ -1345,26 +1382,24 @@
:port => request.port,
:path => request.path,
:query => request.querystring)
end
- def signature(method, expires, request)
-
+ def signature request, options
parts = []
- parts << method
- parts << ""
- parts << ""
- parts << expires
+ parts << request.http_method
+ parts << options[:content_md5].to_s
+ parts << options[:content_type].to_s
+ parts << options[:expires]
if token = config.credential_provider.session_token
parts << "x-amz-security-token:#{token}"
end
parts << request.canonicalized_resource
string_to_sign = parts.join("\n")
secret = config.credential_provider.secret_access_key
Core::Signer.sign(secret, string_to_sign, 'sha1')
-
end
def expiration_timestamp(input)
input = input.to_int if input.respond_to?(:to_int)
case input