Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #5945 -- Treat string literals in template filter arguments as …

…safe

strings for auto-escaping purposes.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@6680 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 0928fa5566bac9404a5a0d1810c2c00ffa81c59f 1 parent 0b0ef3f
Malcolm Tredinnick authored
4  django/template/__init__.py
@@ -594,7 +594,7 @@ def resolve(self, context, ignore_failures=False):
594 594
             arg_vals = []
595 595
             for lookup, arg in args:
596 596
                 if not lookup:
597  
-                    arg_vals.append(arg)
  597
+                    arg_vals.append(mark_safe(arg))
598 598
                 else:
599 599
                     arg_vals.append(arg.resolve(context))
600 600
             if getattr(func, 'needs_autoescape', False):
@@ -707,7 +707,7 @@ def __init__(self, var):
707 707
             # If it's wrapped with quotes (single or double), then
708 708
             # we're also dealing with a literal.
709 709
             if var[0] in "\"'" and var[0] == var[-1]:
710  
-                self.literal = var[1:-1]
  710
+                self.literal = mark_safe(var[1:-1])
711 711
             else:
712 712
                 # Otherwise we'll set self.lookups so that resolve() knows we're
713 713
                 # dealing with a bonafide variable
26  docs/templates.txt
@@ -401,6 +401,32 @@ auto-escaping is on, these extra filters won't change the output -- any
401 401
 variables that use the ``escape`` filter do not have further automatic
402 402
 escaping applied to them.
403 403
 
  404
+String literals and automatic escaping
  405
+--------------------------------------
  406
+
  407
+Sometimes you will pass a string literal as an argument to a filter. For
  408
+example::
  409
+
  410
+    {{ data|default:"This is a string literal." }}
  411
+
  412
+All string literals are inserted **without** any automatic escaping into the
  413
+template, if they are used (it's as if they were all passed through the
  414
+``safe`` filter). The reasoning behind this is that the template author is in
  415
+control of what goes into the string literal, so they can make sure the text
  416
+is correctly escaped when the template is written.
  417
+
  418
+This means you would write ::
  419
+
  420
+    {{ data|default:"3 > 2" }}
  421
+
  422
+...rather than ::
  423
+
  424
+    {{ data|default:"3 > 2" }}  <-- Bad! Don't do this.
  425
+
  426
+This doesn't affect what happens to data coming from the variable itself.
  427
+The variable's contents are still automatically escaped, if necessary, since
  428
+they're beyond the control of the template author.
  429
+
404 430
 Using the built-in reference
405 431
 ============================
406 432
 
9  tests/regressiontests/templates/filters.py
@@ -177,18 +177,17 @@ def get_filter_tests():
177 177
         'filter-unordered_list04': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
178 178
         'filter-unordered_list05': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
179 179
 
180  
-        # If the input to "default" filter is marked as safe, then so is the
181  
-        # output. However, if the default arg is used, auto-escaping kicks in
182  
-        # (if enabled), because we cannot mark the default as safe.
  180
+        # Literal string arguments to the default filter are always treated as
  181
+        # safe strings, regardless of the auto-escaping state.
183 182
         #
184 183
         # Note: we have to use {"a": ""} here, otherwise the invalid template
185 184
         # variable string interferes with the test result.
186  
-        'filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x&lt;"),
  185
+        'filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x<"),
187 186
         'filter-default02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": ""}, "x<"),
188 187
         'filter-default03': ('{{ a|default:"x<" }}', {"a": mark_safe("x>")}, "x>"),
189 188
         'filter-default04': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": mark_safe("x>")}, "x>"),
190 189
 
191  
-        'filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x&lt;"),
  190
+        'filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x<"),
192 191
         'filter-default_if_none02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": None}, "x<"),
193 192
 
194 193
         'filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
13  tests/regressiontests/templates/tests.py
@@ -318,9 +318,9 @@ def get_template_tests(self):
318 318
             # Chained filters, with an argument to the first one
319 319
             'filter-syntax09': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "<b><i>Yes</i></b>"}, "yes"),
320 320
 
321  
-            # Escaped string as argument
  321
+            # Literal string as argument is always "safe" from auto-escaping..
322 322
             'filter-syntax10': (r'{{ var|default_if_none:" endquote\" hah" }}',
323  
-                    {"var": None}, ' endquote&quot; hah'),
  323
+                    {"var": None}, ' endquote" hah'),
324 324
 
325 325
             # Variable as argument
326 326
             'filter-syntax11': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'),
@@ -735,9 +735,10 @@ def get_template_tests(self):
735 735
             'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'),
736 736
 
737 737
             # translation of constant strings
738  
-            'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),
  738
+            'i18n13': ('{{ _("Password") }}', {'LANGUAGE_CODE': 'de'}, 'Passwort'),
739 739
             'i18n14': ('{% cycle "foo" _("Password") _(\'Password\') as c %} {% cycle c %} {% cycle c %}', {'LANGUAGE_CODE': 'de'}, 'foo Passwort Passwort'),
740 740
             'i18n15': ('{{ absent|default:_("Password") }}', {'LANGUAGE_CODE': 'de', 'absent': ""}, 'Passwort'),
  741
+            'i18n16': ('{{ _("<") }}', {'LANGUAGE_CODE': 'de'}, '<'),
741 742
 
742 743
             ### HANDLING OF TEMPLATE_STRING_IF_INVALID ###################################
743 744
 
@@ -885,9 +886,9 @@ def get_template_tests(self):
885 886
             'autoescape-tag06': ("{{ first }}", {"first": mark_safe("<b>first</b>")}, "<b>first</b>"),
886 887
             'autoescape-tag07': ("{% autoescape on %}{{ first }}{% endautoescape %}", {"first": mark_safe(u"<b>Apple</b>")}, u"<b>Apple</b>"),
887 888
 
888  
-            # String arguments to filters, if used in the result, are escaped,
889  
-            # too.
890  
-            'basic-syntax08': (r'{% autoescape on %}{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}', {"var": None}, ' endquote&quot; hah'),
  889
+            # Literal string arguments to filters, if used in the result, are
  890
+            # safe.
  891
+            'basic-syntax08': (r'{% autoescape on %}{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}', {"var": None}, ' endquote" hah'),
891 892
 
892 893
             # The "safe" and "escape" filters cannot work due to internal
893 894
             # implementation details (fortunately, the (no)autoescape block

0 notes on commit 0928fa5

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