Skip to content

Commit 6d0f72f

Browse files
authored
Fix panic in Set Delimiter parsing. (#91)
* Fix panic in Set Delimiter parsing. Mustache supports Set Delimter tags, of the form `{{=<open tag> <close tag>=}}`, which is used to change the delimiters from `{{` and `}}`. Prior to this commit, if there was a sequence that looked like the start of a Set Delimiter tag, but there was not a complete Set Delimiter tag, the library could panic. This commit: * factors out the Set Delimiter tag parsing into a new function, 'parseCustomDelimiter()' * adds checks to make sure an incomplete tag doesn't cause an access off the end of a slice * treats an incomplete Set Delimiter (like `{{=}}`) as a normaal tag This behaviour matches the mustache playground at https://jgonggrijp.gitlab.io/wontache/playground.html. I tried to match the behaviour of the Ruby implementation, but it seems to be inconsistent in this case. * Remove checks that are no inside parseCustomDelimiter() The parse() method contains a check for 'unbalanced' custom delimiter tags (i.e. tags that start with {{=, but don't have a matching closing tag), and throws an error. However, wit the new custom delimiter fix, those tags are treated as normal tags. For example, `{{= %}}` is interpreted as a tag named `= %`, not a malformed custom delimiter tag. This commit removes the extra check that returns an error.
1 parent d50b8fb commit 6d0f72f

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

mustache.go

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -374,15 +374,7 @@ func (tmpl *Template) parseSection(section *sectionElement) error {
374374
}
375375
section.elems = append(section.elems, partial)
376376
case '=':
377-
if tag[len(tag)-1] != '=' {
378-
return newError(tmpl.curline, ErrInvalidMetaTag)
379-
}
380-
tag = strings.TrimSpace(tag[1 : len(tag)-1])
381-
newtags := strings.SplitN(tag, " ", 2)
382-
if len(newtags) == 2 {
383-
tmpl.otag = newtags[0]
384-
tmpl.ctag = newtags[1]
385-
}
377+
tmpl.parseCustomDelimiter(tag)
386378
case '{':
387379
if tag[len(tag)-1] == '}' {
388380
//use a raw tag
@@ -445,15 +437,7 @@ func (tmpl *Template) parse() error {
445437
}
446438
tmpl.elems = append(tmpl.elems, partial)
447439
case '=':
448-
if tag[len(tag)-1] != '=' {
449-
return newError(tmpl.curline, ErrInvalidMetaTag)
450-
}
451-
tag = strings.TrimSpace(tag[1 : len(tag)-1])
452-
newtags := strings.SplitN(tag, " ", 2)
453-
if len(newtags) == 2 {
454-
tmpl.otag = newtags[0]
455-
tmpl.ctag = newtags[1]
456-
}
440+
tmpl.parseCustomDelimiter(tag)
457441
case '{':
458442
//use a raw tag
459443
if tag[len(tag)-1] == '}' {
@@ -469,6 +453,21 @@ func (tmpl *Template) parse() error {
469453
}
470454
}
471455

456+
func (tmpl *Template) parseCustomDelimiter(tag string) {
457+
if len(tag) < 3 || tag[len(tag)-1] != '=' {
458+
tmpl.elems = append(tmpl.elems, &varElement{tag, tmpl.forceRaw})
459+
return
460+
}
461+
trimmedtag := strings.TrimSpace(tag[1 : len(tag)-1])
462+
newtags := strings.SplitN(trimmedtag, " ", 2)
463+
if len(newtags) == 2 {
464+
tmpl.otag = newtags[0]
465+
tmpl.ctag = newtags[1]
466+
} else {
467+
tmpl.elems = append(tmpl.elems, &varElement{tag, tmpl.forceRaw})
468+
}
469+
}
470+
472471
// Evaluate interfaces and pointers looking for a value that can look up the name, via a
473472
// struct field, method, or map key, and return the result of the lookup.
474473
func lookup(contextChain []interface{}, name string, allowMissing bool) (reflect.Value, error) {

mustache_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ var tests = []Test{
9494
{`hello {{! comment }}world`, map[string]string{}, "hello world", nil},
9595
{`{{ a }}{{=<% %>=}}<%b %><%={{ }}=%>{{ c }}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc", nil},
9696
{`{{ a }}{{= <% %> =}}<%b %><%= {{ }}=%>{{c}}`, map[string]string{"a": "a", "b": "b", "c": "c"}, "abc", nil},
97+
// variables that look like malformed custom delimiter tags
98+
{`{{=}}`, map[string]string{"=": "a"}, "a", nil},
99+
{`{{= %}}`, map[string]string{"= %": "a"}, "a", nil},
100+
{`{{==}}`, map[string]string{"==": "a"}, "a", nil},
101+
{`{{= =}}`, map[string]string{"= =": "a"}, "a", nil},
102+
{`{{#A}}{{=}}{{/A}}`, map[string]string{"=": "a"}, "a", nil},
97103

98104
//section tests
99105
{`{{#A}}{{B}}{{/A}}`, Data{true, "hello"}, "hello", nil},

0 commit comments

Comments
 (0)