Permalink
Browse files

Backport html_safe. Use latest rails_xss plugin for forward-compatibi…

…lity with Rails 3.
  • Loading branch information...
1 parent 0c0da1a commit 9ca6df83f606a0fb8be3815328111d0cdaa7c65b Santiago Pastorino and José Ignacio Costa committed with jeremy Feb 4, 2010
Showing with 251 additions and 217 deletions.
  1. +1 −1 actionmailer/test/fixtures/helpers/example_helper.rb
  2. +2 −0 actionpack/CHANGELOG
  3. +1 −1 actionpack/lib/action_controller/caching/fragments.rb
  4. +1 −1 actionpack/lib/action_controller/rack_lint_patch.rb
  5. +1 −2 actionpack/lib/action_view.rb
  6. +0 −44 actionpack/lib/action_view/erb/util.rb
  7. +6 −6 actionpack/lib/action_view/helpers/active_record_helper.rb
  8. +2 −2 actionpack/lib/action_view/helpers/asset_tag_helper.rb
  9. +2 −2 actionpack/lib/action_view/helpers/capture_helper.rb
  10. +7 −7 actionpack/lib/action_view/helpers/date_helper.rb
  11. +2 −2 actionpack/lib/action_view/helpers/debug_helper.rb
  12. +2 −2 actionpack/lib/action_view/helpers/form_helper.rb
  13. +1 −1 actionpack/lib/action_view/helpers/form_options_helper.rb
  14. +3 −3 actionpack/lib/action_view/helpers/form_tag_helper.rb
  15. +1 −1 actionpack/lib/action_view/helpers/number_helper.rb
  16. +2 −2 actionpack/lib/action_view/helpers/prototype_helper.rb
  17. +2 −2 actionpack/lib/action_view/helpers/raw_output_helper.rb
  18. +2 −10 actionpack/lib/action_view/helpers/sanitize_helper.rb
  19. +5 −5 actionpack/lib/action_view/helpers/tag_helper.rb
  20. +1 −1 actionpack/lib/action_view/helpers/text_helper.rb
  21. +2 −2 actionpack/lib/action_view/helpers/translation_helper.rb
  22. +4 −4 actionpack/lib/action_view/helpers/url_helper.rb
  23. +1 −1 actionpack/lib/action_view/partials.rb
  24. +0 −28 actionpack/lib/action_view/safe_buffer.rb
  25. +2 −2 actionpack/lib/action_view/test_case.rb
  26. +2 −2 actionpack/test/controller/caching_test.rb
  27. +19 −0 actionpack/test/controller/output_escaping_test.rb
  28. +12 −0 actionpack/test/template/erb_util_test.rb
  29. +1 −1 actionpack/test/template/form_helper_test.rb
  30. +3 −3 actionpack/test/template/form_tag_helper_test.rb
  31. +1 −1 actionpack/test/template/text_helper_test.rb
  32. +2 −0 activesupport/CHANGELOG
  33. +1 −0 activesupport/lib/active_support.rb
  34. +0 −1 activesupport/lib/active_support/core_ext/string.rb
  35. +117 −44 activesupport/lib/active_support/core_ext/string/output_safety.rb
  36. +36 −29 activesupport/test/core_ext/string_ext_test.rb
  37. +4 −4 {actionpack/test/view → activesupport/test}/safe_buffer_test.rb
