haml 2.2.8 → 2.2.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

data/Rakefile CHANGED
@@ -25,6 +25,7 @@ Rake::TestTask.new do |t|
25
25
  t.libs << 'lib'
26
26
  test_files = FileList['test/**/*_test.rb']
27
27
  test_files.exclude('test/rails/*')
28
+ test_files.exclude('test/plugins/*')
28
29
  test_files.exclude('test/haml/spec/*')
29
30
  t.test_files = test_files
30
31
  t.verbose = true
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.2.8
1
+ 2.2.9
@@ -130,6 +130,8 @@ module Haml
130
130
  Haml::Util.def_static_method(self, :format_script, [:result],
131
131
  :preserve_script, :in_tag, :preserve_tag, :escape_html,
132
132
  :nuke_inner_whitespace, :interpolated, :ugly, <<RUBY)
133
+ <% # Escape HTML here so that the safety of the string is preserved in Rails
134
+ result_name = escape_html ? "html_escape(result.to_s)" : "result.to_s" %>
133
135
  <% unless ugly %>
134
136
  # If we're interpolated,
135
137
  # then the custom tabulation is handled in #push_text.
@@ -140,13 +142,11 @@ module Haml
140
142
  <% end %>
141
143
 
142
144
  tabulation = @real_tabs
143
- result = result.to_s.<% if nuke_inner_whitespace %>strip<% else %>rstrip<% end %>
145
+ result = <%= result_name %>.<% if nuke_inner_whitespace %>strip<% else %>rstrip<% end %>
144
146
  <% else %>
145
- result = result.to_s<% if nuke_inner_whitespace %>.strip<% end %>
147
+ result = <%= result_name %><% if nuke_inner_whitespace %>.strip<% end %>
146
148
  <% end %>
147
149
 
148
- <% if escape_html %> result = html_escape(result) <% end %>
149
-
150
150
  <% if preserve_tag %>
151
151
  result = Haml::Helpers.preserve(result)
152
152
  <% elsif preserve_script %>
@@ -284,6 +284,7 @@ module Haml
284
284
  :ugly => @options[:ugly],
285
285
  :format => @options[:format],
286
286
  :encoding => @options[:encoding],
287
+ :escape_html => @options[:escape_html],
287
288
  }
288
289
  end
289
290
 
@@ -113,9 +113,7 @@ MESSAGE
113
113
  # @yield The block within which to escape newlines
114
114
  def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
115
115
  return find_and_preserve(capture_haml(&block), input || tags) if block
116
-
117
- input = input.to_s
118
- input.gsub(/<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im) do
116
+ input.to_s.gsub(/<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im) do
119
117
  "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
120
118
  end
121
119
  end
@@ -132,10 +130,9 @@ MESSAGE
132
130
  # Escapes newlines within a block of Haml code.
133
131
  #
134
132
  # @yield The block within which to escape newlines
135
- def preserve(input = '', &block)
133
+ def preserve(input = nil, &block)
136
134
  return preserve(capture_haml(&block)) if block
137
-
138
- input.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
135
+ input.to_s.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
139
136
  end
140
137
  alias_method :flatten, :preserve
141
138
 
@@ -470,6 +467,10 @@ END
470
467
  # Returns a copy of `text` with ampersands, angle brackets and quotes
471
468
  # escaped into HTML entities.
472
469
  #
470
+ # Note that if ActionView is loaded and XSS protection is enabled
471
+ # (as is the default for Rails 3.0+, and optional for version 2.3.5+),
472
+ # this won't escape text declared as "safe".
473
+ #
473
474
  # @param text [String] The string to sanitize
474
475
  # @return [String] The sanitized string
475
476
  def html_escape(text)
@@ -35,6 +35,21 @@ module Haml
35
35
  controller.controller_name + " " + controller.action_name
36
36
  end
37
37
  alias_method :generate_content_class_names, :page_class
38
+
39
+ # Treats all input to \{Haml::Helpers#haml\_concat} within the block
40
+ # as being HTML safe for Rails' XSS protection.
41
+ # This is useful for wrapping blocks of code that concatenate HTML en masse.
42
+ #
43
+ # This has no effect if Rails' XSS protection isn't enabled.
44
+ #
45
+ # @yield A block in which all input to `#haml_concat` is treated as raw.
46
+ # @see Haml::Util#rails_xss_safe?
47
+ def with_raw_haml_concat
48
+ @_haml_concat_raw = true
49
+ yield
50
+ ensure
51
+ @_haml_concat_raw = false
52
+ end
38
53
  end
39
54
  end
40
55
  end
@@ -26,6 +26,7 @@ module ActionView
26
26
 
27
27
  def set_output_buffer_with_haml(new)
28
28
  if is_haml?
29
+ new = String.new(new) if Haml::Util.rails_xss_safe? && new.is_a?(ActionView::SafeBuffer)
29
30
  haml_buffer.buffer = new
30
31
  else
31
32
  set_output_buffer_without_haml new
