lib/paperclip/storage/s3.rb in paperclip-3.3.1 vs lib/paperclip/storage/s3.rb in paperclip-3.4.0
- old
+ new
@@ -33,20 +33,21 @@
#
# You can set permission on a per style bases by doing the following:
# :s3_permissions => {
# :original => :private
# }
- # Or globaly:
+ # Or globally:
# :s3_permissions => :private
#
# * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either
# 'http', 'https', or an empty string to generate scheme-less URLs. Defaults to 'http'
# when your :s3_permissions are :public_read (the default), and 'https' when your
# :s3_permissions are anything else.
# * +s3_headers+: A hash of headers or a Proc. You may specify a hash such as
# {'Expires' => 1.year.from_now.httpdate}. If you use a Proc, headers are determined at
# runtime. Paperclip will call that Proc with attachment as the only argument.
+ # Can be defined both globally and within a style-specific hash.
# * +bucket+: This is the name of the S3 bucket that will store your files. Remember
# that the bucket must be unique across all of Amazon S3. If the bucket does not exist
# Paperclip will attempt to create it. The bucket name will not be interpolated.
# You can define the bucket as a Proc if you want to determine it's name at runtime.
# Paperclip will call that Proc with attachment as the only argument.
@@ -81,11 +82,11 @@
# separate parts of your file name.
# * +s3_host_name+: If you are using your bucket in Tokyo region etc, write host_name.
# * +s3_metadata+: These key/value pairs will be stored with the
# object. This option works by prefixing each key with
# "x-amz-meta-" before sending it as a header on the object
- # upload request.
+ # upload request. Can be defined both globally and within a style-specific hash.
# * +s3_storage_class+: If this option is set to
# <tt>:reduced_redundancy</tt>, the object will be stored using Reduced
# Redundancy Storage. RRS enables customers to reduce their
# costs by storing non-critical, reproducible data at lower
# levels of redundancy than Amazon S3's standard storage.
@@ -121,30 +122,21 @@
permission = (@s3_permissions[style.to_s.to_sym] || @s3_permissions[:default])
permission = permission.call(attachment, style) if permission.respond_to?(:call)
(permission == :public_read) ? 'http' : 'https'
end
@s3_metadata = @options[:s3_metadata] || {}
- @s3_headers = @options[:s3_headers] || {}
- @s3_headers = @s3_headers.call(instance) if @s3_headers.respond_to?(:call)
- @s3_headers = (@s3_headers).inject({}) do |headers,(name,value)|
- case name.to_s
- when /^x-amz-meta-(.*)/i
- @s3_metadata[$1.downcase] = value
- else
- name = name.to_s.downcase.sub(/^x-amz-/,'').tr("-","_").to_sym
- headers[name] = value
- end
- headers
- end
+ @s3_headers = {}
+ merge_s3_headers(@options[:s3_headers], @s3_headers, @s3_metadata)
@s3_headers[:storage_class] = @options[:s3_storage_class] if @options[:s3_storage_class]
+ @s3_server_side_encryption = :aes256
if @options[:s3_server_side_encryption].blank?
- @options[:s3_server_side_encryption] = false
+ @s3_server_side_encryption = false
end
- if @options[:s3_server_side_encryption]
- @s3_headers['x-amz-server-side-encryption'] = @options[:s3_server_side_encryption].to_s.upcase
+ if @s3_server_side_encryption
+ @s3_server_side_encryption = @options[:s3_server_side_encryption].to_s.upcase
end
unless @options[:url].to_s.match(/^:s3.*url$/) || @options[:url] == ":asset_host"
@options[:path] = @options[:path].gsub(/:url/, @options[:url]).gsub(/^:rails_root\/public\/system/, '')
@options[:url] = ":s3_path_url"
@@ -219,14 +211,19 @@
[:access_key_id, :secret_access_key].each do |opt|
config[opt] = s3_credentials[opt] if s3_credentials[opt]
end
- AWS::S3.new(config.merge(@s3_options))
+ obtain_s3_instance_for(config.merge(@s3_options))
end
end
+ def obtain_s3_instance_for(options)
+ instances = (Thread.current[:paperclip_s3_instances] ||= {})
+ instances[options] ||= AWS::S3.new(options)
+ end
+
def s3_bucket
@s3_bucket ||= s3_interface.buckets[bucket_name]
end
def s3_object style_name = default_style
@@ -304,12 +301,23 @@
acl = acl.call(self, style) if acl.respond_to?(:call)
write_options = {
:content_type => file.content_type,
:acl => acl
}
+ if @s3_server_side_encryption
+ write_options[:server_side_encryption] = @s3_server_side_encryption
+ end
+
+ style_specific_options = @options[:styles][style]
+ if style_specific_options.is_a?(Hash)
+ merge_s3_headers( style_specific_options[:s3_headers], @s3_headers, @s3_metadata) if style_specific_options.has_key?(:s3_headers)
+ @s3_metadata.merge!(style_specific_options[:s3_metadata]) if style_specific_options.has_key?(:s3_metadata)
+ end
+
write_options[:metadata] = @s3_metadata unless @s3_metadata.empty?
write_options.merge!(@s3_headers)
+
s3_object(style).write(file, write_options)
rescue AWS::S3::Errors::NoSuchBucket => e
create_bucket
retry
ensure
@@ -360,9 +368,22 @@
end
end
def use_secure_protocol?(style_name)
s3_protocol(style_name) == "https"
+ end
+
+ def merge_s3_headers(http_headers, s3_headers, s3_metadata)
+ return if http_headers.nil?
+ http_headers = http_headers.call(instance) if http_headers.respond_to?(:call)
+ http_headers.inject({}) do |headers,(name,value)|
+ case name.to_s
+ when /^x-amz-meta-(.*)/i
+ s3_metadata[$1.downcase] = value
+ else
+ s3_headers[name.to_s.downcase.sub(/^x-amz-/,'').tr("-","_").to_sym] = value
+ end
+ end
end
end
end
end