@@ -1,5 +1,5 @@
module ExampleHelper
def example_format(text)
- "<em><strong><small>#{h(text)}</small></strong></em>".html_safe!
+ "<em><strong><small>#{h(text)}</small></strong></em>".html_safe
end
end
View
@@ -6,6 +6,8 @@
* Fixed that fragment caching should return a cache hit as html_safe (or it would all just get escaped) [DHH]
+* Introduce String#html_safe for rails_xss plugin and forward-compatibility with Rails 3. [Michael Koziarski, Santiago Pastorino, José Ignacio Costa]
+
* Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH]. Examples:
flash[:notice] = 'Post was created'
@@ -37,7 +37,7 @@ def fragment_cache_key(key)
def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc:
if perform_caching
if cache = read_fragment(name, options)
- buffer.concat(cache.html_safe!)
+ buffer.safe_concat(cache.html_safe)
else
pos = buffer.length
block.call
@@ -1,4 +1,4 @@
-# Rack 1.0 does not allow string subclass body. This does not play well with our ActionView::SafeBuffer.
+# Rack 1.0 does not allow string subclass body. This does not play well with our ActiveSupport::SafeBuffer.
# The next release of Rack will be allowing string subclass body - http://github.com/rack/rack/commit/de668df02802a0335376a81ba709270e43ba9d55
# TODO : Remove this monkey patch after the next release of Rack
@@ -49,10 +49,9 @@ def self.load_all!
autoload :TemplateHandler, 'action_view/template_handler'
autoload :TemplateHandlers, 'action_view/template_handlers'
autoload :Helpers, 'action_view/helpers'
- autoload :SafeBuffer, 'action_view/safe_buffer'
end
-require 'action_view/erb/util'
+require 'active_support/core_ext/string/output_safety'
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
@@ -1,44 +0,0 @@
-require 'erb'
-
-class ERB
- module Util
- HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
- JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
-
- # 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
-
- undef :h
- alias h html_escape
-
- module_function :html_escape
- module_function :h
-
- # A utility method for escaping HTML entities in JSON strings.
- # This method is also aliased as <tt>j</tt>.
- #
- # In your ERb templates, use this method to escape any HTML entities:
- # <%=j @person.to_json %>
- #
- # ==== Example:
- # puts json_escape("is a > 0 & a < 10?")
- # # => is a \u003E 0 \u0026 a \u003C 10?
- def json_escape(s)
- s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
- end
-
- alias j json_escape
- module_function :j
- module_function :json_escape
- end
-end
@@ -3,7 +3,7 @@
module ActionView
class Base
- @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe! }
+ @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
cattr_accessor :field_error_proc
end
@@ -82,11 +82,11 @@ def form(record_name, options = {})
submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil)
- contents << hidden_field(record_name, :id) unless record.new_record?
- contents << all_input_tags(record, record_name, options)
+ contents.safe_concat hidden_field(record_name, :id) unless record.new_record?
+ contents.safe_concat all_input_tags(record, record_name, options)
yield contents if block_given?
- contents << submit_tag(submit_value)
- contents << '</form>'
+ contents.safe_concat submit_tag(submit_value)
+ contents.safe_concat '</form>'
end
# Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
@@ -290,7 +290,7 @@ def to_time_select_tag(options = {}, html_options = {})
end
def error_wrapping(html_tag, has_error)
- has_error ? Base.field_error_proc.call(html_tag, self).html_safe! : html_tag
+ has_error ? Base.field_error_proc.call(html_tag, self) : html_tag
end
def error_message
@@ -285,7 +285,7 @@ def javascript_include_tag(*sources)
end
javascript_src_tag(joined_javascript_name, options)
else
- expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe!
+ expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe
end
end
@@ -434,7 +434,7 @@ def stylesheet_link_tag(*sources)
end
stylesheet_tag(joined_stylesheet_name, options)
else
- expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe!
+ expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe
end
end
@@ -118,13 +118,13 @@ def capture(*args, &block)
def content_for(name, content = nil, &block)
ivar = "@content_for_#{name}"
content = capture(&block) if block_given?
- instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}".html_safe!)
+ instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}".html_safe)
nil
end
# Use an alternate output buffer for the duration of the block.
# Defaults to a new empty string.
- def with_output_buffer(buf = "") #:nodoc:
+ def with_output_buffer(buf = ActiveSupport::SafeBuffer.new) #:nodoc:
self.output_buffer, old_buffer = buf, output_buffer
yield
output_buffer
@@ -616,7 +616,7 @@ def select_datetime
build_selects_from_types(order)
else
- "#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe!
+ "#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe
end
end
@@ -835,7 +835,7 @@ def build_select(type, select_options_as_html)
select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
select_html << select_options_as_html.to_s
- (content_tag(:select, select_html, select_options) + "\n").html_safe!
+ (content_tag(:select, select_html, select_options) + "\n").html_safe
end
# Builds a prompt option tag with supplied options or from default options
@@ -865,7 +865,7 @@ def build_hidden(type, value)
:id => input_id_from_type(type),
:name => input_name_from_type(type),
:value => value
- }) + "\n").html_safe!
+ }) + "\n").html_safe
end
# Returns the name attribute for the input tag
@@ -896,7 +896,7 @@ def build_selects_from_types(order)
separator = separator(type) unless type == order.first # don't add on last field
select.insert(0, separator.to_s + send("select_#{type}").to_s)
end
- select.html_safe!
+ select.html_safe
end
# Returns the separator for a given datetime component
@@ -916,15 +916,15 @@ def separator(type)
class InstanceTag #:nodoc:
def to_date_select_tag(options = {}, html_options = {})
- datetime_selector(options, html_options).select_date.html_safe!
+ datetime_selector(options, html_options).select_date.html_safe
end
def to_time_select_tag(options = {}, html_options = {})
- datetime_selector(options, html_options).select_time.html_safe!
+ datetime_selector(options, html_options).select_time.html_safe
end
def to_datetime_select_tag(options = {}, html_options = {})
- datetime_selector(options, html_options).select_datetime.html_safe!
+ datetime_selector(options, html_options).select_datetime.html_safe
end
private
@@ -27,10 +27,10 @@ module DebugHelper
def debug(object)
begin
Marshal::dump(object)
- "<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", "&nbsp; ")}</pre>"
+ "<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", "&nbsp; ")}</pre>".html_safe
rescue Exception => e # errors from Marshal or YAML
# Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
- "<code class='debug_dump'>#{h(object.inspect)}</code>"
+ "<code class='debug_dump'>#{h(object.inspect)}</code>".html_safe
end
end
end
@@ -280,7 +280,7 @@ def form_for(record_or_name_or_array, *args, &proc)
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
fields_for(object_name, *(args << options), &proc)
- concat('</form>'.html_safe!)
+ concat('</form>')
end
def apply_form_for_options!(object_or_array, options) #:nodoc:
@@ -834,7 +834,7 @@ def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
add_default_name_and_id(options)
hidden = tag("input", "name" => options["name"], "type" => "hidden", "value" => options['disabled'] && checked ? checked_value : unchecked_value)
checkbox = tag("input", options)
- (hidden + checkbox).html_safe!
+ (hidden + checkbox).html_safe
end
def to_boolean_select_tag(options = {})
@@ -296,7 +296,7 @@ def options_for_select(container, selected = nil)
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
end
- options_for_select.join("\n").html_safe!
+ options_for_select.join("\n").html_safe
end
# Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
@@ -432,7 +432,7 @@ def field_set_tag(legend = nil, options = nil, &block)
concat(tag(:fieldset, options, true))
concat(content_tag(:legend, legend)) unless legend.blank?
concat(content)
- concat("</fieldset>".html_safe!)
+ concat("</fieldset>")
end
private
@@ -459,14 +459,14 @@ def extra_tags_for_form(html_options)
def form_tag_html(html_options)
extra_tags = extra_tags_for_form(html_options)
- (tag(:form, html_options, true) + extra_tags).html_safe!
+ (tag(:form, html_options, true) + extra_tags).html_safe
end
def form_tag_in_block(html_options, &block)
content = capture(&block)
concat(form_tag_html(html_options))
concat(content)
- concat("</form>".html_safe!)
+ concat("</form>")
end
def token_tag
@@ -89,7 +89,7 @@ def number_to_currency(number, options = {})
:precision => precision,
:delimiter => delimiter,
:separator => separator)
- ).gsub(/%u/, unit)
+ ).gsub(/%u/, unit).html_safe
rescue
number
end
@@ -393,7 +393,7 @@ def remote_form_for(record_or_name_or_array, *args, &proc)
concat(form_remote_tag(options))
fields_for(object_name, *(args << options), &proc)
- concat('</form>'.html_safe!)
+ concat('</form>')
end
alias_method :form_remote_for, :remote_form_for
@@ -1026,7 +1026,7 @@ def method_missing(method, *arguments)
# page.hide 'spinner'
# end
def update_page(&block)
- JavaScriptGenerator.new(@template, &block).to_s.html_safe!
+ JavaScriptGenerator.new(@template, &block).to_s.html_safe
end
# Works like update_page but wraps the generated JavaScript in a <script>
@@ -2,8 +2,8 @@ module ActionView #:nodoc:
module Helpers #:nodoc:
module RawOutputHelper
def raw(stringish)
- stringish.to_s.html_safe!
+ stringish.to_s.html_safe
end
end
end
-end
+end
@@ -49,11 +49,7 @@ module SanitizeHelper
# confuse browsers.
#
def sanitize(html, options = {})
- returning self.class.white_list_sanitizer.sanitize(html, options) do |sanitized|
- if sanitized
- sanitized.html_safe!
- end
- end
+ self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe)
end
# Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
@@ -76,11 +72,7 @@ def sanitize_css(style)
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website!
def strip_tags(html)
- returning self.class.full_sanitizer.sanitize(html) do |sanitized|
- if sanitized
- sanitized.html_safe!
- end
- end
+ self.class.full_sanitizer.sanitize(html).try(:html_safe)
end
# Strips all link tags from +text+ leaving just the link text.
@@ -1,4 +1,4 @@
-require 'action_view/erb/util'
+require 'active_support/core_ext/string/output_safety'
require 'set'
module ActionView
@@ -38,7 +38,7 @@ module TagHelper
# tag("img", { :src => "open &amp; shut.png" }, false, false)
# # => <img src="open &amp; shut.png" />
def tag(name, options = nil, open = false, escape = true)
- "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe!
+ "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end
# Returns an HTML block tag of type +name+ surrounding the +content+. Add
@@ -91,7 +91,7 @@ def content_tag(name, content_or_options_with_block = nil, options = nil, escape
# cdata_section(File.read("hello_world.txt"))
# # => <![CDATA[<hello from a text file]]>
def cdata_section(content)
- "<![CDATA[#{content}]]>".html_safe!
+ "<![CDATA[#{content}]]>".html_safe
end
# Returns an escaped version of +html+ without affecting existing escaped entities.
@@ -125,7 +125,7 @@ def block_called_from_erb?(block)
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
- "<#{name}#{tag_options}>#{content}</#{name}>".html_safe!
+ "<#{name}#{tag_options}>#{content}</#{name}>".html_safe
end
def tag_options(options, escape = true)
@@ -142,7 +142,7 @@ def tag_options(options, escape = true)
else
attrs = options.map { |key, value| %(#{key}="#{value}") }
end
- " #{attrs.sort * ' '}".html_safe! unless attrs.empty?
+ " #{attrs.sort * ' '}".html_safe unless attrs.empty?
end
end
end
@@ -29,7 +29,7 @@ def concat(string, unused_binding = nil)
ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller)
end
- output_buffer << string
+ output_buffer.safe_concat(string)
end
# Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
Oops, something went wrong.

1 comment on commit 9ca6df8

Please sign in to comment.