├── MIT-LICENSE ├── README ├── Rakefile ├── lib └── asset_hosting_with_minimum_ssl.rb └── test └── asset_hosting_with_minimum_ssl_test.rb /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008 David Heinemeier Hansson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | AssetHostingWithMinimumSsl 2 | ========================== 3 | 4 | It's slow to serve assets that doesn't need to be secure over SSL. This plugin will let you send assets over non-SSL as often as possible. 5 | 6 | Note: This plugin requires Rails with a revision of 229f959d15e451890db60dbb73f8565079977814 or newer (Nov 27, 2008). 7 | 8 | 9 | Example 10 | ======= 11 | 12 | In your config/production.rb 13 | 14 | config.action_controller.asset_host = AssetHostingWithMinimumSsl.new( 15 | "http://assets%d.example.com", # will serve non-SSL assetts on http://assets[1-4].example.com 16 | "https://assets1.example.com" # will serve SSL assets on https://assets1.example.com 17 | ) 18 | 19 | 20 | Copyright (c) 2008 David Heinemeier Hansson, released under the MIT license 21 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rake/testtask' 3 | require 'rake/rdoctask' 4 | 5 | desc 'Default: run unit tests.' 6 | task :default => :test 7 | 8 | desc 'Test the asset_hosting_with_minimum_ssl plugin.' 9 | Rake::TestTask.new(:test) do |t| 10 | t.libs << 'lib' 11 | t.pattern = 'test/**/*_test.rb' 12 | t.verbose = true 13 | end 14 | 15 | desc 'Generate documentation for the asset_hosting_with_minimum_ssl plugin.' 16 | Rake::RDocTask.new(:rdoc) do |rdoc| 17 | rdoc.rdoc_dir = 'rdoc' 18 | rdoc.title = 'AssetHostingWithMinimumSsl' 19 | rdoc.options << '--line-numbers' << '--inline-source' 20 | rdoc.rdoc_files.include('README') 21 | rdoc.rdoc_files.include('lib/**/*.rb') 22 | end 23 | -------------------------------------------------------------------------------- /lib/asset_hosting_with_minimum_ssl.rb: -------------------------------------------------------------------------------- 1 | class AssetHostingWithMinimumSsl 2 | attr_accessor :asset_host, :ssl_asset_host 3 | 4 | def initialize(asset_host, ssl_asset_host) 5 | self.asset_host, self.ssl_asset_host = asset_host, ssl_asset_host 6 | end 7 | 8 | def call(source, request) 9 | if request.ssl? 10 | case 11 | when javascript_file?(source) 12 | ssl_asset_host(source) 13 | when safari?(request) 14 | asset_host(source) 15 | when firefox?(request) && image_file?(source) 16 | asset_host(source) 17 | else 18 | ssl_asset_host(source) 19 | end 20 | else 21 | asset_host(source) 22 | end 23 | end 24 | 25 | 26 | private 27 | def asset_host(source) 28 | @asset_host % (source.hash % 4) 29 | end 30 | 31 | def ssl_asset_host(source) 32 | @ssl_asset_host % (source.hash % 4) 33 | end 34 | 35 | 36 | def javascript_file?(source) 37 | source =~ /\.js$/ 38 | end 39 | 40 | def image_file?(source) 41 | source =~ /^\/images/ 42 | end 43 | 44 | 45 | def safari?(request) 46 | request.headers["USER_AGENT"] =~ /Safari/ 47 | end 48 | 49 | def firefox?(request) 50 | request.headers["USER_AGENT"] =~ /Firefox/ 51 | end 52 | end -------------------------------------------------------------------------------- /test/asset_hosting_with_minimum_ssl_test.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'rubygems' 3 | require 'mocha' 4 | 5 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 6 | require 'asset_hosting_with_minimum_ssl' 7 | 8 | 9 | class AssetHostingWithMinimumSslTest < Test::Unit::TestCase 10 | def setup 11 | @asset_host = AssetHostingWithMinimumSsl.new("http://assets%d.example.com/", "https://assets1.example.com/") 12 | end 13 | 14 | def test_ssl_requests_for_javascript_files_should_stay_ssl_regardless_of_the_browser 15 | %w( Safari Firefox IE ).each do |browser| 16 | assert_equal \ 17 | ssl_host, 18 | @asset_host.call("/javascripts/prototype.js", ssl_request_from(browser)) 19 | end 20 | end 21 | 22 | def test_ssl_requests_for_anything_but_js_files_should_go_non_ssl_on_safari 23 | assert_match \ 24 | non_ssl_host, 25 | @asset_host.call("/images/blank.gif", ssl_request_from("Safari")) 26 | 27 | assert_match \ 28 | non_ssl_host, 29 | @asset_host.call("/stylesheets/application.css", ssl_request_from("Safari")) 30 | end 31 | 32 | def test_ssl_requests_for_image_files_should_go_non_ssl_on_firefox 33 | assert_match \ 34 | non_ssl_host, 35 | @asset_host.call("/images/blank.gif", ssl_request_from("Firefox")) 36 | end 37 | 38 | def test_ssl_requests_for_non_image_files_should_stay_ssl_on_firefox 39 | assert_match \ 40 | ssl_host, 41 | @asset_host.call("/stylesheets/application.css", ssl_request_from("Firefox")) 42 | end 43 | 44 | def test_ssl_requests_for_anything_should_stay_ssl_on_ie 45 | assert_match \ 46 | ssl_host, 47 | @asset_host.call("/stylesheets/application.css", ssl_request_from("IE")) 48 | end 49 | 50 | 51 | private 52 | def non_ssl_host 53 | %r|http://assets\d.example.com/| 54 | end 55 | 56 | def ssl_host 57 | "https://assets1.example.com/" 58 | end 59 | 60 | 61 | def ssl_request_from(user_agent) 62 | stub(:headers => { "USER_AGENT" => user_agent }, :ssl? => true) 63 | end 64 | end --------------------------------------------------------------------------------