public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Fixed that FormTagHelper generates illegal html if name contains e.g. square 
brackets [#1238 state:committed]

Signed-off-by: David Heinemeier Hansson <david@loudthinking.com>
geekq (author)
Tue Nov 04 04:46:36 -0800 2008
dhh (committer)
Tue Nov 04 09:24:52 -0800 2008
commit  5fad229e43e2b2541ed39c6ef571975176e6a8d2
tree    823af789d18ef67d0290fab2531ddf70c7ffe79e
parent  b2cd318c2e3f4d19813a5c62903319a6683aa561
...
1
2
 
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,5 +1,7 @@
0
 *2.2.1 [RC2 or 2.2 final]*
0
 
0
+* Fixed that FormTagHelper generated illegal html if name contained square brackets #1238 [Vladimir Dobriakov]
0
+
0
 * Fix regression bug that made date_select and datetime_select raise a Null Pointer Exception when a nil date/datetime was passed and only month and year were displayed #1289 [Bernardo Padua/Tor Erik]
0
 
0
 * Simplified the logging format for parameters (don't include controller, action, and format as duplicates) [DHH]
...
78
79
80
81
 
82
83
84
...
112
113
114
115
 
116
117
118
...
130
131
132
133
 
134
135
136
...
282
283
284
285
 
286
287
288
...
470
471
472
 
 
 
 
 
 
473
474
475
...
78
79
80
 
81
82
83
84
...
112
113
114
 
115
116
117
118
...
130
131
132
 
133
134
135
136
...
282
283
284
 
285
286
287
288
...
470
471
472
473
474
475
476
477
478
479
480
481
0
@@ -78,7 +78,7 @@ module ActionView
0
       #   #    <option>Paris</option><option>Rome</option></select>
0
       def select_tag(name, option_tags = nil, options = {})
0
         html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
0
-        content_tag :select, option_tags, { "name" => html_name, "id" => name }.update(options.stringify_keys)
0
+        content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
0
       end
0
 
0
       # Creates a standard text field; use these text fields to input smaller chunks of text like a username
0
@@ -112,7 +112,7 @@ module ActionView
0
       #   text_field_tag 'ip', '0.0.0.0', :maxlength => 15, :size => 20, :class => "ip-input"
0
       #   # => <input class="ip-input" id="ip" maxlength="15" name="ip" size="20" type="text" value="0.0.0.0" />
0
       def text_field_tag(name, value = nil, options = {})
0
-        tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
0
+        tag :input, { "type" => "text", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
0
       end
0
 
0
       # Creates a label field
0
@@ -130,7 +130,7 @@ module ActionView
0
       #   label_tag 'name', nil, :class => 'small_label'
0
       #   # => <label for="name" class="small_label">Name</label>
0
       def label_tag(name, text = nil, options = {})
0
-        content_tag :label, text || name.to_s.humanize, { "for" => name }.update(options.stringify_keys)
0
+        content_tag :label, text || name.to_s.humanize, { "for" => sanitize_to_id(name) }.update(options.stringify_keys)
0
       end
0
 
0
       # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or
0
@@ -282,7 +282,7 @@ module ActionView
0
       #   check_box_tag 'eula', 'accepted', false, :disabled => true
0
       #   # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
0
       def check_box_tag(name, value = "1", checked = false, options = {})
0
-        html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
0
+        html_options = { "type" => "checkbox", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
0
         html_options["checked"] = "checked" if checked
0
         tag :input, html_options
0
       end
0
@@ -470,6 +470,12 @@ module ActionView
0
             tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
0
           end
0
         end
0
+
0
+        # see http://www.w3.org/TR/html4/types.html#type-name
0
+        def sanitize_to_id(name)
0
+          name.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "_")
0
+        end
0
+
0
     end
0
   end
0
 end
...
12
13
14
 
 
15
16
17
18
19
20
 
 
 
 
 
21
22
23
...
64
65
66
 
 
 
 
 
67
68
69
...
118
119
120
 
 
 
 
 
121
122
123
...
184
185
186
 
 
 
 
 
187
188
189
...
208
209
210
 
 
 
 
 
211
212
213
214
215
 
216
217
218
...
283
284
285
 
 
 
 
 
 
286
...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
71
72
73
74
75
76
77
78
79
80
81
...
130
131
132
133
134
135
136
137
138
139
140
...
201
202
203
204
205
206
207
208
209
210
211
...
230
231
232
233
234
235
236
237
238
239
240
241
 
242
243
244
245
...
310
311
312
313
314
315
316
317
318
319
0
@@ -12,12 +12,19 @@ class FormTagHelperTest < ActionView::TestCase
0
     @controller = @controller.new
0
   end
0
 
0
+  VALID_HTML_ID = /^[A-Za-z][-_:.A-Za-z0-9]*$/ # see http://www.w3.org/TR/html4/types.html#type-name
0
+
0
   def test_check_box_tag
0
     actual = check_box_tag "admin"
0
     expected = %(<input id="admin" name="admin" type="checkbox" value="1" />)
0
     assert_dom_equal expected, actual
0
   end
0
 
0
+  def test_check_box_tag_id_sanitized
0
+    label_elem = root_elem(check_box_tag("project[2][admin]"))
0
+    assert_match VALID_HTML_ID, label_elem['id']
0
+  end
0
+
0
   def test_form_tag
0
     actual = form_tag
0
     expected = %(<form action="http://www.example.com" method="post">)
0
@@ -64,6 +71,11 @@ class FormTagHelperTest < ActionView::TestCase
0
     assert_dom_equal expected, actual
0
   end
0
 
0
+  def test_hidden_field_tag_id_sanitized
0
+    input_elem = root_elem(hidden_field_tag("item[][title]"))
0
+    assert_match VALID_HTML_ID, input_elem['id']
0
+  end
0
+
0
   def test_file_field_tag
0
     assert_dom_equal "<input name=\"picsplz\" type=\"file\" id=\"picsplz\" />", file_field_tag("picsplz")
0
   end
0
@@ -118,6 +130,11 @@ class FormTagHelperTest < ActionView::TestCase
0
     assert_dom_equal expected, actual
0
   end
0
 
0
+  def test_select_tag_id_sanitized
0
+    input_elem = root_elem(select_tag("project[1]people", "<option>david</option>"))
0
+    assert_match VALID_HTML_ID, input_elem['id']
0
+  end
0
+
0
   def test_text_area_tag_size_string
0
     actual = text_area_tag "body", "hello world", "size" => "20x40"
0
     expected = %(<textarea cols="20" id="body" name="body" rows="40">hello world</textarea>)
0
@@ -184,6 +201,11 @@ class FormTagHelperTest < ActionView::TestCase
0
     assert_dom_equal expected, actual
0
   end
0
 
0
+  def test_text_field_tag_id_sanitized
0
+    input_elem = root_elem(text_field_tag("item[][title]"))
0
+    assert_match VALID_HTML_ID, input_elem['id']
0
+  end
0
+
0
   def test_label_tag_without_text
0
     actual = label_tag "title"
0
     expected = %(<label for="title">Title</label>)
0
@@ -208,11 +230,16 @@ class FormTagHelperTest < ActionView::TestCase
0
     assert_dom_equal expected, actual
0
   end
0
 
0
+  def test_label_tag_id_sanitized
0
+    label_elem = root_elem(label_tag("item[title]"))
0
+    assert_match VALID_HTML_ID, label_elem['for']
0
+  end
0
+
0
   def test_boolean_optios
0
     assert_dom_equal %(<input checked="checked" disabled="disabled" id="admin" name="admin" readonly="readonly" type="checkbox" value="1" />), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes")
0
     assert_dom_equal %(<input checked="checked" id="admin" name="admin" type="checkbox" value="1" />), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil)
0
     assert_dom_equal %(<select id="people" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people", "<option>david</option>", :multiple => true)
0
-    assert_dom_equal %(<select id="people[]" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people[]", "<option>david</option>", :multiple => true)
0
+    assert_dom_equal %(<select id="people_" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people[]", "<option>david</option>", :multiple => true)
0
     assert_dom_equal %(<select id="people" name="people"><option>david</option></select>), select_tag("people", "<option>david</option>", :multiple => nil)
0
   end
0
 
0
@@ -283,4 +310,10 @@ class FormTagHelperTest < ActionView::TestCase
0
   def protect_against_forgery?
0
     false
0
   end
0
+
0
+  private
0
+
0
+  def root_elem(rendered_content)
0
+    HTML::Document.new(rendered_content).root.children[0]
0
+  end
0
 end

Comments