@@ -0,0 +1,94 @@
1
+ module Haml
2
+ module Helpers
3
+ # This module overrides Haml helpers to work properly
4
+ # in the context of ActionView.
5
+ # Currently it's only used for modifying the helpers
6
+ # to work with Rails' XSS protection methods.
7
+ module XssMods
8
+ def self.included(base)
9
+ %w[html_escape find_and_preserve preserve list_of surround
10
+ precede succeed capture_haml haml_concat haml_indent
11
+ haml_tag escape_once].each do |name|
12
+ base.send(:alias_method, "#{name}_without_haml_xss", name)
13
+ base.send(:alias_method, name, "#{name}_with_haml_xss")
14
+ end
15
+ end
16
+
17
+ # Don't escape text that's already safe,
18
+ # output is always HTML safe
19
+ def html_escape_with_haml_xss(text)
20
+ return text if text.html_safe?
21
+ html_escape_without_haml_xss(text).html_safe!
22
+ end
23
+
24
+ # Output is always HTML safe
25
+ def find_and_preserve_with_haml_xss(*args, &block)
26
+ find_and_preserve_without_haml_xss(*args, &block).html_safe!
27
+ end
28
+
29
+ # Output is always HTML safe
30
+ def preserve_with_haml_xss(*args, &block)
31
+ preserve_without_haml_xss(*args, &block).html_safe!
32
+ end
33
+
34
+ # Output is always HTML safe
35
+ def list_of_with_haml_xss(*args, &block)
36
+ list_of_without_haml_xss(*args, &block).html_safe!
37
+ end
38
+
39
+ # Input is escaped, output is always HTML safe
40
+ def surround_with_haml_xss(front, back = front, &block)
41
+ surround_without_haml_xss(
42
+ haml_xss_html_escape(front),
43
+ haml_xss_html_escape(back),
44
+ &block).html_safe!
45
+ end
46
+
47
+ # Input is escaped, output is always HTML safe
48
+ def precede_with_haml_xss(str, &block)
49
+ precede_without_haml_xss(haml_xss_html_escape(str), &block).html_safe!
50
+ end
51
+
52
+ # Input is escaped, output is always HTML safe
53
+ def succeed_with_haml_xss(str, &block)
54
+ succeed_without_haml_xss(haml_xss_html_escape(str), &block).html_safe!
55
+ end
56
+
57
+ # Output is always HTML safe
58
+ def capture_haml_with_haml_xss(*args, &block)
59
+ capture_haml_without_haml_xss(*args, &block).html_safe!
60
+ end
61
+
62
+ # Input is escaped
63
+ def haml_concat_with_haml_xss(text = "")
64
+ haml_concat_without_haml_xss(@_haml_concat_raw ? text : haml_xss_html_escape(text))
65
+ end
66
+
67
+ # Output is always HTML safe
68
+ def haml_indent_with_haml_xss
69
+ haml_indent_without_haml_xss.html_safe!
70
+ end
71
+
72
+ # Input is escaped, haml_concat'ed output is always HTML safe
73
+ def haml_tag_with_haml_xss(name, *rest, &block)
74
+ name = haml_xss_html_escape(name.to_s)
75
+ rest.unshift(haml_xss_html_escape(rest.shift.to_s)) unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
76
+ with_raw_haml_concat {haml_tag_without_haml_xss(name, *rest, &block)}
77
+ end
78
+
79
+ # Output is always HTML safe
80
+ def escape_once_with_haml_xss(*args)
81
+ escape_once_without_haml_xss(*args).html_safe!
82
+ end
83
+
84
+ private
85
+
86
+ # Escapes the HTML in the text if and only if
87
+ # Rails XSS protection is enabled *and* the `:escape_html` option is set.
88
+ def haml_xss_html_escape(text)
89
+ return text unless Haml::Util.rails_xss_safe? && haml_buffer.options[:escape_html]
90
+ html_escape(text)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -313,7 +313,7 @@ END
313
313
 
314
314
  @precompiled <<
315
315
  if @options[:ugly]
316
- "_erbout << \"#{text}\";"
316
+ "_hamlout.buffer << \"#{text}\";"
317
317
  else
318
318
  "_hamlout.push_text(\"#{text}\", #{tab_change}, #{@dont_tab_up_next_text.inspect});"
319
319
  end
@@ -329,7 +329,10 @@ END
329
329
  end
330
330
 
331
331
  if contains_interpolation?(text)
332
- push_script unescape_interpolation(text), :escape_html => options[:escape_html]
332
+ options[:escape_html] = self.options[:escape_html] if options[:escape_html].nil?
333
+ push_script(
334
+ unescape_interpolation(text, :escape_html => options[:escape_html]),
335
+ :escape_html => false)
333
336
  else
334
337
  push_text text
335
338
  end
@@ -375,7 +378,7 @@ END
375
378
 
376
379
  push_silent "haml_temp = #{text}"
377
380
  newline_now
