summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/allconfig/load.go4
-rw-r--r--config/security/securityConfig.go20
-rw-r--r--config/security/securityConfig_test.go8
-rw-r--r--scripts/fork_go_templates/main.go2
-rw-r--r--tpl/internal/go_templates/fmtsort/sort_test.go10
-rw-r--r--tpl/internal/go_templates/htmltemplate/context.go21
-rw-r--r--tpl/internal/go_templates/htmltemplate/error.go4
-rw-r--r--tpl/internal/go_templates/htmltemplate/escape.go51
-rw-r--r--tpl/internal/go_templates/htmltemplate/escape_test.go151
-rw-r--r--tpl/internal/go_templates/htmltemplate/exec_test.go50
-rw-r--r--tpl/internal/go_templates/htmltemplate/hugo_template.go6
-rw-r--r--tpl/internal/go_templates/htmltemplate/js.go31
-rw-r--r--tpl/internal/go_templates/htmltemplate/state_string.go6
-rw-r--r--tpl/internal/go_templates/htmltemplate/transition.go62
-rw-r--r--tpl/internal/go_templates/testenv/exec.go12
-rw-r--r--tpl/internal/go_templates/testenv/testenv.go18
-rw-r--r--tpl/internal/go_templates/testenv/testenv_notunix.go5
-rw-r--r--tpl/internal/go_templates/testenv/testenv_test.go27
-rw-r--r--tpl/internal/go_templates/testenv/testenv_unix.go25
-rw-r--r--tpl/internal/go_templates/texttemplate/doc.go8
-rw-r--r--tpl/internal/go_templates/texttemplate/exec.go5
-rw-r--r--tpl/internal/go_templates/texttemplate/exec_test.go50
-rw-r--r--tpl/internal/go_templates/texttemplate/funcs.go2
-rw-r--r--tpl/template.go7
-rw-r--r--tpl/tplimpl/integration_test.go22
25 files changed, 417 insertions, 190 deletions
diff --git a/config/allconfig/load.go b/config/allconfig/load.go
index e7dae1806..7d706c7e3 100644
--- a/config/allconfig/load.go
+++ b/config/allconfig/load.go
@@ -34,7 +34,6 @@ import (
hglob "github.com/gohugoio/hugo/hugofs/glob"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/parser/metadecoders"
- "github.com/gohugoio/hugo/tpl"
"github.com/spf13/afero"
)
@@ -91,9 +90,6 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
return nil, fmt.Errorf("failed to init config: %w", err)
}
- // This is unfortunate, but these are global settings.
- tpl.SetSecurityAllowActionJSTmpl(configs.Base.Security.GoTemplates.AllowActionJSTmpl)
-
loggers.InitGlobalLogger(d.Logger.Level(), configs.Base.PanicOnWarning)
return configs, nil
diff --git a/config/security/securityConfig.go b/config/security/securityConfig.go
index 16f8c23d8..e3bffedca 100644
--- a/config/security/securityConfig.go
+++ b/config/security/securityConfig.go
@@ -68,9 +68,6 @@ type Config struct {
// Allow inline shortcodes
EnableInlineShortcodes bool `json:"enableInlineShortcodes"`
-
- // Go templates related security config.
- GoTemplates GoTemplates `json:"goTemplates"`
}
// Exec holds os/exec policies.
@@ -96,15 +93,6 @@ type HTTP struct {
MediaTypes Whitelist `json:"mediaTypes"`
}
-type GoTemplates struct {
-
- // Enable to allow template actions inside bakcticks in ES6 template literals.
- // This was blocked in Hugo 0.114.0 for security reasons and you now get errors on the form
- // "... appears in a JS template literal" if you have this in your templates.
- // See https://github.com/golang/go/issues/59234
- AllowActionJSTmpl bool
-}
-
// ToTOML converts c to TOML with [security] as the root.
func (c Config) ToTOML() string {
sec := c.ToSecurityMap()
@@ -127,7 +115,6 @@ func (c Config) CheckAllowedExec(name string) error {
}
}
return nil
-
}
func (c Config) CheckAllowedGetEnv(name string) error {
@@ -176,7 +163,6 @@ func (c Config) ToSecurityMap() map[string]any {
"security": m,
}
return sec
-
}
// DecodeConfig creates a privacy Config from a given Hugo configuration.
@@ -206,15 +192,14 @@ func DecodeConfig(cfg config.Provider) (Config, error) {
}
return sc, nil
-
}
func stringSliceToWhitelistHook() mapstructure.DecodeHookFuncType {
return func(
f reflect.Type,
t reflect.Type,
- data any) (any, error) {
-
+ data any,
+ ) (any, error) {
if t != reflect.TypeOf(Whitelist{}) {
return data, nil
}
@@ -222,7 +207,6 @@ func stringSliceToWhitelistHook() mapstructure.DecodeHookFuncType {
wl := types.ToStringSlicePreserveString(data)
return NewWhitelist(wl...)
-
}
}
diff --git a/config/security/securityConfig_test.go b/config/security/securityConfig_test.go
index cdfbe6341..3d58288c9 100644
--- a/config/security/securityConfig_test.go
+++ b/config/security/securityConfig_test.go
@@ -53,7 +53,6 @@ getEnv=["a", "b"]
c.Assert(pc.Exec.OsEnv.Accept("e"), qt.IsFalse)
c.Assert(pc.Funcs.Getenv.Accept("a"), qt.IsTrue)
c.Assert(pc.Funcs.Getenv.Accept("c"), qt.IsFalse)
-
})
c.Run("String whitelist", func(c *qt.C) {
@@ -80,7 +79,6 @@ osEnv="b"
c.Assert(pc.Exec.Allow.Accept("d"), qt.IsFalse)
c.Assert(pc.Exec.OsEnv.Accept("b"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("e"), qt.IsFalse)
-
})
c.Run("Default exec.osEnv", func(c *qt.C) {
@@ -105,7 +103,6 @@ allow="a"
c.Assert(pc.Exec.Allow.Accept("a"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("PATH"), qt.IsTrue)
c.Assert(pc.Exec.OsEnv.Accept("e"), qt.IsFalse)
-
})
c.Run("Enable inline shortcodes, legacy", func(c *qt.C) {
@@ -129,9 +126,7 @@ osEnv="b"
pc, err := DecodeConfig(cfg)
c.Assert(err, qt.IsNil)
c.Assert(pc.EnableInlineShortcodes, qt.IsTrue)
-
})
-
}
func TestToTOML(t *testing.T) {
@@ -140,7 +135,7 @@ func TestToTOML(t *testing.T) {
got := DefaultConfig.ToTOML()
c.Assert(got, qt.Equals,
- "[security]\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^(dart-)?sass(-embedded)?$', '^go$', '^npx$', '^postcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.goTemplates]\n AllowActionJSTmpl = false\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['.*']",
+ "[security]\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^(dart-)?sass(-embedded)?$', '^go$', '^npx$', '^postcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['.*']",
)
}
@@ -169,5 +164,4 @@ func TestDecodeConfigDefault(t *testing.T) {
c.Assert(pc.Exec.OsEnv.Accept("a"), qt.IsFalse)
c.Assert(pc.Exec.OsEnv.Accept("e"), qt.IsFalse)
c.Assert(pc.Exec.OsEnv.Accept("MYSECRET"), qt.IsFalse)
-
}
diff --git a/scripts/fork_go_templates/main.go b/scripts/fork_go_templates/main.go
index 4ab89a547..8e14813ec 100644
--- a/scripts/fork_go_templates/main.go
+++ b/scripts/fork_go_templates/main.go
@@ -16,7 +16,7 @@ import (
)
func main() {
- // The current is built with 2c1e5b05fe39fc5e6c730dd60e82946b8e67c6ba, tag: go1.21.1.
+ // The current is built with 446a5dcf5a3230ce9832682d8f521071d8a34a2b (go 1.22 dev. Thu Oct 5 12:20:11 2023 -0700)
fmt.Println("Forking ...")
defer fmt.Println("Done ...")
diff --git a/tpl/internal/go_templates/fmtsort/sort_test.go b/tpl/internal/go_templates/fmtsort/sort_test.go
index 064b09107..fef952fa6 100644
--- a/tpl/internal/go_templates/fmtsort/sort_test.go
+++ b/tpl/internal/go_templates/fmtsort/sort_test.go
@@ -6,13 +6,14 @@ package fmtsort_test
import (
"fmt"
- "github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
"math"
"reflect"
"sort"
"strings"
"testing"
"unsafe"
+
+ "github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
)
var compareTests = [][]reflect.Value{
@@ -38,7 +39,7 @@ var compareTests = [][]reflect.Value{
ct(reflect.TypeOf(chans[0]), chans[0], chans[1], chans[2]),
ct(reflect.TypeOf(toy{}), toy{0, 1}, toy{0, 2}, toy{1, -1}, toy{1, 1}),
ct(reflect.TypeOf([2]int{}), [2]int{1, 1}, [2]int{1, 2}, [2]int{2, 0}),
- ct(reflect.TypeOf(any(any(0))), iFace, 1, 2, 3),
+ ct(reflect.TypeOf(any(0)), iFace, 1, 2, 3),
}
var iFace any
@@ -190,12 +191,15 @@ func sprintKey(key reflect.Value) string {
var (
ints [3]int
chans = makeChans()
+ // pin runtime.Pinner
)
func makeChans() []chan int {
cs := []chan int{make(chan int), make(chan int), make(chan int)}
// Order channels by address. See issue #49431.
- // TODO: pin these pointers once pinning is available (#46787).
+ for i := range cs {
+ reflect.ValueOf(cs[i]).UnsafePointer()
+ }
sort.Slice(cs, func(i, j int) bool {
return uintptr(reflect.ValueOf(cs[i]).UnsafePointer()) < uintptr(reflect.ValueOf(cs[j]).UnsafePointer())
})
diff --git a/tpl/internal/go_templates/htmltemplate/context.go b/tpl/internal/go_templates/htmltemplate/context.go
index 061f17ddb..3acb9bdf0 100644
--- a/tpl/internal/go_templates/htmltemplate/context.go
+++ b/tpl/internal/go_templates/htmltemplate/context.go
@@ -22,10 +22,15 @@ type context struct {
delim delim
urlPart urlPart
jsCtx jsCtx
- attr attr
- element element
- n parse.Node // for range break/continue
- err *Error
+ // jsBraceDepth contains the current depth, for each JS template literal
+ // string interpolation expression, of braces we've seen. This is used to
+ // determine if the next } will close a JS template literal string
+ // interpolation expression or not.
+ jsBraceDepth []int
+ attr attr
+ element element
+ n parse.Node // for range break/continue
+ err *Error
}
func (c context) String() string {
@@ -121,8 +126,8 @@ const (
stateJSDqStr
// stateJSSqStr occurs inside a JavaScript single quoted string.
stateJSSqStr
- // stateJSBqStr occurs inside a JavaScript back quoted string.
- stateJSBqStr
+ // stateJSTmplLit occurs inside a JavaScript back quoted string.
+ stateJSTmplLit
// stateJSRegexp occurs inside a JavaScript regexp literal.
stateJSRegexp
// stateJSBlockCmt occurs inside a JavaScript /* block comment */.
@@ -176,14 +181,14 @@ func isInTag(s state) bool {
}
// isInScriptLiteral returns true if s is one of the literal states within a
-// <script> tag, and as such occurances of "<!--", "<script", and "</script"
+// <script> tag, and as such occurrences of "<!--", "<script", and "</script"
// need to be treated specially.
func isInScriptLiteral(s state) bool {
// Ignore the comment states (stateJSBlockCmt, stateJSLineCmt,
// stateJSHTMLOpenCmt, stateJSHTMLCloseCmt) because their content is already
// omitted from the output.
switch s {
- case stateJSDqStr, stateJSSqStr, stateJSBqStr, stateJSRegexp:
+ case stateJSDqStr, stateJSSqStr, stateJSTmplLit, stateJSRegexp:
return true
}
return false
diff --git a/tpl/internal/go_templates/htmltemplate/error.go b/tpl/internal/go_templates/htmltemplate/error.go
index a4450a4a9..de4b4de1e 100644
--- a/tpl/internal/go_templates/htmltemplate/error.go
+++ b/tpl/internal/go_templates/htmltemplate/error.go
@@ -222,6 +222,10 @@ const (
// Discussion:
// Package html/template does not support actions inside of JS template
// literals.
+ //
+ // Deprecated: ErrJSTemplate is no longer returned when an action is present
+ // in a JS template literal. Actions inside of JS template literals are now
+ // escaped as expected.
ErrJSTemplate
)
diff --git a/tpl/internal/go_templates/htmltemplate/escape.go b/tpl/internal/go_templates/htmltemplate/escape.go
index 5d47a83d3..334bbce0f 100644
--- a/tpl/internal/go_templates/htmltemplate/escape.go
+++ b/tpl/internal/go_templates/htmltemplate/escape.go
@@ -8,8 +8,6 @@ import (
"bytes"
"fmt"
"html"
-
- //"internal/godebug"
"io"
"regexp"
@@ -64,22 +62,23 @@ func evalArgs(args ...any) string {
// funcMap maps command names to functions that render their inputs safe.
var funcMap = template.FuncMap{
- "_html_template_attrescaper": attrEscaper,
- "_html_template_commentescaper": commentEscaper,
- "_html_template_cssescaper": cssEscaper,
- "_html_template_cssvaluefilter": cssValueFilter,
- "_html_template_htmlnamefilter": htmlNameFilter,
- "_html_template_htmlescaper": htmlEscaper,
- "_html_template_jsregexpescaper": jsRegexpEscaper,
- "_html_template_jsstrescaper": jsStrEscaper,
- "_html_template_jsvalescaper": jsValEscaper,
- "_html_template_nospaceescaper": htmlNospaceEscaper,
- "_html_template_rcdataescaper": rcdataEscaper,
- "_html_template_srcsetescaper": srcsetFilterAndEscaper,
- "_html_template_urlescaper": urlEscaper,
- "_html_template_urlfilter": urlFilter,
- "_html_template_urlnormalizer": urlNormalizer,
- "_eval_args_": evalArgs,
+ "_html_template_attrescaper": attrEscaper,
+ "_html_template_commentescaper": commentEscaper,
+ "_html_template_cssescaper": cssEscaper,
+ "_html_template_cssvaluefilter": cssValueFilter,
+ "_html_template_htmlnamefilter": htmlNameFilter,
+ "_html_template_htmlescaper": htmlEscaper,
+ "_html_template_jsregexpescaper": jsRegexpEscaper,
+ "_html_template_jsstrescaper": jsStrEscaper,
+ "_html_template_jstmpllitescaper": jsTmplLitEscaper,
+ "_html_template_jsvalescaper": jsValEscaper,
+ "_html_template_nospaceescaper": htmlNospaceEscaper,
+ "_html_template_rcdataescaper": rcdataEscaper,
+ "_html_template_srcsetescaper": srcsetFilterAndEscaper,
+ "_html_template_urlescaper": urlEscaper,
+ "_html_template_urlfilter": urlFilter,
+ "_html_template_urlnormalizer": urlNormalizer,
+ "_eval_args_": evalArgs,
}
// escaper collects type inferences about templates and changes needed to make
@@ -164,7 +163,6 @@ func (e *escaper) escape(c context, n parse.Node) context {
panic("escaping " + n.String() + " is unimplemented")
}
-// Modified by Hugo.
// var debugAllowActionJSTmpl = godebug.New("jstmpllitinterp")
// escapeAction escapes an action template node.
@@ -230,16 +228,8 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
c.jsCtx = jsCtxDivOp
case stateJSDqStr, stateJSSqStr:
s = append(s, "_html_template_jsstrescaper")
- case stateJSBqStr:
- if SecurityAllowActionJSTmpl.Load() {
- // debugAllowActionJSTmpl.IncNonDefault()
- s = append(s, "_html_template_jsstrescaper")
- } else {
- return context{
- state: stateError,
- err: errorf(ErrJSTemplate, n, n.Line, "%s appears in a JS template literal", n),
- }
- }
+ case stateJSTmplLit:
+ s = append(s, "_html_template_jstmpllitescaper")
case stateJSRegexp:
s = append(s, "_html_template_jsregexpescaper")
case stateCSS:
@@ -398,6 +388,9 @@ var redundantFuncs = map[string]map[string]bool{
"_html_template_jsstrescaper": {
"_html_template_attrescaper": true,
},
+ "_html_template_jstmpllitescaper": {
+ "_html_template_attrescaper": true,
+ },
"_html_template_urlescaper": {
"_html_template_urlnormalizer": true,
},
diff --git a/tpl/internal/go_templates/htmltemplate/escape_test.go b/tpl/internal/go_templates/htmltemplate/escape_test.go
index 4ad5316fb..b202afde0 100644
--- a/tpl/internal/go_templates/htmltemplate/escape_test.go
+++ b/tpl/internal/go_templates/htmltemplate/escape_test.go
@@ -35,14 +35,14 @@ func (x *goodMarshaler) MarshalJSON() ([]byte, error) {
func TestEscape(t *testing.T) {
data := struct {
- F, T bool
- C, G, H string
- A, E []string
- B, M json.Marshaler
- N int
- U any // untyped nil
- Z *int // typed nil
- W htmltemplate.HTML
+ F, T bool
+ C, G, H, I string
+ A, E []string
+ B, M json.Marshaler
+ N int
+ U any // untyped nil
+ Z *int // typed nil
+ W htmltemplate.HTML
}{
F: false,
T: true,
@@ -57,6 +57,7 @@ func TestEscape(t *testing.T) {
U: nil,
Z: nil,
W: htmltemplate.HTML(`&iexcl;<b class="foo">Hello</b>, <textarea>O'World</textarea>!`),
+ I: "${ asd `` }",
}
pdata := &data
@@ -723,6 +724,21 @@ func TestEscape(t *testing.T) {
"<p name=\"{{.U}}\">",
"<p name=\"\">",
},
+ {
+ "JS template lit special characters",
+ "<script>var a = `{{.I}}`</script>",
+ "<script>var a = `\\u0024\\u007b asd \\u0060\\u0060 \\u007d`</script>",
+ },
+ {
+ "JS template lit special characters, nested lit",
+ "<script>var a = `${ `{{.I}}` }`</script>",
+ "<script>var a = `${ `\\u0024\\u007b asd \\u0060\\u0060 \\u007d` }`</script>",
+ },
+ {
+ "JS template lit, nested JS",
+ "<script>var a = `${ var a = \"{{\"a \\\" d\"}}\" }`</script>",
+ "<script>var a = `${ var a = \"a \\u0022 d\" }`</script>",
+ },
}
for _, test := range tests {
@@ -981,6 +997,31 @@ func TestErrors(t *testing.T) {
"<script>var a = `${a+b}`</script>`",
"",
},
+ {
+ "<script>var tmpl = `asd`;</script>",
+ ``,
+ },
+ {
+ "<script>var tmpl = `${1}`;</script>",
+ ``,
+ },
+ {
+ "<script>var tmpl = `${return ``}`;</script>",
+ ``,
+ },
+ {
+ "<script>var tmpl = `${return {{.}} }`;</script>",
+ ``,
+ },
+ {
+ "<script>var tmpl = `${ let a = {1:1} {{.}} }`;</script>",
+ ``,
+ },
+ {
+ "<script>var tmpl = `asd ${return \"{\"}`;</script>",
+ ``,
+ },
+
// Error cases.
{
"{{if .Cond}}<a{{end}}",
@@ -1127,10 +1168,6 @@ func TestErrors(t *testing.T) {
// html is allowed since it is the last command in the pipeline, but urlquery is not.
`predefined escaper "urlquery" disallowed in template`,
},
- {
- "<script>var tmpl = `asd {{.}}`;</script>",
- `{{.}} appears in a JS template literal`,
- },
}
for _, test := range tests {
buf := new(bytes.Buffer)
@@ -1354,7 +1391,7 @@ func TestEscapeText(t *testing.T) {
},
{
"<a onclick=\"`foo",
- context{state: stateJSBqStr, delim: delimDoubleQuote, attr: attrScript},
+ context{state: stateJSTmplLit, delim: delimDoubleQuote, attr: attrScript},
},
{
`<A ONCLICK="'`,
@@ -1696,6 +1733,94 @@ func TestEscapeText(t *testing.T) {
`<svg:a svg:onclick="x()">`,
context{},
},
+ {
+ "<script>var a = `",
+ context{state: stateJSTmplLit, element: elementScript},
+ },
+ {
+ "<script>var a = `${",
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ "<script>var a = `${}",
+ context{state: stateJSTmplLit, element: elementScript},
+ },
+ {
+ "<script>var a = `${`",
+ context{state: stateJSTmplLit, element: elementScript},
+ },
+ {
+ "<script>var a = `${var a = \"",
+ context{state: stateJSDqStr, element: elementScript},
+ },
+ {
+ "<script>var a = `${var a = \"`",
+ context{state: stateJSDqStr, element: elementScript},
+ },
+ {
+ "<script>var a = `${var a = \"}",
+ context{state: stateJSDqStr, element: elementScript},
+ },
+ {
+ "<script>var a = `${``",
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ "<script>var a = `${`}",
+ context{state: stateJSTmplLit, element: elementScript},
+ },
+ {
+ "<script>`${ {} } asd`</script><script>`${ {} }",
+ context{state: stateJSTmplLit, element: elementScript},
+ },
+ {
+ "<script>var foo = `${ (_ => { return \"x\" })() + \"${",
+ context{state: stateJSDqStr, element: elementScript},
+ },
+ {
+ "<script>var a = `${ {</script><script>var b = `${ x }",
+ context{state: stateJSTmplLit, element: elementScript, jsCtx: jsCtxDivOp},
+ },
+ {
+ "<script>var foo = `x` + \"${",
+ context{state: stateJSDqStr, element: elementScript},
+ },
+ {
+ "<script>function f() { var a = `${}`; }",
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ "<script>{`${}`}",
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ "<script>`${ function f() { return `${1}` }() }`",
+ context{state: stateJS, element: elementScript, jsCtx: jsCtxDivOp},
+ },
+ {
+ "<script>function f() {`${ function f() { `${1}` } }`}",
+ context{state: stateJS, element: elementScript, jsCtx: jsCtxDivOp},
+ },
+ {
+ "<script>`${ { `` }",
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ "<script>`${ { }`",
+ context{state: stateJSTmplLit, element: elementScript},
+ },
+ {
+ "<script>var foo = `${ foo({ a: { c: `${",
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ "<script>var foo = `${ foo({ a: { c: `${ {{.}} }` }, b: ",
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ "<script>`${ `}",
+ context{state: stateJSTmplLit, element: elementScript},
+ },
}
for _, test := range tests {
diff --git a/tpl/internal/go_templates/htmltemplate/exec_test.go b/tpl/internal/go_templates/htmltemplate/exec_test.go
index 8f9b893b4..e91aeafa1 100644
--- a/tpl/internal/go_templates/htmltemplate/exec_test.go
+++ b/tpl/internal/go_templates/htmltemplate/exec_test.go
@@ -325,12 +325,16 @@ var execTests = []execTest{
{"$.U.V", "{{$.U.V}}", "v", tVal, true},
{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
{"simple assignment", "{{$x := 2}}{{$x = 3}}{{$x}}", "3", tVal, true},
- {"nested assignment",
+ {
+ "nested assignment",
"{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{$x}}",
- "3", tVal, true},
- {"nested assignment changes the last declaration",
+ "3", tVal, true,
+ },
+ {
+ "nested assignment changes the last declaration",
"{{$x := 1}}{{if true}}{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{end}}{{$x}}",
- "1", tVal, true},
+ "1", tVal, true,
+ },
// Type with String method.
{"V{6666}.String()", "-{{.V0}}-", "-{6666}-", tVal, true}, // NOTE: -<6666>- in text/template
@@ -377,15 +381,21 @@ var execTests = []execTest{
{".Method3(nil constant)", "-{{.Method3 nil}}-", "-Method3: &lt;nil&gt;-", tVal, true},
{".Method3(nil value)", "-{{.Method3 .MXI.unset}}-", "-Method3: &lt;nil&gt;-", tVal, true},
{"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
- {"method on chained var",
+ {
+ "method on chained var",
"{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
- "true", tVal, true},
- {"chained method",
+ "true", tVal, true,
+ },
+ {
+ "chained method",
"{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
- "true", tVal, true},
- {"chained method on variable",
+ "true", tVal, true,
+ },
+ {
+ "chained method on variable",
"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
- "true", tVal, true},
+ "true", tVal, true,
+ },
{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
@@ -471,10 +481,14 @@ var execTests = []execTest{
{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
// HTML.
- {"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
- "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
- {"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
- "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
+ {
+ "html", `{{html "<script>alert(\"XSS\");</script>"}}`,
+ "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true,
+ },
+ {
+ "html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
+ "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true,
+ },
{"html", `{{html .PS}}`, "a string", tVal, true},
{"html typed nil", `{{html .NIL}}`, "&lt;nil&gt;", tVal, true},
{"html untyped nil", `{{html .Empty0}}`, "&lt;nil&gt;", tVal, true}, // NOTE: "&lt;no value&gt;" in text/template
@@ -838,7 +852,7 @@ var delimPairs = []string{
func TestDelims(t *testing.T) {
const hello = "Hello, world"
- var value = struct{ Str string }{hello}
+ value := struct{ Str string }{hello}
for i := 0; i < len(delimPairs); i += 2 {
text := ".Str"
left := delimPairs[i+0]
@@ -861,7 +875,7 @@ func TestDelims(t *testing.T) {
if err != nil {
t.Fatalf("delim %q text %q parse err %s", left, text, err)
}
- var b = new(strings.Builder)
+ b := new(strings.Builder)
err = tmpl.Execute(b, value)
if err != nil {
t.Fatalf("delim %q exec err %s", left, err)
@@ -962,7 +976,7 @@ const treeTemplate = `
`
func TestTree(t *testing.T) {
- var tree = &Tree{
+ tree := &Tree{
1,
&Tree{
2, &Tree{
@@ -1213,7 +1227,7 @@ var cmpTests = []cmpTest{
func TestComparison(t *testing.T) {
b := new(strings.Builder)
- var cmpStruct = struct {
+ cmpStruct := struct {