]> Cypherpunks repositories - gostls13.git/commitdiff
html/template: fix crash when escaping incomplete template
authorRob Pike <r@golang.org>
Fri, 20 Mar 2015 17:47:52 +0000 (10:47 -0700)
committerRob Pike <r@golang.org>
Fri, 20 Mar 2015 19:57:45 +0000 (19:57 +0000)
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>
src/html/template/escape_test.go
src/html/template/template.go
src/text/template/exec.go

index ef7b8774845e3fc5e6ba0103c85ec9af9f176ed5..9c9502a617ad558d71593145ed1215eb40f1288d 100644 (file)
@@ -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
index ce6170105cc3d346d2974b522c1d18346e64c2b5..64c0041c9c7fa560a5ae4a08d9bb39cc8f464201 100644 (file)
@@ -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
                }
index faf31e3ede29171991fe1881040e49d3203ac7e1..613a778188b71affbe1951d0a8a9ced7a621bd98 100644 (file)
@@ -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,