378
- push_and_tabulate([:loud, "_erbout << #{no_format ? "#{output_temp}.to_s;" : out}",
381
+ push_and_tabulate([:loud, "_hamlout.buffer << #{no_format ? "#{output_temp}.to_s;" : out}",
379
382
  !(opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly])])
380
383
  end
381
384
 
@@ -665,30 +668,37 @@ END
665
668
  nuke_inner_whitespace ||= preserve_tag
666
669
  preserve_tag &&= !options[:ugly]
667
670
 
671
+ escape_html = (action == '&' || (action != '!' && @options[:escape_html]))
672
+
668
673
  case action
669
674
  when '/'; self_closing = true
670
675
  when '~'; parse = preserve_script = true
671
676
  when '='
672
677
  parse = true
673
- value = unescape_interpolation(value[1..-1].strip) if value[0] == ?=
678
+ if value[0] == ?=
679
+ value = unescape_interpolation(value[1..-1].strip, :escape_html => escape_html)
680
+ escape_html = false
681
+ end
674
682
  when '&', '!'
675
683
  if value[0] == ?= || value[0] == ?~
676
684
  parse = true
677
685
  preserve_script = (value[0] == ?~)
678
- value =
679
- if value[1] == ?=
680
- unescape_interpolation(value[2..-1].strip)
681
- else
682
- value[1..-1].strip
683
- end
686
+ if value[1] == ?=
687
+ value = unescape_interpolation(value[2..-1].strip, :escape_html => escape_html)
688
+ escape_html = false
689
+ else
690
+ value = value[1..-1].strip
691
+ end
684
692
  elsif contains_interpolation?(value)
693
+ value = unescape_interpolation(value, :escape_html => escape_html)
685
694
  parse = true
686
- value = unescape_interpolation(value)
695
+ escape_html = false
687
696
  end
688
697
  else
689
698
  if contains_interpolation?(value)
699
+ value = unescape_interpolation(value, :escape_html => escape_html)
690
700
  parse = true
691
- value = unescape_interpolation(value)
701
+ escape_html = false
692
702
  end
693
703
  end
694
704
 
@@ -697,8 +707,6 @@ END
697
707
  value = ''
698
708
  end
699
709
 
700
- escape_html = (action == '&' || (action != '!' && @options[:escape_html]))
701
-
702
710
  object_ref = "nil" if object_ref.nil? || @options[:suppress_eval]
703
711
 
704
712
  attributes = parse_class_and_id(attributes)
@@ -936,7 +944,7 @@ END
936
944
  str.include?('#{')
937
945
  end
938
946
 
939
- def unescape_interpolation(str)
947
+ def unescape_interpolation(str, opts = {})
940
948
  res = ''
941
949
  rest = Haml::Shared.handle_interpolation str.dump do |scan|
942
950
  escapes = (scan[2].size - 1) / 2
@@ -944,7 +952,9 @@ END
944
952
  if escapes % 2 == 1
945
953
  res << '#{'
946
954
  else
947
- res << '#{' + eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"') + "}"# Use eval to get rid of string escapes
955
+ content = eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"')
956
+ content = "Haml::Helpers.html_escape(#{content})" if opts[:escape_html]
957
+ res << '#{' + content + "}"# Use eval to get rid of string escapes
948
958
  end
949
959
  end
950
960
  res + rest
@@ -27,6 +27,21 @@ else
27
27
  require 'haml/template/patch'
28
28
  end
29
29
 
30
+ if ActionView::Base.respond_to?(:xss_safe?) && ActionView::Base.xss_safe?
31
+ Haml::Template.options[:escape_html] = true
32
+
33
+ module Haml::Util
34
+ def rails_xss_safe?
35
+ true
36
+ end
37
+ end
38
+
39
+ require 'haml/helpers/xss_mods'
40
+ module Haml::Helpers
41
+ include XssMods
42
+ end
43
+ end
44
+
30
45
  if defined?(RAILS_ROOT)
31
46
  # Update init.rb to the current version
32
47
  # if it's out of date.
@@ -122,6 +122,28 @@ module Haml
122
122
  end
123
123
  end
124
124
 
125
+ ## Rails XSS Safety
126
+
127
+ # Whether or not ActionView's XSS protection is available and enabled,
128
+ # as is the default for Rails 3.0+, and optional for version 2.3.5+.
129
+ # Overridden in haml/template.rb if this is the case.
130
+ #
131
+ # @return [Boolean]
132
+ def rails_xss_safe?
133
+ false
134
+ end
135
+
136
+ # Assert that a given object (usually a String) is HTML safe
137
+ # according to Rails' XSS handling, if it's loaded.
138
+ #
139
+ # @param text [Object]
140
+ def assert_html_safe!(text)
141
+ return unless rails_xss_safe? && text && !text.to_s.html_safe?
142
+ raise Haml::Error.new("Expected #{text.inspect} to be HTML-safe.")
143
+ end
144
+
145
+ ## Cross-Ruby-Version Compatibility
146
+
125
147
  # Whether or not this is running under Ruby 1.8 or lower.
126
148
  #
127
149
  # @return [Boolean]
@@ -155,6 +177,8 @@ module Haml
155
177
  ruby1_8? ? enum.enum_with_index : enum.each_with_index
156
178
  end
157
179
 
180
+ ## Static Method Stuff
181
+
158
182
  # The context in which the ERB for \{#def\_static\_method} will be run.
159
183
  class StaticConditionalContext
160
184
  # @param set [#include?] The set of variables that are defined for this context.
@@ -1,6 +1,9 @@
1
1
  require 'pathname'
2
2
 
3
3
  module Sass::Tree
4
+ # A static node reprenting a CSS rule.
5
+ #
6
+ # @see Sass::Tree
4
7
  class RuleNode < Node
5
8
  # The character used to include the parent selector
6
9
  PARENT = '&'
@@ -163,6 +163,10 @@ class EngineTest < Test::Unit::TestCase
163
163
  assert_equal("<p>\n 2\n</p>\n", render("%p\n \#{1 + 1}"))
164
164
  end
165
165
 
166
+ def test_escaped_interpolation
167
+ assert_equal("<p>Foo &amp; Bar & Baz</p>\n", render('%p& Foo #{"&"} Bar & Baz'))
168
+ end
169
+
166
170
  def test_nil_tag_value_should_render_as_empty
167
171
  assert_equal("<p></p>\n", render("%p= nil"))
168
172
  end
@@ -598,53 +602,53 @@ HAML
598
602
  end
599
603
 
600
604
  def test_string_double_equals_should_be_esaped
