Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #5730: Conditionally escape widget contents in newforms to avoid

inadvertent double-escaping. This still isn't perfect behaviour (since it's
unaware of the current context's auto-escaping setting), but that's a larger
problem that needs fixing and this change at least makes the existing
behaviour consistent. Patch from SmileyChris.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@6722 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 1c87a7bb58c24f0ba1b89a9e5776eb24116caa08 1 parent dc71611
Malcolm Tredinnick authored November 28, 2007
17  django/newforms/widgets.py
@@ -11,7 +11,7 @@
11 11
 from itertools import chain
12 12
 
13 13
 from django.utils.datastructures import MultiValueDict
14  
-from django.utils.html import escape
  14
+from django.utils.html import escape, conditional_escape
15 15
 from django.utils.translation import ugettext
16 16
 from django.utils.encoding import StrAndUnicode, force_unicode
17 17
 from django.utils.safestring import mark_safe
@@ -155,7 +155,7 @@ def render(self, name, value, attrs=None):
155 155
         value = force_unicode(value)
156 156
         final_attrs = self.build_attrs(attrs, name=name)
157 157
         return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
158  
-                escape(value)))
  158
+                conditional_escape(force_unicode(value))))
159 159
 
160 160
 class DateTimeInput(Input):
161 161
     input_type = 'text'
@@ -217,7 +217,9 @@ def render(self, name, value, attrs=None, choices=()):
217 217
         for option_value, option_label in chain(self.choices, choices):
218 218
             option_value = force_unicode(option_value)
219 219
             selected_html = (option_value == str_value) and u' selected="selected"' or ''
220  
-            output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
  220
+            output.append(u'<option value="%s"%s>%s</option>' % (
  221
+                    escape(option_value), selected_html,
  222
+                    conditional_escape(force_unicode(option_label))))
221 223
         output.append(u'</select>')
222 224
         return mark_safe(u'\n'.join(output))
223 225
 
@@ -254,7 +256,9 @@ def render(self, name, value, attrs=None, choices=()):
254 256
         for option_value, option_label in chain(self.choices, choices):
255 257
             option_value = force_unicode(option_value)
256 258
             selected_html = (option_value in str_values) and ' selected="selected"' or ''
257  
-            output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
  259
+            output.append(u'<option value="%s"%s>%s</option>' % (
  260
+                    escape(option_value), selected_html,
  261
+                    conditional_escape(force_unicode(option_label))))
258 262
         output.append(u'</select>')
259 263
         return mark_safe(u'\n'.join(output))
260 264
 
@@ -278,7 +282,7 @@ def __init__(self, name, value, attrs, choice, index):
278 282
 
279 283
     def __unicode__(self):
280 284
         return mark_safe(u'<label>%s %s</label>' % (self.tag(),
281  
-                self.choice_label))
  285
+                conditional_escape(force_unicode(self.choice_label))))
282 286
 
283 287
     def is_checked(self):
284 288
         return self.value == self.choice_value
@@ -363,7 +367,8 @@ def render(self, name, value, attrs=None, choices=()):
363 367
             cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
364 368
             option_value = force_unicode(option_value)
365 369
             rendered_cb = cb.render(name, option_value)
366  
-            output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(force_unicode(option_label))))
  370
+            output.append(u'<li><label>%s %s</label></li>' % (rendered_cb,
  371
+                    conditional_escape(force_unicode(option_label))))
367 372
         output.append(u'</ul>')
368 373
         return mark_safe(u'\n'.join(output))
369 374
 
44  tests/regressiontests/forms/widgets.py
@@ -2,6 +2,7 @@
2 2
 tests = r"""
3 3
 >>> from django.newforms import *
4 4
 >>> from django.newforms.widgets import RadioFieldRenderer
  5
+>>> from django.utils.safestring import mark_safe
5 6
 >>> import datetime
6 7
 >>> import time
7 8
 >>> import re
@@ -205,6 +206,8 @@
205 206
 u'<textarea rows="10" cols="40" name="msg">value</textarea>'
206 207
 >>> w.render('msg', 'some "quoted" & ampersanded value')
207 208
 u'<textarea rows="10" cols="40" name="msg">some &quot;quoted&quot; &amp; ampersanded value</textarea>'
  209
+>>> w.render('msg', mark_safe('pre &quot;quoted&quot; value'))
  210
+u'<textarea rows="10" cols="40" name="msg">pre &quot;quoted&quot; value</textarea>'
208 211
 >>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20})
209 212
 u'<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>'
210 213
 
@@ -375,6 +378,17 @@
375 378
 <option value="5">5</option>
376 379
 </select>
377 380
 
  381
+# Choices are escaped correctly
  382
+>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
  383
+<select name="escape">
  384
+<option value="1">1</option>
  385
+<option value="2">2</option>
  386
+<option value="3">3</option>
  387
+<option value="bad">you &amp; me</option>
  388
+<option value="good">you &gt; me</option>
  389
+</select>
  390
+
  391
+# Unicode choices are correctly rendered as HTML
378 392
 >>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
379 393
 u'<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
380 394
 
@@ -538,6 +552,17 @@
538 552
 <option value="5">5</option>
539 553
 </select>
540 554
 
  555
+# Choices are escaped correctly
  556
+>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
  557
+<select multiple="multiple" name="escape">
  558
+<option value="1">1</option>
  559
+<option value="2">2</option>
  560
+<option value="3">3</option>
  561
+<option value="bad">you &amp; me</option>
  562
+<option value="good">you &gt; me</option>
  563
+</select>
  564
+
  565
+# Unicode choices are correctly rendered as HTML
541 566
 >>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
542 567
 u'<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
543 568
 
@@ -692,6 +717,14 @@
692 717
 ...
693 718
 IndexError: list index out of range
694 719
 
  720
+# Choices are escaped correctly
  721
+>>> w = RadioSelect()
  722
+>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
  723
+<ul>
  724
+<li><label><input type="radio" name="escape" value="bad" /> you &amp; me</label></li>
  725
+<li><label><input type="radio" name="escape" value="good" /> you &gt; me</label></li>
  726
+</ul>
  727
+
695 728
 # Unicode choices are correctly rendered as HTML
696 729
 >>> w = RadioSelect()
697 730
 >>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
@@ -821,6 +854,17 @@
821 854
 <li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
822 855
 </ul>
823 856
 
  857
+# Choices are escaped correctly
  858
+>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
  859
+<ul>
  860
+<li><label><input type="checkbox" name="escape" value="1" /> 1</label></li>
  861
+<li><label><input type="checkbox" name="escape" value="2" /> 2</label></li>
  862
+<li><label><input type="checkbox" name="escape" value="3" /> 3</label></li>
  863
+<li><label><input type="checkbox" name="escape" value="bad" /> you &amp; me</label></li>
  864
+<li><label><input type="checkbox" name="escape" value="good" /> you &gt; me</label></li>
  865
+</ul>
  866
+
  867
+# Unicode choices are correctly rendered as HTML
824 868
 >>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
825 869
 u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'
826 870
 

0 notes on commit 1c87a7b

Please sign in to comment.
Something went wrong with that request. Please try again.