Permalink
Browse files

The asset_host block takes the controller request as an optional seco…

…nd argument. Example: use a single asset host for SSL requests. Closes #10549.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8578 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent ca4c7ab commit a1b0349362fd6c17af5aeff481996f6fac235828 @jeremy jeremy committed Jan 6, 2008
View
@@ -1,5 +1,7 @@
*SVN*
+* The asset_host block takes the controller request as an optional second argument. Example: use a single asset host for SSL requests. #10549 [Cheah Chu Yeow, Peter B, Tom Taylor]
+
* Support render :text => nil. #6684 [tjennings, PotatoSalad, Cheah Chu Yeow]
* assert_response failures include the exception message. #10688 [Seth Rasmussen]
@@ -3,7 +3,7 @@
module ActionController #:nodoc:
class Base
- # Process a request extracted from an CGI object and return a response. Pass false as <tt>session_options</tt> to disable
+ # Process a request extracted from a CGI object and return a response. Pass false as <tt>session_options</tt> to disable
# sessions (large performance increase if sessions are not needed). The <tt>session_options</tt> are the same as for CGI::Session:
#
# * <tt>:database_manager</tt> - standard options are CGI::Session::FileStore, CGI::Session::MemoryStore, and CGI::Session::PStore
@@ -17,7 +17,7 @@ class Base
# an ArgumentError is raised.
# * <tt>:session_expires</tt> - the time the current session expires, as a +Time+ object. If not set, the session will continue
# indefinitely.
- # * <tt>:session_domain</tt> - the hostname domain for which this session is valid. If not set, defaults to the hostname of the
+ # * <tt>:session_domain</tt> - the hostname domain for which this session is valid. If not set, defaults to the hostname of the
# server.
# * <tt>:session_secure</tt> - if +true+, this session will only work over HTTPS.
# * <tt>:session_path</tt> - the path for which this session applies. Defaults to the directory of the CGI script.
@@ -34,7 +34,8 @@ def process_cgi(cgi, session_options = {}) #:nodoc:
class CgiRequest < AbstractRequest #:nodoc:
attr_accessor :cgi, :session_options
- class SessionFixationAttempt < StandardError; end #:nodoc:
+ class SessionFixationAttempt < StandardError #:nodoc:
+ end
DEFAULT_SESSION_OPTIONS = {
:database_manager => CGI::Session::CookieStore, # store data in cookie
@@ -50,8 +50,10 @@ module Helpers #:nodoc:
# stylesheet_include_tag("application")
# => <link href="http://assets1.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
#
- # The proc takes a single <tt>source</tt> parameter which is the path of the source asset. This can be used to
- # generate a particular asset host depending on the asset path.
+ # The proc takes a <tt>source</tt> parameter (which is the path of the source asset) and an optional
+ # <tt>request</tt> parameter (which is an entire instance of an <tt>ActionController::AbstractRequest</tt>
+ # subclass). This can be used to generate a particular asset host depending on the asset path and the particular
+ # request.
#
# ActionController::Base.asset_host = Proc.new { |source|
# if source.starts_with?('/images')
@@ -65,6 +67,19 @@ module Helpers #:nodoc:
# stylesheet_include_tag("application")
# => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
#
+ # The optional <tt>request</tt> parameter to the proc is useful in particular for serving assets from an
+ # SSL-protected page. The example proc below disables asset hosting for HTTPS connections, while still sending
+ # assets for plain HTTP requests from asset hosts. This is useful for avoiding mixed media warnings when serving
+ # non-HTTP assets from HTTPS web pages when you don't have an SSL certificate for each of the asset hosts.
+ #
+ # ActionController::Base.asset_host = Proc.new { |source, request|
+ # if request.ssl?
+ # "#{request.protocol}#{request.host_with_port}"
+ # else
+ # "#{request.protocol}assets.example.com"
+ # end
+ # }
+ #
# === Using asset timestamps
#
# By default, Rails will append all asset paths with that asset's timestamp. This allows you to set a cache-expiration date for the
@@ -461,7 +476,12 @@ def compute_public_path(source, dir, ext = nil, include_host = true)
def compute_asset_host(source)
if host = ActionController::Base.asset_host
if host.is_a?(Proc)
- host.call(source)
+ case host.arity
+ when 2:
+ host.call(source, @controller.request)
+ else
+ host.call(source)
+ end
else
host % (source.hash % 4)
end
@@ -4,6 +4,15 @@ class ERB
module Util
HTML_ESCAPE = { '&' => '&amp;', '"' => '&quot;', '>' => '&gt;', '<' => '&lt;' }
+ # A utility method for escaping HTML tag characters.
+ # This method is also aliased as <tt>h</tt>.
+ #
+ # In your ERb templates, use this method to escape any unsafe content. For example:
+ # <%=h @person.name %>
+ #
+ # ==== Example:
+ # puts html_escape("is a > 0 & a < 10?")
+ # # => is a &gt; 0 &amp; a &lt; 10?
def html_escape(s)
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
end
@@ -34,6 +34,8 @@ def url_for(*args) "http://www.example.com" end
@request = Class.new do
def relative_url_root() "" end
def protocol() 'http://' end
+ def ssl?() false end
+ def host_with_port() 'localhost' end
end.new
@controller.request = @request
@@ -248,7 +250,7 @@ def test_caching_javascript_include_tag_when_caching_on
end
def test_caching_javascript_include_tag_when_caching_on_with_proc_asset_host
- ENV["RAILS_ASSET_ID"] = ""
+ ENV['RAILS_ASSET_ID'] = ''
ActionController::Base.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" }
ActionController::Base.perform_caching = true
@@ -264,6 +266,43 @@ def test_caching_javascript_include_tag_when_caching_on_with_proc_asset_host
FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'scripts.js'))
end
+ def test_caching_javascript_include_tag_when_caching_on_with_2_argument_proc_asset_host
+ ENV['RAILS_ASSET_ID'] = ''
+ ActionController::Base.asset_host = Proc.new { |source, request|
+ if request.ssl?
+ "#{request.protocol}#{request.host_with_port}"
+ else
+ "#{request.protocol}assets#{source.length}.example.com"
+ end
+ }
+ ActionController::Base.perform_caching = true
+
+ assert_equal '/javascripts/vanilla.js'.length, 23
+ assert_dom_equal(
+ %(<script src="http://assets23.example.com/javascripts/vanilla.js" type="text/javascript"></script>),
+ javascript_include_tag(:all, :cache => 'vanilla')
+ )
+
+ assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'vanilla.js'))
+
+ class << @controller.request
+ def protocol() 'https://' end
+ def ssl?() true end
+ end
+
+ assert_equal '/javascripts/secure.js'.length, 22
+ assert_dom_equal(
+ %(<script src="https://localhost/javascripts/secure.js" type="text/javascript"></script>),
+ javascript_include_tag(:all, :cache => 'secure')
+ )
+
+ assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'secure.js'))
+
+ ensure
+ FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'vanilla.js'))
+ FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'secure.js'))
+ end
+
def test_caching_javascript_include_tag_when_caching_on_and_using_subdirectory
ENV["RAILS_ASSET_ID"] = ""
ActionController::Base.asset_host = 'http://a%d.example.com'

0 comments on commit a1b0349

Please sign in to comment.