601
- assert_equal("<p>4&amp;3</p>\n", render("%p== \#{2+2}&\#{2+1}", :escape_html => true))
602
- assert_equal("<p>4&3</p>\n", render("%p== \#{2+2}&\#{2+1}", :escape_html => false))
605
+ assert_equal("<p>4&&lt;</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => true))
606
+ assert_equal("<p>4&<</p>\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => false))
603
607
  end
604
608
 
605
609
  def test_escaped_inline_string_double_equals
606
- assert_equal("<p>4&amp;3</p>\n", render("%p&== \#{2+2}&\#{2+1}", :escape_html => true))
607
- assert_equal("<p>4&amp;3</p>\n", render("%p&== \#{2+2}&\#{2+1}", :escape_html => false))
610
+ assert_equal("<p>4&&lt;</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => true))
611
+ assert_equal("<p>4&&lt;</p>\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => false))
608
612
  end
609
613
 
610
614
  def test_unescaped_inline_string_double_equals
611
- assert_equal("<p>4&3</p>\n", render("%p!== \#{2+2}&\#{2+1}", :escape_html => true))
612
- assert_equal("<p>4&3</p>\n", render("%p!== \#{2+2}&\#{2+1}", :escape_html => false))
615
+ assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => true))
616
+ assert_equal("<p>4&<</p>\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => false))
613
617
  end
614
618
 
615
619
  def test_escaped_string_double_equals
616
- assert_equal("<p>\n 4&amp;3\n</p>\n", render("%p\n &== \#{2+2}&\#{2+1}", :escape_html => true))
617
- assert_equal("<p>\n 4&amp;3\n</p>\n", render("%p\n &== \#{2+2}&\#{2+1}", :escape_html => false))
620
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true))
621
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false))
618
622
  end
619
623
 
620
624
  def test_unescaped_string_double_equals
621
- assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== \#{2+2}&\#{2+1}", :escape_html => true))
622
- assert_equal("<p>\n 4&3\n</p>\n", render("%p\n !== \#{2+2}&\#{2+1}", :escape_html => false))
625
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true))
626
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false))
623
627
  end
624
628
 
625
629
  def test_string_interpolation_should_be_esaped
626
- assert_equal("<p>4&amp;3</p>\n", render("%p \#{2+2}&\#{2+1}", :escape_html => true))
627
- assert_equal("<p>4&3</p>\n", render("%p \#{2+2}&\#{2+1}", :escape_html => false))
630
+ assert_equal("<p>4&&lt;</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => true))
631
+ assert_equal("<p>4&<</p>\n", render("%p \#{2+2}&\#{'<'}", :escape_html => false))
628
632
  end
629
633
 
630
634
  def test_escaped_inline_string_interpolation
631
- assert_equal("<p>4&amp;3</p>\n", render("%p& \#{2+2}&\#{2+1}", :escape_html => true))
632
- assert_equal("<p>4&amp;3</p>\n", render("%p& \#{2+2}&\#{2+1}", :escape_html => false))
635
+ assert_equal("<p>4&&lt;</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => true))
636
+ assert_equal("<p>4&&lt;</p>\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => false))
633
637
  end
634
638
 
635
639
  def test_unescaped_inline_string_interpolation
636
- assert_equal("<p>4&3</p>\n", render("%p! \#{2+2}&\#{2+1}", :escape_html => true))
637
- assert_equal("<p>4&3</p>\n", render("%p! \#{2+2}&\#{2+1}", :escape_html => false))
640
+ assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => true))
641
+ assert_equal("<p>4&<</p>\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => false))
638
642
  end
639
643
 
640
644
  def test_escaped_string_interpolation
641
- assert_equal("<p>\n 4&amp;3\n</p>\n", render("%p\n & \#{2+2}&\#{2+1}", :escape_html => true))
642
- assert_equal("<p>\n 4&amp;3\n</p>\n", render("%p\n & \#{2+2}&\#{2+1}", :escape_html => false))
645
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true))
646
+ assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => false))
643
647
  end
644
648
 
645
649
  def test_unescaped_string_interpolation
646
- assert_equal("<p>\n 4&3\n</p>\n", render("%p\n ! \#{2+2}&\#{2+1}", :escape_html => true))
647
- assert_equal("<p>\n 4&3\n</p>\n", render("%p\n ! \#{2+2}&\#{2+1}", :escape_html => false))
650
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true))
651
+ assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false))
648
652
  end
649
653
 
650
654
  def test_scripts_should_respect_escape_html_option
@@ -84,8 +84,9 @@ class TemplateTest < Test::Unit::TestCase
84
84
  base
85
85
  end
86
86
 
87
- def render(text)
88
- Haml::Engine.new(text).to_html(@base)
87
+ def render(text, opts = {})
88
+ return @base.render(:inline => text, :type => :haml) if opts == :action_view
89
+ Haml::Engine.new(text, opts).to_html(@base)
89
90
  end
90
91
 
91
92
  def load_result(name)
@@ -95,6 +96,8 @@ class TemplateTest < Test::Unit::TestCase
95
96
  end
96
97
 
97
98
  def assert_renders_correctly(name, &render_method)
99
+ old_options = Haml::Template.options.dup
100
+ Haml::Template.options[:escape_html] = false
98
101
  if ActionPack::VERSION::MAJOR < 2 ||
99
102
  (ActionPack::VERSION::MAJOR == 2 && ActionPack::VERSION::MINOR < 2)
100
103
  render_method ||= proc { |name| @base.render(name) }
@@ -112,6 +115,8 @@ class TemplateTest < Test::Unit::TestCase
112
115
  else
