Browse files

Ensure that the strings returned by SafeBuffer#gsub and friends aren'…

…t considered html_safe?

Also make sure that the versions of those methods which modify a string in place such as gsub! can't be called on safe buffers at all.
  • Loading branch information...
1 parent ce23c6e commit 53a2c0baf2b128dd4808eca313256f6f4bb8c4cd @NZKoz NZKoz committed with tenderlove May 16, 2011
@@ -73,6 +73,7 @@ def html_safe?
module ActiveSupport #:nodoc:
class SafeBuffer < String
+ UNSAFE_STRING_METHODS = ["capitalize", "chomp", "chop", "delete", "downcase", "gsub", "lstrip", "next", "reverse", "rstrip", "slice", "squeeze", "strip", "sub", "succ", "swapcase", "tr", "tr_s", "upcase"].freeze
alias safe_concat concat
def concat(value)
@@ -103,6 +104,18 @@ def to_s
def to_yaml(*args)
+ for unsafe_method in UNSAFE_STRING_METHODS
+ class_eval <<-EOT, __FILE__, __LINE__
+ def #{unsafe_method}(*args)
+ super.to_str
+ end
+ def #{unsafe_method}!(*args)
+ raise TypeError, "Cannot modify SafeBuffer in place"
+ end
+ end
@@ -38,4 +38,16 @@ def setup
new_buffer = @buffer.to_s
assert_equal ActiveSupport::SafeBuffer, new_buffer.class
+ test "Should not return safe buffer from gsub" do
+ altered_buffer = @buffer.gsub('', 'asdf')
+ assert_equal 'asdf', altered_buffer
+ assert !altered_buffer.html_safe?
+ end
+ test "Should not allow gsub! on safe buffers" do
+ assert_raise TypeError do
+ @buffer.gsub!('', 'asdf')
+ end
+ end

7 comments on commit 53a2c0b

steveh commented on 53a2c0b Jun 8, 2011

This breaks String#squish as defined in activesupport/lib/active_support/core_ext/string/filters.rb for ActiveRecord attributes - is that intentional?

nex3 commented on 53a2c0b Jun 8, 2011

This also breaks #gsub with a block, using the $1 etc. to access captures:"fe fo fa").gsub(/f(.)/) do
  "z" + $1

The above should yield "ze zo za", but with this change instead yields "z z z".

morgoth commented on 53a2c0b Jun 8, 2011

This change breaks escape_javascript helper somehow. I will try to debug more and give some feedback.
I'm using this in ajax request with rendering template as haml, so there is lot of layers.

morgoth commented on 53a2c0b Jun 8, 2011

There is a problem with using escape_javascript and rendering partials.
You can see the problem at
Output from escape_javascript(render("partial")) is completely different after this commit (wrong escaping).

nono commented on 53a2c0b Jun 8, 2011

@nex3 : afaik, it's not possible to support this on ruby (ruby 1.8 / 1.9). You have to call #to_str before doing #gsub.

tardate commented on 53a2c0b Jun 8, 2011

We're facing the same issue @morgoth and I've confirmed that the escape_javascript is due to the same breakage of gsub with a $1 matcher reported by @nex3 .. within the gsub block, $1 is nil and does not contain the match.
It's possible to fix escape_javascript by just changing the usage of $1 to instead use explicit block variable i.e. gsub(..){ .. $1 } to gsub(..){ |m| .. m } , but the root cause seems to be that after super.to_str, you no longer have the context for an implicit usage of $1.

I've tested on 3.0-stable and the problem still exists. There doesn't seem to be an issue ticket for this yet .. has anyone logged one?

morgoth commented on 53a2c0b Jun 8, 2011

I opened issue for this: #1553

Please sign in to comment.