1
0
mirror of https://github.com/golang/go synced 2024-11-19 21:04:43 -07:00

html/template: handle nils during indirection

Fixes #5982.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12387043
This commit is contained in:
Josh Bleecher Snyder 2013-08-04 08:41:19 +10:00 committed by Rob Pike
parent 67f2ca3530
commit 53d9b6fcf3
2 changed files with 31 additions and 0 deletions

View File

@ -74,6 +74,9 @@ const (
// indirect returns the value, after dereferencing as many times // indirect returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil). // as necessary to reach the base type (or nil).
func indirect(a interface{}) interface{} { func indirect(a interface{}) interface{} {
if a == nil {
return nil
}
if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
// Avoid creating a reflect.Value if it's not a pointer. // Avoid creating a reflect.Value if it's not a pointer.
return a return a
@ -94,6 +97,9 @@ var (
// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
// or error, // or error,
func indirectToStringerOrError(a interface{}) interface{} { func indirectToStringerOrError(a interface{}) interface{} {
if a == nil {
return nil
}
v := reflect.ValueOf(a) v := reflect.ValueOf(a)
for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
v = v.Elem() v = v.Elem()

View File

@ -259,3 +259,28 @@ func TestStringer(t *testing.T) {
t.Errorf("expected %q got %q", expect, b.String()) t.Errorf("expected %q got %q", expect, b.String())
} }
} }
// https://code.google.com/p/go/issues/detail?id=5982
func TestEscapingNilNonemptyInterfaces(t *testing.T) {
tmpl := Must(New("x").Parse("{{.E}}"))
defer func() {
if r := recover(); r != nil {
t.Errorf("panic during template execution: %v", r)
}
}()
got := new(bytes.Buffer)
testData := struct{ E error }{} // any non-empty interface here will do; error is just ready at hand
tmpl.Execute(got, testData)
// Use this data instead of just hard-coding "<nil>" to avoid
// dependencies on the html escaper and the behavior of fmt w.r.t. nil.
want := new(bytes.Buffer)
data := struct{ E string }{E: fmt.Sprint(nil)}
tmpl.Execute(want, data)
if !bytes.Equal(want.Bytes(), got.Bytes()) {
t.Errorf("expected %q got %q", string(want.Bytes()), string(got.Bytes()))
}
}