113
116
  raise e
114
117
  end
118
+ ensure
119
+ Haml::Template.options = old_options
115
120
  end
116
121
 
117
122
  def test_empty_render_should_remain_empty
@@ -176,12 +181,31 @@ class TemplateTest < Test::Unit::TestCase
176
181
  end
177
182
 
178
183
  def test_haml_options
179
- Haml::Template.options = { :suppress_eval => true }
180
- assert_equal({ :suppress_eval => true }, Haml::Template.options)
184
+ old_options = Haml::Template.options.dup
185
+ Haml::Template.options[:suppress_eval] = true
181
186
  old_base, @base = @base, create_base
182
187
  assert_renders_correctly("eval_suppressed")
188
+ ensure
183
189
  @base = old_base
184
- Haml::Template.options = {}
190
+ Haml::Template.options = old_options
191
+ end
192
+
193
+ def test_with_output_buffer_with_ugly
194
+ return unless Haml::Util.has?(:instance_method, ActionView::Base, :with_output_buffer)
195
+ assert_equal(<<HTML, render(<<HAML, :ugly => true))
196
+ <p>
197
+ foo
198
+ baz
199
+ </p>
200
+ HTML
201
+ %p
202
+ foo
203
+ - with_output_buffer do
204
+ bar
205
+ = "foo".gsub(/./) do |s|
206
+ - s.ord
207
+ baz
208
+ HAML
185
209
  end
186
210
 
187
211
  def test_exceptions_should_work_correctly
@@ -213,5 +237,41 @@ END
213
237
  else
214
238
  assert false
215
239
  end
216
- end
240
+ end
241
+
242
+ ## XSS Protection Tests
243
+
244
+ if Haml::Util.rails_xss_safe?
245
+ def test_escape_html_option_set
246
+ assert Haml::Template.options[:escape_html]
247
+ end
248
+
249
+ def test_xss_protection
250
+ assert_equal("Foo &amp; Bar\n", render('= "Foo & Bar"', :action_view))
251
+ end
252
+
253
+ def test_xss_protection_with_safe_strings
254
+ assert_equal("Foo & Bar\n", render('= "Foo & Bar".html_safe!', :action_view))
255
+ end
256
+
257
+ def test_xss_protection_with_bang
258
+ assert_equal("Foo & Bar\n", render('!= "Foo & Bar"', :action_view))
259
+ end
260
+
261
+ def test_xss_protection_in_interpolation
262
+ assert_equal("Foo &amp; Bar\n", render('Foo #{"&"} Bar', :action_view))
263
+ end
264
+
265
+ def test_xss_protection_with_bang_in_interpolation
266
+ assert_equal("Foo & Bar\n", render('! Foo #{"&"} Bar', :action_view))
267
+ end
268
+
269
+ def test_xss_protection_with_safe_strings_in_interpolation
270
+ assert_equal("Foo & Bar\n", render('Foo #{"&".html_safe!} Bar', :action_view))
271
+ end
272
+
273
+ def test_xss_protection_with_mixed_strings_in_interpolation
274
+ assert_equal("Foo & Bar &amp; Baz\n", render('Foo #{"&".html_safe!} Bar #{"&"} Baz', :action_view))
275
+ end
276
+ end
217
277
  end
@@ -54,6 +54,11 @@ class UtilTest < Test::Unit::TestCase
54
54
  powerset([1, 2, 3]))
55
55
  end
56
56
 
57
+ def test_merge_adjacent_strings
58
+ assert_equal(["foo bar baz", :bang, "biz bop", 12],
59
+ merge_adjacent_strings(["foo ", "bar ", "baz", :bang, "biz", " bop", 12]))
60
+ end
61
+
57
62
  def test_has
58
63
  assert(has?(:instance_method, String, :chomp!))
59
64
  assert(has?(:private_instance_method, Haml::Engine, :set_locals))
@@ -10,3 +10,13 @@ else
10
10
  end
11
11
  require 'action_controller'
12
12
  require 'action_view'
13
+
14
+ ActionController::Base.logger = Logger.new(nil)
15
+
16
+ # Load plugins from test/plugins.
17
+ # This will only work with very basic plugins,
18
+ # since we don't want to load the entirety of Rails.
19
+ Dir[File.dirname(__FILE__) + '/plugins/*'].each do |plugin|
20
+ $: << plugin + '/lib'
21
+ Object.new.instance_eval(File.read(plugin + '/init.rb'))
22
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.8
4
+ version: 2.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Weizenbaum
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-10-11 00:00:00 -07:00
13
+ date: 2009-10-17 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -43,199 +43,200 @@ executables:
43
43
  extensions: []
44
44
 
45
45
  extra_rdoc_files:
46
- - VERSION_NAME
47
- - CONTRIBUTING
48
- - README.md
49
- - MIT-LICENSE
50
46
  - VERSION
47
+ - MIT-LICENSE
48
+ - README.md
49
+ - VERSION_NAME
51
50
  - REVISION
51
+ - CONTRIBUTING
52
52
  files:
53
53
  - rails/init.rb
54
54
  - lib/sass.rb
55
- - lib/sass/css.rb
56
- - lib/sass/script/node.rb
57
- - lib/sass/script/number.rb
58
- - lib/sass/script/operation.rb
59
- - lib/sass/script/literal.rb
60
- - lib/sass/script/functions.rb
61
- - lib/sass/script/bool.rb
62
- - lib/sass/script/color.rb
63
- - lib/sass/script/lexer.rb
64
- - lib/sass/script/parser.rb
65
- - lib/sass/script/variable.rb
66
- - lib/sass/script/string.rb
67
- - lib/sass/script/funcall.rb
68
- - lib/sass/script/unary_operation.rb
55
+ - lib/sass/plugin/rails.rb
56
+ - lib/sass/plugin/merb.rb
69
57
  - lib/sass/script.rb
