diff --git a/NEWS b/NEWS index 04a846dbb..781dd200f 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ master: +* Improvement: Added `:use_accelerate_endpoint` option when using S3 to enable [Amazon S3 Transfer Acceleration](http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html) * Improvement: make the fingerprint digest configurable per attachment. The default remains MD5 but this will change in a future version because it is not considered secure anymore against intentional file corruption. For more diff --git a/lib/paperclip/storage/s3.rb b/lib/paperclip/storage/s3.rb index d0b1755ca..e9f5597eb 100644 --- a/lib/paperclip/storage/s3.rb +++ b/lib/paperclip/storage/s3.rb @@ -102,6 +102,8 @@ module Storage # 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. + # * +use_accelerate_endpoint+: Use accelerate endpoint + # http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html # # You can set storage class on a per style bases by doing the following: # :s3_storage_class => { @@ -152,6 +154,13 @@ def self.extended base @options[:url] = @options[:url].inspect if @options[:url].is_a?(Symbol) @http_proxy = @options[:http_proxy] || nil + + if @options.has_key?(:use_accelerate_endpoint) && + Gem::Version.new(Aws::VERSION) < Gem::Version.new("2.3.0") + raise LoadError, ":use_accelerate_endpoint is only available from aws-sdk version 2.3.0. Please upgrade aws-sdk to a newer version." + end + + @use_accelerate_endpoint = @options[:use_accelerate_endpoint] end Paperclip.interpolates(:s3_alias_url) do |attachment, style| @@ -232,6 +241,8 @@ def s3_interface config[:proxy_uri] = URI::HTTP.build(proxy_opts) end + config[:use_accelerate_endpoint] = true if use_accelerate_endpoint? + [:access_key_id, :secret_access_key, :credential_provider, :credentials].each do |opt| config[opt] = s3_credentials[opt] if s3_credentials[opt] end @@ -257,6 +268,10 @@ def s3_object style_name = default_style s3_bucket.object style_name_as_path(style_name) end + def use_accelerate_endpoint? + !!@use_accelerate_endpoint + end + def using_http_proxy? !!@http_proxy end diff --git a/paperclip.gemspec b/paperclip.gemspec index 4587fbaa1..a71955bd3 100644 --- a/paperclip.gemspec +++ b/paperclip.gemspec @@ -35,7 +35,7 @@ Gem::Specification.new do |s| s.add_development_dependency('rspec', '~> 3.0') s.add_development_dependency('appraisal') s.add_development_dependency('mocha') - s.add_development_dependency('aws-sdk', '>= 2.0.34', '< 3.0') + s.add_development_dependency('aws-sdk', '>= 2.3.0', '< 3.0') s.add_development_dependency('bourne') s.add_development_dependency('cucumber', '~> 1.3.18') s.add_development_dependency('aruba', '~> 0.9.0') diff --git a/spec/paperclip/storage/s3_spec.rb b/spec/paperclip/storage/s3_spec.rb index 036c98aca..a3adb37b5 100644 --- a/spec/paperclip/storage/s3_spec.rb +++ b/spec/paperclip/storage/s3_spec.rb @@ -282,6 +282,59 @@ class << @dummy end end + context "use_accelerate_endpoint", :if => use_accelerate_endpoint_option_is_available_in_aws_sdk? do + context "defaults to false" do + before do + rebuild_model( + storage: :s3, + s3_credentials: {}, + bucket: "bucket", + path: ":attachment/:basename:dotextension", + s3_host_name: "s3-ap-northeast-1.amazonaws.com", + s3_region: "ap-northeast-1" + ) + @dummy = Dummy.new + @dummy.avatar = stringy_file + @dummy.stubs(:new_record?).returns(false) + end + + it "returns a url based on an :s3_host_name path" do + assert_match %r{^//s3-ap-northeast-1.amazonaws.com/bucket/avatars/data[^\.]}, + @dummy.avatar.url + end + + it "uses the S3 client with the use_accelerate_endpoint config is false" do + expect(@dummy.avatar.s3_bucket.client.config.use_accelerate_endpoint).to be(false) + end + end + + context "set to true", :if => use_accelerate_endpoint_option_is_available_in_aws_sdk? do + before do + rebuild_model( + storage: :s3, + s3_credentials: {}, + bucket: "bucket", + path: ":attachment/:basename:dotextension", + s3_host_name: "s3-accelerate.amazonaws.com", + s3_region: "ap-northeast-1", + use_accelerate_endpoint: true + ) + @dummy = Dummy.new + @dummy.avatar = stringy_file + @dummy.stubs(:new_record?).returns(false) + end + + it "returns a url based on an :s3_host_name path" do + assert_match %r{^//s3-accelerate.amazonaws.com/bucket/avatars/data[^\.]}, + @dummy.avatar.url + end + + it "uses the S3 client with the use_accelerate_endpoint config is true" do + expect(@dummy.avatar.s3_bucket.client.config.use_accelerate_endpoint).to be(true) + end + end + end + context "An attachment that uses S3 for storage and has styles that return different file types" do before do rebuild_model (aws2_add_region).merge storage: :s3, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 92e7f431f..eed5d6313 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -38,6 +38,7 @@ config.include TestData config.include Reporting config.extend VersionHelper + config.extend ConditionalFilterHelper config.mock_framework = :mocha config.before(:all) do rebuild_model diff --git a/spec/support/conditional_filter_helper.rb b/spec/support/conditional_filter_helper.rb new file mode 100644 index 000000000..77e160ae7 --- /dev/null +++ b/spec/support/conditional_filter_helper.rb @@ -0,0 +1,5 @@ +module ConditionalFilterHelper + def use_accelerate_endpoint_option_is_available_in_aws_sdk? + (Gem::Version.new(Aws::VERSION) >= Gem::Version.new("2.3.0")) + end +end