diff --git a/src/html/template/css.go b/src/html/template/css.go index 1587af8385..eb92fc92b5 100644 --- a/src/html/template/css.go +++ b/src/html/template/css.go @@ -7,6 +7,7 @@ package template import ( "bytes" "fmt" + "strings" "unicode" "unicode/utf8" ) @@ -156,7 +157,7 @@ func isCSSSpace(b byte) bool { // cssEscaper escapes HTML and CSS special characters using \+ escapes. func cssEscaper(args ...interface{}) string { s, _ := stringify(args...) - var b bytes.Buffer + var b strings.Builder r, w, written := rune(0), 0, 0 for i := 0; i < len(s); i += w { // See comment in htmlEscaper. @@ -168,6 +169,9 @@ func cssEscaper(args ...interface{}) string { default: continue } + if written == 0 { + b.Grow(len(s)) + } b.WriteString(s[written:i]) b.WriteString(repl) written = i + w diff --git a/src/html/template/html.go b/src/html/template/html.go index 2ea5a7d4bc..13a0cd0436 100644 --- a/src/html/template/html.go +++ b/src/html/template/html.go @@ -137,7 +137,7 @@ var htmlNospaceNormReplacementTable = []string{ // htmlReplacer returns s with runes replaced according to replacementTable // and when badRunes is true, certain bad runes are allowed through unescaped. func htmlReplacer(s string, replacementTable []string, badRunes bool) string { - written, b := 0, new(bytes.Buffer) + written, b := 0, new(strings.Builder) r, w := rune(0), 0 for i := 0; i < len(s); i += w { // Cannot use 'for range s' because we need to preserve the width @@ -146,6 +146,9 @@ func htmlReplacer(s string, replacementTable []string, badRunes bool) string { r, w = utf8.DecodeRuneInString(s[i:]) if int(r) < len(replacementTable) { if repl := replacementTable[r]; len(repl) != 0 { + if written == 0 { + b.Grow(len(s)) + } b.WriteString(s[written:i]) b.WriteString(repl) written = i + w @@ -154,6 +157,9 @@ func htmlReplacer(s string, replacementTable []string, badRunes bool) string { // No-op. // IE does not allow these ranges in unquoted attrs. } else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff { + if written == 0 { + b.Grow(len(s)) + } fmt.Fprintf(b, "%s&#x%x;", s[written:i], r) written = i + w } diff --git a/src/html/template/js.go b/src/html/template/js.go index 872f6786b3..04c7c325db 100644 --- a/src/html/template/js.go +++ b/src/html/template/js.go @@ -187,7 +187,7 @@ func jsValEscaper(args ...interface{}) string { } first, _ := utf8.DecodeRune(b) last, _ := utf8.DecodeLastRune(b) - var buf bytes.Buffer + var buf strings.Builder // Prevent IdentifierNames and NumericLiterals from running into // keywords: in, instanceof, typeof, void pad := isJSIdentPart(first) || isJSIdentPart(last) @@ -217,7 +217,7 @@ func jsValEscaper(args ...interface{}) string { if pad { buf.WriteByte(' ') } - b = buf.Bytes() + return buf.String() } return string(b) } @@ -253,7 +253,7 @@ func jsRegexpEscaper(args ...interface{}) string { // It also replaces runes U+2028 and U+2029 with the raw strings `\u2028` and // `\u2029`. func replace(s string, replacementTable []string) string { - var b bytes.Buffer + var b strings.Builder r, w, written := rune(0), 0, 0 for i := 0; i < len(s); i += w { // See comment in htmlEscaper. @@ -269,6 +269,9 @@ func replace(s string, replacementTable []string) string { default: continue } + if written == 0 { + b.Grow(len(s)) + } b.WriteString(s[written:i]) b.WriteString(repl) written = i + w