70
58
  - lib/sass/error.rb
71
- - lib/sass/repl.rb
72
- - lib/sass/tree/comment_node.rb
73
- - lib/sass/tree/node.rb
74
59
  - lib/sass/tree/for_node.rb
75
- - lib/sass/tree/debug_node.rb
76
- - lib/sass/tree/import_node.rb
77
- - lib/sass/tree/while_node.rb
78
- - lib/sass/tree/mixin_def_node.rb
79
- - lib/sass/tree/if_node.rb
80
60
  - lib/sass/tree/mixin_node.rb
81
- - lib/sass/tree/directive_node.rb
82
- - lib/sass/tree/rule_node.rb
61
+ - lib/sass/tree/if_node.rb
83
62
  - lib/sass/tree/prop_node.rb
63
+ - lib/sass/tree/mixin_def_node.rb
84
64
  - lib/sass/tree/variable_node.rb
85
- - lib/sass/plugin/rails.rb
86
- - lib/sass/plugin/merb.rb
87
- - lib/sass/environment.rb
65
+ - lib/sass/tree/debug_node.rb
66
+ - lib/sass/tree/directive_node.rb
67
+ - lib/sass/tree/node.rb
68
+ - lib/sass/tree/comment_node.rb
69
+ - lib/sass/tree/rule_node.rb
70
+ - lib/sass/tree/import_node.rb
71
+ - lib/sass/tree/while_node.rb
88
72
  - lib/sass/files.rb
89
- - lib/sass/engine.rb
90
73
  - lib/sass/plugin.rb
91
- - lib/haml/filters.rb
74
+ - lib/sass/script/parser.rb
75
+ - lib/sass/script/color.rb
76
+ - lib/sass/script/string.rb
77
+ - lib/sass/script/unary_operation.rb
78
+ - lib/sass/script/number.rb
79
+ - lib/sass/script/funcall.rb
80
+ - lib/sass/script/variable.rb
81
+ - lib/sass/script/functions.rb
82
+ - lib/sass/script/bool.rb
83
+ - lib/sass/script/lexer.rb
84
+ - lib/sass/script/operation.rb
85
+ - lib/sass/script/node.rb
86
+ - lib/sass/script/literal.rb
87
+ - lib/sass/css.rb
88
+ - lib/sass/engine.rb
89
+ - lib/sass/repl.rb
90
+ - lib/sass/environment.rb
91
+ - lib/haml/util.rb
92
92
  - lib/haml/exec.rb
93
+ - lib/haml/html.rb
93
94
  - lib/haml/error.rb
95
+ - lib/haml/buffer.rb
94
96
  - lib/haml/template.rb
95
- - lib/haml/shared.rb
96
- - lib/haml/engine.rb
97
- - lib/haml/version.rb
98
- - lib/haml/template/patch.rb
99
97
  - lib/haml/template/plugin.rb
98
+ - lib/haml/template/patch.rb
100
99
  - lib/haml/helpers.rb
101
- - lib/haml/buffer.rb
102
- - lib/haml/html.rb
100
+ - lib/haml/version.rb
101
+ - lib/haml/filters.rb
102
+ - lib/haml/engine.rb
103
103
  - lib/haml/precompiler.rb
104
- - lib/haml/util.rb
105
- - lib/haml/helpers/action_view_mods.rb
104
+ - lib/haml/shared.rb
106
105
  - lib/haml/helpers/action_view_extensions.rb
106
+ - lib/haml/helpers/action_view_mods.rb
107
+ - lib/haml/helpers/xss_mods.rb
107
108
  - lib/haml.rb
108
- - bin/sass
109
109
  - bin/css2sass
110
- - bin/html2haml
110
+ - bin/sass
111
111
  - bin/haml
112
- - test/linked_rails.rb
113
- - test/benchmark.rb
112
+ - bin/html2haml
114
113
  - test/sass/script_test.rb
115
- - test/sass/css2sass_test.rb
116
- - test/sass/results/units.css
117
- - test/sass/results/parent_ref.css
118
- - test/sass/results/compressed.css
119
- - test/sass/results/complex.css
120
- - test/sass/results/compact.css
121
- - test/sass/results/mixins.css
122
- - test/sass/results/line_numbers.css
123
- - test/sass/results/alt.css
124
- - test/sass/results/subdir/subdir.css
125
- - test/sass/results/subdir/nested_subdir/nested_subdir.css
126
- - test/sass/results/nested.css
127
- - test/sass/results/import.css
128
- - test/sass/results/multiline.css
129
- - test/sass/results/script.css
130
- - test/sass/results/basic.css
131
- - test/sass/results/expanded.css
132
- - test/sass/more_results/more_import.css
133
114
  - test/sass/more_results/more1_with_line_comments.css
134
115
  - test/sass/more_results/more1.css
135
- - test/sass/templates/basic.sass
136
- - test/sass/templates/bork.sass
116
+ - test/sass/more_results/more_import.css
117
+ - test/sass/templates/bork2.sass
137
118
  - test/sass/templates/compressed.sass
138
- - test/sass/templates/import.sass
139
- - test/sass/templates/script.sass
140
119
  - test/sass/templates/expanded.sass
