Commit f6853369 authored by Didier Spezia's avatar Didier Spezia Committed by Rob Pike

html/template: prevent panic when escaping actions involving chain nodes

The current escape code panics when an action involves chain nodes.
Such nodes can be seen in the following situation:

{{ . | AAA.B }} - AAA being a registered function

The above expression is actually valid, because AAA could return a
map containing a B key. The tests in text/template explicitly
demonstrate this case.

Fix allIdents to cover also chain nodes.

While I was investigating this issue, I realized that the tests
introduced in similar CL 9621 were incorrect. Parse errors were
caught as expected, but for the wrong reason. Fixed them as well.
No changes in text/template code itself.

Fixes #10801

Change-Id: Ic9fe43b63669298ca52c3f499e2725dd2bb818a8
Reviewed-on: https://go-review.googlesource.com/10340Reviewed-by: default avatarRob Pike <r@golang.org>
parent ae38ef4c
...@@ -205,13 +205,15 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { ...@@ -205,13 +205,15 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
} }
// allIdents returns the names of the identifiers under the Ident field of the node, // allIdents returns the names of the identifiers under the Ident field of the node,
// which might be a singleton (Identifier) or a slice (Field). // which might be a singleton (Identifier) or a slice (Field or Chain).
func allIdents(node parse.Node) []string { func allIdents(node parse.Node) []string {
switch node := node.(type) { switch node := node.(type) {
case *parse.IdentifierNode: case *parse.IdentifierNode:
return []string{node.Ident} return []string{node.Ident}
case *parse.FieldNode: case *parse.FieldNode:
return node.Ident return node.Ident
case *parse.ChainNode:
return node.Field
} }
panic("unidentified node type in allIdents") panic("unidentified node type in allIdents")
} }
......
...@@ -1557,6 +1557,18 @@ func TestEnsurePipelineContains(t *testing.T) { ...@@ -1557,6 +1557,18 @@ func TestEnsurePipelineContains(t *testing.T) {
".X | urlquery | html | print 2 | .f 3", ".X | urlquery | html | print 2 | .f 3",
[]string{"urlquery", "html"}, []string{"urlquery", "html"},
}, },
{
// covering issue 10801
"{{.X | js.x }}",
".X | js.x | urlquery | html",
[]string{"urlquery", "html"},
},
{
// covering issue 10801
"{{.X | (print 12 | js).x }}",
".X | (print 12 | js).x | urlquery | html",
[]string{"urlquery", "html"},
},
} }
for i, test := range tests { for i, test := range tests {
tmpl := template.Must(template.New("test").Parse(test.input)) tmpl := template.Must(template.New("test").Parse(test.input))
......
...@@ -272,8 +272,8 @@ var parseTests = []parseTest{ ...@@ -272,8 +272,8 @@ var parseTests = []parseTest{
// Wrong pipeline // Wrong pipeline
{"wrong pipeline dot", "{{12|.}}", hasError, ""}, {"wrong pipeline dot", "{{12|.}}", hasError, ""},
{"wrong pipeline number", "{{.|12|printf}}", hasError, ""}, {"wrong pipeline number", "{{.|12|printf}}", hasError, ""},
{"wrong pipeline string", "{{.|print|\"error\"}}", hasError, ""}, {"wrong pipeline string", "{{.|printf|\"error\"}}", hasError, ""},
{"wrong pipeline char", "{{12|print|html|'e'}}", hasError, ""}, {"wrong pipeline char", "{{12|printf|'e'}}", hasError, ""},
{"wrong pipeline boolean", "{{.|true}}", hasError, ""}, {"wrong pipeline boolean", "{{.|true}}", hasError, ""},
{"wrong pipeline nil", "{{'c'|nil}}", hasError, ""}, {"wrong pipeline nil", "{{'c'|nil}}", hasError, ""},
{"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""}, {"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment