Skip to content

Commit

Permalink
html/template: fix crash when escaping incomplete template
Browse files Browse the repository at this point in the history
text/template turned this into an error but html/template crashed.
Refactor text/template.Execute to export a new function,
text/template.DefinedTemplates, so html/template can get the same
helpful error message in this case, and invoke it when there is no
definition for a template being escaped.

Fixes #10204.

Change-Id: I1d04e9e7ebca829bc08509caeb65e75da969711f
Reviewed-on: https://go-review.googlesource.com/7855
Reviewed-by: Russ Cox <rsc@golang.org>
  • Loading branch information
robpike committed Mar 20, 2015
1 parent 3f12d27 commit 11dba2e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 14 deletions.
15 changes: 15 additions & 0 deletions src/html/template/escape_test.go
Expand Up @@ -1686,6 +1686,21 @@ func TestPipeToMethodIsEscaped(t *testing.T) {
}
}

// Unlike text/template, html/template crashed if given an incomplete
// template, that is, a template that had been named but not given any content.
// This is issue #10204.
func TestErrorOnUndefined(t *testing.T) {
tmpl := New("undefined")

err := tmpl.Execute(nil, nil)
if err == nil {
t.Error("expected error")
}
if !strings.Contains(err.Error(), "incomplete") {
t.Errorf("expected error about incomplete template; got %s", err)
}
}

func BenchmarkEscapedExecute(b *testing.B) {
tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
var buf bytes.Buffer
Expand Down
3 changes: 3 additions & 0 deletions src/html/template/template.go
Expand Up @@ -56,6 +56,9 @@ func (t *Template) escape() error {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
if t.escapeErr == nil {
if t.Tree == nil {
return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.text.DefinedTemplates())
}
if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
return err
}
Expand Down
39 changes: 25 additions & 14 deletions src/text/template/exec.go
Expand Up @@ -136,24 +136,35 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
}
t.init()
if t.Tree == nil || t.Root == nil {
var b bytes.Buffer
for name, tmpl := range t.tmpl {
if tmpl.Tree == nil || tmpl.Root == nil {
continue
}
if b.Len() > 0 {
b.WriteString(", ")
}
fmt.Fprintf(&b, "%q", name)
state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
}
state.walk(value, t.Root)
return
}

// DefinedTemplates returns a string listing the defined templates,
// prefixed by the string "defined templates are: ". If there are none,
// it returns the empty string. For generating an error message here
// and in html/template.
func (t *Template) DefinedTemplates() string {
if t.common == nil {
return ""
}
var b bytes.Buffer
for name, tmpl := range t.tmpl {
if tmpl.Tree == nil || tmpl.Root == nil {
continue
}
var s string
if b.Len() > 0 {
s = "; defined templates are: " + b.String()
b.WriteString(", ")
}
state.errorf("%q is an incomplete or empty template%s", t.Name(), s)
fmt.Fprintf(&b, "%q", name)
}
state.walk(value, t.Root)
return
var s string
if b.Len() > 0 {
s = "; defined templates are: " + b.String()
}
return s
}

// Walk functions step through the major pieces of the template structure,
Expand Down

0 comments on commit 11dba2e

Please sign in to comment.