141
- - test/sass/templates/nested.sass
120
+ - test/sass/templates/import.sass
121
+ - test/sass/templates/subdir/subdir.sass
122
+ - test/sass/templates/subdir/nested_subdir/_nested_partial.sass
123
+ - test/sass/templates/subdir/nested_subdir/nested_subdir.sass
124
+ - test/sass/templates/basic.sass
142
125
  - test/sass/templates/_partial.sass
126
+ - test/sass/templates/units.sass
127
+ - test/sass/templates/mixins.sass
128
+ - test/sass/templates/multiline.sass
143
129
  - test/sass/templates/line_numbers.sass
130
+ - test/sass/templates/nested.sass
144
131
  - test/sass/templates/compact.sass
145
- - test/sass/templates/subdir/subdir.sass
146
- - test/sass/templates/subdir/nested_subdir/nested_subdir.sass
147
- - test/sass/templates/subdir/nested_subdir/_nested_partial.sass
148
- - test/sass/templates/parent_ref.sass
149
132
  - test/sass/templates/alt.sass
133
+ - test/sass/templates/script.sass
150
134
  - test/sass/templates/importee.sass
151
- - test/sass/templates/mixins.sass
152
- - test/sass/templates/multiline.sass
153
- - test/sass/templates/units.sass
135
+ - test/sass/templates/parent_ref.sass
136
+ - test/sass/templates/bork.sass
154
137
  - test/sass/templates/complex.sass
155
- - test/sass/templates/bork2.sass
156
- - test/sass/more_templates/_more_partial.sass
138
+ - test/sass/css2sass_test.rb
139
+ - test/sass/plugin_test.rb
157
140
  - test/sass/more_templates/more1.sass
158
141
  - test/sass/more_templates/more_import.sass
142
+ - test/sass/more_templates/_more_partial.sass
159
143
  - test/sass/functions_test.rb
144
+ - test/sass/results/nested.css
145
+ - test/sass/results/units.css
146
+ - test/sass/results/script.css
147
+ - test/sass/results/subdir/nested_subdir/nested_subdir.css
148
+ - test/sass/results/subdir/subdir.css
149
+ - test/sass/results/import.css
150
+ - test/sass/results/compact.css
151
+ - test/sass/results/expanded.css
152
+ - test/sass/results/alt.css
153
+ - test/sass/results/mixins.css
154
+ - test/sass/results/complex.css
155
+ - test/sass/results/compressed.css
156
+ - test/sass/results/parent_ref.css
157
+ - test/sass/results/line_numbers.css
158
+ - test/sass/results/multiline.css
159
+ - test/sass/results/basic.css
160
160
  - test/sass/engine_test.rb
161
- - test/sass/plugin_test.rb
162
161
  - test/haml/mocks/article.rb
163
- - test/haml/rhtml/_av_partial_2.rhtml
164
- - test/haml/rhtml/standard.rhtml
165
- - test/haml/rhtml/_av_partial_1.rhtml
166
- - test/haml/rhtml/action_view.rhtml
167
162
  - test/haml/util_test.rb
168
- - test/haml/spec/ruby_haml_test.rb
169
- - test/haml/spec/README.md
170
- - test/haml/spec/lua_haml_spec.lua
171
- - test/haml/spec/tests.json
172
- - test/haml/html2haml_test.rb
173
163
  - test/haml/template_test.rb
164
+ - test/haml/html2haml_test.rb
165
+ - test/haml/rhtml/_av_partial_1.rhtml
166
+ - test/haml/rhtml/standard.rhtml
167
+ - test/haml/rhtml/action_view.rhtml
168
+ - test/haml/rhtml/_av_partial_2.rhtml
174
169
  - test/haml/helper_test.rb
175
- - test/haml/results/tag_parsing.xhtml
176
- - test/haml/results/content_for_layout.xhtml
177
- - test/haml/results/helpers.xhtml
178
- - test/haml/results/original_engine.xhtml
179
- - test/haml/results/very_basic.xhtml
180
- - test/haml/results/helpful.xhtml
181
- - test/haml/results/list.xhtml
182
- - test/haml/results/partials.xhtml
183
- - test/haml/results/eval_suppressed.xhtml
184
- - test/haml/results/nuke_inner_whitespace.xhtml
185
- - test/haml/results/whitespace_handling.xhtml
186
- - test/haml/results/render_layout.xhtml
187
- - test/haml/results/silent_script.xhtml
188
- - test/haml/results/standard.xhtml
189
- - test/haml/results/just_stuff.xhtml
190
- - test/haml/results/partial_layout.xhtml
191
- - test/haml/results/filters.xhtml
192
- - test/haml/results/nuke_outer_whitespace.xhtml
193
- - test/haml/markaby/standard.mab
194
- - test/haml/templates/tag_parsing.haml
195
- - test/haml/templates/nuke_inner_whitespace.haml
170
+ - test/haml/templates/action_view_ugly.haml
171
+ - test/haml/templates/list.haml
172
+ - test/haml/templates/_text_area.haml
173
+ - test/haml/templates/_partial.haml
174
+ - test/haml/templates/nuke_outer_whitespace.haml
175
+ - test/haml/templates/render_layout.haml
176
+ - test/haml/templates/_av_partial_2.haml
196
177
  - test/haml/templates/partial_layout.haml
