Anonymous avatar Anonymous committed e524e26

[1.1.X] Fixed #5971 - Fixed inconsistent behaviour of the TokenParser when parsing filters that follow constant strings or variables. Thanks Dmitri Fedortchenko, Adam Vandenberg and Ramiro Morales.

Backport of r12471.

Comments (0)

Files changed (4)

     tt@gurgle.no
     David Tulig <david.tulig@gmail.com>
     Amit Upadhyay <http://www.amitu.com/blog/>
+    Adam Vandenberg
     Geert Vanderkelen
     Vasil Vangelovski
     I.S. van Oostveen <v.oostveen@idca.nl>

django/template/__init__.py

         "A microparser that parses for a value: some string constant or variable name."
         subject = self.subject
         i = self.pointer
+
+        def next_space_index(subject, i):
+            "Increment pointer until a real space (i.e. a space not within quotes) is encountered"
+            while i < len(subject) and subject[i] not in (' ', '\t'):
+                if subject[i] in ('"', "'"):
+                    c = subject[i]
+                    i += 1
+                    while i < len(subject) and subject[i] != c:
+                        i += 1
+                    if i >= len(subject):
+                        raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
+            	i += 1
+            return i
+
         if i >= len(subject):
             raise TemplateSyntaxError("Searching for value. Expected another value but found end of string: %s" % subject)
         if subject[i] in ('"', "'"):
             if i >= len(subject):
                 raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
             i += 1
+
+            # Continue parsing until next "real" space, so that filters are also included
+            i = next_space_index(subject, i)
+
             res = subject[p:i]
             while i < len(subject) and subject[i] in (' ', '\t'):
                 i += 1
             return res
         else:
             p = i
-            while i < len(subject) and subject[i] not in (' ', '\t'):
-                if subject[i] in ('"', "'"):
-                    c = subject[i]
-                    i += 1
-                    while i < len(subject) and subject[i] != c:
-                        i += 1
-                    if i >= len(subject):
-                        raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
-                i += 1
+            i = next_space_index(subject, i)
             s = subject[p:i]
             while i < len(subject) and subject[i] in (' ', '\t'):
                 i += 1

tests/regressiontests/templates/parser.py

 Testing some internals of the template processing. These are *not* examples to be copied in user code.
 """
 
+token_parsing=r"""
+Tests for TokenParser behavior in the face of quoted strings with spaces.
+
+>>> from django.template import TokenParser
+
+
+Test case 1: {% tag thevar|filter sometag %}
+
+>>> p = TokenParser("tag thevar|filter sometag")
+>>> p.tagname
+'tag'
+>>> p.value()
+'thevar|filter'
+>>> p.more()
+True
+>>> p.tag()
+'sometag'
+>>> p.more()
+False
+
+Test case 2: {% tag "a value"|filter sometag %}
+
+>>> p = TokenParser('tag "a value"|filter sometag')
+>>> p.tagname
+'tag'
+>>> p.value()
+'"a value"|filter'
+>>> p.more()
+True
+>>> p.tag()
+'sometag'
+>>> p.more()
+False
+
+Test case 3: {% tag 'a value'|filter sometag %}
+
+>>> p = TokenParser("tag 'a value'|filter sometag")
+>>> p.tagname
+'tag'
+>>> p.value()
+"'a value'|filter"
+>>> p.more()
+True
+>>> p.tag()
+'sometag'
+>>> p.more()
+False
+"""
+
 filter_parsing = r"""
 >>> from django.template import FilterExpression, Parser
 

tests/regressiontests/templates/tests.py

 
 from context import context_tests
 from custom import custom_filters
-from parser import filter_parsing, variable_parsing
+from parser import token_parsing, filter_parsing, variable_parsing
 from unicode import unicode_tests
 
 try:
 __test__ = {
     'unicode': unicode_tests,
     'context': context_tests,
+    'token_parsing': token_parsing,
     'filter_parsing': filter_parsing,
+    'variable_parsing': variable_parsing,
     'custom_filters': custom_filters,
 }
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.