mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
[Haml] Fix a bug with interpolation and HTML escaping.
Closes gh-44
This commit is contained in:
parent
c83b358f56
commit
83f8b20ea5
3 changed files with 61 additions and 34 deletions
|
@ -9,6 +9,19 @@
|
|||
under certain circumstances.
|
||||
This was mostly an issue under Rails when using methods like `capture`.
|
||||
|
||||
* Fixed a bug where template text was escaped when there was interpolation in a line
|
||||
and the `:escape_html` option was enabled. For example:
|
||||
|
||||
Foo < Bar #{"<"} Baz
|
||||
|
||||
with `:escape_html` used to render as
|
||||
|
||||
Foo &lt; Bar < Baz
|
||||
|
||||
but now renders as
|
||||
|
||||
Foo < Bar < Baz
|
||||
|
||||
## [2.2.8](http://github.com/nex3/haml/commit/2.2.8)
|
||||
|
||||
* Fixed a potential XSS issue with HTML escaping and wacky Unicode nonsense.
|
||||
|
|
|
@ -329,7 +329,10 @@ END
|
|||
end
|
||||
|
||||
if contains_interpolation?(text)
|
||||
push_script unescape_interpolation(text), :escape_html => options[:escape_html]
|
||||
options[:escape_html] = self.options[:escape_html] if options[:escape_html].nil?
|
||||
push_script(
|
||||
unescape_interpolation(text, :escape_html => options[:escape_html]),
|
||||
:escape_html => false)
|
||||
else
|
||||
push_text text
|
||||
end
|
||||
|
@ -665,30 +668,37 @@ END
|
|||
nuke_inner_whitespace ||= preserve_tag
|
||||
preserve_tag &&= !options[:ugly]
|
||||
|
||||
escape_html = (action == '&' || (action != '!' && @options[:escape_html]))
|
||||
|
||||
case action
|
||||
when '/'; self_closing = true
|
||||
when '~'; parse = preserve_script = true
|
||||
when '='
|
||||
parse = true
|
||||
value = unescape_interpolation(value[1..-1].strip) if value[0] == ?=
|
||||
if value[0] == ?=
|
||||
value = unescape_interpolation(value[1..-1].strip, :escape_html => escape_html)
|
||||
escape_html = false
|
||||
end
|
||||
when '&', '!'
|
||||
if value[0] == ?= || value[0] == ?~
|
||||
parse = true
|
||||
preserve_script = (value[0] == ?~)
|
||||
value =
|
||||
if value[1] == ?=
|
||||
unescape_interpolation(value[2..-1].strip)
|
||||
else
|
||||
value[1..-1].strip
|
||||
end
|
||||
if value[1] == ?=
|
||||
value = unescape_interpolation(value[2..-1].strip, :escape_html => escape_html)
|
||||
escape_html = false
|
||||
else
|
||||
value = value[1..-1].strip
|
||||
end
|
||||
elsif contains_interpolation?(value)
|
||||
value = unescape_interpolation(value, :escape_html => escape_html)
|
||||
parse = true
|
||||
value = unescape_interpolation(value)
|
||||
escape_html = false
|
||||
end
|
||||
else
|
||||
if contains_interpolation?(value)
|
||||
value = unescape_interpolation(value, :escape_html => escape_html)
|
||||
parse = true
|
||||
value = unescape_interpolation(value)
|
||||
escape_html = false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -697,8 +707,6 @@ END
|
|||
value = ''
|
||||
end
|
||||
|
||||
escape_html = (action == '&' || (action != '!' && @options[:escape_html]))
|
||||
|
||||
object_ref = "nil" if object_ref.nil? || @options[:suppress_eval]
|
||||
|
||||
attributes = parse_class_and_id(attributes)
|
||||
|
@ -936,7 +944,7 @@ END
|
|||
str.include?('#{')
|
||||
end
|
||||
|
||||
def unescape_interpolation(str)
|
||||
def unescape_interpolation(str, opts = {})
|
||||
res = ''
|
||||
rest = Haml::Shared.handle_interpolation str.dump do |scan|
|
||||
escapes = (scan[2].size - 1) / 2
|
||||
|
@ -944,7 +952,9 @@ END
|
|||
if escapes % 2 == 1
|
||||
res << '#{'
|
||||
else
|
||||
res << '#{' + eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"') + "}"# Use eval to get rid of string escapes
|
||||
content = eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"')
|
||||
content = "Haml::Helpers.html_escape(#{content})" if opts[:escape_html]
|
||||
res << '#{' + content + "}"# Use eval to get rid of string escapes
|
||||
end
|
||||
end
|
||||
res + rest
|
||||
|
|
|
@ -163,6 +163,10 @@ class EngineTest < Test::Unit::TestCase
|
|||
assert_equal("<p>\n 2\n</p>\n", render("%p\n \#{1 + 1}"))
|
||||
end
|
||||
|
||||
def test_escaped_interpolation
|
||||
assert_equal("<p>Foo & Bar & Baz</p>\n", render('%p& Foo #{"&"} Bar & Baz'))
|
||||
end
|
||||
|
||||
def test_nil_tag_value_should_render_as_empty
|
||||
assert_equal("<p></p>\n", render("%p= nil"))
|
||||
end
|
||||
|
@ -598,53 +602,53 @@ HAML
|
|||
end
|
||||
|
||||
def test_string_double_equals_should_be_esaped
|
||||
assert_equal("<p>4&3</p>\n", render("%p== \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>4&3</p>\n", render("%p== \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>4&<</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>4&<</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_escaped_inline_string_double_equals
|
||||
assert_equal("<p>4&3</p>\n", render("%p&== \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>4&3</p>\n", render("%p&== \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>4&<</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>4&<</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_unescaped_inline_string_double_equals
|
||||
assert_equal("<p>4&3</p>\n", render("%p!== \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>4&3</p>\n", render("%p!== \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_escaped_string_double_equals
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n &== \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n &== \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_unescaped_string_double_equals
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_string_interpolation_should_be_esaped
|
||||
assert_equal("<p>4&3</p>\n", render("%p \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>4&3</p>\n", render("%p \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>4&<</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>4&<</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_escaped_inline_string_interpolation
|
||||
assert_equal("<p>4&3</p>\n", render("%p& \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>4&3</p>\n", render("%p& \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>4&<</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>4&<</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_unescaped_inline_string_interpolation
|
||||
assert_equal("<p>4&3</p>\n", render("%p! \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>4&3</p>\n", render("%p! \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_escaped_string_interpolation
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n & \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n & \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_unescaped_string_interpolation
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n ! \#{2+2}&\#{2+1}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&3\n</p>\n", render("%p\n ! \#{2+2}&\#{2+1}", :escape_html => false))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true))
|
||||
assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false))
|
||||
end
|
||||
|
||||
def test_scripts_should_respect_escape_html_option
|
||||
|
|
Loading…
Reference in a new issue