197
- - test/haml/templates/_av_partial_2_ugly.haml
178
+ - test/haml/templates/helpful.haml
179
+ - test/haml/templates/_av_partial_1_ugly.haml
180
+ - test/haml/templates/just_stuff.haml
181
+ - test/haml/templates/standard_ugly.haml
182
+ - test/haml/templates/silent_script.haml
183
+ - test/haml/templates/very_basic.haml
184
+ - test/haml/templates/nuke_inner_whitespace.haml
185
+ - test/haml/templates/eval_suppressed.haml
186
+ - test/haml/templates/tag_parsing.haml
187
+ - test/haml/templates/whitespace_handling.haml
198
188
  - test/haml/templates/partials.haml
189
+ - test/haml/templates/standard.haml
190
+ - test/haml/templates/partialize.haml
199
191
  - test/haml/templates/_layout_for_partial.haml
200
- - test/haml/templates/original_engine.haml
201
- - test/haml/templates/helpers.haml
192
+ - test/haml/templates/_av_partial_1.haml
193
+ - test/haml/templates/filters.haml
202
194
  - test/haml/templates/_layout.erb
203
- - test/haml/templates/action_view_ugly.haml
204
195
  - test/haml/templates/content_for_layout.haml
205
- - test/haml/templates/silent_script.haml
206
- - test/haml/templates/very_basic.haml
207
- - test/haml/templates/render_layout.haml
208
- - test/haml/templates/filters.haml
209
- - test/haml/templates/_av_partial_1.haml
210
- - test/haml/templates/standard_ugly.haml
211
- - test/haml/templates/_partial.haml
212
- - test/haml/templates/nuke_outer_whitespace.haml
196
+ - test/haml/templates/_av_partial_2_ugly.haml
197
+ - test/haml/templates/helpers.haml
198
+ - test/haml/templates/original_engine.haml
213
199
  - test/haml/templates/breakage.haml
214
- - test/haml/templates/list.haml
215
- - test/haml/templates/standard.haml
216
- - test/haml/templates/whitespace_handling.haml
217
- - test/haml/templates/eval_suppressed.haml
218
200
  - test/haml/templates/action_view.haml
219
- - test/haml/templates/_av_partial_2.haml
220
- - test/haml/templates/partialize.haml
221
- - test/haml/templates/just_stuff.haml
222
- - test/haml/templates/helpful.haml
223
- - test/haml/templates/_av_partial_1_ugly.haml
224
- - test/haml/templates/_text_area.haml
201
+ - test/haml/spec/tests.json
202
+ - test/haml/spec/lua_haml_spec.lua
203
+ - test/haml/spec/ruby_haml_test.rb
204
+ - test/haml/spec/README.md
205
+ - test/haml/results/content_for_layout.xhtml
206
+ - test/haml/results/just_stuff.xhtml
207
+ - test/haml/results/whitespace_handling.xhtml
208
+ - test/haml/results/nuke_outer_whitespace.xhtml
209
+ - test/haml/results/silent_script.xhtml
210
+ - test/haml/results/filters.xhtml
211
+ - test/haml/results/standard.xhtml
212
+ - test/haml/results/nuke_inner_whitespace.xhtml
213
+ - test/haml/results/helpful.xhtml
214
+ - test/haml/results/very_basic.xhtml
215
+ - test/haml/results/eval_suppressed.xhtml
216
+ - test/haml/results/partials.xhtml
217
+ - test/haml/results/render_layout.xhtml
218
+ - test/haml/results/original_engine.xhtml
219
+ - test/haml/results/helpers.xhtml
220
+ - test/haml/results/list.xhtml
221
+ - test/haml/results/partial_layout.xhtml
222
+ - test/haml/results/tag_parsing.xhtml
223
+ - test/haml/markaby/standard.mab
225
224
  - test/haml/engine_test.rb
225
+ - test/linked_rails.rb
226
+ - test/benchmark.rb
226
227
  - test/test_helper.rb
227
- - extra/haml-mode.el
228
228
  - extra/sass-mode.el
229
+ - extra/haml-mode.el
229
230
  - extra/update_watch.rb
230
231
  - Rakefile
231
232
  - init.rb
232
233
  - .yardopts
233
- - VERSION_NAME
234
- - CONTRIBUTING
235
- - README.md
236
- - MIT-LICENSE
237
234
  - VERSION
235
+ - MIT-LICENSE
236
+ - README.md
237
+ - VERSION_NAME
238
238
  - REVISION
239
+ - CONTRIBUTING
239
240
  has_rdoc: true
240
241
  homepage: http://haml.hamptoncatlin.com/
241
242
  licenses: []
@@ -267,19 +268,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
267
268
  requirements: []
268
269
 
269
270
  rubyforge_project: haml
270
- rubygems_version: 1.3.4
271
+ rubygems_version: 1.3.5
271
272
  signing_key:
272
273
  specification_version: 3
273
274
  summary: An elegant, structured XHTML/XML templating engine. Comes with Sass, a similar CSS templating engine.
274
275
  test_files:
275
276
  - test/sass/script_test.rb
276
277
  - test/sass/css2sass_test.rb
278
+ - test/sass/plugin_test.rb
277
279
  - test/sass/functions_test.rb
278
280
  - test/sass/engine_test.rb
279
- - test/sass/plugin_test.rb
280
281
  - test/haml/util_test.rb
281
- - test/haml/spec/ruby_haml_test.rb
282
- - test/haml/html2haml_test.rb
283
282
  - test/haml/template_test.rb
283
+ - test/haml/html2haml_test.rb
284
284
  - test/haml/helper_test.rb
285
+ - test/haml/spec/ruby_haml_test.rb
285
286
  - test/haml/engine_test.rb