diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-05-23 15:32:27 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-05-23 22:00:34 +0200 |
commit | 6c3c6686f5d3c7155e2d455b07ac8ab70f42cb88 (patch) | |
tree | 666c09383480c74ba69ea7a0442a67029b83a095 /tpl/internal | |
parent | c34bf48560c91c8a2fa106867af7b08a569609b5 (diff) |
Fix Go template script escaping
Fixes #6695
Diffstat (limited to 'tpl/internal')
25 files changed, 1060 insertions, 293 deletions
diff --git a/tpl/internal/go_templates/cfg/cfg.go b/tpl/internal/go_templates/cfg/cfg.go new file mode 100644 index 000000000..bdbe9df3e --- /dev/null +++ b/tpl/internal/go_templates/cfg/cfg.go @@ -0,0 +1,64 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cfg holds configuration shared by the Go command and internal/testenv. +// Definitions that don't need to be exposed outside of cmd/go should be in +// cmd/go/internal/cfg instead of this package. +package cfg + +// KnownEnv is a list of environment variables that affect the operation +// of the Go command. +const KnownEnv = ` + AR + CC + CGO_CFLAGS + CGO_CFLAGS_ALLOW + CGO_CFLAGS_DISALLOW + CGO_CPPFLAGS + CGO_CPPFLAGS_ALLOW + CGO_CPPFLAGS_DISALLOW + CGO_CXXFLAGS + CGO_CXXFLAGS_ALLOW + CGO_CXXFLAGS_DISALLOW + CGO_ENABLED + CGO_FFLAGS + CGO_FFLAGS_ALLOW + CGO_FFLAGS_DISALLOW + CGO_LDFLAGS + CGO_LDFLAGS_ALLOW + CGO_LDFLAGS_DISALLOW + CXX + FC + GCCGO + GO111MODULE + GO386 + GOARCH + GOARM + GOBIN + GOCACHE + GOENV + GOEXE + GOFLAGS + GOGCCFLAGS + GOHOSTARCH + GOHOSTOS + GOINSECURE + GOMIPS + GOMIPS64 + GOMODCACHE + GONOPROXY + GONOSUMDB + GOOS + GOPATH + GOPPC64 + GOPRIVATE + GOPROXY + GOROOT + GOSUMDB + GOTMPDIR + GOTOOLDIR + GOWASM + GO_EXTLINK_ENABLED + PKG_CONFIG +` diff --git a/tpl/internal/go_templates/fmtsort/sort.go b/tpl/internal/go_templates/fmtsort/sort.go index 70a305a3a..b01229bd0 100644 --- a/tpl/internal/go_templates/fmtsort/sort.go +++ b/tpl/internal/go_templates/fmtsort/sort.go @@ -53,12 +53,16 @@ func Sort(mapValue reflect.Value) *SortedMap { if mapValue.Type().Kind() != reflect.Map { return nil } - key := make([]reflect.Value, mapValue.Len()) - value := make([]reflect.Value, len(key)) + // Note: this code is arranged to not panic even in the presence + // of a concurrent map update. The runtime is responsible for + // yelling loudly if that happens. See issue 33275. + n := mapValue.Len() + key := make([]reflect.Value, 0, n) + value := make([]reflect.Value, 0, n) iter := mapValue.MapRange() - for i := 0; iter.Next(); i++ { - key[i] = iter.Key() - value[i] = iter.Value() + for iter.Next() { + key = append(key, iter.Key()) + value = append(value, iter.Value()) } sorted := &SortedMap{ Key: key, diff --git a/tpl/internal/go_templates/fmtsort/sort_test.go b/tpl/internal/go_templates/fmtsort/sort_test.go index 601ec9d25..364c5bf6d 100644 --- a/tpl/internal/go_templates/fmtsort/sort_test.go +++ b/tpl/internal/go_templates/fmtsort/sort_test.go @@ -119,7 +119,7 @@ var sortTests = []sortTest{ "PTR0:0 PTR1:1 PTR2:2", }, { - map[toy]string{toy{7, 2}: "72", toy{7, 1}: "71", toy{3, 4}: "34"}, + map[toy]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"}, "{3 4}:34 {7 1}:71 {7 2}:72", }, { diff --git a/tpl/internal/go_templates/htmltemplate/content_test.go b/tpl/internal/go_templates/htmltemplate/content_test.go index 2a1abfbfb..b5de701d3 100644 --- a/tpl/internal/go_templates/htmltemplate/content_test.go +++ b/tpl/internal/go_templates/htmltemplate/content_test.go @@ -21,7 +21,7 @@ func TestTypedContent(t *testing.T) { htmltemplate.HTML(`Hello, <b>World</b> &tc!`), htmltemplate.HTMLAttr(` dir="ltr"`), htmltemplate.JS(`c && alert("Hello, World!");`), - htmltemplate.JSStr(`Hello, World & O'Reilly\x21`), + htmltemplate.JSStr(`Hello, World & O'Reilly\u0021`), htmltemplate.URL(`greeting=H%69,&addressee=(World)`), htmltemplate.Srcset(`greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`), htmltemplate.URL(`,foo/,`), @@ -73,7 +73,7 @@ func TestTypedContent(t *testing.T) { `Hello, <b>World</b> &tc!`, ` dir="ltr"`, `c && alert("Hello, World!");`, - `Hello, World & O'Reilly\x21`, + `Hello, World & O'Reilly\u0021`, `greeting=H%69,&addressee=(World)`, `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, `,foo/,`, @@ -103,7 +103,7 @@ func TestTypedContent(t *testing.T) { `Hello, World &tc!`, ` dir="ltr"`, `c && alert("Hello, World!");`, - `Hello, World & O'Reilly\x21`, + `Hello, World & O'Reilly\u0021`, `greeting=H%69,&addressee=(World)`, `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, `,foo/,`, @@ -118,7 +118,7 @@ func TestTypedContent(t *testing.T) { `Hello, World &tc!`, ` dir="ltr"`, `c && alert("Hello, World!");`, - `Hello, World & O'Reilly\x21`, + `Hello, World & O'Reilly\u0021`, `greeting=H%69,&addressee=(World)`, `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, `,foo/,`, @@ -133,7 +133,7 @@ func TestTypedContent(t *testing.T) { `Hello, <b>World</b> &tc!`, ` dir="ltr"`, `c && alert("Hello, World!");`, - `Hello, World & O'Reilly\x21`, + `Hello, World & O'Reilly\u0021`, `greeting=H%69,&addressee=(World)`, `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, `,foo/,`, @@ -149,7 +149,7 @@ func TestTypedContent(t *testing.T) { // Not escaped. `c && alert("Hello, World!");`, // Escape sequence not over-escaped. - `"Hello, World & O'Reilly\x21"`, + `"Hello, World & O'Reilly\u0021"`, `"greeting=H%69,\u0026addressee=(World)"`, `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, `",foo/,"`, @@ -165,7 +165,7 @@ func TestTypedContent(t *testing.T) { // Not JS escaped but HTML escaped. `c && alert("Hello, World!");`, // Escape sequence not over-escaped. - `"Hello, World & O'Reilly\x21"`, + `"Hello, World & O'Reilly\u0021"`, `"greeting=H%69,\u0026addressee=(World)"`, `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, `",foo/,"`, @@ -174,30 +174,30 @@ func TestTypedContent(t *testing.T) { { `<script>alert("{{.}}")</script>`, []string{ - `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, - `a[href =~ \x22\/\/example.com\x22]#foo`, - `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, - ` dir=\x22ltr\x22`, - `c \x26\x26 alert(\x22Hello, World!\x22);`, + `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, + `a[href =~ \u0022\/\/example.com\u0022]#foo`, + `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, + ` dir=\u0022ltr\u0022`, + `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, // Escape sequence not over-escaped. - `Hello, World \x26 O\x27Reilly\x21`, - `greeting=H%69,\x26addressee=(World)`, - `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `Hello, World \u0026 O\u0027Reilly\u0021`, + `greeting=H%69,\u0026addressee=(World)`, + `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, `,foo\/,`, }, }, { `<script type="text/javascript">alert("{{.}}")</script>`, []string{ - `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, - `a[href =~ \x22\/\/example.com\x22]#foo`, - `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, - ` dir=\x22ltr\x22`, - `c \x26\x26 alert(\x22Hello, World!\x22);`, + `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, + `a[href =~ \u0022\/\/example.com\u0022]#foo`, + `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, + ` dir=\u0022ltr\u0022`, + `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, // Escape sequence not over-escaped. - `Hello, World \x26 O\x27Reilly\x21`, - `greeting=H%69,\x26addressee=(World)`, - `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `Hello, World \u0026 O\u0027Reilly\u0021`, + `greeting=H%69,\u0026addressee=(World)`, + `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, `,foo\/,`, }, }, @@ -211,7 +211,7 @@ func TestTypedContent(t *testing.T) { // Not escaped. `c && alert("Hello, World!");`, // Escape sequence not over-escaped. - `"Hello, World & O'Reilly\x21"`, + `"Hello, World & O'Reilly\u0021"`, `"greeting=H%69,\u0026addressee=(World)"`, `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`, `",foo/,"`, @@ -227,7 +227,7 @@ func TestTypedContent(t *testing.T) { `Hello, <b>World</b> &tc!`, ` dir="ltr"`, `c && alert("Hello, World!");`, - `Hello, World & O'Reilly\x21`, + `Hello, World & O'Reilly\u0021`, `greeting=H%69,&addressee=(World)`, `greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`, `,foo/,`, @@ -236,15 +236,15 @@ func TestTypedContent(t *testing.T) { { `<button onclick='alert("{{.}}")'>`, []string{ - `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`, - `a[href =~ \x22\/\/example.com\x22]#foo`, - `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`, - ` dir=\x22ltr\x22`, - `c \x26\x26 alert(\x22Hello, World!\x22);`, + `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`, + `a[href =~ \u0022\/\/example.com\u0022]#foo`, + `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`, + ` dir=\u0022ltr\u0022`, + `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`, // Escape sequence not over-escaped. - `Hello, World \x26 O\x27Reilly\x21`, - `greeting=H%69,\x26addressee=(World)`, - `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, + `Hello, World \u0026 O\u0027Reilly\u0021`, + `greeting=H%69,\u0026addressee=(World)`, + `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`, `,foo\/,`, }, }, @@ -256,7 +256,7 @@ func TestTypedContent(t *testing.T) { `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, `%20dir%3d%22ltr%22`, `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, - `Hello%2c%20World%20%26%20O%27Reilly%5cx21`, + `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`, // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done. `greeting=H%69,&addressee=%28World%29`, `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`, @@ -271,7 +271,7 @@ func TestTypedContent(t *testing.T) { `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`, `%20dir%3d%22ltr%22`, `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`, - `Hello%2c%20World%20%26%20O%27Reilly%5cx21`, + `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`, // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done. `greeting=H%69,&addressee=%28World%29`, `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`, diff --git a/tpl/internal/go_templates/htmltemplate/doc.go b/tpl/internal/go_templates/htmltemplate/doc.go index 0a3004a9b..b6a1504f8 100644 --- a/tpl/internal/go_templates/htmltemplate/doc.go +++ b/tpl/internal/go_templates/htmltemplate/doc.go @@ -73,6 +73,51 @@ functions. For these internal escaping functions, if an action pipeline evaluates to a nil interface value, it is treated as though it were an empty string. +Namespaced and data- attributes + +Attributes with a namespace are treated as if they had no namespace. +Given the excerpt + + <a my:href="{{.}}"></a> + +At parse time the attribute will be treated as if it were just "href". +So at parse time the template becomes: + + <a my:href="{{. | urlescaper | attrescaper}}"></a> + +Similarly to attributes with namespaces, attributes with a "data-" prefix are +treated as if they had no "data-" prefix. So given + + <a data-href="{{.}}"></a> + +At parse time this becomes + + <a data-href="{{. | urlescaper | attrescaper}}"></a> + +If an attribute has both a namespace and a "data-" prefix, only the namespace +will be removed when determining the context. For example + + <a my:data-href="{{.}}"></a> + +This is handled as if "my:data-href" was just "data-href" and not "href" as +it would be if the "data-" prefix were to be ignored too. Thus at parse +time this becomes just + + <a my:data-href="{{. | attrescaper}}"></a> + +As a special case, attributes with the namespace "xmlns" are always treated +as containing URLs. Given the excerpts + + <a xmlns:title="{{.}}"></a> + <a xmlns:href="{{.}}"></a> + <a xmlns:onclick="{{.}}"></a> + +At parse time they become: + + <a xmlns:title="{{. | urlescaper | attrescaper}}"></a> + <a xmlns:href="{{. | urlescaper | attrescaper}}"></a> + <a xmlns:onclick="{{. | urlescaper | attrescaper}}"></a> + Errors See the documentation of ErrorCode for details. diff --git a/tpl/internal/go_templates/htmltemplate/escape_test.go b/tpl/internal/go_templates/htmltemplate/escape_test.go index 9e9db7800..075db4e13 100644 --- a/tpl/internal/go_templates/htmltemplate/escape_test.go +++ b/tpl/internal/go_templates/htmltemplate/escape_test.go @@ -242,7 +242,7 @@ func TestEscape(t *testing.T) { { "jsStr", "<button onclick='alert("{{.H}}")'>", - `<button onclick='alert("\x3cHello\x3e")'>`, + `<button onclick='alert("\u003cHello\u003e")'>`, }, { "badMarshaler", @@ -263,7 +263,7 @@ func TestEscape(t *testing.T) { { "jsRe", `<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`, - `<button onclick='alert(/foo\x2bbar/.test(""))'>`, + `<button onclick='alert(/foo\u002bbar/.test(""))'>`, }, { "jsReBlank", @@ -829,7 +829,7 @@ func TestEscapeSet(t *testing.T) { "main": `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`, "helper": `{{11}} of {{"<100>"}}`, }, - `<button onclick="title='11 of \x3c100\x3e'; ...">11 of <100></button>`, + `<button onclick="title='11 of \u003c100\u003e'; ...">11 of <100></button>`, }, // A non-recursive template that ends in a different context. // helper starts in jsCtxRegexp and ends in jsCtxDivOp. diff --git a/tpl/internal/go_templates/htmltemplate/example_test.go b/tpl/internal/go_templates/htmltemplate/example_test.go index a3e7910ee..a93b8d2fb 100644 --- a/tpl/internal/go_templates/htmltemplate/example_test.go +++ b/tpl/internal/go_templates/htmltemplate/example_test.go @@ -119,9 +119,9 @@ func Example_escape() { // "Fran & Freddie's Diner" <tasty@example.com> // "Fran & Freddie's Diner" <tasty@example.com> // "Fran & Freddie's Diner"32<tasty@example.com> - // \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E - // \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E - // \"Fran & Freddie\'s Diner\"32\x3Ctasty@example.com\x3E + // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E + // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E + // \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E } diff --git a/tpl/internal/go_templates/htmltemplate/js.go b/tpl/internal/go_templates/htmltemplate/js.go index 57622d152..cfd413461 100644 --- a/tpl/internal/go_templates/htmltemplate/js.go +++ b/tpl/internal/go_templates/htmltemplate/js.go @@ -164,7 +164,6 @@ func jsValEscaper(args ...interface{}) string { } // TODO: detect cycles before calling Marshal which loops infinitely on // cyclic data. This may be an unacceptable DoS risk. - b, err := json.Marshal(a) if err != nil { // Put a space before comment so that if it is flush against @@ -179,8 +178,8 @@ func jsValEscaper(args ...interface{}) string { // TODO: maybe post-process output to prevent it from containing // "<!--", "-->", "<![CDATA[", "]]>", or "</script" // in case custom marshalers produce output containing those. - - // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output. + // Note: Do not use \x escaping to save bytes because it is not JSON compatible and this escaper + // supports ld+json content-type. if len(b) == 0 { // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should // not cause the output `x=y/*z`. @@ -261,6 +260,8 @@ func replace(s string, replacementTable []string) string { r, w = utf8.DecodeRuneInString(s[i:]) var repl string switch { + case int(r) < len(lowUnicodeReplacementTable): + repl = lowUnicodeReplacementTable[r] case int(r) < len(replacementTable) && replacementTable[r] != "": repl = replacementTable[r] case r == '\u2028': @@ -284,67 +285,80 @@ func replace(s string, replacementTable []string) string { return b.String() } +var lowUnicodeReplacementTable = []string{ + 0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`, + '\a': `\u0007`, + '\b': `\u0008`, + '\t': `\t`, + '\n': `\n`, + '\v': `\u000b`, // "\v" == "v" on IE 6. + '\f': `\f`, + '\r': `\r`, + 0xe: `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`, + 0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`, + 0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`, +} + var jsStrReplacementTable = []string{ - 0: `\0`, + 0: `\u0000`, '\t': `\t`, '\n': `\n`, - '\v': `\x0b`, // "\v" == "v" on IE 6. + '\v': `\u000b`, // "\v" == "v" on IE 6. '\f': `\f`, '\r': `\r`, // Encode HTML specials as hex so the output can be embedded // in HTML attributes without further encoding. - '"': `\x22`, - '&': `\x26`, - '\'': `\x27`, - '+': `\x2b`, + '"': `\u0022`, + '&': `\u0026`, + '\'': `\u0027`, + '+': `\u002b`, '/': `\/`, - '<': `\x3c`, - '>': `\x3e`, + '<': `\u003c`, + '>': `\u003e`, '\\': `\\`, } // jsStrNormReplacementTable is like jsStrReplacementTable but does not // overencode existing escapes since this table has no entry for `\`. var jsStrNormReplacementTable = []string{ - 0: `\0`, + 0: `\u0000`, '\t': `\t`, '\n': `\n`, - '\v': `\x0b`, // "\v" == "v" on IE 6. + '\v': `\u000b`, // "\v" == "v" on IE 6. '\f': `\f`, '\r': `\r`, // Encode HTML specials as hex so the output can be embedded // in HTML attributes without further encoding. - '"': `\x22`, - '&': `\x26`, - '\'': `\x27`, - '+': `\x2b`, + '"': `\u0022`, + '&': `\u0026`, + '\'': `\u0027`, + '+': `\u002b`, '/': `\/`, - '<': `\x3c`, - '>': `\x3e`, + '<': `\u003c`, + '>': `\u003e`, } - var jsRegexpReplacementTable = []string{ - 0: `\0`, + 0: `\u0000`, '\t': `\t`, '\n': `\n`, - '\v': `\x0b`, // "\v" == "v" on IE 6. + '\v': `\u000b`, // "\v" == "v" on IE 6. '\f': `\f`, '\r': `\r`, // Encode HTML specials as hex so the output can be embedded // in HTML attributes without further encoding. - '"': `\x22`, + '"': `\u0022`, '$': `\$`, - '&': `\x26`, - '\'': `\x27`, + '&': `\u0026`, + '\'': `\u0027`, '(': `\(`, ')': `\)`, '*': `\*`, - '+': `\x2b`, + '+': `\u002b`, '-': `\-`, '.': `\.`, '/': `\/`, - '<': `\x3c`, - '>': `\x3e`, + '<': `\u003c`, + '>': `\u003e`, '?': `\?`, '[': `\[`, '\\': `\\`, @@ -384,11 +398,11 @@ func isJSType(mimeType string) bool { // https://tools.ietf.org/html/rfc7231#section-3.1.1 // https://tools.ietf.org/html/rfc4329#section-3 // https://www.ietf.org/rfc/rfc4627.txt - mimeType = strings.ToLower(mimeType) // discard parameters if i := strings.Index(mimeType, ";"); i >= 0 { mimeType = mimeType[:i] } + mimeType = strings.ToLower(mimeType) mimeType = strings.TrimSpace(mimeType) switch mimeType { case diff --git a/tpl/internal/go_templates/htmltemplate/js_test.go b/tpl/internal/go_templates/htmltemplate/js_test.go index 0a6f332a6..e15087f0f 100644 --- a/tpl/internal/go_templates/htmltemplate/js_test.go +++ b/tpl/internal/go_templates/htmltemplate/js_test.go @@ -139,7 +139,7 @@ func TestJSValEscaper(t *testing.T) { {"foo", `"foo"`}, // Newlines. {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, - // "\v" == "v" on IE 6 so use "\x0b" instead. + // "\v" == "v" on IE 6 so use "\u000b" instead. {"\t\x0b", `"\t\u000b"`}, {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, {[]interface{}{}, "[]"}, @@ -175,7 +175,7 @@ func TestJSStrEscaper(t *testing.T) { }{ {"", ``}, {"foo", `foo`}, - {"\u0000", `\0`}, + {"\u0000", `\u0000`}, {"\t", `\t`}, {"\n", `\n`}, {"\r", `\r`}, @@ -185,14 +185,14 @@ func TestJSStrEscaper(t *testing.T) { {"\\n", `\\n`}, {"foo\r\nbar", `foo\r\nbar`}, // Preserve attribute boundaries. - {`"`, `\x22`}, - {`'`, `\x27`}, + {`"`, `\u0022`}, + {`'`, `\u0027`}, // Allow embedding in HTML without further escaping. - {`&`, `\x26amp;`}, + {`&`, `\u0026amp;`}, // Prevent breaking out of text node and element boundaries. - {"</script>", `\x3c\/script\x3e`}, - {"<![CDATA[", `\x3c![CDATA[`}, - {"]]>", `]]\x3e`}, + {"</script>", `\u003c\/script\u003e`}, + {"<![CDATA[", `\u003c![CDATA[`}, + {"]]>", `]]\u003e`}, // https://de |