diff options
Diffstat (limited to 'src/html/template/escape.go')
-rw-r--r-- | src/html/template/escape.go | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/src/html/template/escape.go b/src/html/template/escape.go index 36021c0a8d..ba898b8677 100644 --- a/src/html/template/escape.go +++ b/src/html/template/escape.go @@ -10,6 +10,7 @@ import ( "html" "internal/godebug" "io" + "regexp" "text/template" "text/template/parse" ) @@ -728,6 +729,26 @@ var delimEnds = [...]string{ delimSpaceOrTagEnd: " \t\n\f\r>", } +var ( + // Per WHATWG HTML specification, section 4.12.1.3, there are extremely + // complicated rules for how to handle the set of opening tags <!--, + // <script, and </script when they appear in JS literals (i.e. strings, + // regexs, and comments). The specification suggests a simple solution, + // rather than implementing the arcane ABNF, which involves simply escaping + // the opening bracket with \x3C. We use the below regex for this, since it + // makes doing the case-insensitive find-replace much simpler. + specialScriptTagRE = regexp.MustCompile("(?i)<(script|/script|!--)") + specialScriptTagReplacement = []byte("\\x3C$1") +) + +func containsSpecialScriptTag(s []byte) bool { + return specialScriptTagRE.Match(s) +} + +func escapeSpecialScriptTags(s []byte) []byte { + return specialScriptTagRE.ReplaceAll(s, specialScriptTagReplacement) +} + var doctypeBytes = []byte("<!DOCTYPE") // escapeText escapes a text template node. @@ -786,6 +807,11 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context { b.Write(s[written:cs]) written = i1 } + if isInScriptLiteral(c.state) && containsSpecialScriptTag(s[i:i1]) { + b.Write(s[written:i]) + b.Write(escapeSpecialScriptTags(s[i:i1])) + written = i1 + } if i == i1 && c.state == c1.state { panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:])) } |